Skip to content
← Go back

Adopting Helix-isms

Published: >

Table of Contents

Open Table of Contents

What is bro yapping about?

I love Neovim, the switch from VSCode to neovim has been gratifying for many reasons. A big one being rediscovering joy in putting time into thing and thing rewarding you with being speedy (no citations here trust me bro I am faster), more things to learn and knowledge.

What am I talking about? How about discovering more about language servers, abstract syntax trees and lower level understanding of how editors works - the concept of buffers and windows and “tabs” (tabs != tabs as you will come to realise).

While I’d like to believe that vim makes me faster, the main reason I think it did for me was to enjoy and not fear the terminal. It’s not as if devs graduate out of university fearing the terminal but it’s more that they didn’t take enough time to familiarise it and learn it beyond git clone, commit, push.

In the spirit of learning and enjoying tools and terminals - I will be discussing Helix today.

And then there was Helix

Why did I learn helix? My baby External Link Globe nvim config repo has matured into a fine 846 commits boy already. So what was the issue? The main reason was portability - and it stemmed directly from my previous #complain article about how I hate setting up new Linux machines.

Neovim is chunky. It is chunky because I fed it 86 plugins as of this moment. Some plugins require binaries beyond neovim. Some require other esoteric setup I already forgot about. Mostly I just tire of having to move about plugins, update them, solve new config issues. Just to get it working on remote machines or new system when I just want to do quick fixes. Or maybe there was not enough horse power to even run it (See $1/month VPS).

Helix is a new kid on the block. It offers familiar yet different philosophy of the motion verb grammar we’re all used to. It took me a good few days to get used to it and then to get used to AND discover how amazing multicursor first editing is. Man I do not miss typing clunky :s//g statement when I want to quickly replace X things in a file.

Best of all, it doesn’t have big dependencies to lug around apart from your config.toml - but you’d have to do that anyway if you are a CLI binary fiend.

External Link Globe github/helix

What I like about Helix binds

Basics

Indentation

Literally just > once in normal mode to indent stuff.

keymap("n", ">", function()
    local count = vim.v.count1 -- Gets the count (default 1)
    for _ = 1, count do
        vim.cmd('normal! >>')
    end
end)

keymap("n", "<", function()
    local count = vim.v.count1
    for _ = 1, count do
        vim.cmd('normal! <<')
    end
end)

Jump to word

The keybind gw is something I never realised I wanted. I was always awkwardly using <C-space><C-space> to hop to word with labels given in the visible screen. flash.nvim and hop.nvim users will know what I am talking about. I never found the right bind for it but [g]o to [w]ord makes so much sense that I feel silly for not doing that. I mean, did you even know that gw and gq in neovim does formatting?

External Link Globe :help gw External Link Globe :help gq External Link Globe gh/hop.nvim External Link Globe gh/flash.nvim

keymap({ "n" }, "gw", flash_util.flash_word)

Go to start/end of line

Any one of you a big fan of $? Me neither. What about 0 to go to start of line? Oh but you know that gj and gk does soft-wrap aware vertical movement right? So why does gh and gl doesn’t also move to start/end of line?? This is the default behaviour in Helix that I enjoyed.

keymap({ "n", "v", "x" }, "gh", "0")
keymap({ "n", "v", "x" }, "gl", "$")

The multicursor elephant in the room

This is honestly the main selling point of Helix, first class multicursors. Yes you can Ctrl+D just like in VSCode but with bells and whistles. And of course, a different approach. If I hadn’t mentioned it yet, helix is a select-first verb later approach. To give you a quick example the “normal” mode in helix is basically a sliding window visual mode. See this sentence:

AI will not take my heckin job

If your cursor was at the start of the sentence and you press “w” (for [w]ord) multiple times, you would hover over the first word from start/end then the next word’s start/end. It will not encompass the second word from the start unless you initiate “selection” mode.

Ok this is getting confusing with normal=visual and visual=select mode. Let me summarise.

Select the text THEN decide what you do - Helix

Delete the next 2 words - Vim

This builds on to what I am trying to talk about - multicursor. In helix, you can initiate multicursor mode much like VSCode by entering select mode, highlight over the block and press * to create a cursor at next matching word. Ok nothing fancy there. To build on this, when you highlight over the chunk of text you can also perform 2 operations for more nuance multicursor. Select and Split (not to be confused with select mode).

See this example:

Ok you're right, maybe ChatGPT will take my job. ChatGPT has been getting better,
although ChatGPT latest version is a little questionable and the public facing model
(behind subscription paywall) seems to degrade over time. It has gotten stupider since
I've used it. But man, I'm still going to pay for ChatGPT.

The vim-idiomatic way would be to :s/ChatGPT/MyFavouriteSlopLLM/g and be done with it. But in Helix you can highlight the range and press s to directly select ChatGPT in the block, see visually all the multicursors added and real time word change. It actually makes so much sense that it blew me away. The split mode would be if I needed to reorder stuff by using the existing multicursor model and rotate through the content between them. See this example:

3,4,1,2

I would do this xS,)) which expands to

These are extremely basic examples but it should be enough to give you a brief example before I move on to telling you how to put this into neovim.

The one and only multicursor.nvim

The plugin basically can do everything I described in helix, their multicursor is best I’ve used and I never explored its featureset until I tried helix. Here’s my config

External Link Globe github/multicursor.nvim

set({ "n", "x" }, "ga", mc.addCursorOperator, { desc = "[MULTC] Operator" })
set({ "v", "x" }, "<leader>s", mc.splitCursors, { desc = "[MULTC] Split Regex" })
set({ "n", "x" }, "<C-up>", function() mc.lineAddCursor(-1) end, { desc = "[MULTC] Add Cursor Up" })
set({ "n", "x" }, "<C-down>", function() mc.lineAddCursor(1) end, { desc = "[MULTC] Add Cursor Down" })
set({ "n", "x" }, "<leader>/", mc.searchAllAddCursors, { desc = "[MULTC] All Search Matches" })
set({ "v", "x" }, "s", mc.matchCursors, { desc = "[MULTC] All Search Matches" })
set("n", "gV", mc.restoreCursors, { desc = "[MULTC] Restore Cursors" })
set({ "n", "x" }, "<c-q>", mc.toggleCursor, { desc = "[MULTC] Manual" })

-- When "multicursor exists" mode
mc.addKeymapLayer(function(layerSet)
    layerSet({ "n", "x" }, "Q", function() mc.matchSkipCursor(-1) end, { desc = "[MULTC] Skip Prev" })
    layerSet({ "n", "x" }, "q", function() mc.matchSkipCursor(1) end, { desc = "[MULTC] Skip Next" })

    layerSet({ "n", "x" }, "<left>", mc.prevCursor, { desc = "[MULTC] Prev" })
    layerSet({ "n", "x" }, "<right>", mc.nextCursor, { desc = "[MULTC] Next" })

    layerSet({ "n", "x" }, "<BS>", mc.deleteCursor, { desc = "[MULTC] Delete Cursor" })

    layerSet("n", "<CR>", mc.enableCursors, { desc = "[MULTC] Confirm" })
    layerSet("n", "<esc>", mc.clearCursors, { desc = "[MULTC] Clear" })
    layerSet("n", ",", mc.clearCursors, { desc = "[MULTC] Clear" })

    layerSet({ "v", "x" }, "(", function() mc.transposeCursors(-1) end, { desc = "[MULTC] Rotate content left" })
    layerSet({ "v", "x" }, ")", function() mc.transposeCursors(1) end, { desc = "[MULTC] Rotate content right" })

    layerSet({ "v", "x" }, "&", mc.alignCursors, { desc = "[MULTC] Align contents" })
end)

What I wish Vim had

Helix has columns in their pickers. Vim bros… they can filter based on the columns. This is actually so good you don’t understand. When you use pickers in neovim you basically had to fuzzy over every detail, see these examples:

image of helix picker image of helix picker - with column filter image of helix picker - with multiple column

This makes an insane amount of sense. Imagine doing AST symbol picker over the entire workspace and select test function with columns where the path may contain the word “graph”. You would basically use ripgrep for this instead. This works, first-class in helix. Insane work guys, I really love it.

This sounds very possible as well of course for vim as a plugin, but would you do this to be telescope compatible? or snacks? or perhaps fff? All??? I won’t be answering these questions myself for now as I am busy but maybe one day when I am decently caffeinated I will give this a shot.

What Helix doesn’t have

Sessions

My workflow for editing is basically z proj kris dev then nv for hydrating sessions based on the directory. Neovim does have session based options but iirc you have to save your sessions manually. There are plugins to help with this and it is the exact workflow I’ve described and used for years. There has been External Link Globe direct work done on this for helix already which I am planning to add to my maintained fork. I hope to one day see this merged to take one thing potential merge conflict off my fork list. Maybe one day when the plugins PR get merged I won’t have to worry about self-rolling a fork anymore.

External Link Globe github/helix/plugins-pr

Quickfix list

Honestly, I didn’t know how good I had it until I don’t. Quickfix list is GOATED. The ability to locate all the issues and context switch directly to the problem location or remotely solved the problems is something surgeons wished they had. That would be a godlike surgical power. I love quickfix, I love dumping pickers to quickfix and I love remotely fixing things in the quickfix list.

External Link Globe github/quicker.nvim

My final thoughts on using both

To keep this mega brief; try Helix if you like Vim. At least try to understand the multicursor model. It’s a great alternative to doing :s// all day.

Learning Vim made me rediscover the joy of learning. Learning vim led me to learning helix. Now I love both. This article was written in Helix. All my remote machines have my maintained helix fork binary. My workstation main for serious development will still be neovim - 800 config repos will make it hard for anyone to move on :)

I am thankful for every opensource developers to make these awesome tools I can enjoy shitposting about.

Links

nvim config repo - External Link Globe https://github.com/ktunprasert/nvim
I hate setting up new Linux machines - /posts/i-hate-setting-up-new-linux-machines
github/helix - External Link Globe https://github.com/helix-editor/helix
:help gw - External Link Globe https://neovim.io/doc/user/change.html#gw
:help gq - External Link Globe https://neovim.io/doc/user/change.html#gq
gh/hop.nvim - External Link Globe https://github.com/smoka7/hop.nvim
gh/flash.nvim - External Link Globe https://github.com/folke/flash.nvim
github/multicursor.nvim - External Link Globe https://github.com/jake-stewart/multicursor.nvim
direct work - External Link Globe https://github.com/helix-editor/helix/pull/9143
github/helix/plugins-pr - External Link Globe https://github.com/helix-editor/helix/pull/8675
github/quicker.nvim - External Link Globe https://github.com/stevearc/quicker.nvim



Next Post
I hate setting up new Linux machines