Ctrl, Shift and Alt modifiers are encoded respectively with the prefixes
-C-, S- and A-. Special keys are encoded as follows:
+
Ctrl, Shift and Alt modifiers are encoded respectively with the prefixes C-, S- and A-.
+
The Super key - the Windows/Linux
+key or the Command key on Mac keyboards - is also supported when using a terminal emulator that
+supports the enhanced keyboard protocol.
+The super key is encoded with prefixes Meta-, Cmd- or Win-. These are all synonyms for the
+super modifier - binding a key with a Win- modifier will mean it can be used with the
+Windows/Linux key or the Command key.
+
[keys.normal]
+C-s = ":write" # Ctrl and 's' to write
+Cmd-s = ":write" # Cmd or Win or Meta and 's' to write
+
+
Special keys are encoded as follows:
Key name
Representation
Backspace
"backspace"
Space
"space"
diff --git a/master/remapping.html b/master/remapping.html
index 761942943..53f293d31 100644
--- a/master/remapping.html
+++ b/master/remapping.html
@@ -225,8 +225,18 @@ c = ":run-shell-command cargo build"
t = ":run-shell-command cargo test"
Ctrl, Shift and Alt modifiers are encoded respectively with the prefixes
-C-, S- and A-. Special keys are encoded as follows:
+
Ctrl, Shift and Alt modifiers are encoded respectively with the prefixes C-, S- and A-.
+
The Super key - the Windows/Linux
+key or the Command key on Mac keyboards - is also supported when using a terminal emulator that
+supports the enhanced keyboard protocol.
+The super key is encoded with prefixes Meta-, Cmd- or Win-. These are all synonyms for the
+super modifier - binding a key with a Win- modifier will mean it can be used with the
+Windows/Linux key or the Command key.
+
[keys.normal]
+C-s = ":write" # Ctrl and 's' to write
+Cmd-s = ":write" # Cmd or Win or Meta and 's' to write
+
+
Special keys are encoded as follows:
Key name
Representation
Backspace
"backspace"
Space
"space"
diff --git a/master/searchindex.js b/master/searchindex.js
index 4ec85af9d..b5acac239 100644
--- a/master/searchindex.js
+++ b/master/searchindex.js
@@ -1 +1 @@
-Object.assign(window.search, {"doc_urls":["title-page.html#helix","install.html#installing-helix","install.html#pre-built-binaries","package-managers.html#package-managers","package-managers.html#linux","package-managers.html#ubuntu","package-managers.html#fedorarhel","package-managers.html#arch-linux-extra","package-managers.html#nixos","package-managers.html#flatpak","package-managers.html#snap","package-managers.html#appimage","package-managers.html#macos","package-managers.html#homebrew-core","package-managers.html#macports","package-managers.html#windows","package-managers.html#winget","package-managers.html#scoop","package-managers.html#chocolatey","package-managers.html#msys2","building-from-source.html#building-from-source","building-from-source.html#configuring-helixs-runtime-files","building-from-source.html#validating-the-installation","building-from-source.html#configure-the-desktop-shortcut","usage.html#using-helix","usage.html#modes","usage.html#buffers","usage.html#selection-first-editing","usage.html#multiple-selections","usage.html#motions","registers.html#registers","registers.html#user-defined-registers","registers.html#default-registers","registers.html#special-registers","surround.html#surround","textobjects.html#selecting-and-manipulating-text-with-textobjects","textobjects.html#navigating-using-tree-sitter-textobjects","syntax-aware-motions.html#moving-the-selection-with-syntax-aware-motions","pickers.html#using-pickers","pickers.html#filtering-picker-results","keymap.html#keymap","keymap.html#normal-mode","keymap.html#movement","keymap.html#changes","keymap.html#selection-manipulation","keymap.html#search","keymap.html#minor-modes","keymap.html#insert-mode","keymap.html#select--extend-mode","keymap.html#picker","keymap.html#prompt","commands.html#commands","commands.html#typable-commands","commands.html#static-commands","lang-support.html#language-support","from-vim.html#migrating-from-vim","configuration.html#configuration","editor.html#editor","editor.html#editor-section","editor.html#editorclipboard-provider-section","editor.html#editorstatusline-section","editor.html#editorlsp-section","editor.html#editorcursor-shape-section","editor.html#editorfile-picker-section","editor.html#editorauto-pairs-section","editor.html#editorauto-save-section","editor.html#editorsearch-section","editor.html#editorwhitespace-section","editor.html#editorindent-guides-section","editor.html#editorgutters-section","editor.html#editorsoft-wrap-section","editor.html#editorsmart-tab-section","editor.html#editorinline-diagnostics-section","themes.html#themes","themes.html#creating-a-theme","themes.html#overview","themes.html#the-details-of-theme-creation","themes.html#color-palettes","themes.html#modifiers","themes.html#underline-style","themes.html#inheritance","themes.html#scopes","remapping.html#key-remapping","remapping.html#minor-modes","remapping.html#special-keys-and-modifiers","languages.html#languages","languages.html#languagestoml-files","languages.html#language-configuration","languages.html#file-type-detection-and-the-file-types-key","languages.html#language-server-configuration","languages.html#configuring-language-servers-for-a-language","languages.html#tree-sitter-grammar-configuration","languages.html#choosing-grammars","guides/index.html#guides","guides/adding_languages.html#adding-new-languages-to-helix","guides/adding_languages.html#language-configuration","guides/adding_languages.html#grammar-configuration","guides/adding_languages.html#queries","guides/adding_languages.html#common-issues","guides/textobject.html#adding-textobject-queries","guides/textobject.html#queries-for-textobject-based-navigation","guides/indent.html#adding-indent-queries","guides/indent.html#indent-queries","guides/indent.html#capture-types","guides/indent.html#predicates","guides/indent.html#scopes","guides/injection.html#adding-injection-queries","guides/injection.html#capture-types","guides/injection.html#settings","guides/injection.html#predicates"],"index":{"documentStore":{"docInfo":{"0":{"body":38,"breadcrumbs":2,"title":1},"1":{"body":28,"breadcrumbs":3,"title":2},"10":{"body":17,"breadcrumbs":4,"title":1},"100":{"body":35,"breadcrumbs":8,"title":4},"101":{"body":116,"breadcrumbs":7,"title":3},"102":{"body":127,"breadcrumbs":6,"title":2},"103":{"body":549,"breadcrumbs":6,"title":2},"104":{"body":114,"breadcrumbs":5,"title":1},"105":{"body":115,"breadcrumbs":5,"title":1},"106":{"body":39,"breadcrumbs":7,"title":3},"107":{"body":64,"breadcrumbs":6,"title":2},"108":{"body":50,"breadcrumbs":5,"title":1},"109":{"body":28,"breadcrumbs":5,"title":1},"11":{"body":46,"breadcrumbs":4,"title":1},"12":{"body":0,"breadcrumbs":4,"title":1},"13":{"body":3,"breadcrumbs":5,"title":2},"14":{"body":3,"breadcrumbs":4,"title":1},"15":{"body":7,"breadcrumbs":4,"title":1},"16":{"body":33,"breadcrumbs":4,"title":1},"17":{"body":3,"breadcrumbs":4,"title":1},"18":{"body":3,"breadcrumbs":4,"title":1},"19":{"body":12,"breadcrumbs":4,"title":1},"2":{"body":55,"breadcrumbs":4,"title":3},"20":{"body":136,"breadcrumbs":5,"title":2},"21":{"body":234,"breadcrumbs":7,"title":4},"22":{"body":20,"breadcrumbs":5,"title":2},"23":{"body":68,"breadcrumbs":6,"title":3},"24":{"body":21,"breadcrumbs":3,"title":2},"25":{"body":38,"breadcrumbs":2,"title":1},"26":{"body":19,"breadcrumbs":2,"title":1},"27":{"body":30,"breadcrumbs":4,"title":3},"28":{"body":29,"breadcrumbs":3,"title":2},"29":{"body":26,"breadcrumbs":2,"title":1},"3":{"body":21,"breadcrumbs":5,"title":2},"30":{"body":33,"breadcrumbs":3,"title":1},"31":{"body":48,"breadcrumbs":5,"title":3},"32":{"body":27,"breadcrumbs":4,"title":2},"33":{"body":72,"breadcrumbs":4,"title":2},"34":{"body":71,"breadcrumbs":3,"title":1},"35":{"body":102,"breadcrumbs":6,"title":4},"36":{"body":46,"breadcrumbs":7,"title":5},"37":{"body":145,"breadcrumbs":9,"title":5},"38":{"body":26,"breadcrumbs":4,"title":2},"39":{"body":119,"breadcrumbs":5,"title":3},"4":{"body":5,"breadcrumbs":4,"title":1},"40":{"body":71,"breadcrumbs":3,"title":1},"41":{"body":11,"breadcrumbs":4,"title":2},"42":{"body":165,"breadcrumbs":3,"title":1},"43":{"body":226,"breadcrumbs":3,"title":1},"44":{"body":265,"breadcrumbs":4,"title":2},"45":{"body":51,"breadcrumbs":3,"title":1},"46":{"body":887,"breadcrumbs":4,"title":2},"47":{"body":194,"breadcrumbs":4,"title":2},"48":{"body":59,"breadcrumbs":5,"title":3},"49":{"body":82,"breadcrumbs":3,"title":1},"5":{"body":16,"breadcrumbs":4,"title":1},"50":{"body":136,"breadcrumbs":3,"title":1},"51":{"body":4,"breadcrumbs":3,"title":1},"52":{"body":837,"breadcrumbs":4,"title":2},"53":{"body":2586,"breadcrumbs":4,"title":2},"54":{"body":562,"breadcrumbs":5,"title":2},"55":{"body":53,"breadcrumbs":4,"title":2},"56":{"body":102,"breadcrumbs":2,"title":1},"57":{"body":42,"breadcrumbs":3,"title":1},"58":{"body":469,"breadcrumbs":4,"title":2},"59":{"body":64,"breadcrumbs":5,"title":3},"6":{"body":4,"breadcrumbs":4,"title":1},"60":{"body":259,"breadcrumbs":4,"title":2},"61":{"body":111,"breadcrumbs":4,"title":2},"62":{"body":41,"breadcrumbs":5,"title":3},"63":{"body":151,"breadcrumbs":5,"title":3},"64":{"body":62,"breadcrumbs":5,"title":3},"65":{"body":45,"breadcrumbs":5,"title":3},"66":{"body":30,"breadcrumbs":4,"title":2},"67":{"body":73,"breadcrumbs":4,"title":2},"68":{"body":40,"breadcrumbs":5,"title":3},"69":{"body":121,"breadcrumbs":4,"title":2},"7":{"body":30,"breadcrumbs":6,"title":3},"70":{"body":84,"breadcrumbs":5,"title":3},"71":{"body":136,"breadcrumbs":5,"title":3},"72":{"body":156,"breadcrumbs":5,"title":3},"73":{"body":14,"breadcrumbs":3,"title":1},"74":{"body":28,"breadcrumbs":4,"title":2},"75":{"body":68,"breadcrumbs":3,"title":1},"76":{"body":0,"breadcrumbs":5,"title":3},"77":{"body":83,"breadcrumbs":4,"title":2},"78":{"body":28,"breadcrumbs":3,"title":1},"79":{"body":16,"breadcrumbs":4,"title":2},"8":{"body":64,"breadcrumbs":4,"title":1},"80":{"body":21,"breadcrumbs":3,"title":1},"81":{"body":668,"breadcrumbs":3,"title":1},"82":{"body":251,"breadcrumbs":5,"title":2},"83":{"body":66,"breadcrumbs":5,"title":2},"84":{"body":56,"breadcrumbs":6,"title":3},"85":{"body":9,"breadcrumbs":3,"title":1},"86":{"body":63,"breadcrumbs":4,"title":2},"87":{"body":320,"breadcrumbs":4,"title":2},"88":{"body":140,"breadcrumbs":8,"title":6},"89":{"body":149,"breadcrumbs":5,"title":3},"9":{"body":10,"breadcrumbs":4,"title":1},"90":{"body":214,"breadcrumbs":6,"title":4},"91":{"body":90,"breadcrumbs":6,"title":4},"92":{"body":38,"breadcrumbs":4,"title":2},"93":{"body":15,"breadcrumbs":2,"title":1},"94":{"body":9,"breadcrumbs":7,"title":4},"95":{"body":60,"breadcrumbs":5,"title":2},"96":{"body":30,"breadcrumbs":5,"title":2},"97":{"body":51,"breadcrumbs":4,"title":1},"98":{"body":53,"breadcrumbs":5,"title":2},"99":{"body":86,"breadcrumbs":7,"title":3}},"docs":{"0":{"body":"Docs for bleeding edge master can be found at https://docs.helix-editor.com/master . See the usage section for a quick overview of the editor, keymap section for all available keybindings and the configuration section for defining custom keybindings, setting themes, etc. For everything else (e.g., how to install supported language servers), see the Helix Wiki . Refer the FAQ for common questions.","breadcrumbs":"Helix » Helix","id":"0","title":"Helix"},"1":{"body":"To install Helix, follow the instructions specific to your operating system. Note that: To get the latest nightly version of Helix, you need to build from source . To take full advantage of Helix, install the language servers for your preferred programming languages. See the wiki for instructions.","breadcrumbs":"Installation » Installing Helix","id":"1","title":"Installing Helix"},"10":{"body":"Helix is available on Snapcraft and can be installed with: snap install --classic helix This will install Helix as both /snap/bin/helix and /snap/bin/hx, so make sure /snap/bin is in your PATH.","breadcrumbs":"Installation » Package Managers » Snap","id":"10","title":"Snap"},"100":{"body":"Tree-sitter based navigation in Helix is done using captures in the following order: object.movement object.around object.inside For example if a function.around capture has been already defined for a language in its textobjects.scm file, function navigation should also work automatically. function.movement should be defined only if the node captured by function.around doesn't make sense in a navigation context.","breadcrumbs":"Guides » Adding textobject queries » Queries for textobject based navigation","id":"100","title":"Queries for textobject based navigation"},"101":{"body":"Helix uses tree-sitter to correctly indent new lines. This requires a tree- sitter grammar and an indent.scm query file placed in runtime/queries/ {language}/indents.scm. The indentation for a line is calculated by traversing the syntax tree from the lowest node at the beginning of the new line (see Indent queries ). Each of these nodes contributes to the total indent when it is captured by the query (in what way depends on the name of the capture. Note that it matters where these added indents begin. For example, multiple indent level increases that start on the same line only increase the total indent level by 1. See Capture types . By default, Helix uses the hybrid indentation heuristic. This means that indent queries are not used to compute the expected absolute indentation of a line but rather the expected difference in indentation between the new and an already existing line. This difference is then added to the actual indentation of the already existing line. Since this makes errors in the indent queries harder to find, it is recommended to disable it when testing via :set indent-heuristic tree-sitter. The rest of this guide assumes that the tree-sitter heuristic is used.","breadcrumbs":"Guides » Adding indent queries » Adding indent queries","id":"101","title":"Adding indent queries"},"102":{"body":"When Helix is inserting a new line through o, O, or , to determine the indent level for the new line, the query in indents.scm is run on the document. The starting position of the query is the end of the line above where a new line will be inserted. For o, the inserted line is the line below the cursor, so that starting position of the query is the end of the current line. fn need_hero(some_hero: Hero, life: Life) -> { matches!(some_hero, Hero { // ←─────────────────╮ strong: true,//←╮ ↑ ↑ │ fast: true, // │ │ ╰── query start │ sure: true, // │ ╰───── cursor ├─ traversal soon: true, // ╰──────── new line inserted │ start node }) && // │\n// ↑ │\n// ╰───────────────────────────────────────────────╯ some_hero > life\n} For O, the newly inserted line is the current line, so the starting position of the query is the end of the line above the cursor. fn need_hero(some_hero: Hero, life: Life) -> { // ←─╮ matches!(some_hero, Hero { // ←╮ ↑ │ strong: true,// ↑ ╭───╯ │ │ fast: true, // │ │ query start ─╯ │ sure: true, // ╰───┼ cursor ├─ traversal soon: true, // ╰ new line inserted │ start node }) && // │ some_hero > life // │\n} // ←──────────────────────────────────────────────╯ From this starting node, the syntax tree is traversed up until the root node. Each indent capture is collected along the way, and then combined according to their capture types and scopes to a final indent level for the line.","breadcrumbs":"Guides » Adding indent queries » Indent queries","id":"102","title":"Indent queries"},"103":{"body":"@indent (default scope tail): Increase the indent level by 1. Multiple occurrences in the same line do not stack. If there is at least one @indent and one @outdent capture on the same line, the indent level isn't changed at all. @outdent (default scope all): Decrease the indent level by 1. The same rules as for @indent apply. @indent.always (default scope tail): Increase the indent level by 1. Multiple occurrences on the same line do stack. The final indent level is @indent.always – @outdent.always. If an @indent and an @indent.always are on the same line, the @indent is ignored. @outdent.always (default scope all): Decrease the indent level by 1. The same rules as for @indent.always apply. @align (default scope all): Align everything inside this node to some anchor. The anchor is given by the start of the node captured by @anchor in the same pattern. Every pattern with an @align should contain exactly one @anchor. Indent (and outdent) for nodes below (in terms of their starting line) the @align node is added to the indentation required for alignment. @extend: Extend the range of this node to the end of the line and to lines that are indented more than the line that this node starts on. This is useful for languages like Python, where for the purpose of indentation some nodes (like functions or classes) should also contain indented lines that follow them. @extend.prevent-once: Prevents the first extension of an ancestor of this node. For example, in Python a return expression always ends the block that it is in. Note that this only stops the extension of the next @extend capture. If multiple ancestors are captured, only the extension of the innermost one is prevented. All other ancestors are unaffected (regardless of whether the innermost ancestor would actually have been extended). @indent / @outdent Consider this example: fn shout(things: Vec) { // ↑ // ├───────────────────────╮ indent level // @indent ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄ // │ let it_all = |out| { things.filter(|thing| { // │ 1 // ↑ ↑ │ // ├───────────────────────┼─────┼┄┄┄┄┄┄┄┄┄┄┄┄┄┄ // @indent @indent │ // │ 2 thing.can_do_with(out) // │ })}; // ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄ //↑↑↑ │ 1\n} //╰┼┴──────────────────────────────────────────────┴┄┄┄┄┄┄┄┄┄┄┄┄┄┄\n// 3x @outdent ((block) @indent)\n[\"}\" \")\"] @outdent Note how on the second line, we have two blocks begin on the same line. In this case, since both captures occur on the same line, they are combined and only result in a net increase of 1. Also note that the closing }s are part of the @indent captures, but the 3 @outdents also combine into 1 and result in that line losing one indent level. @extend / @extend.prevent-once For an example of where @extend can be useful, consider Python, which is whitespace-sensitive. ] (parenthesized_expression) (function_definition) (class_definition)\n] @indent class Hero: def __init__(self, strong, fast, sure, soon):# ←─╮ self.is_strong = strong # │ self.is_fast = fast # ╭─── query start │ self.is_sure = sure # │ ╭─ cursor │ self.is_soon = soon # │ │ │ # ↑ ↑ │ │ │ # │ ╰──────╯ │ │ # ╰─────────────────────╯ │ # ├─ traversal def need_hero(self, life): # │ start node return ( # │ self.is_strong # │ and self.is_fast # │ and self.is_sure # │ and self.is_soon # │ and self > life # │ ) # ←─────────────────────────────────────────╯ Without braces to catch the scope of the function, the smallest descendant of the cursor on a line feed ends up being the entire inside of the class. Because of this, it will miss the entire function node and its indent capture, leading to an indent level one too small. To address this case, @extend tells helix to \"extend\" the captured node's span to the line feed and every consecutive line that has a greater indent level than the line of the node. (parenthesized_expression) @indent ] (function_definition) (class_definition)\n] @indent @extend class Hero: def __init__(self, strong, fast, sure, soon):# ←─╮ self.is_strong = strong # │ self.is_fast = fast # ╭─── query start ├─ traversal self.is_sure = sure # │ ╭─ cursor │ start node self.is_soon = soon # │ │ ←───────────────╯ # ↑ ↑ │ │ # │ ╰──────╯ │ # ╰─────────────────────╯ def need_hero(self, life): return ( self.is_strong and self.is_fast and self.is_sure and self.is_soon and self > life ) Furthermore, there are some cases where extending to everything with a greater indent level may not be desirable. Consider the need_hero function above. If our cursor is on the last line of the returned expression. class Hero: def __init__(self, strong, fast, sure, soon): self.is_strong = strong self.is_fast = fast self.is_sure = sure self.is_soon = soon def need_hero(self, life): return ( self.is_strong and self.is_fast and self.is_sure and self.is_soon and self > life ) # ←─── cursor #←────────── where cursor should go on new line In Python, the are a few tokens that will always end a scope, such as a return statement. Since the scope ends, so should the indent level. But because the function span is extended to every line with a greater indent level, a new line would just continue on the same level. And an @outdent would not help us here either, since it would cause everything in the parentheses to become outdented as well. To help, we need to signal an end to the extension. We can do this with @extend.prevent-once. (parenthesized_expression) @indent ] (function_definition) (class_definition)\n] @indent @extend (return_statement) @extend.prevent-once @indent.always / @outdent.always As mentioned before, normally if there is more than one @indent or @outdent capture on the same line, they are combined. Sometimes, there are cases when you may want to ensure that every indent capture is additive, regardless of how many occur on the same line. Consider this example in YAML. - foo: bar\n# ↑ ↑\n# │ ╰─────────────── start of map\n# ╰───────────────── start of list element baz: quux # ←─── cursor # ←───────────── where the cursor should go on a new line garply: waldo - quux: bar: baz xyzzy: thud fred: plugh In YAML, you often have lists of maps. In these cases, the syntax is such that the list element and the map both start on the same line. But we really do want to start an indentation for each of these so that subsequent keys in the map hang over the list and align properly. This is where @indent.always helps. ((block_sequence_item) @item @indent.always @extend (#not-one-line? @item)) ((block_mapping_pair key: (_) @key value: (_) @val (#not-same-line? @key @val) ) @indent.always @extend\n)","breadcrumbs":"Guides » Adding indent queries » Capture types","id":"103","title":"Capture types"},"104":{"body":"In some cases, an S-expression cannot express exactly what pattern should be matched. For that, tree-sitter allows for predicates to appear anywhere within a pattern, similar to how #set! declarations work: (some_kind (child_kind) @indent (#predicate? arg1 arg2 ...)\n) The number of arguments depends on the predicate that's used. Each argument is either a capture (@name) or a string (\"some string\"). The following predicates are supported by tree-sitter: #eq?/#not-eq?: The first argument (a capture) must/must not be equal to the second argument (a capture or a string). #match?/#not-match?: The first argument (a capture) must/must not match the regex given in the second argument (a string). #any-of?/#not-any-of?: The first argument (a capture) must/must not be one of the other arguments (strings). Additionally, we support some custom predicates for indent queries: #not-kind-eq?: The kind of the first argument (a capture) must not be equal to the second argument (a string). #same-line?/#not-same-line?: The captures given by the 2 arguments must/must not start on the same line. #one-line?/#not-one-line?: The captures given by the fist argument must/must span a total of one line.","breadcrumbs":"Guides » Adding indent queries » Predicates","id":"104","title":"Predicates"},"105":{"body":"Added indents don't always apply to the whole node. For example, in most cases when a node should be indented, we actually only want everything except for its first line to be indented. For this, there are several scopes (more scopes may be added in the future if required): tail: This scope applies to everything except for the first line of the captured node. all: This scope applies to the whole captured node. This is only different from tail when the captured node is the first node on its line. For example, imagine we have the following function fn aha() { // ←─────────────────────────────────────╮ let take = \"on me\"; // ←──────────────╮ scope: │ let take = \"me on\"; // ├─ \"tail\" ├─ (block) @indent let ill = be_gone_days(1 || 2); // │ │\n} // ←───────────────────────────────────┴──────────┴─ \"}\" @outdent // scope: \"all\" We can write the following query with the #set! declaration: ((block) @indent (#set! \"scope\" \"tail\"))\n(\"}\" @outdent (#set! \"scope\" \"all\")) As we can see, the \"tail\" scope covers the node, except for the first line. Everything up to and including the closing brace gets an indent level of 1. Then, on the closing brace, we encounter an outdent with a scope of \"all\", which means the first line is included, and the indent level is cancelled out on this line. (Note these scopes are the defaults for @indent and @outdent—they are written explicitly for demonstration.)","breadcrumbs":"Guides » Adding indent queries » Scopes","id":"105","title":"Scopes"},"106":{"body":"Writing language injection queries allows one to highlight a specific node as a different language. In addition to the standard language injection options used by tree-sitter, there are a few Helix specific extensions that allow for more control. And example of a simple query that would highlight all strings as bash in Nix: ((string_expression (string_fragment) @injection.content) (#set! injection.language \"bash\"))","breadcrumbs":"Guides » Adding injection queries » Adding Injection Queries","id":"106","title":"Adding Injection Queries"},"107":{"body":"@injection.language (standard): The captured node may contain the language name used to highlight the node captured by @injection.content. @injection.content (standard): Marks the content to be highlighted as the language captured with @injection.language et al . @injection.filename (extension): The captured node may contain a filename with a file-extension known to Helix, highlighting @injection.content as that language. This uses the language extensions defined in both the default languages.toml distributed with Helix, as well as user defined languages. @injection.shebang (extension): The captured node may contain a shebang used to choose a language to highlight as. This also uses the shebangs defined in the default and user languages.toml.","breadcrumbs":"Guides » Adding injection queries » Capture Types","id":"107","title":"Capture Types"},"108":{"body":"injection.combined (standard): Indicates that all the matching nodes in the tree should have their content parsed as one nested document. injection.language (standard): Forces the captured content to be highlighted as the given language injection.include-children (standard): Indicates that the content node’s entire text should be re-parsed, including the text of its child nodes. By default, child nodes’ text will be excluded from the injected document. injection.include-unnamed-children (extension): Same as injection.include-children but only for unnamed child nodes.","breadcrumbs":"Guides » Adding injection queries » Settings","id":"108","title":"Settings"},"109":{"body":"#eq? (standard): The first argument (a capture) must be equal to the second argument (a capture or a string). #match? (standard): The first argument (a capture) must match the regex given in the second argument (a string). #any-of? (standard): The first argument (a capture) must be one of the other arguments (strings).","breadcrumbs":"Guides » Adding injection queries » Predicates","id":"109","title":"Predicates"},"11":{"body":"Install Helix using the Linux AppImage format. Download the official Helix AppImage from the latest releases page. chmod +x helix-*.AppImage # change permission for executable mode\n./helix-*.AppImage # run helix You can optionally add the .desktop file . Helix must be installed in PATH with the name hx. For example: mkdir -p \"$HOME/.local/bin\"\nmv helix-*.AppImage \"$HOME/.local/bin/hx\" and make sure ~/.local/bin is in your PATH.","breadcrumbs":"Installation » Package Managers » AppImage","id":"11","title":"AppImage"},"12":{"body":"","breadcrumbs":"Installation » Package Managers » macOS","id":"12","title":"macOS"},"13":{"body":"brew install helix","breadcrumbs":"Installation » Package Managers » Homebrew Core","id":"13","title":"Homebrew Core"},"14":{"body":"port install helix","breadcrumbs":"Installation » Package Managers » MacPorts","id":"14","title":"MacPorts"},"15":{"body":"Install on Windows using Winget , Scoop , Chocolatey or MSYS2 .","breadcrumbs":"Installation » Package Managers » Windows","id":"15","title":"Windows"},"16":{"body":"Windows Package Manager winget command-line tool is by default available on Windows 11 and modern versions of Windows 10 as a part of the App Installer. You can get App Installer from the Microsoft Store . If it's already installed, make sure it is updated with the latest version. winget install Helix.Helix","breadcrumbs":"Installation » Package Managers » Winget","id":"16","title":"Winget"},"17":{"body":"scoop install helix","breadcrumbs":"Installation » Package Managers » Scoop","id":"17","title":"Scoop"},"18":{"body":"choco install helix","breadcrumbs":"Installation » Package Managers » Chocolatey","id":"18","title":"Chocolatey"},"19":{"body":"For 64-bit Windows 8.1 or above: pacman -S mingw-w64-ucrt-x86_64-helix","breadcrumbs":"Installation » Package Managers » MSYS2","id":"19","title":"MSYS2"},"2":{"body":"Download pre-built binaries from the GitHub Releases page . The tarball contents include an hx binary and a runtime directory. To set up Helix: Add the hx binary to your system's $PATH to allow it to be used from the command line. Copy the runtime directory to a location that hx searches for runtime files. A typical location on Linux/macOS is ~/.config/helix/runtime. To see the runtime directories that hx searches, run hx --health. If necessary, you can override the default runtime location by setting the HELIX_RUNTIME environment variable.","breadcrumbs":"Installation » Pre-built binaries","id":"2","title":"Pre-built binaries"},"20":{"body":"Configuring Helix's runtime files Linux and macOS Windows Multiple runtime directories Note to packagers Validating the installation Configure the desktop shortcut Requirements: Clone the Helix GitHub repository into a directory of your choice. The examples in this documentation assume installation into either ~/src/ on Linux and macOS, or %userprofile%\\src\\ on Windows. The Rust toolchain The Git version control system A C++14 compatible compiler to build the tree-sitter grammars, for example GCC or Clang If you are using the musl-libc standard library instead of glibc the following environment variable must be set during the build to ensure tree-sitter grammars can be loaded correctly: RUSTFLAGS=\"-C target-feature=-crt-static\" Clone the repository: git clone https://github.com/helix-editor/helix\ncd helix Compile from source: cargo install --path helix-term --locked This command will create the hx executable and construct the tree-sitter grammars in the local runtime folder. 💡 If you do not want to fetch or build grammars, set an environment variable HELIX_DISABLE_AUTO_GRAMMAR_BUILD 💡 Tree-sitter grammars can be fetched and compiled if not pre-packaged. Fetch grammars with hx --grammar fetch and compile them with hx --grammar build. This will install them in the runtime directory within the user's helix config directory (more details below ).","breadcrumbs":"Installation » Building from source » Building from source","id":"20","title":"Building from source"},"21":{"body":"Linux and macOS The runtime directory is one below the Helix source, so either export a HELIX_RUNTIME environment variable to point to that directory and add it to your ~/.bashrc or equivalent: export HELIX_RUNTIME=~/src/helix/runtime Or, create a symbolic link: ln -Ts $PWD/runtime ~/.config/helix/runtime If the above command fails to create a symbolic link because the file exists either move ~/.config/helix/runtime to a new location or delete it, then run the symlink command above again. Windows Either set the HELIX_RUNTIME environment variable to point to the runtime files using the Windows setting (search for Edit environment variables for your account) or use the setx command in Cmd: setx HELIX_RUNTIME \"%userprofile%\\source\\repos\\helix\\runtime\" 💡 %userprofile% resolves to your user directory like C:\\Users\\Your-Name\\ for example. Or, create a symlink in %appdata%\\helix\\ that links to the source code directory: Method Command PowerShell New-Item -ItemType Junction -Target \"runtime\" -Path \"$Env:AppData\\helix\\runtime\" Cmd cd %appdata%\\helix mklink /D runtime \"%userprofile%\\src\\helix\\runtime\" 💡 On Windows, creating a symbolic link may require running PowerShell or Cmd as an administrator. Multiple runtime directories When Helix finds multiple runtime directories it will search through them for files in the following order: runtime/ sibling directory to $CARGO_MANIFEST_DIR directory (this is intended for developing and testing helix only). runtime/ subdirectory of OS-dependent helix user config directory. $HELIX_RUNTIME Distribution-specific fallback directory (set at compile time—not run time— with the HELIX_DEFAULT_RUNTIME environment variable) runtime/ subdirectory of path to Helix executable. This order also sets the priority for selecting which file will be used if multiple runtime directories have files with the same name. Note to packagers If you are making a package of Helix for end users, to provide a good out of the box experience, you should set the HELIX_DEFAULT_RUNTIME environment variable at build time (before invoking cargo build) to a directory which will store the final runtime files after installation. For example, say you want to package the runtime into /usr/lib/helix/runtime. The rough steps a build script could follow are: export HELIX_DEFAULT_RUNTIME=/usr/lib/helix/runtime cargo build --profile opt --locked cp -r runtime $BUILD_DIR/usr/lib/helix/ cp target/opt/hx $BUILD_DIR/usr/bin/hx This way the resulting hx binary will always look for its runtime directory in /usr/lib/helix/runtime if the user has no custom runtime in ~/.config/helix or HELIX_RUNTIME.","breadcrumbs":"Installation » Building from source » Configuring Helix's runtime files","id":"21","title":"Configuring Helix's runtime files"},"22":{"body":"To make sure everything is set up as expected you should run the Helix health check: hx --health For more information on the health check results refer to Health check .","breadcrumbs":"Installation » Building from source » Validating the installation","id":"22","title":"Validating the installation"},"23":{"body":"If your desktop environment supports the XDG desktop menu you can configure Helix to show up in the application menu by copying the provided .desktop and icon files to their correct folders: cp contrib/Helix.desktop ~/.local/share/applications\ncp contrib/helix.png ~/.icons # or ~/.local/share/icons It is recommended to convert the links in the .desktop file to absolute paths to avoid potential problems: sed -i -e \"s|Exec=hx %F|Exec=$(readlink -f ~/.cargo/bin/hx) %F|g\" \\ -e \"s|Icon=helix|Icon=$(readlink -f ~/.icons/helix.png)|g\" ~/.local/share/applications/Helix.desktop To use another terminal than the system default, you can modify the .desktop file. For example, to use kitty: sed -i \"s|Exec=hx %F|Exec=kitty hx %F|g\" ~/.local/share/applications/Helix.desktop\nsed -i \"s|Terminal=true|Terminal=false|g\" ~/.local/share/applications/Helix.desktop","breadcrumbs":"Installation » Building from source » Configure the desktop shortcut","id":"23","title":"Configure the desktop shortcut"},"24":{"body":"For a full interactive introduction to Helix, refer to the tutor which can be accessed via the command hx --tutor or :tutor. 💡 Currently, not all functionality is fully documented, please refer to the key mappings list.","breadcrumbs":"Usage » Using Helix","id":"24","title":"Using Helix"},"25":{"body":"Helix is a modal editor, meaning it has different modes for different tasks. The main modes are: Normal mode : For navigation and editing commands. This is the default mode. Insert mode : For typing text directly into the document. Access by typing i in normal mode. Select/extend mode : For making selections and performing operations on them. Access by typing v in normal mode.","breadcrumbs":"Usage » Modes","id":"25","title":"Modes"},"26":{"body":"Buffers are in-memory representations of files. You can have multiple buffers open at once. Use pickers or commands like :buffer-next and :buffer-previous to open buffers or switch between them.","breadcrumbs":"Usage » Buffers","id":"26","title":"Buffers"},"27":{"body":"Inspired by Kakoune , Helix follows the selection → action model. This means that whatever you are going to act on (a word, a paragraph, a line, etc.) is selected first and the action itself (delete, change, yank, etc.) comes second. A cursor is simply a single width selection.","breadcrumbs":"Usage » Selection-first editing","id":"27","title":"Selection-first editing"},"28":{"body":"Also inspired by Kakoune, multiple selections are a core mode of interaction in Helix. For example, the standard way of replacing multiple instance of a word is to first select all instances (so there is one selection per instance) and then use the change action (c) to edit them all at the same time.","breadcrumbs":"Usage » Multiple selections","id":"28","title":"Multiple selections"},"29":{"body":"Motions are commands that move the cursor or modify selections. They're used for navigation and text manipulation. Examples include w to move to the next word, or f to find a character. See the Movement section of the keymap for more motions.","breadcrumbs":"Usage » Motions","id":"29","title":"Motions"},"3":{"body":"Linux Ubuntu Fedora/RHEL Arch Linux extra NixOS Flatpak Snap AppImage macOS Homebrew Core MacPorts Windows Winget Scoop Chocolatey MSYS2 Packaging status","breadcrumbs":"Installation » Package Managers » Package managers","id":"3","title":"Package managers"},"30":{"body":"User-defined registers Default registers Special registers In Helix, registers are storage locations for text and other data, such as the result of a search. Registers can be used to cut, copy, and paste text, similar to the clipboard in other text editors. Usage is similar to Vim, with \" being used to select a register.","breadcrumbs":"Usage » Registers » Registers","id":"30","title":"Registers"},"31":{"body":"Helix allows you to create your own named registers for storing text, for example: \"ay - Yank the current selection to register a. \"op - Paste the text in register o after the selection. If a register is selected before invoking a change or delete command, the selection will be stored in the register and the action will be carried out: \"hc - Store the selection in register h and then change it (delete and enter insert mode). \"md - Store the selection in register m and delete it.","breadcrumbs":"Usage » Registers » User-defined registers","id":"31","title":"User-defined registers"},"32":{"body":"Commands that use registers, like yank (y), use a default register if none is specified. These registers are used as defaults: Register character Contains / Last search : Last executed command \" Last yanked text @ Last recorded macro","breadcrumbs":"Usage » Registers » Default registers","id":"32","title":"Default registers"},"33":{"body":"Some registers have special behavior when read from and written to. Register character When read When written _ No values are returned All values are discarded # Selection indices (first selection is 1, second is 2, etc.) This register is not writable . Contents of the current selections This register is not writable % Name of the current file This register is not writable + Reads from the system clipboard Joins and yanks to the system clipboard * Reads from the primary clipboard Joins and yanks to the primary clipboard When yanking multiple selections to the clipboard registers, the selections are joined with newlines. Pasting from these registers will paste multiple selections if the clipboard was last yanked to by the Helix session. Otherwise the clipboard contents are pasted as one selection.","breadcrumbs":"Usage » Registers » Special registers","id":"33","title":"Special registers"},"34":{"body":"Helix includes built-in functionality similar to vim-surround . The keymappings have been inspired from vim-sandwich : Surround demo Key Sequence Action ms (after selecting text) Add surround characters to selection mr Replace the closest surround characters md Delete the closest surround characters You can use counts to act on outer pairs. Surround can also act on multiple selections. For example, to change every occurrence of (use) to [use]: % to select the whole file s to split the selections on a search term Input use and hit Enter mr([ to replace the parentheses with square brackets Multiple characters are currently not supported, but planned for future release.","breadcrumbs":"Usage » Surround » Surround","id":"34","title":"Surround"},"35":{"body":"In Helix, textobjects are a way to select, manipulate and operate on a piece of text in a structured way. They allow you to refer to blocks of text based on their structure or purpose, such as a word, sentence, paragraph, or even a function or block of code. Textobject demo Textobject tree-sitter demo ma - Select around the object (va in Vim, in Kakoune) mi - Select inside the object (vi in Vim, in Kakoune) Key after mi or ma Textobject selected w Word W WORD p Paragraph (, [, ', etc. Specified surround pairs m The closest surround pair f Function t Type (or Class) a Argument/parameter c Comment T Test g Change 💡 f, t, etc. need a tree-sitter grammar active for the current document and a special tree-sitter query file to work properly. Only some grammars currently have the query file implemented. Contributions are welcome!","breadcrumbs":"Usage » Textobjects » Selecting and manipulating text with textobjects","id":"35","title":"Selecting and manipulating text with textobjects"},"36":{"body":"Navigating between functions, classes, parameters, and other elements is possible using tree-sitter and textobject queries. For example to move to the next function use ]f, to move to previous type use [t, and so on. Tree-sitter-nav-demo For the full reference see the unimpaired section of the key bind documentation. 💡 This feature relies on tree-sitter textobjects and requires the corresponding query file to work properly.","breadcrumbs":"Usage » Textobjects » Navigating using tree-sitter textobjects","id":"36","title":"Navigating using tree-sitter textobjects"},"37":{"body":"Alt-p, Alt-o, Alt-i, and Alt-n (or Alt and arrow keys) allow you to move the selection according to its location in the syntax tree. For example, many languages have the following syntax for function calls: func(arg1, arg2, arg3); A function call might be parsed by tree-sitter into a tree like the following. (call function: (identifier) ; func arguments: (arguments ; (arg1, arg2, arg3) (identifier) ; arg1 (identifier) ; arg2 (identifier))) ; arg3 Use :tree-sitter-subtree to view the syntax tree of the primary selection. In a more intuitive tree format: ┌────┐ │call│ ┌─────┴────┴─────┐ │ │\n┌─────▼────┐ ┌────▼────┐\n│identifier│ │arguments│\n│ \"func\" │ ┌────┴───┬─────┴───┐\n└──────────┘ │ │ │ │ │ │ ┌─────────▼┐ ┌────▼─────┐ ┌▼─────────┐ │identifier│ │identifier│ │identifier│ │ \"arg1\" │ │ \"arg2\" │ │ \"arg3\" │ └──────────┘ └──────────┘ └──────────┘ If you have a selection that wraps arg1 (see the tree above), and you use Alt-n, it will select the next sibling in the syntax tree: arg2. // before\nfunc([arg1], arg2, arg3)\n// after\nfunc(arg1, [arg2], arg3); Similarly, Alt-o will expand the selection to the parent node, in this case, the arguments node. func[(arg1, arg2, arg3)]; There is also some nuanced behavior that prevents you from getting stuck on a node with no sibling. When using Alt-p with a selection on arg1, the previous child node will be selected. In the event that arg1 does not have a previous sibling, the selection will move up the syntax tree and select the previous element. As a result, using Alt-p with a selection on arg1 will move the selection to the \"func\" identifier.","breadcrumbs":"Usage » Syntax aware motions » Moving the selection with syntax-aware motions","id":"37","title":"Moving the selection with syntax-aware motions"},"38":{"body":"Helix has a variety of pickers, which are interactive windows used to select various kinds of items. These include a file picker, global search picker, and more. Most pickers are accessed via keybindings in space mode . Pickers have their own keymap for navigation.","breadcrumbs":"Usage » Pickers » Using pickers","id":"38","title":"Using pickers"},"39":{"body":"Most pickers perform fuzzy matching using fzf syntax . Two exceptions are the global search picker, which uses regex, and the workspace symbol picker, which passes search terms to the language server. Note that OR operations (|) are not currently supported. If a picker shows multiple columns, you may apply the filter to a specific column by prefixing the column name with %. Column names can be shortened to any prefix, so %p, %pa or %pat all mean the same as %path. For example, a query of helix %p .toml !lang in the global search picker searches for the term \"helix\" within files with paths ending in \".toml\" but not including \"lang\". You can insert the contents of a register using Ctrl-r followed by a register name. For example, one could insert the currently selected text using Ctrl-r-., or the directory of the current file using Ctrl-r-% followed by Ctrl-w to remove the last path section. The global search picker will use the contents of the search register if you press Enter without typing a filter. For example, pressing *-Space-/-Enter will start a global search for the currently selected text.","breadcrumbs":"Usage » Pickers » Filtering Picker Results","id":"39","title":"Filtering Picker Results"},"4":{"body":"The following third party repositories are available:","breadcrumbs":"Installation » Package Managers » Linux","id":"4","title":"Linux"},"40":{"body":"Normal mode Movement Changes Shell Selection manipulation Search Minor modes View mode Goto mode Match mode Window mode Space mode Popup Completion Menu Signature-help Popup Unimpaired Insert mode Select / extend mode Picker Prompt 💡 Mappings marked ( LSP ) require an active language server for the file. 💡 Mappings marked ( TS ) require a tree-sitter grammar for the file type. ⚠️ Some terminals' default key mappings conflict with Helix's. If any of the mappings described on this page do not work as expected, check your terminal's mappings to ensure they do not conflict. See the wiki for known conflicts.","breadcrumbs":"Usage » Keymap » Keymap","id":"40","title":"Keymap"},"41":{"body":"Normal mode is the default mode when you launch helix. You can return to it from other modes by pressing the Escape key.","breadcrumbs":"Usage » Keymap » Normal mode","id":"41","title":"Normal mode"},"42":{"body":"NOTE: Unlike Vim, f, F, t and T are not confined to the current line. Key Description Command h, Left Move left move_char_left j, Down Move down move_visual_line_down k, Up Move up move_visual_line_up l, Right Move right move_char_right w Move next word start move_next_word_start b Move previous word start move_prev_word_start e Move next word end move_next_word_end W Move next WORD start move_next_long_word_start B Move previous WORD start move_prev_long_word_start E Move next WORD end move_next_long_word_end t Find 'till next char find_till_char f Find next char find_next_char T Find 'till previous char till_prev_char F Find previous char find_prev_char G Go to line number goto_line Alt-. Repeat last motion (f, t, m, [ or ]) repeat_last_motion Home Move to the start of the line goto_line_start End Move to the end of the line goto_line_end Ctrl-b, PageUp Move page up page_up Ctrl-f, PageDown Move page down page_down Ctrl-u Move cursor and page half page up page_cursor_half_up Ctrl-d Move cursor and page half page down page_cursor_half_down Ctrl-i Jump forward on the jumplist jump_forward Ctrl-o Jump backward on the jumplist jump_backward Ctrl-s Save the current selection to the jumplist save_selection","breadcrumbs":"Usage » Keymap » Movement","id":"42","title":"Movement"},"43":{"body":"Key Description Command r Replace with a character replace R Replace with yanked text replace_with_yanked ~ Switch case of the selected text switch_case ` Set the selected text to lower case switch_to_lowercase Alt-` Set the selected text to upper case switch_to_uppercase i Insert before selection insert_mode a Insert after selection (append) append_mode I Insert at the start of the line insert_at_line_start A Insert at the end of the line insert_at_line_end o Open new line below selection open_below O Open new line above selection open_above . Repeat last insert N/A u Undo change undo U Redo change redo Alt-u Move backward in history earlier Alt-U Move forward in history later y Yank selection yank p Paste after selection paste_after P Paste before selection paste_before \" Select a register to yank to or paste from select_register > Indent selection indent < Unindent selection unindent = Format selection ( LSP ) format_selections d Delete selection delete_selection Alt-d Delete selection, without yanking delete_selection_noyank c Change selection (delete and enter insert mode) change_selection Alt-c Change selection (delete and enter insert mode, without yanking) change_selection_noyank Ctrl-a Increment object (number) under cursor increment Ctrl-x Decrement object (number) under cursor decrement Q Start/stop macro recording to the selected register (experimental) record_macro q Play back a recorded macro from the selected register (experimental) replay_macro Shell Key Description Command | Pipe each selection through shell command, replacing with output shell_pipe Alt-| Pipe each selection into shell command, ignoring output shell_pipe_to ! Run shell command, inserting output before each selection shell_insert_output Alt-! Run shell command, appending output after each selection shell_append_output $ Pipe each selection into shell command, keep selections where command returned 0 shell_keep_pipe","breadcrumbs":"Usage » Keymap » Changes","id":"43","title":"Changes"},"44":{"body":"Key Description Command s Select all regex matches inside selections select_regex S Split selection into sub selections on regex matches split_selection Alt-s Split selection on newlines split_selection_on_newline Alt-minus Merge selections merge_selections Alt-_ Merge consecutive selections merge_consecutive_selections & Align selection in columns align_selections _ Trim whitespace from the selection trim_selections ; Collapse selection onto a single cursor collapse_selection Alt-; Flip selection cursor and anchor flip_selections Alt-: Ensures the selection is in forward direction ensure_selections_forward , Keep only the primary selection keep_primary_selection Alt-, Remove the primary selection remove_primary_selection C Copy selection onto the next line (Add cursor below) copy_selection_on_next_line Alt-C Copy selection onto the previous line (Add cursor above) copy_selection_on_prev_line ( Rotate main selection backward rotate_selections_backward ) Rotate main selection forward rotate_selections_forward Alt-( Rotate selection contents backward rotate_selection_contents_backward Alt-) Rotate selection contents forward rotate_selection_contents_forward % Select entire file select_all x Select current line, if already selected, extend to next line extend_line_below X Extend selection to line bounds (line-wise selection) extend_to_line_bounds Alt-x Shrink selection to line bounds (line-wise selection) shrink_to_line_bounds J Join lines inside selection join_selections Alt-J Join lines inside selection and select the inserted space join_selections_space K Keep selections matching the regex keep_selections Alt-K Remove selections matching the regex remove_selections Ctrl-c Comment/uncomment the selections toggle_comments Alt-o, Alt-up Expand selection to parent syntax node ( TS ) expand_selection Alt-i, Alt-down Shrink syntax tree object selection ( TS ) shrink_selection Alt-p, Alt-left Select previous sibling node in syntax tree ( TS ) select_prev_sibling Alt-n, Alt-right Select next sibling node in syntax tree ( TS ) select_next_sibling Alt-a Select all sibling nodes in syntax tree ( TS ) select_all_siblings Alt-I, Alt-Shift-down Select all children nodes in syntax tree ( TS ) select_all_children Alt-e Move to end of parent node in syntax tree ( TS ) move_parent_node_end Alt-b Move to start of parent node in syntax tree ( TS ) move_parent_node_start","breadcrumbs":"Usage » Keymap » Selection manipulation","id":"44","title":"Selection manipulation"},"45":{"body":"Search commands all operate on the / register by default. To use a different register, use \". Key Description Command / Search for regex pattern search ? Search for previous pattern rsearch n Select next search match search_next N Select previous search match search_prev * Use current selection as the search pattern, automatically wrapping with \\b on word boundaries search_selection_detect_word_boundaries Alt-* Use current selection as the search pattern search_selection","breadcrumbs":"Usage » Keymap » Search","id":"45","title":"Search"},"46":{"body":"These sub-modes are accessible from normal mode and typically switch back to normal mode after a command. Key Description Command v Enter select (extend) mode select_mode g Enter goto mode N/A m Enter match mode N/A : Enter command mode command_mode z Enter view mode N/A Z Enter sticky view mode N/A Ctrl-w Enter window mode N/A Space Enter space mode N/A These modes (except command mode) can be configured by remapping keys . View mode Accessed by typing z in normal mode . View mode is intended for scrolling and manipulating the view without changing the selection. The \"sticky\" variant of this mode (accessed by typing Z in normal mode) is persistent and can be exited using the escape key. This is useful when you're simply looking over text and not actively editing it. Key Description Command z, c Vertically center the line align_view_center t Align the line to the top of the screen align_view_top b Align the line to the bottom of the screen align_view_bottom m Align the line to the middle of the screen (horizontally) align_view_middle j, down Scroll the view downwards scroll_down k, up Scroll the view upwards scroll_up Ctrl-f, PageDown Move page down page_down Ctrl-b, PageUp Move page up page_up Ctrl-u Move cursor and page half page up page_cursor_half_up Ctrl-d Move cursor and page half page down page_cursor_half_down Goto mode Accessed by typing g in normal mode . Jumps to various locations. Key Description Command g Go to line number else start of file goto_file_start e Go to the end of the file goto_last_line f Go to files in the selections goto_file h Go to the start of the line goto_line_start l Go to the end of the line goto_line_end s Go to first non-whitespace character of the line goto_first_nonwhitespace t Go to the top of the screen goto_window_top c Go to the middle of the screen goto_window_center b Go to the bottom of the screen goto_window_bottom d Go to definition ( LSP ) goto_definition y Go to type definition ( LSP ) goto_type_definition r Go to references ( LSP ) goto_reference i Go to implementation ( LSP ) goto_implementation a Go to the last accessed/alternate file goto_last_accessed_file m Go to the last modified/alternate file goto_last_modified_file n Go to next buffer goto_next_buffer p Go to previous buffer goto_previous_buffer . Go to last modification in current file goto_last_modification j Move down textual (instead of visual) line move_line_down k Move up textual (instead of visual) line move_line_up w Show labels at each word and select the word that belongs to the entered labels goto_word Match mode Accessed by typing m in normal mode . Please refer to the relevant sections for detailed explanations about surround and textobjects . Key Description Command m Goto matching bracket ( TS ) match_brackets s Surround current selection with surround_add r Replace surround character with surround_replace d Delete surround character surround_delete a