19 min read

A minimalist but powerful modal text editor with multi selections and visual mode at its core

Modal editor ?

Stating the obvious, an editor shouldn’t be a hundred megabytes behemoth, capable of 3D rendering and 4K movies decoding. It shouldn’t take several seconds to warm up, eating half the computer memory on the way, just to edit a bunch of 10Kb files. Because this is what Atom and Visual Studio, behind their respective web browser, eventually are and do.

Although this fact is slowly acknowledged (see zed by Atom developers), there is one category of editors that always focused on efficiency.

Modal and terminal editors are at the opposite side of editors spectrum in terms of resources consumption, and the first encounter with one its kind is generally a mix of bad feelings :

  • This is something from the seventies for a bunch of nostalgic geeks.
  • This is only useful for sysadmin on remote servers.
  • This is so retarded, where is the UI ? Where do I click ?
  • How editing a text can be so cumbersome and counterintuitive ? I can’t even save my file !

If some editors are legacy from decades of software development, others were born very recently. This resilience to trends should at least trigger some curiosity in you.

Touch typing

You should be a touch-typist to really understand modal editors. I wasn’t, and I didn’t.

If you don’t use the home row, you probably should use a non-modal editor like Sublime Text or emacs which offer a better user experience in a much more resources efficient way than browser based editors.

There is no intended elitism in that statement. Everybody can learn touch typing for free at any age and really should, if only for the sake of his eyes and bones joints. During all my computer science studies, nobody talked about touch typing. To make things worse, in France, “touch typing” translation is “dactylographie” which is a job name that can be translated back to secretary and is like at the opposite of what you want to do when you study computer science. It is also associated with fast typing speed which people quickly dismiss because if you ask, everybody is already typing quickly enough.

As a programmer you are even told that speed is useless because you spend more time reading code than writing or that one day, projects like AlphaCode or OpenAI Codex, will replace the developer and his primitive keyboard altogether.

Yet, touch typing is probably the single most important skill that put my productivity through the roof, and it’s definitely the one which opened the door of modal editors to me.

Touch typing is not about speed. It really doesn’t matter if you type at 30 WPM, or put differently if your typing speed didn’t improve from the time you used only 2 fingers. As long as you free your mind and think about more important things than reaching the right keys, it’s a huge win.

NEVER looking back at the keyboard again is the ONLY way to acquire a muscle memory for typing. That exact same memory that allows you to do much more complex things like coordinating the hundreds of muscles needed to walk while keeping your balance, without even thinking about it. You can walk while having a deep conversation with someone ? You can certainly touch type !

If you think you already know the position of the keys without looking, it all boils down to a simple test to be sure that it’s your muscle memory at work here: You should type the exact same way in the dark without a back-lit keyboard than in plain day.

From that standpoint, you will see that h, j, k, l are better than arrows to move around text, and that, in order to differentiate writing an h from moving to the left you need different modes when typing, hence a modal editor. For the anecdote there was no arrow on keyboard when vi was created, but this is a different story and the argument is even more relevant today with arrows.

Everything that takes you out of the home row will feel like a distraction and that explains why the UI is kept to a bare minimum (not because the developers are lazy or stuck in a time when no UI existed like I heard several times ;).

Vi set the base rules of modal editing which didn’t evolve much despite numerous attempts to reboot the original project.

What’s all the fuzz about ?

Kakoune is a modal terminal editor developed in modern C++ by a long time vim power user. With multi-cursors (popularized by Sublime Text) in mind from its inception and visual selections at the center of the editing workflows, it tries to always show you the subjects before executing the action that will apply upon them.

Where vim uses the verb before the subject (ex: 3, d, w for blindly deleting a word 3 times), Kakoune uses selections (ex: 3,W,d for visually selecting 3 Words and then deleting them).

trampoline is a great tutorial to understand basic Kakoune workflows and to see why it was a fresh air in the modal editor world.

With a compiled size of 3Mb, Kakoune starts in a few hundreds milliseconds with all plugins activated. It has been stripped out of everything you’d think is essential for modern editing like a rendering engine, a layout engine, a plugin manager, or even a scripting language, putting at test a famous quote:

“Perfection is achieved not when there is nothing left to add, but when there is nothing left to remove”

Antoine de Saint-Exupéry

Nothing’s perfect, but astonishingly enough, with some efforts, Kakoune can do pretty much the same things as Visual Code, also it doesn’t look as polished at first glance.

Less is more

Probably the most annoying thing when you first try Kakoune, is that it looks like it’s missing everything. Not even a way to edit 2 files side by side ? Come on !

Kakoune in fact, delegates number of that kind of functionalities to other software and this orthogonal design is its mantra. Its core feature is just moving characters around without even taking care of the rendering, and for that it is simply super efficient.

No rendering

Kakoune like most terminal editors, doesn’t even render the characters on screen. Why reinventing the wheel ? Let the best in class alacritty do the hard work of dealing with hardware acceleration.

No layout manager

You have a status bar, a command prompt, basic info boxes, completion menu, and that’s nearly everything.

To be able to have multiple editor panes you need a terminal multiplexer like tmux or a tiled window manager, and launch multiple Kakoune processes (connected or not to the same session). That strategy seems weird and inefficient at first, but Kakoune is so light on resources that launching a whole new process is as fast as opening a new window or a new pane in other editors.

I personally use kwin to arrange 2 to 3 borderless Kakoune windows horizontally and vertically side by side in a dedicated workspace.

No file browser

Kakoune has an effective fuzzy finder for commands and arguments completion in the prompt mode, but the open command only considers completion per directory level and there is no integrated way to see your files’ hierarchy.

Opening files in Kakoune with fzf

There are several plugins that allow you to use an external file picker with a GUI or TUI. I personally use kakoune.cr and sk

No integrated LSP

One of the best contribution of visual code and Microsoft is to have dissociated languages features from the editor and defining the Language Server Protocol.

Kakoune doesn’t support LSP out of the box, but hopefully there is a Kakoune plugin written in rust to fill the gap: kak-lsp. Although not as feature-complete than competition, certainly because of the limited UI and API of Kakoune, it is doing the job pretty well, and you can perfectly edit a svelte project with it.

No integrated script language

Kakoune calls it kakscript, but it is mainly a syntax for declarative statements (define commands, variables, macros, hooks). It has no control flow, so it is definitively not a script language.

But how is done integration like LSP ? This normally involves complex interactions between the editor and the language server ?

No plugin API

And how is it possible to have plugins (LSP) without a plugin API in the first place ?

Kakoune has expansions expressions that can take their values, among other sources, from external commands. A simple hook system allows calling external commands through expansions on special event (open, close, …) that in turn generate Kakoune statements which can be evaluated, and that’s all you really need.

That makes Kakoune language agnostic. You can generate statements from whatever language you like (script or compiled). Statements can be command definitions, keystrokes (or primitives), evaluations and can mimic anything you can do inside the editor (moving, selecting, editing, calling external commands, …), even in the background and without leaving traces in command history.

No plugin manager

Now you know that you have plugins without an integrated script language and without a plugin API, how do you manage them ?

Kakoune just loads everything it finds from an autoload directory. git can be considered as a basic Kakoune plugin manager and this is the solution I use. Define a git submodule from every plugin you are interested in, then use symlinks inside the autoload directory, and update targets regularly with git pull. It gives you instant startup time.

There are several autoload scripts like plug.kak that can help you manage your plugins through a basic interface inside Kakoune, but don’t expect a browser and users reviews.

The most starred GitHub Kakoune plugins are listed here

Simple is beautiful

Uncluttered status line

The default status line is really simple and like a shell, it is defined by a string containing expansions expressions. You can use the following plugins to add all sort of useful information :

Basic features delegated

Even simple editor functions like sorting line or wrapping paragraph, are delegated to external tools.

  • To sort some lines, select them and pipe the selection to the sort command line utility with | sort.

  • For auto wrapping a paragraph to 120 columns width, select and pipe it to fmt utility with | fmt -w 120++.

The pipe primitive simply replaces the selection with the result of the executed command on the selection. It is as powerful as damn simple.

If you want to insert the result of a command, let’s say a calendar, you can use another primitive: ! cal.

You can then create a mapping for repeating these tasks with a simple keystroke.

Buffer for everything

Another example of a delegated core editor functionality is pattern searching on files. Kakoune relies for that on the grep shell command, and on a FIFO buffer, which is simply a buffer which content is written by an external program.

Kakoune runs the grep command line tool in a separate FIFO buffer and switch to that buffer. A special mode is activated to highlight file names and keywords and map the Enter key to a macro that will open the file mentioned on the current line in a new (or existing) editing buffer, and move at the right position.

This is Kakoune orthogonal design at work. The main advantage here is that Kakoune doesn’t have to implement that functionality and even if grep interface is basic, it works and is stable since epoch. As for the pipe command, the process can be generalized to interact with any external tools that output text.

kakpipe is a rust plugin that allows you to launch any command in a colorful FIFO buffer by just giving its name along its arguments. It does the highlighting (if the command outputs colors) and the process management for you, killing the processes and cleaning everything when you close the buffer. It’s the easiest way to integrate external command line tools to Kakoune and get rid of your shell.

Peer and remote editing

Kakoune is built around a client/server architecture and use a stream socket to share and control sessions locally. You can open 2 Kakoune windows on the same session and the same file and see instant modifications from both sides as you type.

Kakoune.cr use the Kakoune socket to open files in an existing session and act as a bridge between external tools and Kakoune. Associated with sk you can have real-time fuzzy search with preview pane instead of the grep command presented above.

Remote editing, and by extension peer editing, is abstracted the exact same way through the stream socket. Like any terminal editor you can edit remotely some files inside a remote shell (ssh), but you can also launch Kakoune locally and connect to a remote session. socat for instance can create a virtual local socket that will forward everything to a remote one, so each side can use his own environment and still see/edit the same files in real-time.

IoT ready

Because Kakoune is light on resources, it works on embedded and IoT devices without a glitch.

Workflow example

Editing with Kakoune is really different from vim and clones. You can see some workflows based on vim typing challenges at Kakoune TV.

Let’s see how to format a Markdown table the Kakoune way. We start by typing the cells contents

|my|table| ||| |this is | a multi column | |and multiline | table| |with a \| escaped ||

We need to vertically align all the | and Kakoune has a primitive for that: &.

It takes selections in different lines and align their anchors (the end of selection by default) with spaces. It works if there are several selections by line, and even with different number of selections per line. So we just need to select all the pipes and align.

The only difficulty came from the escaped pipe in the last line which we need to unselect some way before aligning.

The workflow is this one:

  1. select the paragraph with Alt i, p which select the inner text object which is a paragraph

  2. select the pipes with s, \, |, Enter to have x selections of |. The s primitive takes a regular expression as argument, and as | means or, we have to escape it with \.

  3. Unselect the escaped pipe on the last line. We need to change the main selection by hitting ( twice and deselecting with Alt ,

  4. finally, hit & to align everything

|my |table | | | | |this is | a multi column | |and multiline | table | |with a \| escaped | |

To fill the header with - is simple

  1. go anywhere on the second line and hit x to select the whole line

  2. select all the spaces (x selections of 1 char) with s space Enter

  3. replace selections with - with r,-

|my |table | |--------------------|----------------| |this is | a multi column | |and multiline | table | |with a \| escaped | |
my table
this is a multi-column
and multiline table
with a | escaped

By looking at the status after the s sequence, you can see that Kakoune has made 36 selections of one space to apply the primitive r on.

Dealing with selections has been a game changer for me. I think it is much more natural to think about how iteratively and interactively make the right selections and apply the right verbs on them, than to think about regex and capture groups upfront of your changes.

What’s next ?

Modal editors are here to stay as this is still the most efficient and ubiquitous way of editing files as long as you trained to touch type.

Kakoune has inspired a lot of editors but is still the reference to me. One can complain that it’s too much locked on orthogonal design, and that the project lead rejects on purpose any implementation (API, panes, …) that goes against this principle. This hard line explains why you generally dislike Kakoune at first and love it in the long term, but this has also impacted negatively Kakoune adoption which should have been better given the pertinence of its modus operandi.

You have to spend some time to choose among all those orthogonal implementations and setup manually all the pieces together to fit your editing workflows and your desktop environment. Kakoune author wants to keep its development cool and fun, which certainly is, but at the same time, the burden of having a nice functional environment lies on the users’ shoulders.

One editor that has the potential to take over is helix editor, not only because it borrows Kakoune main principles, but because it is based on much modern code base (Tree-sitter vs regex). It doesn’t have such a radical position on orthogonality, and comes with a lot of features out of the box (LSP, multi panes, richer UI, file picker, …). It is more user-friendly as a consequence.

Furthermore, it is coded in rust, which by itself drains a lot of interest, and above all eases refactoring while keeping memory and thread safety under control (which is way harder and less fun to do in C++). This will be a major advantage for implementing all the features advertised on the road-map like the WASM plugin system or the ability to choose between GUI or TUI.