commit
c6c885345e
5 changed files with 104 additions and 19 deletions
10
README.md
10
README.md
|
@ -85,10 +85,18 @@ To adjust the search engine default and add/remove search engines, see the [sear
|
||||||
|
|
||||||
Open a URL or search keywords by search engine in new tab.
|
Open a URL or search keywords by search engine in new tab.
|
||||||
|
|
||||||
#### `:q` command
|
#### `:quit` command
|
||||||
|
|
||||||
Close the current tab.
|
Close the current tab.
|
||||||
|
|
||||||
|
#### `:bdelete` command
|
||||||
|
|
||||||
|
Close a certain tab.
|
||||||
|
|
||||||
|
#### `:bdeletes` command
|
||||||
|
|
||||||
|
Close tabs matches with keywords.
|
||||||
|
|
||||||
#### `:winopen` command
|
#### `:winopen` command
|
||||||
|
|
||||||
Open a URL or search keywords by search engine in new window.
|
Open a URL or search keywords by search engine in new window.
|
||||||
|
|
|
@ -68,6 +68,7 @@ const setCommand = (args) => {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// eslint-disable-next-line complexity
|
||||||
const exec = (tab, line, settings) => {
|
const exec = (tab, line, settings) => {
|
||||||
let [name, args] = parsers.parseCommandLine(line);
|
let [name, args] = parsers.parseCommandLine(line);
|
||||||
|
|
||||||
|
@ -84,6 +85,18 @@ const exec = (tab, line, settings) => {
|
||||||
case 'b':
|
case 'b':
|
||||||
case 'buffer':
|
case 'buffer':
|
||||||
return bufferCommand(args);
|
return bufferCommand(args);
|
||||||
|
case 'bd':
|
||||||
|
case 'bdel':
|
||||||
|
case 'bdelete':
|
||||||
|
return tabs.closeTabByKeywords(args.join(' '));
|
||||||
|
case 'bd!':
|
||||||
|
case 'bdel!':
|
||||||
|
case 'bdelete!':
|
||||||
|
return tabs.closeTabByKeywordsForce(args.join(' '));
|
||||||
|
case 'bdeletes':
|
||||||
|
return tabs.closeTabsByKeywords(args.join(' '));
|
||||||
|
case 'bdeletes!':
|
||||||
|
return tabs.closeTabsByKeywordsForce(args.join(' '));
|
||||||
case 'addbookmark':
|
case 'addbookmark':
|
||||||
return addBookmarkCommand(tab, args).then((item) => {
|
return addBookmarkCommand(tab, args).then((item) => {
|
||||||
if (!item) {
|
if (!item) {
|
||||||
|
|
|
@ -65,6 +65,25 @@ const getOpenCompletions = (command, keywords, searchConfig) => {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getBufferCompletions = (command, keywords, excludePinned) => {
|
||||||
|
return tabs.getCompletions(keywords, excludePinned).then((got) => {
|
||||||
|
let items = got.map((tab) => {
|
||||||
|
return {
|
||||||
|
caption: tab.title,
|
||||||
|
content: command + ' ' + tab.title,
|
||||||
|
url: tab.url,
|
||||||
|
icon: tab.favIconUrl
|
||||||
|
};
|
||||||
|
});
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
name: 'Buffers',
|
||||||
|
items: items
|
||||||
|
}
|
||||||
|
];
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const getCompletions = (line, settings) => {
|
const getCompletions = (line, settings) => {
|
||||||
let typedWords = line.trim().split(/ +/);
|
let typedWords = line.trim().split(/ +/);
|
||||||
let typing = '';
|
let typing = '';
|
||||||
|
@ -88,22 +107,17 @@ const getCompletions = (line, settings) => {
|
||||||
return getOpenCompletions(name, keywords, settings.search);
|
return getOpenCompletions(name, keywords, settings.search);
|
||||||
case 'b':
|
case 'b':
|
||||||
case 'buffer':
|
case 'buffer':
|
||||||
return tabs.getCompletions(keywords).then((gotTabs) => {
|
return getBufferCompletions(name, keywords, false);
|
||||||
let items = gotTabs.map((tab) => {
|
case 'bd!':
|
||||||
return {
|
case 'bdel!':
|
||||||
caption: tab.title,
|
case 'bdelete!':
|
||||||
content: name + ' ' + tab.title,
|
case 'bdeletes!':
|
||||||
url: tab.url,
|
return getBufferCompletions(name, keywords, false);
|
||||||
icon: tab.favIconUrl
|
case 'bd':
|
||||||
};
|
case 'bdel':
|
||||||
});
|
case 'bdelete':
|
||||||
return [
|
case 'bdeletes':
|
||||||
{
|
return getBufferCompletions(name, keywords, true);
|
||||||
name: 'Buffers',
|
|
||||||
items: items
|
|
||||||
}
|
|
||||||
];
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
return Promise.resolve([]);
|
return Promise.resolve([]);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
const getCompletions = (keyword) => {
|
const getCompletions = (keyword, excludePinned) => {
|
||||||
return browser.tabs.query({ currentWindow: true }).then((tabs) => {
|
return browser.tabs.query({ currentWindow: true }).then((tabs) => {
|
||||||
let matched = tabs.filter((t) => {
|
let matched = tabs.filter((t) => {
|
||||||
return t.url.includes(keyword) || t.title && t.title.includes(keyword);
|
return t.url.includes(keyword) || t.title && t.title.includes(keyword);
|
||||||
|
}).filter((t) => {
|
||||||
|
return !(excludePinned && t.pinned);
|
||||||
});
|
});
|
||||||
return matched;
|
return matched;
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import * as tabCompletions from './completions/tabs';
|
||||||
|
|
||||||
const closeTab = (id) => {
|
const closeTab = (id) => {
|
||||||
return browser.tabs.get(id).then((tab) => {
|
return browser.tabs.get(id).then((tab) => {
|
||||||
if (!tab.pinned) {
|
if (!tab.pinned) {
|
||||||
|
@ -10,6 +12,50 @@ const closeTabForce = (id) => {
|
||||||
return browser.tabs.remove(id);
|
return browser.tabs.remove(id);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const closeTabByKeywords = (keyword) => {
|
||||||
|
return browser.tabs.query({ currentWindow: true }).then((tabs) => {
|
||||||
|
let matched = tabs.filter((t) => {
|
||||||
|
return t.url.includes(keyword) || t.title.includes(keyword);
|
||||||
|
}).filter(t => !t.pinned);
|
||||||
|
|
||||||
|
if (matched.length === 0) {
|
||||||
|
throw new Error('No matching buffer for ' + keyword);
|
||||||
|
} else if (matched.length > 1) {
|
||||||
|
throw new Error('More than one match for ' + keyword);
|
||||||
|
}
|
||||||
|
browser.tabs.remove(matched[0].id);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const closeTabByKeywordsForce = (keyword) => {
|
||||||
|
return browser.tabs.query({ currentWindow: true }).then((tabs) => {
|
||||||
|
let matched = tabs.filter((t) => {
|
||||||
|
return t.url.includes(keyword) || t.title.includes(keyword);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (matched.length === 0) {
|
||||||
|
throw new Error('No matching buffer for ' + keyword);
|
||||||
|
} else if (matched.length > 1) {
|
||||||
|
throw new Error('More than one match for ' + keyword);
|
||||||
|
}
|
||||||
|
browser.tabs.remove(matched[0].id);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const closeTabsByKeywords = (keyword) => {
|
||||||
|
tabCompletions.getCompletions(keyword).then((tabs) => {
|
||||||
|
let tabs2 = tabs.filter(tab => !tab.pinned);
|
||||||
|
browser.tabs.remove(tabs2.map(tab => tab.id));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const closeTabsByKeywordsForce = (keyword) => {
|
||||||
|
tabCompletions.getCompletions(keyword).then((tabs) => {
|
||||||
|
browser.tabs.remove(tabs.map(tab => tab.id));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const reopenTab = () => {
|
const reopenTab = () => {
|
||||||
return browser.sessions.getRecentlyClosed({
|
return browser.sessions.getRecentlyClosed({
|
||||||
maxResults: 1
|
maxResults: 1
|
||||||
|
@ -119,7 +165,9 @@ const duplicate = (id) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
closeTab, closeTabForce, reopenTab, selectAt, selectByKeyword,
|
closeTab, closeTabForce, closeTabByKeywords, closeTabByKeywordsForce,
|
||||||
|
closeTabsByKeywords, closeTabsByKeywordsForce,
|
||||||
|
reopenTab, selectAt, selectByKeyword,
|
||||||
selectPrevTab, selectNextTab, selectFirstTab,
|
selectPrevTab, selectNextTab, selectFirstTab,
|
||||||
selectLastTab, selectTab, reload, updateTabPinned,
|
selectLastTab, selectTab, reload, updateTabPinned,
|
||||||
toggleTabPinned, duplicate
|
toggleTabPinned, duplicate
|
||||||
|
|
Reference in a new issue