Skip to content

Auto-pair & smart indentation

As you type, the editor closes brackets and quotes for you, keeps your indentation on new lines, opens blocks between braces, and applies one consistent indent unit (tabs or spaces) to the Tab key, backspace-unindent and auto-indent alike. Everything here is a built-in feature of the editor; the matching menu commands and the indent-style setting come from the bundled Indentation plugin.

It is meant to be invisible — it only acts on the character you just typed, and stands down wherever it would get in the way (inside comments and strings, in front of existing words, with the wrong partner character).

Auto-pairing brackets and quotes

Typing an opening bracket or quote inserts its partner and leaves the caret between the two:

You type You get Caret
( () between
[ [] between
{ {} between
" "" between
' '' between

A few rules keep this from being annoying:

  • Type-over. Typing a closing character when the same character is already to the right of the caret steps over it instead of inserting a second one — so typing straight through () or "" leaves a single, balanced pair.
  • No pairing in front of a word. An opener is only completed when the next character is whitespace, a closer, or end of line — so adding ( just before existing text does not inject a stray ) into the middle of it.
  • Apostrophe-aware quotes. A ' typed right after a letter (as in don't) is treated as an apostrophe and is not paired. Quotes only auto-pair in a neutral context (start of a token, after whitespace or an operator).
  • Angle brackets only in markup. <> auto-pair only in HTML/XML documents, where < opens a tag. Everywhere else < is a comparison or shift operator and is left alone.

Wrapping a selection (type-to-wrap)

With text selected, typing an opener does not replace the selection — it wraps it:

select value  then type (        →   (value)
  • Works with ( [ { " ' (not < — outside markup it's an operator).
  • The inner text stays selected afterwards, so wraps chain: type ( then " and you get ("value").
  • With multiple carets, every selection is wrapped independently — and the whole operation is one undo step.

Deleting a pair

Pressing Backspace with the caret between an empty auto-inserted pair ((|), [|], {|}, "|", '|', or <|> in markup) deletes both characters in one step, so you can undo an auto-pair with a single keystroke. Once there is content between the pair, Backspace behaves normally.

Smart indentation on Enter

Pressing Enter carries the current line's leading whitespace onto the new line, so you stay at the same depth without re-typing tabs or spaces:

  • Keep indent. The new line starts with the same indentation as the line you left.
  • Open one level. If the line you left ends with an opener ({, [, (), the new line is indented one extra level.
  • Open a block. If the caret sits between an opener and its matching closer, the block opens out: the new line is indented one level deeper and the closer drops to its own line at the opener's depth.
if (cond) {|}        Enter        if (cond) {
                     ───────►          |
                                   }

Indent style — tabs, spaces, or auto

One indent unit drives the Tab key, backspace-unindent and the automatic indentation above, so they always agree. Choose it in Preferences ▸ Plugins ▸ Indentation:

Style Behaviour
Tabs (default for new files) One level is a real tab character; Spaces per indent sets its visual width.
Spaces One level is Spaces per indent space characters.
Auto (detect from document) The editor scans the document's existing indentation and follows it — a tab-indented file keeps using tabs, a 2-space file keeps using two spaces. A file with no indentation yet falls back to the default (tabs).

New, untitled files default to Tabs, width 4.

Adjusting indentation by hand

The Indentation plugin adds two commands (also under Edit ▸ Indent) that indent or outdent every line touched by the selection — or the caret's line when nothing is selected:

Command Shortcut
Increase Indent Ctrl+]
Decrease Indent Ctrl+[

Per-language defaults

Some languages have one near-universal indentation convention, and the editor ships it as that language's default — a freshly opened file of the type indents correctly with no configuration at all:

Language Default
Python 4 spaces (PEP 8)
Rust 4 spaces (rustfmt)
Markdown 4 spaces (nested lists)
YAML 2 spaces (tabs are not allowed)
JSON 2 spaces
Go tabs (gofmt)
C / C++ tabs

Every other language deliberately carries no default and follows your global indent setting. Switching a document's language by hand (the Language menu) re-applies the matching default immediately.

The default lives in the language's definition file (colorizers/<id>.json, key "indent": { "style": "tabs|spaces", "width": N }). A power user can change a shipped default by placing an edited copy of that file in the user override directory — the catalog replaces definitions by id.

Planned: per-language overrides in Preferences

A settings table for overriding these defaults per language (without touching any JSON) is designed and planned as the next step of this feature; until it lands, the JSON override above and the layers below are the ways to steer indentation.

Where the indent unit comes from (precedence)

When several sources have an opinion about indentation, the editor resolves them in one place and applies the winner, highest precedence first:

  1. The project's .editorconfig — when present and "Apply .editorconfig settings" is on, a project's indent_style / indent_size / tab_width win for matching files.
  2. The language's shipped default — the table above, when the document's language declares one.
  3. Your global indent setting — the Tabs / Spaces / Auto choice above.

So a project that ships an .editorconfig overrides everything for that project's files; a Python file outside any such project indents with PEP-8 spaces even when your global setting is tabs; and everything else follows your global setting. You can always change a document's indentation by hand afterwards.

The precedence holds the moment anything changes: applying a different Tabs / Spaces / Auto choice in Preferences re-resolves the open document immediately, so a file governed by an .editorconfig or a language default keeps its indentation without you having to switch tabs.

Multi-caret

All of the above apply at every caret when you edit with multiple carets: typing ( inserts () at each, Enter keeps each line's indentation, and Backspace between empty pairs deletes both cells at each. A single Undo reverts the whole multi-caret edit in one step.

Backspace across mixed carets

Backspace only deletes pairs when every caret sits between an empty pair. If some carets are elsewhere, Backspace falls back to its normal behaviour at all of them, so it never deletes a stray closer at one caret while editing a word at another.

In comments and strings

When a syntax colorizer is active, auto-pairing and the brace-driven block-open stand down inside comments and string/character literals — there a { or " is ordinary text, not code, so the editor leaves it exactly as typed. Plain indentation (carrying the previous line's whitespace) still works. In a plain-text document with no colorizer there is nothing to suppress, so pairing behaves the same everywhere.