Skip to main content

Primary

Keymap

Loading...

Syntax

Syntax Node (Coarse).

This selection mode is powered by Tree-sitter.

This is one of my favourite selection mode, as it enable structural editing.

There are two Syntax Node selection modes:

  • Coarse: faster movement, lower accuracy
  • Fine: higher accuracy, slower movement
MovementMeaning
Left/RightNext/Previous named sibling node
UpParent node
DownFirst named child
CurrentSelect the largest node
JumpJump to largest node

Largest Node

Using the following Javascript expression as example:

fox.bar();

There are several syntax nodes that start with f1:

  • fox (identifier)
  • fox.bar (member expression)
  • fox.bar() (call expression)

Suppose the cursor is below f, pressing s selects fox.bar(), because fox.bar() is the largest node that starts with f.

Named node

When creating a Tree sitter grammar file for a language, the author can choose to not give names to a certain kind of nodes.

For example, "," are usually unnamed ( anonymous) in most language grammars, thus it will be skipped when using the Previous/Next movement in Syntax Node.

See more at https://tree-sitter.github.io/tree-sitter/using-parsers#named-vs-anonymous-nodes.

Examples

Loading...

Syntax*

Fine Syntax Node.

MovementMeaning
Left/RightNext/Previous sibling node (including anonymous)
UpParent node
ShrinkFirst child (including anonymous)
CurrentSmallest node that matches the current selection
JumpJump to smallest node

Fine Syntax Node is useful when you start to expand the selection starting from the current smallest node.

Suppose we have the following Javascript expression, and the current selection is hello, and we want to select hello.world().

hello.world().foo().bar().spam().wise();

If we press d, the whole expression will be selected1, and we will need to press i several times to shrink the selection down to hello.world().

However, if we use D instead, the selection will remain as hello, and pressing i multiple times will get us to hello.world().

Line

In this selection mode, the selection is trimmed, which means that the leading and trailing spaces of each line are not selected.

MovementMeaning
Up/DownMove to line above/below
Alpha/BetaMove to the first/last line of the current file
LeftMove to the parent line

Parent lines are highlighted lines that represent the parent nodes of the current selection.

This is useful for example when you are within the body of a function and you want to jump to the function name.

This is also practical in the File Explorer because the file explorer is rendered using YAML, so going to Parent Line means going to the parent folder!

Loading...

Line*

Full Line.

Same as Line, however, leading whitespaces are selected, and trailing whitespaces, including newline characters are also selected.

Token

Token.

Each unit is a sequence of alphanumeric characters including - and _.

MovementSymbolsAlphanumeric
Left/Right
Alpha/Beta
Jump
Up/Down
Current

Left/Right movement skips symbols, while Alpha/Beta movement moves to symbols only.

This means Left/Right movements are optimized for navigating alphanumeric tokens, while Alpha/Beta movements are optimized for symbolic tokens, which is useful for navigating sentences.

Why don't Left/Right movements also navigate symbols? Because they would be too slow; it would take a lot of unnecessary keypresses to reach the target.

Suppose the following example:

use crate::{components::editor::OpenFile, char_index::CharIndex};

If the current selection is selecting use, the following table demonstrates how many steps it takes to navigate to OpenFile.

Navigation include/exclude symbolsStepsCount
Includecrate : : { components : : editor : : OpenFile11
Excludecrate components editor OpenFile4

Why do we need the Alpha/Beta movements to navigate symbols? Because sometimes, we just need to move to a symbol.

For example, in the following code, suppose we wanted to add an & symbol before [Color].

fn apply_style(&self, colors: [Color]);

If there are no movements for Token which navigate to symbols, then we are forced to change the selection mode to either Word or Char, before inserting.

Loading...

Word

This selects word within a token.

For example, myOatPepperBanana consists of 4 short words, namely: my, Oat, Pepper and Banana.

This is useful for renaming identifiers, especially if we only want to change a single word of the name. 1

Loading...

Word*

Fine Word.

This is similar to Word, except that it does not skip symbols.

Loading...

Char

Character.

In this selection mode, the movements behave like the usual editor, where Left/Right means left/right, and so on.

Alpha/Beta means the first/last character of the current word.

Loading...

Footnotes

  1. You can try it out at https://astexplorer.net/, using the @typescript-eslint/parser. 2 3