Skip to content
| Marketplace
Sign in
Visual Studio Code>Other>HopOut - Tab Out of Brackets & QuotesNew to Visual Studio Code? Get it now.
HopOut - Tab Out of Brackets & Quotes

HopOut - Tab Out of Brackets & Quotes

Mei Okubo

| (0) | Free
Move outside the nearest enclosing quote, bracket or paren. Structure-aware, multi-cursor, multi-line, and it never takes Tab away from snippets, IntelliSense or Copilot.
Installation
Launch VS Code Quick Open (Ctrl+P), paste the following command, and press enter.
Copied to clipboard
More Info

HopOut

Move outside the nearest enclosing quote, bracket or paren. VS Code has cursorRight and jumpToBracket, but no command that means "get me out of this pair". HopOut adds that command, and puts it on Tab in the one situation where Tab has nothing better to do.

print("hello|")      Tab  ->   print("hello"|)      Tab  ->   print("hello")|
{ a: [1, 2|] }       Tab  ->   { a: [1, 2]| }       Tab  ->   { a: [1, 2] }|
say("hel|lo")     Ctrl+'  ->   say("hello"|)                (from anywhere inside)

| is the cursor.

Keys and commands

Key Command What it does
Tab hopOut.tab Hops past the closing delimiter directly ahead of the cursor. In every other position Tab is not intercepted at all.
Shift+Tab hopOut.shiftTab Right after a hop, puts the cursor back where it was. Otherwise outdents as usual.
Ctrl+' (Cmd+') hopOut.outForward Moves past the closing delimiter of the nearest enclosing pair, from anywhere inside it, across lines. Press again for the next pair out.
Ctrl+Shift+' (Cmd+Shift+') hopOut.outBackward Moves in front of the opening delimiter of the nearest enclosing pair.
hopOut.toggle Turns Tab hopping on or off. The setting is saved, so it survives restarts.

All of them work with multiple cursors. With Tab, either every cursor hops or none does.

How Tab stays out of the way

Tab already has many jobs in VS Code. HopOut only takes it when VS Code would otherwise have inserted indentation:

  • The keybinding is gated on a context key, hopOut.canHop, that is true only while a hop is possible at the cursor. Everywhere else the key press never reaches the extension, so indenting, Emmet, snippets and other extensions behave exactly as if HopOut were not installed, with no added latency.
  • It yields to the suggestion list, snippet placeholders, editor.tabCompletion, inline suggestions and Next Edit Suggestions (Copilot), Cursor Tab, a selection (which Tab indents), and Vim/Neovim normal mode.
  • It never hops into a pair: in foo(|"bar") the quote ahead is an opening quote, so Tab indents.
  • In the indentation at the start of a line Tab always indents.

Settings

Setting Default
hopOut.enabled true Let Tab hop. Per-language: "[markdown]": { "hopOut.enabled": false }.
hopOut.pairs ( ) [ ] { } " " ' ' ` ` Pairs written as open close. Multi-character delimiters are fine: "<!-- -->", "/* */", "{% %}". A single token is used on both sides: "$", "**". Per-language overridable.
hopOut.languageAwarePairs true Adds < > in HTML/XML/Vue/Svelte/JSX, emphasis and math delimiters in Markdown, triple quotes in Python/TOML/Elixir/Julia, math delimiters in LaTeX; stops treating ' as a quote in Rust, OCaml, F# and Lisps.
hopOut.tab.trigger adjacent adjacent: hop only when the closer is directly ahead. line: hop from anywhere inside a pair that closes on this line, e.g. the middle of a string. enclosing: hop from anywhere inside a pair, even one that closes on a later line.
hopOut.tab.skipWhitespace true { a: 1| } counts as directly ahead.
hopOut.tab.fromLineEnd false At the end of a line, hop past a closer that starts a following line (from the last statement of a block to after its }).
hopOut.tab.chain false Hop past all consecutive closers at once: "}) in one press.
hopOut.tab.alsoHopOver [] Extra text to hop over when directly ahead, e.g. [";", ","].
hopOut.tab.priorityOverSnippets false During a snippet, prefer hopping over jumping to the next placeholder.
hopOut.shiftTab.undoHop true Shift+Tab undoes the last hop.
hopOut.maxScanLines 500 Lines examined before and after the cursor.

To insert a real tab where HopOut would hop, bind the built-in tab command to a key of your choice, or run HopOut: Toggle Tab Hopping.

Why another tab-out extension

HopOut was written after reading the source and issue trackers of the existing ones. Each row is a reported problem and what HopOut does about it.

Problem in existing extensions Reported in HopOut
Works on single characters, not pairs: jumps into strings and tags, treats ., :, = as stops, cannot tell an opening quote from a closing one TabOut #5, #24 Scans the code structure: quotes with escapes, nested brackets, comments. Only ever hops out.
Cannot leave a string unless the cursor touches the closing quote TabOutX #3 Ctrl+' from anywhere; hopOut.tab.trigger: "line" puts it on Tab.
Current line only TabOut #47 Explicit commands cross lines; fromLineEnd and enclosing do so for Tab.
No multi-character delimiters (*/, -->, $$, \]) TabOut #57, #21, #27 Any length; block comments and Markdown/LaTeX delimiters built in.
Breaks snippet placeholders (regressed again in 2026) TabOut #58, #4, #10; the opposite wish in #46 Yields while the snippet has a next placeholder. priorityOverSnippets for the other camp.
Steals Tab from Copilot suggestions and Next Edit Suggestions TabOut #31, #52, #54; TabOutX #2; Leaper #19 Yields to inline suggestions, inline edits (accept and jump) and Cursor Tab.
Breaks suggestion acceptance, tab completion, Emmet, indentation TabOut #51, #16, #9, #5 Every Tab press used to go through the extension, which then tried to re-create the default. HopOut is not involved unless a hop is possible.
Tab lags over SSH/WSL, or fires seconds late TabOut #37, #29 Runs in the local (UI) extension host even in remote windows, and ordinary Tab presses never reach it.
No multiple cursors TabOut #7 (still excluded by its keybinding); TabOutX Supported in every command.
Shift+Tab hijacks outdent on any line containing a "special" character TabOut 0.2.4 source; #12 Shift+Tab only undoes a hop that just happened.
Only pairs typed in this session are known; nothing in existing code, pasted code or code inserted by completions Leaper README, #15 Reads the document, so where the pair came from is irrelevant.
One press per delimiter in "}) TabOut #8 hopOut.tab.chain.
Toggle is forgotten on restart; TabOutX reads its settings once at startup TabOut and TabOutX source Toggle writes the setting; all settings apply immediately.
No per-language configuration enabled, pairs and the tab.* settings can be overridden per language.
No entry point for VS Code for the Web TabOut, TabOutX and Leaper manifests No Node dependencies and a browser entry point (built, but not yet exercised in a web host).

What it does not do

HopOut uses a fast structural scan, not a full parser for each language, so:

  • Syntax it cannot see, such as regular expression literals containing quotes, heredocs, or a string nested in the interpolation of a string with the same quote, can make it miss a pair. A missed pair means Tab indents; a closing bracket directly ahead is always hopped over regardless.
  • The context key that routes Tab follows the cursor a few milliseconds behind. A macro that types a bracket and presses Tab in the same instant, or an extension host that is busy at that moment, gets a normal indent instead of a hop. That is the price of never delaying an ordinary Tab.
  • With emmet.triggerExpansionOnTab, an abbreviation sitting directly in front of a closing delimiter is hopped past instead of expanded. Accepting it from the suggestion list works.
  • When another extension binds Tab in the same context (Markdown All in One in lists, for example), VS Code decides which one wins. Disable HopOut for that language if it gets in the way.
  • AI tools that take Tab through their own context keys, other than Copilot and Cursor, are unknown to the keybinding. Add their key to the when clause of hopOut.tab in Keyboard Shortcuts.

Coming from TabOut

Uninstall or disable TabOut, TabOutX or Leaper so two extensions do not compete for Tab. tabout.charactersToTabOutFrom entries like { "open": "[", "close": "]" } become "[ ]" in hopOut.pairs; single characters such as ; or , go in hopOut.tab.alsoHopOver.

Development

npm install
npm test                  # unit tests for the scanning engine
npm run test:integration  # runs inside an installed VS Code with a throwaway profile, pressing real keys
npm run package           # builds the .vsix

src/engine.ts is the scanner and has no VS Code dependency. src/languages.ts holds the per-language comment syntax and pair adjustments. src/extension.ts keeps the context keys in sync and implements the commands.

License

MIT

  • Contact us
  • Jobs
  • Privacy
  • Manage cookies
  • Terms of use
  • Trademarks
  • Your Privacy Choices
  • Consumer Health Privacy
© 2026 Microsoft