Merge pull request #621 from chocolateboy/tab-close-select-left
Add an option to close the current tab and select the tab to the left
This commit is contained in:
commit
7104f122f9
10 changed files with 174 additions and 120 deletions
212
README.md
212
README.md
|
@ -6,41 +6,43 @@
|
||||||
[](https://circleci.com/gh/ueokande/vim-vixen)
|
[](https://circleci.com/gh/ueokande/vim-vixen)
|
||||||
[](https://david-dm.org/ueokande/vim-vixen?type=dev)
|
[](https://david-dm.org/ueokande/vim-vixen?type=dev)
|
||||||
|
|
||||||
Vim Vixen is a Firefox add-on which allows you to navigate with the keyboard on the browser.
|
Vim Vixen is a Firefox add-on which allows you to easily navigate the web by
|
||||||
Firefox started to support WebExtensions API and will stop supporting add-ons using legacy APIs from version 57.
|
keyboard. Since version 57, Firefox has migrated to the WebExtensions API and
|
||||||
For this reason, many legacy add-ons do not work on Firefox 57.
|
has dropped support for legacy add-ons. Vim Vixen is a new choice for Vim users
|
||||||
Vim Vixen is a new choice for Vim users since Vim Vixen uses the WebExtensions API.
|
since it uses the WebExtensions API.
|
||||||
|
|
||||||
## Basic usage
|
## Basic usage
|
||||||
|
|
||||||
### Key-maps
|
### Keymaps
|
||||||
|
|
||||||
The key-maps are configurable in the add-ons preferences by navigating to `about:addons` and selecting "Extensions".
|
Keymaps are configurable in the add-on's preferences by navigating to `about:addons` and selecting "Extensions".
|
||||||
The default mappings are as follows:
|
The default mappings are as follows:
|
||||||
|
|
||||||
#### Console
|
#### Console
|
||||||
|
|
||||||
- <kbd>:</kbd>: open console
|
- <kbd>:</kbd>: open the console
|
||||||
- <kbd>o</kbd>, <kbd>t</kbd>, <kbd>w</kbd>: open a page in current tab, new tab, or new window
|
- <kbd>o</kbd>, <kbd>t</kbd>, <kbd>w</kbd>: open a page in the current tab, a new tab, or new window
|
||||||
- <kbd>O</kbd>, <kbd>T</kbd>, <kbd>W</kbd>: similar to <kbd>o</kbd>, <kbd>t</kbd>, <kbd>w</kbd>, but that contains current URL
|
- <kbd>O</kbd>, <kbd>T</kbd>, <kbd>W</kbd>: similar to <kbd>o</kbd>, <kbd>t</kbd>, <kbd>w</kbd>, but using the current URL
|
||||||
- <kbd>b</kbd>: Select tabs by URL or title
|
- <kbd>b</kbd>: select tabs by URL or title
|
||||||
- <kbd>a</kbd>: add current page to the bookmarks
|
- <kbd>a</kbd>: add the current page to your bookmarks
|
||||||
|
|
||||||
See [console commands](#console-commands) section for more detailed description
|
See the [console commands](#console-commands) section for a more detailed description.
|
||||||
|
|
||||||
#### Tabs
|
#### Tabs
|
||||||
- <kbd>d</kbd>: delete tab
|
|
||||||
- <kbd>!</kbd><kbd>d</kbd>: delete pinned tab
|
- <kbd>d</kbd>: delete the current tab and select the tab to its right
|
||||||
- <kbd>u</kbd>: reopen close tab
|
- <kbd>D</kbd>: delete the current tab and select the tab to its left
|
||||||
- <kbd>r</kbd>: reload current tab
|
- <kbd>!</kbd><kbd>d</kbd>: delete a pinned tab
|
||||||
- <kbd>R</kbd>: reload current tab without cache
|
- <kbd>u</kbd>: reopen a close tab
|
||||||
- <kbd>K</kbd> or <kbd>g</kbd><kbd>T</kbd>: select previous tab
|
- <kbd>r</kbd>: reload the current tab
|
||||||
- <kbd>J</kbd> or <kbd>g</kbd><kbd>t</kbd>: select next tab
|
- <kbd>R</kbd>: reload the current tab, bypassing the cache
|
||||||
- <kbd>g</kbd><kbd>0</kbd>: select first tab
|
- <kbd>K</kbd> or <kbd>g</kbd><kbd>T</kbd>: select the previous tab
|
||||||
- <kbd>g</kbd><kbd>$</kbd>: select last tab
|
- <kbd>J</kbd> or <kbd>g</kbd><kbd>t</kbd>: select the next tab
|
||||||
- <kbd>Ctrl</kbd>+<kbd>6</kbd>: open previously selected tab
|
- <kbd>g</kbd><kbd>0</kbd>: select the first tab
|
||||||
- <kbd>z</kbd><kbd>p</kbd>: pin tab
|
- <kbd>g</kbd><kbd>$</kbd>: select the last tab
|
||||||
- <kbd>z</kbd><kbd>d</kbd>: duplicate tab
|
- <kbd>Ctrl</kbd>+<kbd>6</kbd>: open the previously-selected tab
|
||||||
|
- <kbd>z</kbd><kbd>p</kbd>: pin the curent tab tab
|
||||||
|
- <kbd>z</kbd><kbd>d</kbd>: duplicate the current tab
|
||||||
|
|
||||||
#### Scrolling
|
#### Scrolling
|
||||||
|
|
||||||
|
@ -48,18 +50,19 @@ See [console commands](#console-commands) section for more detailed description
|
||||||
- <kbd>j</kbd>: scroll down
|
- <kbd>j</kbd>: scroll down
|
||||||
- <kbd>h</kbd>: scroll left
|
- <kbd>h</kbd>: scroll left
|
||||||
- <kbd>l</kbd>: scroll right
|
- <kbd>l</kbd>: scroll right
|
||||||
- <kbd>Ctrl</kbd>+<kbd>U</kbd>: scroll up for a half page
|
- <kbd>Ctrl</kbd>+<kbd>U</kbd>: scroll up half a page
|
||||||
- <kbd>Ctrl</kbd>+<kbd>D</kbd>: scroll down for a half page
|
- <kbd>Ctrl</kbd>+<kbd>D</kbd>: scroll down half a page
|
||||||
- <kbd>Ctrl</kbd>+<kbd>B</kbd>: scroll up for a whole page
|
- <kbd>Ctrl</kbd>+<kbd>B</kbd>: scroll up a page
|
||||||
- <kbd>Ctrl</kbd>+<kbd>F</kbd>: scroll down for a whole page
|
- <kbd>Ctrl</kbd>+<kbd>F</kbd>: scroll down a page
|
||||||
- <kbd>g</kbd><kbd>g</kbd>: scroll to top of a page
|
- <kbd>g</kbd><kbd>g</kbd>: scroll to the top of a page
|
||||||
- <kbd>G</kbd>: scroll to bottom of a page
|
- <kbd>G</kbd>: scroll to the bottom of a page
|
||||||
- <kbd>0</kbd>: scroll to the leftmost part of a page
|
- <kbd>0</kbd>: scroll to the leftmost part of a page
|
||||||
- <kbd>$</kbd>: scroll to the rightmost part of a page
|
- <kbd>$</kbd>: scroll to the rightmost part of a page
|
||||||
- <kbd>m</kbd>: set a mark from current position
|
- <kbd>m</kbd>: set a mark for the current position
|
||||||
- <kbd>'</kbd>: jump to position by the mark
|
- <kbd>'</kbd>: jump to a marked position
|
||||||
|
|
||||||
Lowercase alphabet mark (`[a-z]`) stores position on the current tab. Upper alphabet and numeric mark (`[A-Z0-9]`) stores position and tab.
|
Lowercase marks (`[a-z]`) store the position of the current tab. Uppercase and
|
||||||
|
numeric marks (`[A-Z0-9]`) store the position and the tab.
|
||||||
|
|
||||||
#### Zoom
|
#### Zoom
|
||||||
|
|
||||||
|
@ -69,109 +72,111 @@ Lowercase alphabet mark (`[a-z]`) stores position on the current tab. Upper alph
|
||||||
|
|
||||||
#### Navigation
|
#### Navigation
|
||||||
|
|
||||||
- <kbd>f</kbd>: start following links in the page in the current tab
|
- <kbd>f</kbd>: follow links in the page in the current tab
|
||||||
- <kbd>F</kbd>: start following links in the page in new tabs
|
- <kbd>F</kbd>: follow links in the page in a new tab
|
||||||
- <kbd>H</kbd>: go back in history
|
- <kbd>H</kbd>: go back in history
|
||||||
- <kbd>L</kbd>: go forward in history
|
- <kbd>L</kbd>: go forward in history
|
||||||
- <kbd>[</kbd><kbd>[</kbd>, <kbd>]</kbd><kbd>]</kbd>: find prev or next links and open it
|
- <kbd>[</kbd><kbd>[</kbd>, <kbd>]</kbd><kbd>]</kbd>: find a link to the previous/next page and open it
|
||||||
- <kbd>g</kbd><kbd>u</kbd>: go to parent directory
|
- <kbd>g</kbd><kbd>u</kbd>: go to the parent directory
|
||||||
- <kbd>g</kbd><kbd>U</kbd>: go to root directory
|
- <kbd>g</kbd><kbd>U</kbd>: go to the root directory
|
||||||
- <kbd>g</kbd><kbd>i</kbd>: focus first input
|
- <kbd>g</kbd><kbd>i</kbd>: focus the first input field
|
||||||
|
|
||||||
|
Vim Vixen can be configured to follow links opened in tabs in the background
|
||||||
|
instead of switching to a new tab immediately. To do this, you'll need to update
|
||||||
|
the config file: change the `"background"` property of the `"follow.start"`
|
||||||
|
action to `true`, e.g.:
|
||||||
|
|
||||||
Plugin can be configured to follow links in new tabs in background instead of
|
|
||||||
switching to a new tab immediately. To do this you need to update config file:
|
|
||||||
change `"background"` property of `"follow.start"` action to true:
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"keymaps": {
|
"keymaps": {
|
||||||
"F": { "type": "follow.start", "newTab": true, "background": true },
|
"F": { "type": "follow.start", "newTab": true, "background": true }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Misc
|
#### Misc
|
||||||
|
|
||||||
- <kbd>y</kbd>: copy URL in current tab
|
- <kbd>y</kbd>: copy the URL of the current tab to the clipboard
|
||||||
- <kbd>p</kbd>: open clipboard's URL in current tab
|
- <kbd>p</kbd>: open the clipboard's URL in the current tab
|
||||||
- <kbd>P</kbd>: open clipboard's URL in new tab
|
- <kbd>P</kbd>: open the clipboard's URL in new tab
|
||||||
- <kbd>Shift</kbd>+<kbd>Esc</kbd>: enable or disable the add-on in current tab.
|
- <kbd>Shift</kbd>+<kbd>Esc</kbd>: enable or disable the add-on in the current tab
|
||||||
- <kbd>/</kbd>: start to find a keyword in the page
|
- <kbd>/</kbd>: start searching for text in the page
|
||||||
- <kbd>n</kbd>: find next keyword in the page
|
- <kbd>n</kbd>: find the next search result in the page
|
||||||
- <kbd>N</kbd>: find prev keyword in the page
|
- <kbd>N</kbd>: find the previous search result in the page
|
||||||
- <kbd>g</kbd><kbd>f</kbd>: view page source
|
- <kbd>g</kbd><kbd>f</kbd>: view the source of the current tab
|
||||||
|
|
||||||
### Console commands
|
### Console commands
|
||||||
|
|
||||||
Vim Vixen provides a console for `ex`-style commands similar to Vimperator.
|
Vim Vixen provides a console for `ex`-style commands, similar to Vimperator.
|
||||||
|
|
||||||
Open the console with <kbd>:</kbd>. Or start it with initial values using
|
Open the console with <kbd>:</kbd>. Or populate it with initial values using
|
||||||
<kbd>o</kbd>/<kbd>O</kbd>, <kbd>t</kbd>/<kbd>T</kbd>,
|
<kbd>o</kbd>/<kbd>O</kbd>, <kbd>t</kbd>/<kbd>T</kbd>, or
|
||||||
or <kbd>w</kbd>/<kbd>W</kbd>.
|
<kbd>w</kbd>/<kbd>W</kbd>.
|
||||||
|
|
||||||
#### `:open` command
|
#### `:open`
|
||||||
|
|
||||||
The `:open` command operates two different ways, depending on the parameter.
|
The `:open` command operates two different ways, depending on the parameter.
|
||||||
When the parameter is a URL, that URL is opened in the current tab.
|
When the parameter is a URL, it's opened in the current tab.
|
||||||
|
|
||||||
```
|
```
|
||||||
:open http://github.com/ueokande
|
:open http://github.com/ueokande
|
||||||
```
|
```
|
||||||
|
|
||||||
Otherwise, the current tab will open a search page with the supplied string (defaults to Google).
|
Otherwise, the current tab opens a search page with the supplied string (defaults to Google).
|
||||||
|
|
||||||
```
|
```
|
||||||
:open How to contribute to Vim-Vixen
|
:open How to contribute to Vim-Vixen
|
||||||
```
|
```
|
||||||
|
|
||||||
To use a search engine other than the default, specify which search engine to use as the first parameter.
|
To use a search engine other than the default, specify the search engine to use as the first parameter.
|
||||||
|
|
||||||
```
|
```
|
||||||
:open yahoo How to contribute to Vim-Vixen
|
:open yahoo How to contribute to Vim-Vixen
|
||||||
```
|
```
|
||||||
|
|
||||||
To adjust the search engine default and add/remove search engines, see the [search engines](#search-engines) section.
|
To adjust the default search-engine and add/remove search engines, see the [search engines](#search-engines) section.
|
||||||
|
|
||||||
#### `:tabopen` command
|
#### `:tabopen`
|
||||||
|
|
||||||
Open a URL or search keywords by search engine in new tab.
|
Open a URL or search-engine query in a new tab.
|
||||||
|
|
||||||
#### `:quit` or `:q` command
|
#### `:quit` or `:q`
|
||||||
|
|
||||||
Close the current tab.
|
Close the current tab.
|
||||||
|
|
||||||
#### `:quitall` or `:qa` command
|
#### `:quitall` or `:qa`
|
||||||
|
|
||||||
Close all tabs.
|
Close all tabs.
|
||||||
|
|
||||||
#### `:bdelete` command
|
#### `:bdelete`
|
||||||
|
|
||||||
Close a certain tab.
|
Close a certain tab.
|
||||||
|
|
||||||
You can add `!` at the end of the command to close tab even if it is pinned:
|
You can add `!` to the end of the command to close a tab even if it is pinned:
|
||||||
|
|
||||||
```
|
```
|
||||||
:bdelete!
|
:bdelete!
|
||||||
```
|
```
|
||||||
|
|
||||||
#### `:bdeletes` command
|
#### `:bdeletes`
|
||||||
|
|
||||||
Close tabs matches with keywords.
|
Close tabs matching the specified keywords.
|
||||||
|
|
||||||
You can add `!` at the end of the command to close even pinned tabs:
|
You can add `!` to the end of the command to close pinned tabs:
|
||||||
|
|
||||||
```
|
```
|
||||||
:bdeletes!
|
:bdeletes!
|
||||||
```
|
```
|
||||||
|
|
||||||
#### `:winopen` command
|
#### `:winopen`
|
||||||
|
|
||||||
Open a URL or search keywords by search engine in new window.
|
Open a URL or search-engine query in a new window.
|
||||||
|
|
||||||
#### `:buffer` command
|
#### `:buffer`
|
||||||
|
|
||||||
Select tabs by URL or title matched by keywords.
|
Select tabs by URL or title keywords.
|
||||||
|
|
||||||
#### `:addbookmark` command
|
#### `:addbookmark`
|
||||||
|
|
||||||
Create a bookmark from the current URL.
|
Create a bookmark from the current URL.
|
||||||
|
|
||||||
|
@ -179,20 +184,19 @@ Create a bookmark from the current URL.
|
||||||
:addbookmark My bookmark title
|
:addbookmark My bookmark title
|
||||||
```
|
```
|
||||||
|
|
||||||
The key map <kbd>a</kbd> is a convenient way to create a bookmark from the
|
The keymap <kbd>a</kbd> is a convenient way to create a bookmark for the
|
||||||
current page. That shows `:addbookmark` with a title from the current page into
|
current page. It populates the console with `:addbookmark` and the title of
|
||||||
console.
|
the current page.
|
||||||
|
|
||||||
#### `:set` command
|
#### `:set`
|
||||||
|
|
||||||
`:set` command can temporary override properties using console. See
|
The `:set` command can be used to temporarily override properties in the
|
||||||
[properties](#properties) section for more detailed description of available
|
console. See the [properties](#properties) section for more details on
|
||||||
properties.
|
the available properties.
|
||||||
|
|
||||||
### Properties
|
### Properties
|
||||||
|
|
||||||
Plugin supports configurable properties which can be configured in JSON
|
Vim Vixen can be configured by defining settings in a JSON document, e.g.:
|
||||||
settings:
|
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
|
@ -202,33 +206,35 @@ settings:
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Properties can be temporary overwritten by `:set` command in console.
|
Properties can be temporarily overridden by using the `:set` command in the
|
||||||
|
console.
|
||||||
|
|
||||||
List of available properties you can find below:
|
The following properties are available:
|
||||||
|
|
||||||
#### `smoothscroll` property
|
#### `smoothscroll`
|
||||||
|
|
||||||
Enable/disable smooth scroll.
|
Enable/disable smooth scrolling.
|
||||||
|
|
||||||
```
|
```
|
||||||
:set smoothscroll " enable smooth scroll
|
:set smoothscroll " enable smooth scrolling
|
||||||
:set nosmoothscroll " disable smooth scroll
|
:set nosmoothscroll " disable smooth scrolling
|
||||||
```
|
```
|
||||||
|
|
||||||
#### `hintchars` property
|
#### `hintchars`
|
||||||
|
|
||||||
Set hint characters
|
Set hint characters.
|
||||||
|
|
||||||
```
|
```
|
||||||
:set hintchars=0123456789
|
:set hintchars=0123456789
|
||||||
```
|
```
|
||||||
|
|
||||||
#### `complete` property
|
#### `complete`
|
||||||
|
|
||||||
Set completion items on `open`, `tabopen` `winopen` commands.
|
Set completion items on `open`, `tabopen`, and `winopen` commands.
|
||||||
The allowed value is character sequence of `s`, `b`, or `h`.
|
The allowed value is character sequence of `s`, `b`, or `h`.
|
||||||
Hit <kbd>Tab</kbd> or <kbd>Shift</kbd>+<kbd>Tab</kbd> to Select an item from the completion list.
|
Hit <kbd>Tab</kbd> or <kbd>Shift</kbd>+<kbd>Tab</kbd> to select an item from the completion list.
|
||||||
Each character presents as following:
|
Each character represents the following:
|
||||||
|
|
||||||
- `s`: search engines
|
- `s`: search engines
|
||||||
- `b`: bookmark items
|
- `b`: bookmark items
|
||||||
- `h`: history items.
|
- `h`: history items.
|
||||||
|
@ -239,10 +245,10 @@ Each character presents as following:
|
||||||
|
|
||||||
### Search engines
|
### Search engines
|
||||||
|
|
||||||
Vim Vixen supports search by search engines like Google and Yahoo.
|
Vim Vixen supports searching with search engines such as Google and Yahoo.
|
||||||
|
|
||||||
You can configure search engines, including the default search engine, in the add-ons preferences.
|
You can configure search engines, including the default search engine, in the add-on's preferences.
|
||||||
The URLs specified in `"engines"` must contain a {}-placeholder, which will be
|
The URLs specified in `"engines"` must contain a `{}`-placeholder, which will be
|
||||||
replaced with the search keyword parameters of the command.
|
replaced with the search keyword parameters of the command.
|
||||||
|
|
||||||
```json
|
```json
|
||||||
|
@ -264,7 +270,7 @@ replaced with the search keyword parameters of the command.
|
||||||
### Blacklist
|
### Blacklist
|
||||||
|
|
||||||
The blacklist allows you to disable the plugin for certain pages by URL patterns.
|
The blacklist allows you to disable the plugin for certain pages by URL patterns.
|
||||||
For instance, when you describe `"*.slack.com"`, the plugin is disabled on any Slack rooms.
|
For instance, you could use `"*.slack.com"` to disable the plugin on all Slack channels.
|
||||||
In addition, you can also specify path patterns, such as `"example.com/mail/*"`.
|
In addition, you can also specify path patterns, such as `"example.com/mail/*"`.
|
||||||
|
|
||||||
```json
|
```json
|
||||||
|
@ -279,6 +285,14 @@ In addition, you can also specify path patterns, such as `"example.com/mail/*"`.
|
||||||
You can toggle Vim Vixen between disabled and enabled with
|
You can toggle Vim Vixen between disabled and enabled with
|
||||||
<kbd>shift</kbd>+<kbd>Esc</kbd>.
|
<kbd>shift</kbd>+<kbd>Esc</kbd>.
|
||||||
|
|
||||||
|
## Compatibility
|
||||||
|
|
||||||
|
- Firefox 60 ESR
|
||||||
|
|
||||||
|
## Copyright
|
||||||
|
|
||||||
|
Copyright © 2017-2019 by Shin'ya Ueoka
|
||||||
|
|
||||||
## Licence
|
## Licence
|
||||||
|
|
||||||
MIT
|
MIT
|
||||||
|
|
|
@ -24,7 +24,8 @@ module.exports = {
|
||||||
"G": { "type": "scroll.bottom" },
|
"G": { "type": "scroll.bottom" },
|
||||||
"$": { "type": "scroll.end" },
|
"$": { "type": "scroll.end" },
|
||||||
"d": { "type": "tabs.close" },
|
"d": { "type": "tabs.close" },
|
||||||
"D": { "type": "tabs.close.right" },
|
"D": { "type": "tabs.close", "select": "left" },
|
||||||
|
"x$": { "type": "tabs.close.right" },
|
||||||
"!d": { "type": "tabs.close.force" },
|
"!d": { "type": "tabs.close.force" },
|
||||||
"u": { "type": "tabs.reopen" },
|
"u": { "type": "tabs.reopen" },
|
||||||
"K": { "type": "tabs.prev", "count": 1 },
|
"K": { "type": "tabs.prev", "count": 1 },
|
||||||
|
|
|
@ -55,18 +55,32 @@ describe("tab test", () => {
|
||||||
await browser.windows.remove(win.id);
|
await browser.windows.remove(win.id);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('deletes tab by d', async () => {
|
it('deletes tab and selects right by d', async () => {
|
||||||
|
await browser.tabs.update(tabs[3].id, { active: true });
|
||||||
let body = await session.findElementByCSS('body');
|
let body = await session.findElementByCSS('body');
|
||||||
await body.sendKeys('d');
|
await body.sendKeys('d');
|
||||||
|
|
||||||
let current = await browser.tabs.query({ windowId: win.id });
|
let current = await browser.tabs.query({ windowId: win.id });
|
||||||
assert(current.length === tabs.length - 1);
|
assert(current.length === tabs.length - 1);
|
||||||
|
assert(current[3].active);
|
||||||
|
assert(current[3].url === tabs[4].url);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('deletes tabs to the right by D', async () => {
|
it('deletes tab and selects left by D', async () => {
|
||||||
|
await browser.tabs.update(tabs[3].id, { active: true });
|
||||||
|
let body = await session.findElementByCSS('body');
|
||||||
|
await body.sendKeys(Key.Shift, 'D');
|
||||||
|
|
||||||
|
let current = await browser.tabs.query({ windowId: win.id });
|
||||||
|
assert(current.length === tabs.length - 1);
|
||||||
|
assert(current[2].active);
|
||||||
|
assert(current[2].url === tabs[2].url);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('deletes all tabs to the right by x$', async () => {
|
||||||
await browser.tabs.update(tabs[1].id, { active: true });
|
await browser.tabs.update(tabs[1].id, { active: true });
|
||||||
let body = await session.findElementByCSS('body');
|
let body = await session.findElementByCSS('body');
|
||||||
await body.sendKeys(Key.Shift, 'd');
|
await body.sendKeys('x', '$');
|
||||||
|
|
||||||
let current = await browser.tabs.query({ windowId: win.id });
|
let current = await browser.tabs.query({ windowId: win.id });
|
||||||
assert(current.length === 2);
|
assert(current.length === 2);
|
||||||
|
|
|
@ -32,7 +32,7 @@ export default class OperationController {
|
||||||
doOperation(operation: operations.Operation): Promise<any> {
|
doOperation(operation: operations.Operation): Promise<any> {
|
||||||
switch (operation.type) {
|
switch (operation.type) {
|
||||||
case operations.TAB_CLOSE:
|
case operations.TAB_CLOSE:
|
||||||
return this.tabUseCase.close(false);
|
return this.tabUseCase.close(false, operation.select === 'left');
|
||||||
case operations.TAB_CLOSE_RIGHT:
|
case operations.TAB_CLOSE_RIGHT:
|
||||||
return this.tabUseCase.closeRight();
|
return this.tabUseCase.closeRight();
|
||||||
case operations.TAB_CLOSE_FORCE:
|
case operations.TAB_CLOSE_FORCE:
|
||||||
|
|
|
@ -12,11 +12,15 @@ export default class TabUseCase {
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async close(force: boolean): Promise<any> {
|
async close(force: boolean, selectLeft = false): Promise<any> {
|
||||||
let tab = await this.tabPresenter.getCurrent();
|
let tab = await this.tabPresenter.getCurrent();
|
||||||
if (!force && tab.pinned) {
|
if (!force && tab.pinned) {
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
if (selectLeft && tab.index > 0) {
|
||||||
|
let tabs = await this.tabPresenter.getAll();
|
||||||
|
await this.tabPresenter.select(tabs[tab.index - 1].id as number);
|
||||||
|
}
|
||||||
return this.tabPresenter.remove([tab.id as number]);
|
return this.tabPresenter.remove([tab.id as number]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -90,7 +90,7 @@ class Scroller {
|
||||||
clearTimeout(lastTimeoutId);
|
clearTimeout(lastTimeoutId);
|
||||||
lastTimeoutId = null;
|
lastTimeoutId = null;
|
||||||
}
|
}
|
||||||
lastTimeoutId = setTimeout(resetScrolling, 100);
|
lastTimeoutId = window.setTimeout(resetScrolling, 100);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,11 +18,11 @@ const fields = [
|
||||||
['mark.set.prefix', 'Set mark at current position'],
|
['mark.set.prefix', 'Set mark at current position'],
|
||||||
['mark.jump.prefix', 'Jump to the mark'],
|
['mark.jump.prefix', 'Jump to the mark'],
|
||||||
], [
|
], [
|
||||||
['tabs.close', 'Close a tab'],
|
['tabs.close?{"select":"right"}', 'Close a tab'],
|
||||||
['tabs.close.right', 'Close tabs to the right'],
|
['tabs.close.right', 'Close all tabs to the right'],
|
||||||
['tabs.reopen', 'Reopen closed tab'],
|
['tabs.reopen', 'Reopen closed tab'],
|
||||||
['tabs.next', 'Select next Tab'],
|
['tabs.next', 'Select next tab'],
|
||||||
['tabs.prev', 'Select prev Tab'],
|
['tabs.prev', 'Select prev tab'],
|
||||||
['tabs.first', 'Select first tab'],
|
['tabs.first', 'Select first tab'],
|
||||||
['tabs.last', 'Select last tab'],
|
['tabs.last', 'Select last tab'],
|
||||||
['tabs.reload?{"cache":false}', 'Reload current tab'],
|
['tabs.reload?{"cache":false}', 'Reload current tab'],
|
||||||
|
@ -50,8 +50,8 @@ const fields = [
|
||||||
['command.show', 'Open console'],
|
['command.show', 'Open console'],
|
||||||
['command.show.open?{"alter":false}', 'Open URL'],
|
['command.show.open?{"alter":false}', 'Open URL'],
|
||||||
['command.show.open?{"alter":true}', 'Alter URL'],
|
['command.show.open?{"alter":true}', 'Alter URL'],
|
||||||
['command.show.tabopen?{"alter":false}', 'Open URL in new Tab'],
|
['command.show.tabopen?{"alter":false}', 'Open URL in new tab'],
|
||||||
['command.show.tabopen?{"alter":true}', 'Alter URL in new Tab'],
|
['command.show.tabopen?{"alter":true}', 'Alter URL in new tab'],
|
||||||
['command.show.winopen?{"alter":false}', 'Open URL in new window'],
|
['command.show.winopen?{"alter":false}', 'Open URL in new window'],
|
||||||
['command.show.winopen?{"alter":true}', 'Alter URL in new window'],
|
['command.show.winopen?{"alter":true}', 'Alter URL in new window'],
|
||||||
['command.show.buffer', 'Open buffer command'],
|
['command.show.buffer', 'Open buffer command'],
|
||||||
|
|
|
@ -353,7 +353,8 @@ export const DefaultSettingData: SettingData = SettingData.valueOf({
|
||||||
"G": { "type": "scroll.bottom" },
|
"G": { "type": "scroll.bottom" },
|
||||||
"$": { "type": "scroll.end" },
|
"$": { "type": "scroll.end" },
|
||||||
"d": { "type": "tabs.close" },
|
"d": { "type": "tabs.close" },
|
||||||
"D": { "type": "tabs.close.right" },
|
"D": { "type": "tabs.close", "select": "left" },
|
||||||
|
"x$": { "type": "tabs.close.right" },
|
||||||
"!d": { "type": "tabs.close.force" },
|
"!d": { "type": "tabs.close.force" },
|
||||||
"u": { "type": "tabs.reopen" },
|
"u": { "type": "tabs.reopen" },
|
||||||
"K": { "type": "tabs.prev" },
|
"K": { "type": "tabs.prev" },
|
||||||
|
|
|
@ -146,7 +146,8 @@ export const DefaultSetting: Settings = {
|
||||||
'G': { 'type': 'scroll.bottom' },
|
'G': { 'type': 'scroll.bottom' },
|
||||||
'$': { 'type': 'scroll.end' },
|
'$': { 'type': 'scroll.end' },
|
||||||
'd': { 'type': 'tabs.close' },
|
'd': { 'type': 'tabs.close' },
|
||||||
'D': { 'type': 'tabs.close.right' },
|
'D': { 'type': 'tabs.close', 'select': 'left' },
|
||||||
|
'x$': { 'type': 'tabs.close.right' },
|
||||||
'!d': { 'type': 'tabs.close.force' },
|
'!d': { 'type': 'tabs.close.force' },
|
||||||
'u': { 'type': 'tabs.reopen' },
|
'u': { 'type': 'tabs.reopen' },
|
||||||
'K': { 'type': 'tabs.prev' },
|
'K': { 'type': 'tabs.prev' },
|
||||||
|
|
|
@ -201,6 +201,7 @@ export interface PageHomeOperation {
|
||||||
|
|
||||||
export interface TabCloseOperation {
|
export interface TabCloseOperation {
|
||||||
type: typeof TAB_CLOSE;
|
type: typeof TAB_CLOSE;
|
||||||
|
select?: 'left' | 'right';
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TabCloseForceOperation {
|
export interface TabCloseForceOperation {
|
||||||
|
@ -367,28 +368,41 @@ export type Operation =
|
||||||
const assertOptionalBoolean = (obj: any, name: string) => {
|
const assertOptionalBoolean = (obj: any, name: string) => {
|
||||||
if (Object.prototype.hasOwnProperty.call(obj, name) &&
|
if (Object.prototype.hasOwnProperty.call(obj, name) &&
|
||||||
typeof obj[name] !== 'boolean') {
|
typeof obj[name] !== 'boolean') {
|
||||||
throw new TypeError(`Not a boolean parameter '${name}'`);
|
throw new TypeError(`Not a boolean parameter: '${name}'`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const assertOptionalString = (obj: any, name: string, values?: string[]) => {
|
||||||
|
if (Object.prototype.hasOwnProperty.call(obj, name)) {
|
||||||
|
let value = obj[name];
|
||||||
|
if (typeof value !== 'string') {
|
||||||
|
throw new TypeError(`Not a string parameter: '${name}'`);
|
||||||
|
}
|
||||||
|
if (values && values.length && values.indexOf(value) === -1) {
|
||||||
|
// eslint-disable-next-line max-len
|
||||||
|
throw new TypeError(`Invalid parameter for '${name}': '${value}'`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const assertRequiredNumber = (obj: any, name: string) => {
|
const assertRequiredNumber = (obj: any, name: string) => {
|
||||||
if (!Object.prototype.hasOwnProperty.call(obj, name) ||
|
if (!Object.prototype.hasOwnProperty.call(obj, name) ||
|
||||||
typeof obj[name] !== 'number') {
|
typeof obj[name] !== 'number') {
|
||||||
throw new TypeError(`Missing number parameter '${name}`);
|
throw new TypeError(`Missing number parameter: '${name}`);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const assertRequiredString = (obj: any, name: string) => {
|
const assertRequiredString = (obj: any, name: string) => {
|
||||||
if (!Object.prototype.hasOwnProperty.call(obj, name) ||
|
if (!Object.prototype.hasOwnProperty.call(obj, name) ||
|
||||||
typeof obj[name] !== 'string') {
|
typeof obj[name] !== 'string') {
|
||||||
throw new TypeError(`Missing string parameter '${name}`);
|
throw new TypeError(`Missing string parameter: '${name}`);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// eslint-disable-next-line complexity, max-lines-per-function
|
// eslint-disable-next-line complexity, max-lines-per-function
|
||||||
export const valueOf = (o: any): Operation => {
|
export const valueOf = (o: any): Operation => {
|
||||||
if (!Object.prototype.hasOwnProperty.call(o, 'type')) {
|
if (!Object.prototype.hasOwnProperty.call(o, 'type')) {
|
||||||
throw new TypeError(`missing 'type' field`);
|
throw new TypeError(`Missing 'type' field`);
|
||||||
}
|
}
|
||||||
switch (o.type) {
|
switch (o.type) {
|
||||||
case COMMAND_SHOW_OPEN:
|
case COMMAND_SHOW_OPEN:
|
||||||
|
@ -416,6 +430,12 @@ export const valueOf = (o: any): Operation => {
|
||||||
type: PAGE_HOME,
|
type: PAGE_HOME,
|
||||||
newTab: Boolean(typeof o.newTab === undefined ? false : o.newTab),
|
newTab: Boolean(typeof o.newTab === undefined ? false : o.newTab),
|
||||||
};
|
};
|
||||||
|
case TAB_CLOSE:
|
||||||
|
assertOptionalString(o, 'select', ['left', 'right']);
|
||||||
|
return {
|
||||||
|
type: TAB_CLOSE,
|
||||||
|
select: (typeof o.select === undefined ? 'right' : o.select),
|
||||||
|
};
|
||||||
case TAB_RELOAD:
|
case TAB_RELOAD:
|
||||||
assertOptionalBoolean(o, 'cache');
|
assertOptionalBoolean(o, 'cache');
|
||||||
return {
|
return {
|
||||||
|
@ -458,7 +478,6 @@ export const valueOf = (o: any): Operation => {
|
||||||
case NAVIGATE_ROOT:
|
case NAVIGATE_ROOT:
|
||||||
case FOCUS_INPUT:
|
case FOCUS_INPUT:
|
||||||
case PAGE_SOURCE:
|
case PAGE_SOURCE:
|
||||||
case TAB_CLOSE:
|
|
||||||
case TAB_CLOSE_FORCE:
|
case TAB_CLOSE_FORCE:
|
||||||
case TAB_CLOSE_RIGHT:
|
case TAB_CLOSE_RIGHT:
|
||||||
case TAB_REOPEN:
|
case TAB_REOPEN:
|
||||||
|
@ -483,5 +502,5 @@ export const valueOf = (o: any): Operation => {
|
||||||
case REPEAT_LAST:
|
case REPEAT_LAST:
|
||||||
return { type: o.type };
|
return { type: o.type };
|
||||||
}
|
}
|
||||||
throw new TypeError('unknown operation type: ' + o.type);
|
throw new TypeError('Unknown operation type: ' + o.type);
|
||||||
};
|
};
|
||||||
|
|
Reference in a new issue