Skip to content

News

Release 24.03 Highlights

The Helix 24.03 release has arrived! First, a very big thank you to everyone who made this release possible. This release saw changes from 125 contributors.

New to Helix? Helix is a modal text editor with built-in support for multiple selections, Language Server Protocol (LSP), tree-sitter, and experimental support for Debug Adapter Protocol (DAP).

Let’s check out this release’s highlights.

Amp-like jumping

Jumping features are popular in the (Neo)Vim plugin space and there are even plugins to add the same functionality to other tools like browsers. They allow you to move your selection efficiently across even large parts of the view, like you could by clicking with a mouse, but by entering “labels” instead. 24.03 introduces jumping commands inspired by the Amp editor’s jump mode. Press gw to add the jump labels and then enter one of the labels to jump to the word under that label. Using gw in select mode (v) extends the selection.

Block comments

In the past, Helix has only been able to toggle line comments like // and # and languages like OCaml have been left with workarounds like a “line” comment token of (*. In 24.03 Helix can now toggle block comments as well. Use C-c or <space>c to smartly add or remove line or block comments around the current selection based on the language’s comment token configuration, <space>c to toggle block comments around the current selection, or <space><A-c> to toggle only line comments on the current line.

Improvements to tree-sitter injections

Helix uses tree-sitter incremental parsing for syntax highlighting, textobjects, indentation and some motions and commands. 24.03 improves how we handle injections - a powerful tree-sitter feature for parsing documents with multiple languages. For example you might have JavaScript, CSS or other languages within a <script> or <style> tag in HTML. The HTML parser doesn’t need to know how to parse all of these languages. Instead it can inject JavaScript or CSS parsers to handle the <script> or <style> tag contents.

One of these improvements is to the :tree-sitter-subtree command that displays an S-expression of the syntax tree under the cursor. 24.03 shows the injection layer under the selection instead of only the root layer. For example in this asciicast we now show the syntax tree for the JavaScript parts of the document while in the past we only showed the HTML part of the tree.

The other big improvement is to the tree-sitter motions. A-o (alt + o) expands the selection to the parent node of the syntax tree node covered by the current selection. A-i shrinks to the child node and A-n and A-p go to the next and previous nodes, respectively. Previously these commands only worked on the root layer (for example HTML in the asciicast) but they now find the injection layer that contains the selection and move along that layer’s syntax tree. Internally we organize injection layers into a tree-like structure so that these motions can switch layers when needed.

Stay tuned for future changes that improve injections, like finding textobjects within injected content.

Internal improvements

24.03 also saw major internal improvements. The first comes from a new “event system” - a system built around Tokio channels and tasks that allows different parts of the Helix codebase to communicate with one another. The event system also adds generic ways to debounce and run tasks in background threads so we can prevent locking up the UI. Some parts of the code base have already been migrated to the event system like LSP completion and signature-help. In 24.03 you’ll notice that LSP completion doesn’t automatically pop up after just navigating around in insert mode, for example with arrow keys. It’s now hooked into document changes instead, so it can smartly pop up when you start changing a document rather than every time the editor goes idle.

The other major improvement to be excited for is the general replacement of the regex crate with regex-cursor, a streaming regex implementation compatible with ropey, the rope crate we use to represent all documents. regex-cursor is capable of running on discontiguous strings - input that may not be collocated in memory. In a rope, different parts of the document might be stored separately internally. To use the regex API we needed to convert slices of the document to a regular Rust String, duplicating the memory footprint of that slice of the document. regex-cursor operates on the chunks of the rope instead, which greatly improves efficiency.

Wrapping up

As always, this is just the highlights from the 24.03 release. Check out the full changelog for the details.

Come chat about usage and development questions in the Matrix space and follow along with Helix’s development in the GitHub repository.

Release 23.10 Highlights

The Helix 23.10 release is finally here! 23.10 introduces some very large internal changes that enable some powerful features. A very big thank you to everyone who made this release possible.

New to Helix? Helix is a modal text editor with built-in support for multiple selections, Language Server Protocol (LSP), tree-sitter, and experimental support for Debug Adapter Protocol (DAP).

Let’s check out this release’s highlights.

Multiple language servers

23.10 brings a big change to the way we handle language servers. Previously each language could only support one language server at a time but now you can configure multiple to work in tandem. For example you might use the TypeScript language server for JavaScript/TypeScript development and also configure efm-langserver for Prettier formatting and ESLint diagnostics. With the new support for multiple language servers, you can specify which features to use from each language server.

This brings a big change to the way language servers are configured in your language configuration (languages.toml). All language servers are now specified separately from languages and then each language selects which language server(s) to use. From the example above, you might configure efm- langserver and typescript-language-server like so:

[language-server.efm]
command = "efm-langserver"
config.documentFormatting = true
[language-server.typescript-language-server]
command = "typescript-language-server"
args = ["--stdio"]
config.hostInfo = "helix"
[[language]]
name = "typescript"
auto-format = true
language-servers = [
{ name = "efm", only-features = ["format", "diagnostics"] },
{ name = "typescript-language-server", except-features = ["format", "diagnostics"] },
]

See more details in the language configuration docs.

Fuzzy matching with Nucleo

Helix uses “fuzzy” matching to filter as-you-type in components like the file picker. Previously we used the popular skim/fuzzy-matcher crates but in the 23.10 release we’ve switched to the new nucleo crate. Nucleo is significantly faster than skim and fzf, handles Unicode correctly, and uses a bonus system that feels more intuitive.

Nucleo also enables us to lazily stream in new items, which is a big boost for the user experience for pickers. In the asciicast above I’m scanning through my computer’s /nix/store, a huge directory containing more than twenty million files. The file picker now works gradually as we scan through the directory and matches files as we find them.

Nucleo also paves the way for future picker upgrades. Stay tuned to the upcoming release notes to see where we’ll take the picker.

Smart tab

Smart tab is a new feature bound to the tab key in the default keymap. When you press tab and the line to the left of the cursor isn’t all whitespace, the cursor will jump to the end of the syntax tree’s parent node. For example:

{
key = "value";
nested = {
key2 = "value2"; # When the cursor is at the end of the line here, <tab>
# jumps right after the closing brace on the next line.
};
}

This is useful in languages like Nix for adding semicolons at the end of an attribute set or jumping to the end of a block in a C-like language:

Expanded support for registers

Registers allow you to save and paste values. For example you might select a paragraph, use "ay to yank it into the a register, and later use "ap to paste that paragraph. Some registers have special effects when read or written to though like the _ “blackhole” register: any values written are discarded and nothing can be read. Special registers have been expanded to include some useful ones from Kakoune and clipboard registers:

  • %: the current buffer name
  • #: the number of each selection, 1-indexed
  • .: the contents of each selection
  • * and +: system and primary clipboards

Also check out the new register statusline element. It appears when you select a register with ". Notice the reg=# in the bottom-right corner of the statusline in the asciicast when we select the # register and how it goes away when we paste that register (p) or increment the selections (C-a).

Initial support for LSP DidChangeWatchedFiles

Some language servers use the DidChangeWatchedFiles notification to discover changes to related files in other languages. For example, rust-analyzer will fetch and index new dependencies when you add them to your Cargo.toml. Helix will now send file change notifications when the file is changed by Helix itself. Full support for DidChangeWatchedFiles will require a file watcher but for now we’re able to support the most common use-case for DidChangeWatchedFiles.

Syntax highlight regex prompts

Regex prompts like those created with s, S or | are now syntax highlighted via tree-sitter-regex. The highlighting makes special characters more obvious and can catch syntax errors like trailing backslashes.

Wrapping up

As always, this is just the tip of the iceberg for the 23.10 release. Check out the changelog for the full details.

Come chat about usage and development questions in the Matrix space and follow along with Helix’s development in the GitHub repository.

Release 23.03 Highlights

Helix is a modal text editor with built-in support for multiple selections, Language Server Protocol (LSP), tree-sitter, and experimental support for Debug Adapter Protocol (DAP).

Today marks the 23.03 release. First, a big thank you to everyone involved! This release includes changes from 102 contributors. Today’s release brings some especially useful and exciting features, so let’s jump right in.

Soft-wrap

Soft-wrap breaks up lines to fit in view without inserting actual line break characters into the text (so called “hard-wrapping”). This can be useful for reading and editing documentation or code with especially long lines. Enable soft-wrap in your config with the editor.soft-wrap.enable key:

~/.config/helix/config.toml
[editor.soft-wrap]
enable = true

Heuristics for where to break lines and the wrap indicator may also be configured.

Soft-wrap is the first feature implemented on top of a new “virtual text” API within the Helix codebase. The virtual text API allows us to decorate and manipulate the actual text in a document without disturbing positioning and modifications. The virtual text API opens the door for many new exciting features like the inlay hints we’ll see next.

Inlay hints

Inlay hints are a new feature in the latest LSP specification. Language servers can provide editors with hints to show in a document. In the example above, rust-analyzer provides type hints for variables and intermediary expressions as well as parameter names in function calls.

Inlay hints can be enabled in your config with the lsp.display-inlay-hints key.

Initial support for snippets

LSP snippets are a way for language servers to provide more complex completions for an editor. Language servers can specify where to place cursors within a completion (tabstops), placeholder values and more. Helix now has initial support for LSP completions, leaving more advanced snippet features like virtual placeholders, multiple tabstops, and variable substitutions for future work.

Dynamic workspace symbol picker

The workspace symbol picker (<space>S) is an LSP-driven feature for looking up a symbol in a project. Large projects might have many symbols, though, so this symbol picker typically wouldn’t load them all at once. The workspace symbol picker has been reworked in this release though to dynamically re-request symbols with a new query as you type in the picker. This lets the language server narrow down the number of symbols and only tell Helix about the ones relevant to the search. This rework fixes compatibility with some language servers which returned empty symbols with no query (gopls, pyright, clangd) or limited results (rust-analyzer).

The “dynamic picker” introduced in this refactor may benefit other pickers in the future, for example allowing the global search picker (<space>/) to update on-the-fly as you change the query.

Version control HEAD statusline element

A new statusline element has been added which displays the version control HEAD. Add this to your statusline by introducing the "version-control" element in the editor.statusline section of your config for the left, center or right sides.

Enhanced keyboard protocol

Support for the enhanced keyboard protocol is now enabled. Terminals that support the protocol (Kitty, WezTerm) can now send unambiguous keycodes to Helix, enabling key combinations that weren’t possible to bind before like C-/, C-h or S-backspace. This functionality works out-of-the-box for terminals that support the protocol.

Runtime directory refactor

Helix keeps files like tree-sitter parsers and queries, themes and the tutor file in a special “runtime” directory. This directory is typically installed by your package manager and shouldn’t be modified by hand. Multiple runtime directories are now supported, so you can keep the runtime files installed by your package manager unchanged while adding new tree-sitter parsers and queries to a local runtime directory. On Unix systems you can add files to the ~/.config/helix/runtime directory which take precedence over the runtime directory installed by a package manager.

Wrapping up

These flashy features are just the tip of the iceberg though. Check out the 23.03 changelog for the full details on all of the changes in this release.

Come chat about usage and development questions in the Matrix space and follow along with Helix’s development in the GitHub repository.

Release 22.12 Highlights

Helix is a modal text editor with built-in support for multiple selections, Language Server Protocol (LSP), tree-sitter, and experimental support for Debug Adapter Protocol (DAP).

Today we cut the 22.12 release. This release is big and featureful and saw contributions from 99 contributors. Thank you all! 🎊

Helix now has a logo! Thank you @jakehl for your contribution!

Looking for an introduction to Helix or to see Helix out in the wild? Check out these new videos on Helix.

Now let’s jump into the highlights.

Git diff gutter

The new git diff gutter tracks the changes in the current buffer compared to the the git index. The markers in the gutter indicate additions, modifications, and removals compared to the file checked in to git. The git diff gutter is enabled by default.

Also be sure to try out the new hunk textobject: ]g jumps to the next changed hunk and [g jumps to the previous.

Underline styles and colors

Terminals with support for extended underlines can render underlines with styles like curls or dots as well as colors. Extended underlines can be used to improve the display of LSP diagnostics. These can be configured in themes with the new underline key:

"diagnostic.error" = { underline = { style = "curl", color = "red" } }

The existing underline modifier is now an alias for the "line" style.

If you’re looking to use this in a theme that hasn’t configured it yet, you can use the new theme inheritance feature to modify just the scopes you would like to change:

~/.config/helix/themes/my-onedark.toml
inherits = "onedark"
"diagnostic.error" = { fg = "errorfg", bg = "errorbg", underline = { color = "red" } }

Autosave when the terminal loses focus

Terminals with support for focus events can now automatically save the current file when you focus on a new window. Enable this behavior by setting the editor.auto-save configuration key to true.

Multi-cursor completion

Editing with multiple selections is a central feature within helix. LSP auto-completion now applies to all cursors when editing with multiple selections, making it easy to replace multiple instances of a symbol with auto-complete’s help.

Bufferline

The bufferline is a listing of buffers displayed at the top of a window. It provides an at-a-glance view of the buffers you’re working with. Set the editor.bufferline configuration key to "always" to always show the bufferline, "multiple" to show the bufferline only when there are multiple buffers open, and "never" to disable it.

Behind-the-scenes improvements

22.12 brings also brings important changes to Helix’s plumbing:

  • The code-path for writing files has been overhauled. This fixes a number of edge cases around writing large files and failures to write.
  • Performance has been improved for tree-sitter parsing, querying and the handling of injections. This is a noticeable speed boost for large markdown files in particular since markdown uses injections extensively.
  • Failure handling in the LSP code-paths has been improved. Helix now gracefully handles cases like language servers not supporting capabilities and unexpected language server crashes.
  • The speed and memory usage of the :reload command has been vastly improved. This comes from the creation of imara-diff, a new diffing implementation which is faster than the one used internally by git!

Wrapping up

There are many more changes arriving now in 22.12 than we can fit in this post. Check out the 22.12 changelog for the full details on all of the performance boosts, usability improvements and fixes in 22.12.

Contribute and follow along with development in the Helix GitHub repository and be sure to join in on discussions in the Matrix channel.

Release 22.08 Highlights

Helix is a modal text editor with built-in support for multiple selections, Language Server Protocol (LSP), tree-sitter, and experimental support for Debug Adapter Protocol (DAP).

Today marks the 22.08 release, a release with plenty of fixes and new features. A big thank you to our contributors! This release had 87 contributors. 🎉

Let’s check out the highlighted features for 22.08.

Indent guides

Indent guides provide a visual representation for the current indentation level. Enable indent guides with the editor.indent-guides.render key. The character used as a guide is also customizable.

Cursorline

The cursorline is a horizontal highlighted bar that follows your cursor. Cursorlines may be themed for the primary and all secondary cursors and can be enabled or disabled separate from theming with the editor.cursorline option.

Mode colors

The mode indicator in the statusline may now be styled based on the current mode. This feature may be enabled with the editor.color-modes option and colors may be configured using ui.statusline.{insert,normal,select} keys in themes.

Configurable statusline

The statusline may now be configured in the editor.statusline section of the config. Elements may be placed on the left, center or right of the statusline with a configurable separator and spacers. Two new elements may now also be added to your statusline: file-line-ending and position-percentage.

LSP signature help

Signature help provides documentation as you type the arguments to a function call and tracks which function parameter is currently being entered. Signature help is enabled by default.

LSP document highlight

The document highlight request (Space-h) creates a selection for all instances of the symbol under the primary cursor. Helix has robust support for multiple selections, so you may edit all selections simultaneously (for example with c) or cycle between selections ((/)).

LSP diagnostics pickers

The new buffer and workspace diagnostics pickers may be used to jump to Language Server diagnostics like warnings and errors. Use Space-g to open the picker with diagnostics for the current buffer and Space-G to view all diagnostics in a workspace.

Jumplist picker

The jumplist saves a history of selections. Save selections with C-s and jump forward with C-i and backward with C-o. The jumplist is a powerful tool, especially when working with Language Server goto-definition or global search which both save to the jumplist automatically.

22.08 adds a new picker that can be used to jump across entries in the jumplist. The preview pane shows the line of the saved primary selection. Bring up the jumplist picker with Space-j.

External formatters

Many Language Servers provide format-on-save capabilities. For languages without Language Servers or for Language Servers that do not implement formatting, an external formatter binary may now be configured. The document is passed through the formatter’s stdin and replaced with the formatted output from stdout.

An external formatter may also be used when you prefer the formatting from an external tool over formatting provided by a Language Server. For example if you configure black for formatting Python, formatting will be accomplished with black rather than pylsp.

Bracketed paste

Bracketed paste is terminal emulator feature that allows terminal programs to recognize paste sequences and handle the pasted text. Without bracketed paste support, text pasted with operating-system level paste (C-v) looked to Helix like text that was entered very quickly which lead to some odd side-effects like awkward indentation or mysteriously appearing auto-pair characters.

22.08 adds support for bracketed paste, so now all pastes into Helix from terminal emulators that support bracketed paste work as if you had pressed Space-p in normal mode. In the above cast, the entire text of Moby-Dick is pasted with C-v in insert mode instantly.

Wrapping up

These changes are just the highlights. Check out the full changelog to see all that’s changed since 22.05. Release binaries can be found on the release page.

Be ready for more exciting changes in Helix 22.10 expected in October! Contribute and follow along with development in the Helix GitHub repository and be sure to join in on discussions in the Matrix channel.