HelixNotes
Notes on learning the Helix text editor.
Keymap: https://docs.helix-editor.com/keymap.html
Up to date as of Feb 2023, Helix release 22.12.
Joys
Language server integration is a breeze. For me this is kinda Helix’s
killer feature, and it is good enough to make language servers actually
worth using. In vim you need a plugin for the language server, and then
you need a plugin for LSP support to exist at all, and then you need a
plugin to manage your plugins, and then often in my experience the
language server plugin still doesn’t work great and actually getting
anything useful out of it requires learning a whole new set of
keybindings that are different for each LSP plugin. Then if the language
server, any of those three plugins, or something else changes or breaks
unexpectedly you get to spend a fun afternoon fixing it instead of doing
whatever it was you wanted to do. In Helix language server support is
built-in so it all just slots together automatically. If you have the
language server for a particular language installed somewhere in your
path, Helix will detect it and use it transparently. If you don’t,
hx --health
will tell you about it. That’s the beginning
and end of the process.
I gotta say, I am digging the more explorable approach and more combinator-y keybindings. Most of Helix’s more seldom-used options are accessible through a small number of menus or searchable text interfaces, and tell you what the shortcuts for them are if they exist. Many times now I have gone “I should be able to do…” or “I bet this is part of…” or “I know I saw there was a way to do…” and was correct. And the tutorial, while incomplete, does a pretty darn good job of getting your brain plugged into how Helix works.
Combinators generally Just Work how you expect! And you find little
uses for them all the time. I found myself mashing J
a
bunch to join lines together while writing this up, and was like “…I can
just select all the lines and hit J
once, can’t I?” Lo and
behold, it can. x
in normal mode just selects an entire
line, vx
enters selection mode and selects the entire line
and then leaves you in selection mode to do other things.
Selection mode in general is a joy, the multiple cursors are
something I appreciate even if I am not good at using them yet. AND
getting out of multiple-cursor mode is just ;
which is very easy to remember and very easy to reach, so if you
fat-finger something and get into a weird state it’s fast and easy to
undo.
wc
and Wc
are probably my most commonly
used commands now, and I can’t even remember how to do the equivalent in
vim.
The most common keybindings are the same as vim. This is good because they’re also some of vim’s best keybindings.
For many things, if there’s a single-button command like
w
or n
, the upper-case version of it is the
same operation with some common, complementary difference. Search upward
instead of downward, select a word breaking on different characters,
etc. There’s some exceptions of course, like c
(change) and
C
(add Cursor). But the mnemonics are also usually pretty
good.
Its handling of “enclosing things” like brackets and quotes is
generally correct by default. That makes me pretty damn happy. Vim can
do this but it’s arcane as fuck and I can never remember the correct
keybindings for it. In Helix it’s m
for match mode and then
whatever menu option you want.
Many of the basic things Just Work The Right Way. Autoformatting on save. Indentation. Syntax highlighting. Displaying messages. Split-window operations. File buffers. Useful status line. Inline menus and file/buffer pickers show help docs, useful previews, and shortcuts if applicable. Displaying filtered options when typing into a list.
Differences (from vim)
You don’t seem to have vim’s C-v
box-selection mode.
Instead you use multiple cursors for it. Works just fine. Potentially
better when you are good at using multiple cursors, you can do things
like select jaggy boxes.
There are many modes! Normal/command and insert mode like vim, but
also select mode, goto mode, match mode, window mode, space mode (a
general catch-all for menu commands invoked by hitting the spacebar in
normal mode), and view mode (which I don’t even know what it’s for). All
of these except the most-common select-mode have a popup menu that tells
you keybindings, which I think really might be a perfect juxtaposition
of GUI and CLI. vim and emacs implicitly have most of these modes as
well, is the thing, they just hide them as command line sub-languages
(s//
being the archetypical example) or special keybinding
sub-languages (C-w $FOO
in vim).
Upon consideration, this actually is pretty useful because it results
in less pressure for good key mnemonics, by making the command tree
deeper rather than broader. (Keystroke golf is a specific anti-goal of
Helix; it does optimize for common operations, but doesn’t see the need
to make an uncommon operation one keystroke when there’s a
more-orthogonal 3-keystroke combination for it.) For example, in vim
%
switches to a matching paren if there’s a paren under the
cursor. Or, in the s//
sublanguage, %
means
“match the entire file”. In Helix, %
always means “do X to
the entire file” for whatever valid X. (There was more to this or
another example but I forget what.)
Turning the stunningly ubiquitous s/foo/bar
regex
replacement into s
to search for and select a regex and
then c
to change it to something else is… well, it Feels
Weird. Seems to work pretty well in practice though, at least so far! I
can think of some things I don’t know how to do with it, like ask for
confirmation or un-select a single instance of the selection, but I also
haven’t needed those in the last couple weeks. Apparently the Helix Way
to do those things is to do your multi-cursor selection, and then you
can alter your selection as you wish.
Annoyances
Wrapping
No automatic hard-wrap for lines, you have to select them and use the
:reflow
command, and its reflowing is not as good as vim’s.
However, I can bind :reflow
to C-r
in
selection mode, so I can just do x C-r
to reflow text. Not
quite Vg
, but, oh well.
Hitting enter when in a comment block doesn’t extend the comment
block correctly, which is weird and also irks me. Can you make it so
that if you hit enter while in a comment it adds the comment character
at the start of the next line? There’s a PR open for it that from the
look of it the originator really wants to get done, and it’s been on
their “to do soon” list for like six months. (Issue #1730.) Big ol
mood. On the upside, doing a :reflow
over a block of
comments does seem to work correctly… usually. On the downside,
using J
to join lines that contain comments leaves the
leadin comment characters on the new line, presumably for the same
reason. In general it looks like the interaction between comments and
commands that change lines (J
, :reflow
, etc)
is still being worked on.
Also, auto hard-wrapping of text files would still be nice. Maybe I
can make it trigger on file save at least? Ehhhhhhh, its hard-wrap
doesn’t handle markdown well ’cause it eliminates the blank newlines
between paragraphs. Very annoying, it makes editing Markdown in general
way more narsty than it should be. I should find a shortcut for “select
all non-blank lines in file”, then I could do that and then
:reflow
. v%s
to select the whole file, modify
selection by regex, and then using the regex .+
to select
lines with one or more character will do the job. Seems to be the
closest I can get right now. Pretty oogly though.
On the other hand, moving the cursor up and down in a long soft-wrapped line moves the cursor up and down in the window, not up and down an actual line, so maybe you can just not hard-wrap things and it’s fine? Nah, then it’s annoying to go to the end or beginning of a line and end up far away from where you want to be.
Movement and selection by line
The emacs C-k
and C-u
for “delete to end of
line” and “delete to beginning of line” work in insertion mode, and in
prompts, but not in normal mode. Weird.
Another pet peeve I need to solve: x
selects the current
line. Repeating x
selects subsequent lines. I need a good
way to select the current lines and previous lines as well.
vx
and starts the selection at the beginning of the current
line, so doing that and then moving the cursor upwards requires you to
start on the line after the one you want to select.
I do wish there were more convenient selection-mode shortcuts for
“beginning of line” and “end of line” than home
and
end
, something closer to the home row. Might have to
conjure forth my own?
Nit: At the end of the line, doing a
to enter insert
mode enters insert mode after the end of the current line, which is thus
far never what I want. vim does the end of the current line, basically
when a
does “insert after current char” it means “insert
after current char, except when current char is a newline”. There’s an
article somewhere talking about consistency vs. “what you actually want”
in a very similar case, that of Emacs’s “swap characters” operation when
done at the end of a line.
Buffers
How do you go to a named buffer? Doing space b
and
moving the cursor down to select hir.rs
from the list is
entirely inferior to typing :b hi<tab>
. …maybe I’ll
make a PR for it. Well, you can do space b
and then type
the first bit of your buffer name and it will filter for it, so… maybe
almost as nice? Very different feel. We’ll leave it a few more
weeks and see if I get used to it.
Apparently Helix has a PR in-progress to let you do :b
or such to switch to another buffer… by numeric index, not by name. That
is just so bad it seems useless. Sure you can have multiple buffers with
the same name, that’s why you disambiguate those ones with a trailing
number.
Misc
No Debian package, gotta build it from source. Maybe I can fix this someday?
I figured out a bug in syntax highlighting that turned out to be a
problem for tmux being bug-for-bug compatible with screen, and then not
reloading the config file if I start a new session while one already
exists. So! Apparently vim
detects tmux
and
works around the workaround.
Helix’s paren matching uses the LSP and thus is actually kinda worse
than vim’s in some situations. If I do /* thing { ... }
and
want to flip to the end of the block to put the comment at the end of it
then I can’t use mm
for it, because it doesn’t parse
successfully and thus can’t find the matching }
. Hmmmm.
Okay, what I CAN do is do vx
to select the first line,
mm
to select to the end of the block, and THEN use
C-c
to comment it all out. Hmmmmmmmmmmmmmmmmm. Not sure if
it’s better or worse, but certainly different. OTOH, vim’s lack of any
ability to toggle comments on and off for a region without a plugin is
one of its more irksome features. All in all the broader take seems to
be that relying on a LSP to do everything is both a blessing and a
curse. Usually worth it so far though.
I’d ask for help on some of these on the Helix Matrix chat, but… man,
someday I would love to see a Matrix client that just actually
works without any bullshit involved. I really fucking hate it. So far
nheko and neochat still fail that test on my Pinebook Pro
running sway
; nheko complains about not being able to
connect to a password key service that isn’t running, neochat sits there
saying “loading” for an eon and when it eventually does something the UI
is broken. The github discussions and issues are pretty good though. The
community appears surprisingly large and active.
Conclusions
Is Helix Good(tm)? Yes.
Does Helix still have rough edges you will encounter in day-to-day life? Yes.
Is it good enough to use despite those? For me, so far, yes. This is the test kakoune failed for me at the time I tried it, its rough edges were too rough.
Is it good enough to be worth retraining your fingers away from ubiquitous vim keybindings? For me, so far, yes.
There is no single killer feature that’s Better Than Vim, the LSP integration is the closest it has, and for me that’s a pretty good convenience but not a requirement. But when you combine it with the combinator-rich command style, the actively helpful UI, the generally excellent array of “it’s 2023, the editor should be able to…” features, and the generally lightweight and speedy feel of it… I think it’s actually a worthy successor to vim.