Jump and SelectJump/move the cursor to the next or previous occurrence of some typed character or group of characters (in a keybinding). Notable Changes in v0.9.0Can use full regular expressions in Notable Changes in v0.8.0Support for all symbols provided by `vscode.executeDocumentSymbolProvider for the current file's language. All symbols are not supported by each language service. Notable Changes in v0.7.0A command
Example function jump keybinding
Notable Changes in v0.6.0Deprecated : The settings
are all deprecated. They still work in your
Notable Changes in v0.5.0See Using regular expressions in a keybinding.
See the GitHub Discussions to provide input on new features. How It WorksChoose one of your keybindings, say Alt+f to jump forward.
Using
|
| Setting | options | Default |
|---|---|---|
| restrictSearch | document/line | document |
| putCursorForwardJump | beforeCharacter/afterCharacter | beforeCharacter |
| putCursorForwardSelect | beforeCharacter/afterCharacter | afterCharacter |
| putCursorBackwardJump | beforeCharacter/afterCharacter | beforeCharacter |
| putCursorBackwardSelect | beforeCharacter/afterCharacte | beforeCharacter |
restrictSearch
"line" : Move the cursor or select within the current line only
"document : Move the cursor or select within the entire document
putCursorForwardJump: cursor is moving forward or down in the document
"beforeCharacter" : Move the cursor to before the next chosen character
"afterCharacter" : Move the cursor to after the next chosen character
putCursorForwardSelect: cursor and selection is moving forward or down in the document
"beforeCharacter" : Select to before the previous chosen character
"afterCharacter" : Select to after the previous chosen character
putCursorBackwardJump: cursor is moving backward or up in the document
"beforeCharacter" : Move the cursor to before the next chosen character
"afterCharacter" : Move the cursor to after the next chosen character
putCursorBackwardSelect: cursor and selection is moving backward or up in the document
"beforeCharacter" : Select to before the previous chosen character
"afterCharacter" : Select to after the previous chosen character
Examples:
"putCursorForwardJump": "beforeCharacter" if text is |abcde|f jumping forward from a to f would put the cursor before f.
"putCursorForwardJump": "afterCharacter" if text is |abcdef| jumping forward from a to f would put the cursor after f.
Selections will act the same way: either the selection will not include the chosen character (the one you type) or the selection will include that character.
Example of modified settings (in settings.json) after setting the values in the Settings UI (search for "jump"):
"jump-and-select.defaults": {
"putCursorOnForwardSelect": "beforeCharacter",
"putCursorOnBackwardJump": "afterCharacter"
}
- Note:
beforeCharactershould really bebeforeQueryandafterCharactershould beafterQuery. The original names are from a time when you could only input one typed character at a time. But in the keybindingstextargument you can have multiple characters likehowdyorabc\\$or^\\s*?$and the cursor will go before or after that entire query. So think of them asbeforeQueryandafterQuery- which may be a single or multiple characters.
There is a precedence to the option values. Any option set in a keybinding takes precedence over the jump-and-select.defaults setting which takes precedence over the deprecated settings mentioned above.
Extension Commands
jump-and-select.jumpForward: Move to the next occurrence of the character. Alt+fjump-and-select.jumpForwardSelect: Select from the cursor to the next occurrence of the character. Shift+Alt+fjump-and-select.jumpBackward: Move to the previous occurrence of the character. Alt+bjump-and-select.jumpBackwardSelect: Select from the cursor to the previous occurrence of the character. Shift+Alt+bjump-and-select.abortMultiMode: Abort or leavemultiMode- to return to regular text entry. No default keybinding. Appears in the Command Palette (or Keyboard Shortcuts) asJump-Select: Abort MultiModewhenmultimodeis active.
When you trigger one of these commands, you will not see the next character you type - instead that character will trigger a search for that character. A space is considered a character (but oddly tabs are not?), as well as the regular expression characters ^ and $.
jump-and-select.byFunction: Move the cursor to the previous, parent, current or next function top or bottom and optionally select that entrei function. See Function Traversal for more.
Example Keybindings
You can change the default arguments, like restrictSearch/putCursorForwardJump/putCursorBackwardJump/etc , in your Settings UI. Search for jump-and-select and you should see these options.
You can set the command arguments like this in your keybindings.json and these will override the settings defaults for these keybindings:
{
"key": "alt+f", // <== change this to whatever you want
"command": "jump-and-select.jumpForward"
// "when": "editorTextFocus && editorLangId == javascript" // for example
}
{
"key": "alt+r",
"command": "jump-and-select.jumpBackwardSelect",
"args": {
// the args that can be used in a keybinding
"text": "hello", // no default
// "putCursorForwardJump" is used if the command is 'jumpForward' or 'jumpForwardMultiMode'
// "putCursorForwardSelect" is used if the command is 'jumpForwardSelect' or 'jumpForwardSelectMultiMode'
// "putCursorBackwardJump" is used if the command is 'jumpBackward' or 'jumpBackwardMultiMode'
"putCursorBackwardSelect": "beforeCharacter", // or "afterCharacter"
"restrictSearch": "document" // or "line" to search in the current line only
}
}
In this last example, you would use putCursorBackwardSelect and not putCursorForwardSelect because the command jumpBackwardSelect is jumping backward and thus putCursorForwardSelect is an error. For commands that are jumping forward use putCursorForwardJump or putCursorForwardSelect.
For more on using keybindings and macros.
Multimode Commands
What is MultiMode? It means you can trigger the command ONCE and then move/select as many times as you want.
A clickable button appears in the Status Bar to indicate that to exit/stop the command and get back to normal text insertion/deletion you can exit multiMode by hitting the Return (unfortunately Escape will not work). That Status Bar reminder will hide when you do exit the command successfully and reappear the next time you invoke a MultiMode command.
You can also exit multiMode by clicking on the StatusBarItem or by invoking the command Jump-Select: Abort MultiMode (jump-and-select.abortMultiMode) either from a keybinding you set up or through the Command Palette.
jump-and-select.jumpForwardMultiMode: Move to the next occurrence of the character. Alt+m Alt+fjump-and-select.jumpForwardSelectMultiMode: Select from the cursor to the next occurrence of the character. Shift+Alt+m Shift+Alt+fjump-and-select.jumpBackwardMultiMode: Move to the previous occurrence of the character. Alt+m Alt+bjump-and-select.jumpBackwardSelectMultiMode: Select from the cursor to the previous occurrence of the character. Shift+Alt+m Shift+Alt+b
To trigger Alt+m Alt+f you can hold down the Alt key and then hit m and then f and release and MultiMode is running. These are just suggested keybindings, use whatever you want. Think of Alt+m as standing for MultiMode.
Once you are in multiMode you can move the cursor anywhere you want and continue to jump from that new position.
Jumping to Empty Lines / Line Start / Line End while in MultiMode
The built-in type command that MultiMode listens to only fires for actual character insertion, so keys like Tab or Ctrl+Tab never reach it.
But you can bind them directly via the extension's jumpForwardMultiMode / jumpBackwardMultiMode commands, with when context clauses to only fire while a MultiMode session is active. See With no isRegex for what ^, $, and ^$ mean as text values.
While in MultiMode, jumpAndSelect.statusBarItem.visible is true, and jumpAndSelect.multiMode.select tells you whether the active session is a plain MultiMode session (false) or a Select-MultiMode session (true). Pairing both contexts per key means the right command variant runs.
Here's are keybindings for your keybindings.json for:
- Tab = next empty line,
- Shift+Tab = previous empty line,
- Ctrl+Tab = end of line, and
- Ctrl+Shift+Tab = start of line
- each with a plain-move and a Select-MultiMode variant:
// Tab -> next empty line
{
"key": "tab",
"command": "jump-and-select.jumpForwardMultiMode",
"when": "editorTextFocus && jumpAndSelect.statusBarItem.visible && !jumpAndSelect.multiMode.select",
"args": { "text": "^$" }
// "args": { "text": "^\\s*?$" } to also include lines with only whitespace or completely blank
},
{
"key": "tab",
"command": "jump-and-select.jumpForwardSelectMultiMode",
"when": "editorTextFocus && jumpAndSelect.statusBarItem.visible && jumpAndSelect.multiMode.select",
"args": { "text": "^$" }
// "args": { "text": "^\\s*?$" } to also include lines with only whitespace or completely blank
},
// Shift+Tab -> previous empty line
{
"key": "shift+tab",
"command": "jump-and-select.jumpBackwardMultiMode",
"when": "editorTextFocus && jumpAndSelect.statusBarItem.visible && !jumpAndSelect.multiMode.select",
"args": { "text": "^$" }
// "args": { "text": "^\\s*?$" } to also include lines with only whitespace or completely blank
},
{
"key": "shift+tab",
"command": "jump-and-select.jumpBackwardSelectMultiMode",
"when": "editorTextFocus && jumpAndSelect.statusBarItem.visible && jumpAndSelect.multiMode.select",
"args": { "text": "^$" }
// "args": { "text": "^\\s*?$" } to also include lines with only whitespace or completely blank
},
// Ctrl+Tab -> end of line
{
"key": "ctrl+tab",
"command": "jump-and-select.jumpForwardMultiMode",
"when": "editorTextFocus && jumpAndSelect.statusBarItem.visible && !jumpAndSelect.multiMode.select",
"args": { "text": "$" }
},
{
"key": "ctrl+tab",
"command": "jump-and-select.jumpForwardSelectMultiMode",
"when": "editorTextFocus && jumpAndSelect.statusBarItem.visible && jumpAndSelect.multiMode.select",
"args": { "text": "$" }
},
// Ctrl+Shift+Tab -> start of line
{
"key": "ctrl+shift+tab",
"command": "jump-and-select.jumpBackwardMultiMode",
"when": "editorTextFocus && jumpAndSelect.statusBarItem.visible && !jumpAndSelect.multiMode.select",
"args": { "text": "^" }
},
{
"key": "ctrl+shift+tab",
"command": "jump-and-select.jumpBackwardSelectMultiMode",
"when": "editorTextFocus && jumpAndSelect.statusBarItem.visible && jumpAndSelect.multiMode.select",
"args": { "text": "^" }
}
These aren't bound by default - Tab and Ctrl+Tab are heavily overloaded elsewhere in VS Code, so this is opt-in. Because every when clause requires jumpAndSelect.statusBarItem.visible, none of this affects Tab or Ctrl+Tab outside of an active MultiMode session.
Expanding the Selection
If you already have a selection or create one with one of the 'Select' commands (jumpForwardSelect, jumpForwardSelectMultiMode, jumpBackwardSelect, or jumpBackwardSelectMultiMode) and do another 'select' command that pre-existing selection will be expanded.
The selection can be expanded forward with either the jumpForwardSelect or jumpForwardSelectMultiMode command.
The selection can be expanded backward with either the jumpBackwardSelect or jumpBackwardSelectMultiMode command.
This can be done either by triggering the default commands or by triggering a keybinding.
The below demo shows creating a backwards selection to the ( and then a forwards expansion of that selection to the ).
Here is a single keybinding combining the two operations from above.
{
"key": "alt+t",
"command": "runCommands",
"args": {
"commands": [
{
"command": "jump-and-select.jumpBackwardSelect",
"args": {
"text": "(",
"putCursorBackwardSelect": "afterCharacter"
}
},
{
"command": "jump-and-select.jumpForwardSelect",
"args": {
"text": ")",
"putCursorForwardSelect": "beforeCharacter"
}
}
]
},
// "when": "editorTextFocus && !editorReadonly && editorLangId == rust"
// "when": "editorTextFocus && !editorReadonly && resourceExtname =~ /\\.(js|ts)/"
}
Another example, using a combination of jump-and-select.jumpBackwardSelectMultiMode and then this keybinding:
{
"key": "alt+p",
"command": "jump-and-select.jumpForwardSelect",
"args": {
"text": "^$" // select to next empty line
},
}
Selecting only the match with select
By default, when using one of the ...Select commands, the selection is "extended": the anchor stays where it was and only the active end moves to the match, so everything between the old and new position gets selected. This is "select": "extends", the default. Set "select": "match" to select only the matched text itself instead:
{
"key": "shift+alt+r",
"command": "jump-and-select.jumpForwardSelect",
"args": {
"text": "^${selectedText}(?:(?=\\w))",
"isRegex": true,
"select": "match" // or "extends"
}
}
With "select": "match", the resulting selection covers exactly the matched text, not the span from your original cursor position to the match. putCursorOnForwardSelect/putCursorOnBackwardSelect still control which end of the match the cursor lands on (active) - only where the other end (anchor) comes from changes, from "your original position" to "the other edge of the match". The select option works with both literal and isRegex: true searches, and with ${selectedText} per selection when using multiple cursors. It's only available on the ...Select commands (jumpForwardSelect, jumpBackwardSelect, and their MultiMode variants).
${selectedText}
text may contain the literal template ${selectedText}, which is replaced per selection with that selection's currently highlighted text before matching. With multiple cursors, each selection can have different selected text, so each cursor searches for its own selection's text. This works whether or not isRegex is set - for example, without isRegex, "text": "${selectedText}" jumps to the next literal occurrence of whatever you have selected.
Using regular expressions in a keybinding
Full regular expressions with isRegex
The ^, $, and ^$ patterns above are the only regular expressions evaluated by default. To use a full regular expression in text, add "isRegex": true to the keybinding's args:
{
"key": "alt+r",
"command": "jump-and-select.jumpForward",
"args": {
"text": "^${selectedText}(?:(?=\\w))",
"isRegex": true
// "restrictSearch": "document",
}
}
With isRegex: true:
textis passed directly to JavaScript'sRegExp, with them(multiline) flag, so^/$anchor to line boundaries even whenrestrictSearchisdocument.- Regex metacharacters follow normal regex escaping rules, not the
^/$double-escaping convention described above. Because the pattern lives inside a JSON string in keybindings.json, you still need to double-escape backslashes - e.g.\wmust be written as"\\w". - An invalid regular expression is treated as "no match" rather than throwing an error.
{
"key": "alt+k",
"command": "jump-and-select.jumpForward",
"description": "cursor moves to next line that is empty or has whitespace only",
"description2": "and puts cursor after any whitespace that may occur on that line"
"args": {
"text": "^\\s*?$",
"isRegex": true,
"putCursorOnForwardJump": "afterCharacter" // or 'beforeCharacter'
}
}
With no isRegex
With a "text": "..." option and no "isRegex", you can only use these regular expression patterns: ^, $, or ^$. Those will always be evaluated as regular expressions, never as literals. For example,
{
"key": "alt+p",
"command": "jump-and-select.jumpForward",
"args": {
"text": "^", // go to start of line
// "text": "$", // go to end of line
// "text": "^$", // go to next/previous empty line
// "restrictSearch": "line" // or document
},
}
- Note, you can also use
^and$as key inputs to any of the commands outside of a keybinding - they will also be interpreted as regular expression characters.
If you want to jump to a literal ^ or $, you will need to put them into a keybinding and double-escape them like so:
{
"key": "alt+p",
"command": "jump-and-select.jumpForward",
"args": {
"text": "howdy\\$", // "123\\^" or "\\^\\$" also work,
}
}
You can have any number of double-escaped \\^ and \\$ mixed with other text and it will all be treated as literal (non-regular expression) characters.
A. With one of the jumpForward... commands:
"restrictSearch": "document" or no restrictSearch argument (document is the default):
- "^" : the cursor would go to the start of the next line - that is forwards. If the cursor is already at the start of a line: it will go to the start of the next line.
- "$" : the cursor would go to the end of the current line. If the cursor is already at the end of a line: it will go to the end of the next line.
- "^$" : the cursor would go to the next empty line.
"restrictSearch": "line":
- "^" : nothing would happen. Can't go forward to the start of the same line.
- "$" : the cursor will go to the end of the current line.
- "^$" : nothing would happen. Never leave the current line.
2. With one of the jumpBackward... commands:
"restrictSearch": "document" or no restrictSearch argument (document is the default):
- "^" : the cursor would go to the start of the current line - that is backwards. If the cursor is already at the start of a line: it will go to the start of the previous line.
- "$" : the cursor would go to the end of the current line. If the cursor is already at the end of a line: it will go to the end of the previous line.
- "^$" : the cursor would go to the previous empty line.
"restrictSearch": "line":
- "^" : the cursor will go to the start of the current line - that is backwards.
- "$" : nothing would happen. Can't go backward to the end of the same line.
- "^$" : nothing would happen. Never leave the current line.
- Note:
^or$or^$also work to expand existing selections. It is easiest to set up a simple keybinding like
{
"key": "alt+p",
"command": "jump-and-select.jumpForwardSelect", // and try the other commands
"args": {
"text": "^",
// "text": "$",
// "text": "^$",
"restrictSearch": "document" // the default so not necessary
// "restrictSearch": "line"
},
// "when": ""
}
to see how they work in action.
StatusBar colors
Color options for the StatusBarItem are very limited. Right now these are the settings you can modify:
"workbench.colorCustomizations": {
// errorBackground and warningBackground are the only background colors supported by vscode for statusBarItems
// this extension uses the errorBackground (warning was not originally supported)
"statusBarItem.errorBackground": "#fff", // default is red
"statusBarItem.errorForeground": "#000", // default is white
"statusBarItem.errorHoverBackground": "#000", // affects the error statusBarItems only
"statusBarItem.errorHoverForeground": "#ff0000", // affects the error statusBarItems only
// or
"statusBarItem.hoverBackground": "#000", // affects all statusBarItems
"statusBarItem.hoverForeground": "#fff", // affects all statusBarItems
}
The errorBackground default is #f00 or red. Changing it will change the errorBackground color for all extensions or vscode itself that provide a StatusBarItem that needs an errorBackground. In this demo I left the settings at their default values.
If you see this error message you may have forgotten to exit (via the Enter) the MultiMode and tried to initiate some other jump-and-select command:
"restrictSearch": "line" option and selections
If you have "restrictSearch": "line" and have an existing selection in the code and then trigger one of the commands, what exactly is considered to be the 'line'?
The one 'line' will be where the cursor is - this is known as the active end of the selection. So if you make a multiline selection first, the one 'line' will be where the end of the selection is that has the active cursor.
Also, when this selection searches forward on a line, it will do so FROM the cursor. Likewise, if it is searching backward on a 'line' with a selection, it will search backwards from the position of the active cursor.
A note on the precedence of the options.
We have seen that there are three possibilities for the options (like "restrictSearch" for example):
- options in a keybinding;
- options in settings;
- and options in the deprecated settings;
- no options in (1), (2) or (3).
The options take precedence in that order: 1 > 2 > 3 > 4. All the options have defaults, so even in case (4) the default values will be applied.
1. If after triggering one of the commands you decide you don't want to move the cursor after all, Enter will exit the command and you can resume typing.
2. If after triggering one of the commands you decide you want to move the cursor first, left/rightArrow keys or clicking in the file elsewhere will move the cursor without exiting the command. You can then type a chosen character to move/select from the new cursor position.
3. If the next or previous jump would be out of the editor's viewport, it will be revealed. For multiple selections, the first selection made (which could appear after other selections) will be revealed.
Known Issues
This extension may not play well with vim or neovim or similar due to registering the same 'type' command as those extensions do. However, this extension disposes of that binding immediately after typing one character so it may not be an issue...
For some unknown reason, tabs (\t) are not considered a typed character and don't work. Spaces do work though.
TODO
[ ] - Explore allowing input via 'paste' as well.
[ X ] - Consider adding a setting to make queries be interpreted as regex's in keybindings.
[ ] - Consider cancelling multiMode if change editor.
[ ] - Should there be a notification for no match on a query?
[ ] - Add a kbWhere option for no matches in remaining children?
[ ] - multimode and jumpBySymbol?
[ ] - Consider adding negated kinds of symbols in symbols options.
[ ] - Consider adding topScopeNextStart/topScopeNextEnd and topScopePreviousStart/topScopePreviousEnd?
Release Notes
0.0.41 Added setting to restrict movement/selection to current line or full document.
Added setting to move/select before or after the chosen character.
Separated settings to put cursor before/after the chosen character for both forward/backward.
Added support for keybindings and all args therein.
Added support for regular expressions in keybindings and macros.
Renamed torestrictSearchsetting andargsoption.
Added intellisense/completions for keybindings, includingargsoptions.0.5.0 Removed regex interpretation of keybinding queries.
Selections are continuous - extending each current selection, even with^/$/^$.
Make all jumps reveal - at bottom.
Fix putCursorForward/Backward if next to a match.
Make the StatusBarItem show immediately.
AddAbort MultiModecommand. In Command Palette and clicking the StatusBarItem.
Prevent multiple StatusBarItems.
Swapped in JSON Schemakeybindings.schema.jsoncinstead of CompletionProvider.
Better^,$, and^$selecting in keybindings.
Enable literal\\^and\\$in keybindings.
Simplified the QueryObject and made a default noMatch.
Use EOL length for forward^/$for multi-OS lengths.
Made a Discussions item for new features.
0.5.2 Fix backwards bug not using start of first line.
0.5.3 empty line (^$) jumps work in files that DON'T normalize \n to \r\n - specific settings-type files.
0.5.4 empty line (^$) "fix" - just check for existence of \r\n in the file to set which regex to use.0.6.0 Deprecated all previous settings in favor of one
defaults.
Added a jump and a select version of each option.
For "^$" just use/(?<=\r?\n)\r?\n/g)/regex.
Use more "editor.document.eol" for match and query lengths.
Added configs.js withdefaults.restrictSearch ?? "document", for example.0.7.0 Added jump
bySymbolcommand: goto function, class or method.
Added jumpSymbols.md0.8.0 Work on next and previous, deepSymbolRecursion for those options.
0.8.1 Added support for all symbols in vscode.SymbolKind's.
Reworked child/next/previous. Added visitAllSymbols() and isRightKind().0.9.0 Re-added regex supprt in
textwithisRegexoption.
Added aselectoption ("match"or"extends") - select match only, or extend the selection.
Added${selectedText}"variable" resolution.