Artificial truth

archives | latest | homepage | atom/rss/twitter

The more you see, the less you believe.

Helix as a glorious modern vim
Tue 29 November 2022 — download

I've been a vim user for more than 20 years now. I've moved to neovim a couple of years ago, attracted by the smaller codebase, the gradual port to lua both for plugins and internals, tree-sitter integration, LSP support, …

But I gradually grown to dislike it: rewriting my vimrc into lua felt like a cumbersome chore that only increases its verbosity at the price of its portability, for no gains at all. LSP support is done via yet another plugin and a ton of boilerplate, same for tree-sitter. Moreover, neovim doesn't have plans to have support for vimscript9, meaning that the plugin ecosystem will soon be split into vimscript/lua/vimscript9.

Speaking of plugins: everything requires one: Want a theme? plugin. Want fuzzy-finding? plugins. Want a file explorer that doesn't look horrible? plugin. Want to show vcs annotations? plugin. Modern debugging support? plugin. LSP support? plugins. Language independent commenting? plugin. Snippets? plugin. Code outline? plugin. EditorConfig support? plugin.

Coupled with configuration directives that evolved organically for more than 30 years, it makes things brittle. For example, set ttyfast, let c_ansi_typedefs=1, autocmd BufnewFile,BufReadPost *.c,*.cpp,*.h,*.hpp syn match cType "\<[a-zA-Z_][a-zA-Z0-9_]\+_t\>", nnoremap <Leader>oc :e %<.c<CR>, map <Leader>q ::b#<bar>bd#<CR>, set fillchars+=vert:│, … Good luck figuring out what they're doing, or even why you added them to your configuration in the first place. Reading (neo)vim's documentation is a trip down memory-lane: :help php3.vim (1997) is still a thing, :help java.vim mentions java 1.0.2 (1996), :help mapple.vim mentions Maple V RC4 (1996), :help postscript.vim says that the default highlighted version is Postscript 2 (1991) "since this is the most prevalent version currently.", :help xf86conf.vim only mentions XFree86 v3 (1994) and XFree86 v4 (2000), …

Speaking of legacy, some keymaps are weird as well: C-] to follow a symbol but C-t to jump back because C-[ is equivalent to <Esc>, u to undo but C-r to redo, the g prefix is usually used for go to commands like gd for go to declaration, except that g~ is to swap case, gUU to uppercase the current line,nd gv to reselect the previous selection. z is to manage folds except z{number} is to resize panes and z= is to suggest spellings for the words under/after the cursor. Autocompletion is interesting as well, with C-x to enter completion, then C-l, C-n, C-k, C-t, C-i, C-], C-f, C-d, C-v, C-u, C-q, s or C-p depending on how you want to autocomplete, and so on.

Moreover, while the idea of modal editing is the best thing since the invention of the banana curving machine, vim's Verb → Object construct is awkward at best. Text editing isn't linguistics: I might say "I want to delete this line of text", but what I'm thinking when dealing with code is "this part of the code, here, I'd like to delete it". It's pretty common to apply an action to the wrong object: maybe you wanted to delete 6 lines instead of 5, but you eyeballed it wrong? It's possible to fix this by making use of vim's visual mode, transforming it into Selection → Action, letting you see what you're doing.

Helix' logo

Enter Helix: written in Rust, inspired by vim and kakoune, with a neat vision: Cross-platform, modal, terminal first, native, lightweight, batteries included, modern, actively developed, …

Visually, my neovim and my helix are super-similar, but for the later, there is no need to fiddle around to get LSP working, it just works. For openmw, a large C++ project, I only had to cd openmw; mkdir build; cd build; cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=1 ..; make -j $(nproc) to generate the compile_commands.json and that was it, LSP was simply working. To use tree-sitter, hx -g fetch build and that's it. EditorConfig is natively supported. Multi-selection is a thing, no need to hack with macros and visual mode. Every cool thing from vim is there as well: buffers, registers, windows, command mode, … it also comes with a bunch of modern themes: no plugins required.

While vim commands are burned in my brain, helix' ones are making way more sense. For example, to replace the word one with two in a whole document:

  • vim: :%s/one/two/g<Cr>, with : to enter command mode, % to apply the next operand to the whole document, s for searching, / as a marker, one as the word to be replaced, marker again, two to replace, marker, g to replace globally.
  • helix: %sone<Cr>ctwo<esc>, with % to select the whole document, s to select, one for the word to select, then c to change with two.

In insert mode, helix uses the Readline Emacs Key Binding, aka the one used in bash, zsh, osx, emacs, … so should one get lost, insert mode has familiar shortcuts. Moreover, if you don't like the default configuration or keybindings, it's ok: everything can be changed by editing a toml file. It's possible to map any keymap to any command, like C = ["goto_line_start", "extend_to_line_bounds", "change_selection"] and d = { d = ["extend_to_line_bounds", "delete_selection"], t = ["extend_till_char"], s = ["surround_delete"], i = ["select_textobject_inner"], a = ["select_textobject_around"] } to make C and d behave like in vim, without resorting to cryptic black magic vimscript-like incantations. Check helix-vim for inspiration, or even my config if you're feeling adventurous.

There are of course still a bit of rough edges, like the lack of soft wrap, no git integration, no EditoConfig support, no :help, no virtual text support, no snippets support, more than 150 dependencies, my helix folder (sources + binaries) weights 1.5G, … but it's getting there.

If you want to give it a try, there is of course an equivalent to vimtutor that can be invoked via the :tutor command, and there are cheat-sheets and documentation. And if you don't want to read things and simply start using it, minor modes will make it easy: pressing <space> will open a menu in which pressing w (for Window Management) opens another one and so on. The same system is used for registers management, jumping to places, command mode, match mode, …

Moreover, it's fast compared to vim/neovim: editing large yaml file isn't sluggish, visual selection and completion are instant, syntax highlighting doesn't choke on long lines, …

In a couple of years, or maybe months, this could become a serious contender to (neo)vim, but more importantly, my main editor.