<!DOCTYPE HTML>
< html lang = "en" class = "colibri" dir = "ltr" >
< head >
<!-- Book generated using mdBook -->
< meta charset = "UTF-8" >
< title > Usage< / title >
<!-- Custom HTML head -->
< meta name = "description" content = "" >
< meta name = "viewport" content = "width=device-width, initial-scale=1" >
< meta name = "theme-color" content = "#ffffff" >
< link rel = "icon" href = "favicon.svg" >
< link rel = "shortcut icon" href = "favicon.png" >
< link rel = "stylesheet" href = "css/variables.css" >
< link rel = "stylesheet" href = "css/general.css" >
< link rel = "stylesheet" href = "css/chrome.css" >
< link rel = "stylesheet" href = "css/print.css" media = "print" >
<!-- Fonts -->
< link rel = "stylesheet" href = "FontAwesome/css/font-awesome.css" >
< link rel = "stylesheet" href = "fonts/fonts.css" >
<!-- Highlight.js Stylesheets -->
< link rel = "stylesheet" href = "highlight.css" >
< link rel = "stylesheet" href = "tomorrow-night.css" >
< link rel = "stylesheet" href = "ayu-highlight.css" >
<!-- Custom theme stylesheets -->
< link rel = "stylesheet" href = "custom.css" >
< / head >
< body class = "sidebar-visible no-js" >
< div id = "body-container" >
<!-- Provide site root to javascript -->
< script >
var path_to_root = "";
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "colibri" : "colibri";
< / script >
<!-- Work around some values being stored in localStorage wrapped in quotes -->
< script >
try {
var theme = localStorage.getItem('mdbook-theme');
var sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') & & theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
}
if (sidebar.startsWith('"') & & sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
< / script >
<!-- Set the theme before any content is loaded, prevents flash -->
< script >
var theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
var html = document.querySelector('html');
html.classList.remove('colibri')
html.classList.add(theme);
var body = document.querySelector('body');
body.classList.remove('no-js')
body.classList.add('js');
< / script >
< input type = "checkbox" id = "sidebar-toggle-anchor" class = "hidden" >
<!-- Hide / unhide sidebar before it is displayed -->
< script >
var body = document.querySelector('body');
var sidebar = null;
var sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
} else {
sidebar = 'hidden';
}
sidebar_toggle.checked = sidebar === 'visible';
body.classList.remove('sidebar-visible');
body.classList.add("sidebar-" + sidebar);
< / script >
< nav id = "sidebar" class = "sidebar" aria-label = "Table of contents" >
< div class = "sidebar-scrollbox" >
< ol class = "chapter" > < li class = "chapter-item expanded affix " > < a href = "title-page.html" > Helix< / a > < / li > < li class = "chapter-item expanded " > < a href = "install.html" > < strong aria-hidden = "true" > 1.< / strong > Installation< / a > < / li > < li class = "chapter-item expanded " > < a href = "usage.html" class = "active" > < strong aria-hidden = "true" > 2.< / strong > Usage< / a > < / li > < li > < ol class = "section" > < li class = "chapter-item expanded " > < a href = "keymap.html" > < strong aria-hidden = "true" > 2.1.< / strong > Keymap< / a > < / li > < li class = "chapter-item expanded " > < a href = "commands.html" > < strong aria-hidden = "true" > 2.2.< / strong > Commands< / a > < / li > < li class = "chapter-item expanded " > < a href = "lang-support.html" > < strong aria-hidden = "true" > 2.3.< / strong > Language support< / a > < / li > < / ol > < / li > < li class = "chapter-item expanded " > < a href = "from-vim.html" > < strong aria-hidden = "true" > 3.< / strong > Migrating from Vim< / a > < / li > < li class = "chapter-item expanded " > < a href = "configuration.html" > < strong aria-hidden = "true" > 4.< / strong > Configuration< / a > < / li > < li > < ol class = "section" > < li class = "chapter-item expanded " > < a href = "themes.html" > < strong aria-hidden = "true" > 4.1.< / strong > Themes< / a > < / li > < li class = "chapter-item expanded " > < a href = "remapping.html" > < strong aria-hidden = "true" > 4.2.< / strong > Key remapping< / a > < / li > < li class = "chapter-item expanded " > < a href = "languages.html" > < strong aria-hidden = "true" > 4.3.< / strong > Languages< / a > < / li > < / ol > < / li > < li class = "chapter-item expanded " > < a href = "guides/index.html" > < strong aria-hidden = "true" > 5.< / strong > Guides< / a > < / li > < li > < ol class = "section" > < li class = "chapter-item expanded " > < a href = "guides/adding_languages.html" > < strong aria-hidden = "true" > 5.1.< / strong > Adding languages< / a > < / li > < li class = "chapter-item expanded " > < a href = "guides/textobject.html" > < strong aria-hidden = "true" > 5.2.< / strong > Adding textobject queries< / a > < / li > < li class = "chapter-item expanded " > < a href = "guides/indent.html" > < strong aria-hidden = "true" > 5.3.< / strong > Adding indent queries< / a > < / li > < li class = "chapter-item expanded " > < a href = "guides/injection.html" > < strong aria-hidden = "true" > 5.4.< / strong > Adding injection queries< / a > < / li > < / ol > < / li > < / ol >
< / div >
< div id = "sidebar-resize-handle" class = "sidebar-resize-handle" > < / div >
< / nav >
<!-- Track and set sidebar scroll position -->
< script >
var sidebarScrollbox = document.querySelector('#sidebar .sidebar-scrollbox');
sidebarScrollbox.addEventListener('click', function(e) {
if (e.target.tagName === 'A') {
sessionStorage.setItem('sidebar-scroll', sidebarScrollbox.scrollTop);
}
}, { passive: true });
var sidebarScrollTop = sessionStorage.getItem('sidebar-scroll');
sessionStorage.removeItem('sidebar-scroll');
if (sidebarScrollTop) {
// preserve sidebar scroll position when navigating via links within sidebar
sidebarScrollbox.scrollTop = sidebarScrollTop;
} else {
// scroll sidebar to current active section when navigating via "next/previous chapter" buttons
var activeSection = document.querySelector('#sidebar .active');
if (activeSection) {
activeSection.scrollIntoView({ block: 'center' });
}
}
< / script >
< div id = "page-wrapper" class = "page-wrapper" >
< div class = "page" >
< div id = "menu-bar-hover-placeholder" > < / div >
< div id = "menu-bar" class = "menu-bar sticky" >
< div class = "left-buttons" >
< label id = "sidebar-toggle" class = "icon-button" for = "sidebar-toggle-anchor" title = "Toggle Table of Contents" aria-label = "Toggle Table of Contents" aria-controls = "sidebar" >
< i class = "fa fa-bars" > < / i >
< / label >
< button id = "theme-toggle" class = "icon-button" type = "button" title = "Change theme" aria-label = "Change theme" aria-haspopup = "true" aria-expanded = "false" aria-controls = "theme-list" >
< i class = "fa fa-paint-brush" > < / i >
< / button >
< ul id = "theme-list" class = "theme-popup" aria-label = "Themes" role = "menu" >
< li role = "none" > < button role = "menuitem" class = "theme" id = "light" > Light< / button > < / li >
< li role = "none" > < button role = "menuitem" class = "theme" id = "rust" > Rust< / button > < / li >
< li role = "none" > < button role = "menuitem" class = "theme" id = "coal" > Coal< / button > < / li >
< li role = "none" > < button role = "menuitem" class = "theme" id = "navy" > Navy< / button > < / li >
< li role = "none" > < button role = "menuitem" class = "theme" id = "ayu" > Ayu< / button > < / li >
< li role = "none" > < button role = "menuitem" class = "theme" id = "colibri" > Colibri< / button > < / li >
< / ul >
< button id = "search-toggle" class = "icon-button" type = "button" title = "Search. (Shortkey: s)" aria-label = "Toggle Searchbar" aria-expanded = "false" aria-keyshortcuts = "S" aria-controls = "searchbar" >
< i class = "fa fa-search" > < / i >
< / button >
< / div >
< h1 class = "menu-title" > < / h1 >
< div class = "right-buttons" >
< a href = "print.html" title = "Print this book" aria-label = "Print this book" >
< i id = "print-button" class = "fa fa-print" > < / i >
< / a >
< a href = "https://github.com/helix-editor/helix" title = "Git repository" aria-label = "Git repository" >
< i id = "git-repository-button" class = "fa fa-github" > < / i >
< / a >
< a href = "https://github.com/helix-editor/helix/edit/master/book/src/usage.md" title = "Suggest an edit" aria-label = "Suggest an edit" >
< i id = "git-edit-button" class = "fa fa-edit" > < / i >
< / a >
< / div >
< / div >
< div id = "search-wrapper" class = "hidden" >
< form id = "searchbar-outer" class = "searchbar-outer" >
< input type = "search" id = "searchbar" name = "searchbar" placeholder = "Search this book ..." aria-controls = "searchresults-outer" aria-describedby = "searchresults-header" >
< / form >
< div id = "searchresults-outer" class = "searchresults-outer hidden" >
< div id = "searchresults-header" class = "searchresults-header" > < / div >
< ul id = "searchresults" >
< / ul >
< / div >
< / div >
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
< script >
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
< / script >
< div id = "content" class = "content" >
< main >
< h1 id = "using-helix" > < a class = "header" href = "#using-helix" > Using Helix< / a > < / h1 >
<!-- toc:start -->
< ul >
< li > < a href = "#registers" > Registers< / a >
< ul >
< li > < a href = "#user-defined-registers" > User-defined registers< / a > < / li >
< li > < a href = "#special-registers" > Special registers< / a > < / li >
< / ul >
< / li >
< li > < a href = "#surround" > Surround< / a > < / li >
< li > < a href = "#selecting-and-manipulating-text-with-textobjects" > Selecting and manipulating text with textobjects< / a > < / li >
< li > < a href = "#navigating-using-tree-sitter-textobjects" > Navigating using tree-sitter textobjects< / a > < / li >
< li > < a href = "#moving-the-selection-with-syntax-aware-motions" > Moving the selection with syntax-aware motions< / a > < / li >
< / ul >
<!-- toc:end -->
< p > For a full interactive introduction to Helix, refer to the
< a href = "https://github.com/helix-editor/helix/blob/master/runtime/tutor" > tutor< / a > which
can be accessed via the command < code > hx --tutor< / code > or < code > :tutor< / code > .< / p >
< blockquote >
< p > 💡 Currently, not all functionality is fully documented, please refer to the
< a href = "./keymap.html" > key mappings< / a > list.< / p >
< / blockquote >
< h2 id = "registers" > < a class = "header" href = "#registers" > Registers< / a > < / h2 >
< p > 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 < code > " < / code > being
used to select a register.< / p >
< h3 id = "user-defined-registers" > < a class = "header" href = "#user-defined-registers" > User-defined registers< / a > < / h3 >
< p > Helix allows you to create your own named registers for storing text, for
example:< / p >
< ul >
< li > < code > " ay< / code > - Yank the current selection to register < code > a< / code > .< / li >
< li > < code > " op< / code > - Paste the text in register < code > o< / code > after the selection.< / li >
< / ul >
< p > 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:< / p >
< ul >
< li > < code > " hc< / code > - Store the selection in register < code > h< / code > and then change it (delete and enter insert mode).< / li >
< li > < code > " md< / code > - Store the selection in register < code > m< / code > and delete it.< / li >
< / ul >
< h3 id = "default-registers" > < a class = "header" href = "#default-registers" > Default registers< / a > < / h3 >
< p > Commands that use registers, like yank (< code > y< / code > ), use a default register if none is specified.
These registers are used as defaults:< / p >
< div class = "table-wrapper" > < table > < thead > < tr > < th > Register character< / th > < th > Contains< / th > < / tr > < / thead > < tbody >
< tr > < td > < code > /< / code > < / td > < td > Last search< / td > < / tr >
< tr > < td > < code > :< / code > < / td > < td > Last executed command< / td > < / tr >
< tr > < td > < code > " < / code > < / td > < td > Last yanked text< / td > < / tr >
< tr > < td > < code > @< / code > < / td > < td > Last recorded macro< / td > < / tr >
< / tbody > < / table >
< / div >
< h3 id = "special-registers" > < a class = "header" href = "#special-registers" > Special registers< / a > < / h3 >
< p > Some registers have special behavior when read from and written to.< / p >
< div class = "table-wrapper" > < table > < thead > < tr > < th > Register character< / th > < th > When read< / th > < th > When written< / th > < / tr > < / thead > < tbody >
< tr > < td > < code > _< / code > < / td > < td > No values are returned< / td > < td > All values are discarded< / td > < / tr >
< tr > < td > < code > #< / code > < / td > < td > Selection indices (first selection is < code > 1< / code > , second is < code > 2< / code > , etc.)< / td > < td > This register is not writable< / td > < / tr >
< tr > < td > < code > .< / code > < / td > < td > Contents of the current selections< / td > < td > This register is not writable< / td > < / tr >
< tr > < td > < code > %< / code > < / td > < td > Name of the current file< / td > < td > This register is not writable< / td > < / tr >
< tr > < td > < code > +< / code > < / td > < td > Reads from the system clipboard< / td > < td > Joins and yanks to the system clipboard< / td > < / tr >
< tr > < td > < code > *< / code > < / td > < td > Reads from the primary clipboard< / td > < td > Joins and yanks to the primary clipboard< / td > < / tr >
< / tbody > < / table >
< / div >
< p > 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.< / p >
< h2 id = "surround" > < a class = "header" href = "#surround" > Surround< / a > < / h2 >
< p > Helix includes built-in functionality similar to < a href = "https://github.com/tpope/vim-surround" > vim-surround< / a > .
The keymappings have been inspired from < a href = "https://github.com/machakann/vim-sandwich" > vim-sandwich< / a > :< / p >
< p > < img src = "https://user-images.githubusercontent.com/23398472/122865801-97073180-d344-11eb-8142-8f43809982c6.gif" alt = "Surround demo" / > < / p >
< div class = "table-wrapper" > < table > < thead > < tr > < th > Key Sequence< / th > < th > Action< / th > < / tr > < / thead > < tbody >
< tr > < td > < code > ms< char> < / code > (after selecting text)< / td > < td > Add surround characters to selection< / td > < / tr >
< tr > < td > < code > mr< char_to_replace> < new_char> < / code > < / td > < td > Replace the closest surround characters< / td > < / tr >
< tr > < td > < code > md< char_to_delete> < / code > < / td > < td > Delete the closest surround characters< / td > < / tr >
< / tbody > < / table >
< / div >
< p > You can use counts to act on outer pairs.< / p >
< p > Surround can also act on multiple selections. For example, to change every occurrence of < code > (use)< / code > to < code > [use]< / code > :< / p >
< ol >
< li > < code > %< / code > to select the whole file< / li >
< li > < code > s< / code > to split the selections on a search term< / li >
< li > Input < code > use< / code > and hit Enter< / li >
< li > < code > mr([< / code > to replace the parentheses with square brackets< / li >
< / ol >
< p > Multiple characters are currently not supported, but planned for future release.< / p >
< h2 id = "selecting-and-manipulating-text-with-textobjects" > < a class = "header" href = "#selecting-and-manipulating-text-with-textobjects" > Selecting and manipulating text with textobjects< / a > < / h2 >
< p > 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.< / p >
< p > < img src = "https://user-images.githubusercontent.com/23398472/124231131-81a4bb00-db2d-11eb-9d10-8e577ca7b177.gif" alt = "Textobject demo" / >
< img src = "https://user-images.githubusercontent.com/23398472/132537398-2a2e0a54-582b-44ab-a77f-eb818942203d.gif" alt = "Textobject tree-sitter demo" / > < / p >
< ul >
< li > < code > ma< / code > - Select around the object (< code > va< / code > in Vim, < code > < alt-a> < / code > in Kakoune)< / li >
< li > < code > mi< / code > - Select inside the object (< code > vi< / code > in Vim, < code > < alt-i> < / code > in Kakoune)< / li >
< / ul >
< div class = "table-wrapper" > < table > < thead > < tr > < th > Key after < code > mi< / code > or < code > ma< / code > < / th > < th > Textobject selected< / th > < / tr > < / thead > < tbody >
< tr > < td > < code > w< / code > < / td > < td > Word< / td > < / tr >
< tr > < td > < code > W< / code > < / td > < td > WORD< / td > < / tr >
< tr > < td > < code > p< / code > < / td > < td > Paragraph< / td > < / tr >
< tr > < td > < code > (< / code > , < code > [< / code > , < code > '< / code > , etc.< / td > < td > Specified surround pairs< / td > < / tr >
< tr > < td > < code > m< / code > < / td > < td > The closest surround pair< / td > < / tr >
< tr > < td > < code > f< / code > < / td > < td > Function< / td > < / tr >
< tr > < td > < code > t< / code > < / td > < td > Type (or Class)< / td > < / tr >
< tr > < td > < code > a< / code > < / td > < td > Argument/parameter< / td > < / tr >
< tr > < td > < code > c< / code > < / td > < td > Comment< / td > < / tr >
< tr > < td > < code > T< / code > < / td > < td > Test< / td > < / tr >
< tr > < td > < code > g< / code > < / td > < td > Change< / td > < / tr >
< / tbody > < / table >
< / div >
< blockquote >
< p > 💡 < code > f< / code > , < code > t< / code > , etc. need a tree-sitter grammar active for the current
document and a special tree-sitter query file to work properly. < a href = "./lang-support.html" > Only
some grammars< / a > currently have the query file implemented.
Contributions are welcome!< / p >
< / blockquote >
< h2 id = "navigating-using-tree-sitter-textobjects" > < a class = "header" href = "#navigating-using-tree-sitter-textobjects" > Navigating using tree-sitter textobjects< / a > < / h2 >
< p > 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 < code > ]f< / code > , to move to previous
type use < code > [t< / code > , and so on.< / p >
< p > < img src = "https://user-images.githubusercontent.com/23398472/152332550-7dfff043-36a2-4aec-b8f2-77c13eb56d6f.gif" alt = "Tree-sitter-nav-demo" / > < / p >
< p > For the full reference see the < a href = "./keymap.html#unimpaired" > unimpaired< / a > section of the key bind
documentation.< / p >
< blockquote >
< p > 💡 This feature relies on tree-sitter textobjects
and requires the corresponding query file to work properly.< / p >
< / blockquote >
< h2 id = "moving-the-selection-with-syntax-aware-motions" > < a class = "header" href = "#moving-the-selection-with-syntax-aware-motions" > Moving the selection with syntax-aware motions< / a > < / h2 >
< p > < code > Alt-p< / code > , < code > Alt-o< / code > , < code > Alt-i< / code > , and < code > Alt-n< / code > (or < code > Alt< / code > 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:< / p >
< pre > < code class = "language-js" > func(arg1, arg2, arg3);
< / code > < / pre >
< p > A function call might be parsed by tree-sitter into a tree like the following.< / p >
< pre > < code class = "language-tsq" > (call
function: (identifier) ; func
arguments:
(arguments ; (arg1, arg2, arg3)
(identifier) ; arg1
(identifier) ; arg2
(identifier))) ; arg3
< / code > < / pre >
< p > Use < code > :tree-sitter-subtree< / code > to view the syntax tree of the primary selection. In
a more intuitive tree format:< / p >
< pre > < code > ┌────┐
│call│
┌─────┴────┴─────┐
│ │
┌─────▼────┐ ┌────▼────┐
│identifier│ │arguments│
│ " func" │ ┌────┴───┬─────┴───┐
└──────────┘ │ │ │
│ │ │
┌─────────▼┐ ┌────▼─────┐ ┌▼─────────┐
│identifier│ │identifier│ │identifier│
│ " arg1" │ │ " arg2" │ │ " arg3" │
└──────────┘ └──────────┘ └──────────┘
< / code > < / pre >
< p > If you have a selection that wraps < code > arg1< / code > (see the tree above), and you use
< code > Alt-n< / code > , it will select the next sibling in the syntax tree: < code > arg2< / code > .< / p >
< pre > < code class = "language-js" > // before
func([arg1], arg2, arg3)
// after
func(arg1, [arg2], arg3);
< / code > < / pre >
< p > Similarly, < code > Alt-o< / code > will expand the selection to the parent node, in this case, the
arguments node.< / p >
< pre > < code class = "language-js" > func[(arg1, arg2, arg3)];
< / code > < / pre >
< p > There is also some nuanced behavior that prevents you from getting stuck on a
node with no sibling. When using < code > Alt-p< / code > with a selection on < code > arg1< / code > , the previous
child node will be selected. In the event that < code > arg1< / code > does not have a previous
sibling, the selection will move up the syntax tree and select the previous
element. As a result, using < code > Alt-p< / code > with a selection on < code > arg1< / code > will move the
selection to the " func" < code > identifier< / code > .< / p >
< / main >
< nav class = "nav-wrapper" aria-label = "Page navigation" >
<!-- Mobile navigation buttons -->
< a rel = "prev" href = "install.html" class = "mobile-nav-chapters previous" title = "Previous chapter" aria-label = "Previous chapter" aria-keyshortcuts = "Left" >
< i class = "fa fa-angle-left" > < / i >
< / a >
< a rel = "next prefetch" href = "keymap.html" class = "mobile-nav-chapters next" title = "Next chapter" aria-label = "Next chapter" aria-keyshortcuts = "Right" >
< i class = "fa fa-angle-right" > < / i >
< / a >
< div style = "clear: both" > < / div >
< / nav >
< / div >
< / div >
< nav class = "nav-wide-wrapper" aria-label = "Page navigation" >
< a rel = "prev" href = "install.html" class = "nav-chapters previous" title = "Previous chapter" aria-label = "Previous chapter" aria-keyshortcuts = "Left" >
< i class = "fa fa-angle-left" > < / i >
< / a >
< a rel = "next prefetch" href = "keymap.html" class = "nav-chapters next" title = "Next chapter" aria-label = "Next chapter" aria-keyshortcuts = "Right" >
< i class = "fa fa-angle-right" > < / i >
< / a >
< / nav >
< / div >
< script >
window.playground_copyable = true;
< / script >
< script src = "elasticlunr.min.js" > < / script >
< script src = "mark.min.js" > < / script >
< script src = "searcher.js" > < / script >
< script src = "clipboard.min.js" > < / script >
< script src = "highlight.js" > < / script >
< script src = "book.js" > < / script >
<!-- Custom JS scripts -->
< / div >
< / body >
< / html >