Cached at:
05/13/26, 10:14 AM
# kakoune is a text editor
Source: [https://ficd.sh/blog/kakoune-is-a-text-editor/](https://ficd.sh/blog/kakoune-is-a-text-editor/)
introduction
Welcome\!
My goal with this article is to help you develop a comprehensive understanding of the[Kakoune](https://kakoune.org/)text editor:*what*it is,*how*it works, and*why*it has that design\.
Although this is not exactly a tutorial, we build up these concepts gradually, and plenty concrete usage examples and demo videos are provided to supplement the discussion\.
This piece is quite long, and densely loaded with information\. I suggest treating it like a long\-term learning resource you can chip away at, rather than trying to tackle it all in one session\.
I hope this ends up being useful, both to new users and existing Kakoune enthusiasts\. If you have any questions or comments about this post, please don’t hesitate to[contact me](https://ficd.sh/contact)\.
---
This article was written without AI assistance\. If you are interested in a more human internet, please consider subscribing to my[RSS feed](https://ficd.sh/rss.xml)to be notified of future posts\.
- [What is kakoune?](https://ficd.sh/blog/kakoune-is-a-text-editor/#what-is-kakoune)
- [beyond vim](https://ficd.sh/blog/kakoune-is-a-text-editor/#beyond-vim)
- [What does subject : verb order even mean?](https://ficd.sh/blog/kakoune-is-a-text-editor/#what-does-subject-verb-order-even-mean)
- [kakoune’s inverted grammar](https://ficd.sh/blog/kakoune-is-a-text-editor/#kakounes-inverted-grammar)
- [orthogonality and atomic edits](https://ficd.sh/blog/kakoune-is-a-text-editor/#orthogonality-and-atomic-edits)
- [A deeper dive into keys & commands](https://ficd.sh/blog/kakoune-is-a-text-editor/#a-deeper-dive-into-keys-commands)- [executing keys](https://ficd.sh/blog/kakoune-is-a-text-editor/#executing-keys) - [evaluating commands](https://ficd.sh/blog/kakoune-is-a-text-editor/#evaluating-commands) - [commands are keys](https://ficd.sh/blog/kakoune-is-a-text-editor/#commands-are-keys)
- [multiple selections](https://ficd.sh/blog/kakoune-is-a-text-editor/#multiple-selections)
- [registers & marks](https://ficd.sh/blog/kakoune-is-a-text-editor/#registers-marks)
- [iterative learning](https://ficd.sh/blog/kakoune-is-a-text-editor/#iterative-learning)
- [a server\-client editor](https://ficd.sh/blog/kakoune-is-a-text-editor/#a-server-client-editor)
- [editing with pipes](https://ficd.sh/blog/kakoune-is-a-text-editor/#editing-with-pipes)
- [command expansions](https://ficd.sh/blog/kakoune-is-a-text-editor/#command-expansions)
- [writing plugins](https://ficd.sh/blog/kakoune-is-a-text-editor/#writing-plugins)
- [shell expansions](https://ficd.sh/blog/kakoune-is-a-text-editor/#shell-expansions)
- [conclusion](https://ficd.sh/blog/kakoune-is-a-text-editor/#conclusion)- [acknowledgments](https://ficd.sh/blog/kakoune-is-a-text-editor/#acknowledgments) - [further reading](https://ficd.sh/blog/kakoune-is-a-text-editor/#further-reading) - [automatically generating demo videos](https://ficd.sh/blog/kakoune-is-a-text-editor/#automatically-generating-demo-videos)
## [What is kakoune?](https://ficd.sh/blog/kakoune-is-a-text-editor/#what-is-kakoune)
[Kakoune](https://kakoune.org/)\(*French: \[kakun\]*\) is a modal screen\-based text editor created in 2011 by French programmer Maxime Coste[1](https://ficd.sh/blog/kakoune-is-a-text-editor/#fn:wiki), better known as[mawww](https://github.com/mawww)\. Having begun its life as a C\+\+ rewrite of Vim, it has since evolved into a project with a strong identity and unique design goals\.
A non\-exhaustive overview of Kakoune’s most interesting features[2](https://ficd.sh/blog/kakoune-is-a-text-editor/#fn:kakorg):
- **Multiple selections and multi\-cursor editing are first\-class**\(regex filtering, splitting, aligning, etc\.\)\.
- **Interactivity and experimentation are core design principles**\.
- **Orthogonal design with powerful editing primitives**\(selection rotation, indentation leveling, case manipulation…\)
- **Client/Server architecture in which the windows of your session are managed by your terminal or window manager**\(tmux, i3, niri…\)\.
- **Highly extendable with an easy\-to\-learn hook & macro system**\(unofficially called “Kakscript”\)\.
- Large focus on**Unix philosophy**; Kakoune not only integrates with, but relies on standard Unix tools\.
note on helix
[Kakoune](https://kakoune.org/)has served as a major inspiration for the[Helix](https://github.com/helix-editor/helix)editor\. However, Helix has diverged on some key design points, and the two cannot be discussed interchangeably\. Thus, Helix is outside the scope of this discussion\. With that said, although much of this article won’t apply to Helix, some of it might, due to its shared DNA with Kakoune, so Helix users may still find this discussion valuable\.
## [beyond vim](https://ficd.sh/blog/kakoune-is-a-text-editor/#beyond-vim)
Let’s consider “Vim motions” as an editing language\. This “core” doesn’t*need*to be surrounded by Vim; there are many editors \(VS Code, JetBrains…\) that support Vim motions\. Thus, a user that learns Vim motions in one tool can quickly adapt to another tool that supports them\.
A side effect of this is that, because of Vim’s ubiquity, a lot of people have come to view “Vim\-like bindings” as***the*standard**for keyboard\-driven, modal editing\. In other words, users expect editors to be mostly compatible with their existing “Vim binding muscle memory”\. Some people won’t consider an editor that expects them to change their approach\.
I think that’s a shame, because although I’m sure Vim is so popular for a reason,*we can certainly do better*\. No design is immune to being iterated on and improved\. Kakoune does this in an innovative way: by**inverting the subject–verb order**\.
## [What does subject : verb order even mean?](https://ficd.sh/blog/kakoune-is-a-text-editor/#what-does-subject-verb-order-even-mean)
When people say they expect “Vim bindings”, what they really mean isn’t specific keys… sure, we’re used to`hjkl`for movement, but we can get used to something else just as fast\. What matters most is Vim’s**modal text editing grammar**\.
It distinguishes between*insert mode*\(regular typing\) and*normal mode*: in which*keys*comprise*words*composed into*sentences*that describe text edits in the form*verb*followed by*subject*\.
This structure closely mirrors English, so it feels natural for us to reason about\. For example, we might express “delete this word” as`dw`:`d`for “delete” as the verb, and`w`for “until the start of the next word” as the subject\.
There’s[no shortage](https://stackoverflow.com/a/1220118)of[excellent writing](https://takac.github.io/2013/01/30/vim-grammar/)on[Vim’s text editing language](https://learnvim.irian.to/basics/vim_grammar)\. However, let me briefly challenge the intuitiveness of verb : subject for text editing\.
---
How often have you found yourself in the following situation? You’re editing the middle of a sentence, and now you want to delete from the cursor up to a certain word\. You know exactly how far to go; since you can clearly see the target with your eyes\. The challenge: how to share this information with the editor?
Well, the optimal \(Vim\-like\) command would be`d<count\>w`, where`<count\>`is a number key representing how many words you want to delete\. However, how do you know that number? It’s trivial for 2\-3 words, but how about something like 13? Sure, you could literally*count*them, but that’s going to take forever and take you out of the groove\.
Another option is to guess\. But sadly, your first \(and only\) visual indicator of how far you went is*after*the edit has been applied\. So if you were off by a few words, you’ll have to undo and repeat the entire action with a different count\.
Thankfully, Vim has an easy solution to the problem: visual mode\! Simply press`v`, and now you can use`w`and other motion keys to create a clearly visible*selection*\(subject\), after which you can press another key to execute the*action*\(verb\)\. By seeing exactly what you’re going to operate on*before*doing the action, you can reduce misfires greatly\.
However, Vim’s visual mode isn’t the most ergonomic\. There are different versions of it \(linewise, blockwise, …\), and it’s a fully separate mode in which key behaviors may differ in surprising ways\. Furthermore, when you finally press an “operator” key, the editor usually returns to normal mode — so if you prefer visual editing, be prepared to press`v`*a lot*\.
Vim’s visual mode*inverts*the verb order from its normal mode\. Subject first,*then*verb\. The selection*always*comes before the action; as a consequence, you will*see*what you’re acting on before you act\.
A friend of mine[3](https://ficd.sh/blog/kakoune-is-a-text-editor/#fn:jd)said it like this: Vim’s inclusion of visual mode is a reluctant admission that the verb\-subject order isn’t good enough to cover all cases — but instead of adjusting course and adopting a better grammar, Vim decided to bolt support for it on top of the existing model, ballooning editing complexity to high heaven\.
## [kakoune’s inverted grammar](https://ficd.sh/blog/kakoune-is-a-text-editor/#kakounes-inverted-grammar)
Luckily for the visual mode enjoyers of the world, there is a better solution out there\. This is the exact situation where Kakoune’s editing language gets it chance to shine\.
Imagine a normal mode that*is*visual mode\. What if, instead of being relegated to a finicky sub\-mode, visual selection\-based editing was not only supported, but had the entire editing experience optimized around it?
Well, you don’t need to imagine it, because Kakoune*is*that subject\-verb native editor\. For example,`w`doesn’t just move the cursor forward to the next word, it moves the entire*selection area*\. The meaning of`w`is “select to next word start”; no mention of any “cursor”\. Here’s how that looks:

Of course, where this really shines is*incrementally updating your selection*\. Let’s return to the previous example of selecting\. In Kakoune, the “shift” modifier changes the meaning of many keys: instead of*selecting something different*, it*extends what’s selected*\. Most keys that move around \(like`w`,`b`,`h`,`j`,`k`,`l`\) have a shift\-modified “extend” version\. In the example below, let’s use`W`to increase our selection, one word at a time\.

Many Kakoune keys also support support a “count”, which is a way to modify the action with some number\. For example, pressing`5w`has the same result as pressing`w`five times\. So if we know how far we need to select, we can use a count to easily select it without unnecessary repeated key presses\.
Here’s the best part: if we overshoot, we don’t have to undo and try again\. We can just press`B`as many times as we need to decrease our selection\. Once we’re happy with our selection, we can press any key that*operates*\(i\.e\. a verb\), such as`d`for “delete”\.

Something really important to note: it’s no so much “the selection always comes before” as it is “**there’s always a selection**”\. A key that operates on a selection will*always*work, because even your “cursor” is just a single\-character selection\.
Although editing in Kakoune can feel like “make the selection, than do the action”, there is no actual requirement to follow up a selection key with an action key\. You can spend as much time as you want perfecting your selection before finally pressing a key like`d`or`y`to operate on it\.
Another benefit of Kakoune’s verb\-order\-inversion is that it reduces the total number of modes\. By merging Vim’s visual mode into normal mode, we can eliminate some mental overhead and reduce total keystrokes \(no more spamming keys to toggle in and out of visual mode\)\.
## [orthogonality and atomic edits](https://ficd.sh/blog/kakoune-is-a-text-editor/#orthogonality-and-atomic-edits)
There’s another interesting consequence of Kakoune’s grammar inversion:**it completely eliminates the need for operator\-pending mode**\. A quick summary of what that is, in case you’re not too familiar with Vim:
It’s not fully accurate to say that`d2w`is completely a normal mode command in Vim\. The reason:`d`on its own can’t actually do anything\. You haven’t yet specified*what*to delete\! So when you press the first key \(the verb\), Vim enters a mode called “operator pending”, in which it waits for your follow up:*the subject*\! Once you’ve input`2w`, Vim can complete the sentence`d2w`and execute the edit\.
In Kakoune, the operator \(verb\) always knows what to operate on: the selections, at least one of which**must always exist**\. This makes the behavior of normal mode keys*atomic*\.`d`is defined as “delete the content of the selection”, and given the same buffer state \(text & selections\), it will always behave the same way\.
This key difference from Vim makes composing actions into edits remarkably easy to improvise, because any key can follow any key\. In essence, there are only two main kinds of keys in Kakoune’s normal mode:
- Keys that*change what is selected*\(move the selection, expand it, shrink it, etc\.\)
- Keys that*operate on what is selected*\(delete, copy, duplicate, replace, etc\.\)
This means edits aren’t grouped into “sentences” like`d2w`or`cib`\. For the most part, \(with the exception of counts, registers, and keys that switch you out of normal mode\), one key is one step\. Since these steps are incremental, not only do you get visual feedback for each step, but “logical edits” \(e\.g\. delete this word, copy that sentence\) can also be*partially*undone with`u`\.
## [A deeper dive into keys & commands](https://ficd.sh/blog/kakoune-is-a-text-editor/#a-deeper-dive-into-keys-commands)
Kakoune has two ways to receive instructions:
1. executing keys
2. evaluating commands
### [executing keys](https://ficd.sh/blog/kakoune-is-a-text-editor/#executing-keys)
Keystrokes are simple enough\. Not simple as in trivial to learn — there’s a lot of them,[listed here](https://github.com/mawww/kakoune/blob/master/doc/pages/keys.asciidoc)— but simple to express in writing: we simply string keys together\. For example, the sequence`hhW`represents pressing`h`twice, then`W`\(Shift \+`w`\)\.
For some keys, we can use a special notation if needed:
- Modifier keys:- `<a\-X\>`:`Alt \+ X` - `<c\-X\>`:`Control \+ X` - `<c\-a\-X\>`:`Control \+ Alt \+ X` - etc…
- Special keys:- `<lt\>, <gt\>`: escaped`<`and`\>` - `<esc\>`: escape \(as seen above\) - `<ret\>`: enter - `<tab\>`,`<space\>`, etc…
spaces
Certain keys can be represented multiple ways\. For example, you can write`<space\>`explicitly, or simply put an actual space in the sequence\. In the key sequences written under the demo videos, I’m using`<space\>`to denote literal presses of the space bar\. You can ignore the actual whitespaces, those are just there to make it easier to read and have no further meaning\.
Why is this “key notation” important? Well, it’s**canonical**\. Besides being a more pleasant shorthand \(`<a\-x\>`is easier to write than`Alt \+ x`all the time\), it gives us all a shared language to discuss and share Kakoune edits\. Additionally, Kakoune can actually parse these strings and execute them via the`execute\-keys`command\. Speaking of commands…
### [evaluating commands](https://ficd.sh/blog/kakoune-is-a-text-editor/#evaluating-commands)
Kakoune can evaluate a*string*as a set of*commands*\. A sequence of such commands is often called**Kakscript**, though it’s not officially a scripting language\. Much like a shell, its input is split into*words*, which are then interpreted as commands with arguments\. There’s shell\-like quoting, and commands can be separated by newlines or semicolons\.
```
# comments BTW
edit -existing src/main.c; set-option buffer indentwidth 4
write src/main.c.bak
```
Like a shell\(wow\! who would’ve guessed?\)script, Kakoune can even read & evaluate commands \(Kakscript\) from a file \(`\.kak`extension by convention\)\. There’s even a command*called*`evaluate\-commands`\(`eval`for short\) which, you guessed it, pretty much does the same thing as`eval`in the shell\.
In case you’re unfamiliar, that means it takes its arguments as strings and evaluates them as commands\. A number of helpful flags are available, such as`\-buffer`, which runs those commands in a different buffer context, and`\-itersel`, which runs once for each selection as if that selection were the only one\. It also allows for nested evaluation, which becomes useful when working with expansions \([discussed later](https://ficd.sh/blog/kakoune-is-a-text-editor/#command-expansions)\)\.
quoting rules
Kakscript is mostly shell\-like, since it has comments, word splitting, escaping newlines with`\\`, and so on\. However, it has some unorthodox quoting rules, briefly described here\.
In short, Kakoune has two kinds of quote delimiters:*balanced*and*matching*\. The usual single`'`and double`"`quotation marks are*matching*:
- `"\.\.\."`
- `'\.\.\.'`
You can also use a`%`prefix to pick your own delimiter, which can be**any**non\-alphabetic Unicode symbol\. For example:
- `%\|\.\.\.\|`
- `%~\.\.\.~`
- `%ε\.\.\.ε`
Any matching delimiter can be doubled to escape it within the string\. For example,`"foo""bar"`contains`foo"bar`, and`%\|foo\|\|bar\|`evaluates to`foo\|bar`\.
Balanced delimiters are also`%`\-prefixed and follow slightly different rules\. Only the four kinds of ASCII brackets are supported:
- `%\{\.\.\.\}`
- `%\(\.\.\.\)`
- `%\[\.\.\.\]`
- `%<\.\.\.\>`
These can’t be escaped by doubling them, but nested, balanced pairs are escaped automatically:
- `%\{foo\{\}bar\}`: contains literal`foo\{\}bar`
- `%\(foo\(\)bar\)`: contains literal`foo\(\)bar`
- `%\[foo\[\]bar\]`: contains literal`foo\[\]bar`
- `%<foo<\>bar\>`: contains literal`foo<\>bar`
Although these rules may seem like arbitrary complexity on the surface, they become really helpful when writing scripts with many nested layers of string evaluation\.
As we’ll discover later, Kakscript often embeds POSIX shell, which also uses`'`and`"`for quoting\. Using Kakoune’s unique quoting forms lets us write shell scripts without needing to constantly worry about escaping delimiters\.
To read about Kakscript in more detail, see the[manual](https://github.com/mawww/kakoune/blob/master/doc/pages/command-parsing.asciidoc)\. For a more in\-depth discussion on its semantics, see my[devlog](https://ficd.sh/blog/kaklang-devlog-1)on writing a Kakscript parser\.
### [commands are keys](https://ficd.sh/blog/kakoune-is-a-text-editor/#commands-are-keys)
Of course, commands can be written and evaluated on the fly: pressing`:`opens a prompt into which you can type a command and press`<ret\>`to evaluate it\. The same rules apply: comments, quoting, word\-splitting all work the same\.
Which leads us to an interesting observation…
I argue that commands are just a subset of keys, because any valid command can be typed at the`:`prompt\. Thus, the command`write src/main\.c`is also the key sequence`:write src/main\.c<ret\>`\. These are just two notations to express the same thing\.
In fact, there’s nothing special about even`:`\. It’s just a key whose job is to bring up the prompt, wait for input until`<ret\>`is pressed, then evaluate it\. The same if true of*any*key that uses a prompt, such as`/`\(search\) and`<a\-k\>`\(filter\)\.
So, why does this matter? It means that commands can be evaluated in*any*context where keys are valid, because there always exists some sequence of keys to produce any command\. This is true even in insert mode, wherein`<a\-;\>`can be used to escape to normal mode for one command:`<a\-;\>:write src/main\.c<ret\>`
Let’s illustrate why the “commands are keys” principle is so important with an example\. Consider the common case of binding a key to some action\. In Kakoune, we can use the`map`command tomapa key to a sequence\. For example, let’s make the tab key select the current line, but with whitespace trimmed:
```
map global normal <tab> x_
```

Let’s try a more common one: binding`<c\-s\>`save the file\. There’s a small difference, though: there isn’t a key for saving, there’s only the`write`command\. Thankfully, that’s no problem for us, because as we observed earlier, any valid command can be expressed as a key sequence\. Thus, to complete the binding:
```
map global normal <c-s> ':w<ret>'
```
Now, let’s consider the inverse:*executing keys from a command context*\. It turns out, this is possible too, thanks to the`execute\-keys`command \(`exec`for short\)\. It’s a bit like`map`in that it executes… well… you know, but the execution happens immediately, and it also exposes some options for us to tweak\. To understand how this can be useful, let’s create another binding like before\. This time, we’ll make the`=`key duplicate the current line:
```
# x to select the line, y to yank (copy), p to paste below
map global normal '=' 'xyp'
```

This works, but there’s two problems: because those keys are being executed literally as if you had pressed them, we end up with side effects: our previous selection is lost, and our clipboard gets overwritten\. What if we wanted to keep working with either of those after duplicating the line?
This is where`execute\-keys`becomes relevant\. Beside just executing the key sequence we give it \(just like`map`\!\), this command provides some options that can really help us out\.
The first of these is`\-draft`, which executes keys in a “disposable context”\. This basically means that our selection state gets restored after the command runs\. Consider this example, where the key sequence`glbcFOO<esc\>`selects the last word on the line and replaces it\. You can see for yourself how running it with without`\-draft`results in a different cursor position than we started with:

While using`\-draft`indeed keeps the original selection:

`\-save\-regs`does something very similar, except for*registers*, which are like Kakoune’s clipboards\. \(Yes, you can use multiple at once, and it’s as powerful as you’d expect\!\) Registers all have names, and it happens that the*default*register \(the one stuff gets copied to when you press`y`\) is called`"`\(aka`dquote`\)\. Thus, we can complete our improved line duplication command like so:
```
# duplicate the line, preserve register and selections
execute-keys -draft -save-regs '"' 'xyp'
```
Like before, we just need to write the above command in “key notation” to successfully bind it:
```
map global normal '=' ':execute-keys -draft -save-regs dquote xyp<ret>'
```

As you can see, the interplay between commands and keys has its uses for both interactive editing as well as scripting & macros\. Even if you don’t plan to write any plugins, these tricks are bound to come in handy in your own configurations\.
isolated mappings
Kakoune’s key mappings are*isolated*\. If a mapped key refers to itself \(e\.g\.`map global normal x <i\-p\>x`\), the right\-hand side will always use the canonical meaning of that key; recursion is never allowed\.
Isolation also means that any keys bound by`map`have*no*effect on`execute\-keys`or subsequent`map`commands\. \(`execute\-keys`does have a`\-with\-maps`option, but its use is generally discouraged\)\.
A positive effect of this isolation is that key sequences are fully portable across Kakoune configurations, which enables the easy sharing of macros, custom commands, plugin implementations, etc\.
For example, as a Colemak\-DH user, I’ve mapped`mnei`to`hjkl`for navigation\. However, plugins are completely safe to use`hjkl`internally; my custom mappings won’t interfere\. Similarly, when we write our own plugins or custom hooks, we are expected to use the canonical keys as well\.
## [multiple selections](https://ficd.sh/blog/kakoune-is-a-text-editor/#multiple-selections)
As I mentioned earlier, multiple selections are a core editing feature in Kakoune\. This is intuitively understood as multi\-cursor editing; but since a cursor in Kakoune is just a selection of size 1, it’s important to think of it as multi\-*selection*editing\.
Commands that we understand as acting on “the” selection/cursor actually act on**all**selections\. It just happens that most of the time, we only have one selection\. But if we have*multiple*, pressing`d`, for example, deletes*all of them*:

The concept is simple, but incredibly powerful\. Multi\-selections don’t necessarily empower us to make edits that are*impossible*in Vim\-like editors… but they certainly make the whole experience a lot more ergonomic\! Hang tight, you’ll see why in a moment\.
So, how does one create multiple selections in the first place? One way is the`s`key, which lets us create them by matching a regex\. In short, you first select some area; then, you press`s`, type a regex, and press enter\. You’ll end up with all non\-overlapping matches inside the original selection as new selections\.

The most common use case for this is the classic “search and replace”\. Let’s try replacing every occurrence of “foo” with “bar” in this example\. We begin by pressing`%`, which selects the entire buffer \(think`ggVG`in Vim, or`<c\-a\>`in a “typical” IDE\)\. We need to do this because keys like`s`always operate*on the selection*; you must be explicit about saying “please search the whole buffer”\.
So, pressing`s`brings up a prompt, we type`foo`, and after hitting enter, we end up with each match selected\. That’s the search part down, how about replace? We do it the exact same way we’d replace a single selection: press`c`\(change\), which deletes the selection and enters insert mode\. We can type our replacement,`bar`, and press escape to return to normal mode when we’re done\.

You may be thinking, big whoop, isn’t this basically the same as`:s/foo/bar/g<ret\>`in Vim? Yes, but with a big difference: you get visual feedback for**every step**of the edit\. Besides helping you catch regex mistakes earlier \(you’ll clearly see if the wrong thing is selected\), the main advantage of Kakoune’s approach is that it lets you branch into a different option at almost any step\.
You don’t*have*to replace the matches; you could copy them \(`y`\), make all letters uppercase \(`<a\-\`\>`\),[pipe them to a program](https://ficd.sh/blog/kakoune-is-a-text-editor/#editing-with-pipes)\(`\|`\)… You can actually do anything, because as we learned earlier, multiple selections aren’t anything special; most keys you press just have their effects repeated across selections\.
Thus, the power of multi\-selection shines when making more complex edits\. Let’s demonstrate that with some brief examples\. Don’t worry about understanding each step, these are just to give you an idea of what’s possible\. I’ll share the key sequences so you can try them out yourselves\.
Here’s me turning each sentence of a passage into a bullet point:

> ``` %<a-I>s a<ret><esc> I-<space> <lt> ```
And how about swapping the contents of these if/else blocks:

## [registers & marks](https://ficd.sh/blog/kakoune-is-a-text-editor/#registers-marks)
We briefly mentioned*registers*in a previous section, but it’s worth investigating them a little deeper, since they’re a big part of editing with Kakoune\. In case you’re not familiar with the concept, you can think of registers like Kakoune’s internal clipboard\.
When we copy some text with`y`, it gets put in the default register\.`p`pastes text from that same default register\. Like Vim, Kakoune lets us use the ASCII letter keys as*named registers*\. Double quote`"`is the “register key”, so to copy some text into register`a`, we can press`"ay`\. To paste text from register`x`, we type`"xp`\. This can be done with any key that uses a register\.
Note
This is also why`"`or`<dquote\>`is the name of the default yank register\!
You can already imagine how having multiple named clipboards is useful, but registers really shine when we make use of Kakoune’s*special registers*\. You can see them all listed in`:doc registers`, but let’s focus on the most useful one: the*mark*register, called`^`or “caret”\.
Other editors, like Vim, let you “mark” positions in the buffer\. You can then “return” to a marked position easily\. This feature can be lifesaving when navigating around a complicated codebase\. Kakoune has marks too, and of course, they can be used like bookmarks as well\. But Kakoune marks have a key property that make them incredibly powerful:**they don’t just mark positions, they save*selection descriptions*to registers**\.
It’s a bit like creating a snapshot of your entire selection state and returning to it later\. We use`Z`\(uppercase\) to save a mark, and`z`\(lowercase\) to restore it\. Named registers can be used too, like`"aZ`and`"az`\. Consider the following example, in which we’re about to do a search and replace but get distracted by something else\. Using marks, we’re able to follow distractions to our heart’s content, since we can return to the previous editing state easily:

> ``` <a-i>p sfoo<ret> Z /TODO<ret> x2J sbaz<ret> cbar<esc>, 2kxd zcoof<esc> ```
We can also perform*combinations*on marks, which are accessible through`<a\-z\>`and`<a\-Z\>`\. The most common is`a`for append\.`<a\-z\>a`selects the mark plus our current selection*without*changing the mark, while`<a\-Z\>a`appends the current selection*to*the mark\.
Mark combinations are great for creating super precise selections*incrementally*, without needing to conjure up some crazy regex to select it all in one go\. In this example, I use`<a\-Z\>a`\(append to register\) to select a bunch of words, then capitalize all of them with a single press of`~`:

> ``` wwZ jbb<a-Z>a 5w<a-Z>a 2j3b<a-Z>a glb<a-Z>a z~ ```
We can also use the “union” mark combination \(`<a\-z\>u`\) to select an area by separately defining its start and end points\. If we save a mark with`Z`, select something else, then press`<a\-z\>u`, the entire area between those two points is selected\. This is super handy for selecting a large chunk of text that doesn’t all fit on the screen at once:

> ``` xZ 20jvt 20jvt 6j x <a-z>u <a-;> d vv ```
## [iterative learning](https://ficd.sh/blog/kakoune-is-a-text-editor/#iterative-learning)
Despite Kakoune’s high complexity, you can actually get up to speed with it pretty quickly\. The truth is, most edits you’ll want to do can be expressed with a smaller number of basic keys that you can learn in a day\. At this point, you’ll likely be somewhat inefficient, but nothing is stopping you from actually using Kakoune to complete your daily work at a reasonable pace\.
The*real*learning experience comes with the gradual process of*refinement*as you discover*more efficient ways*to perform edits you already know\. Kakoune is very well suited to being “discovered” in this way because the two main kinds of keys \(change the selection, act on the selection\) are simple to reason about\. Once you understand Kakoune’s conceptual framework, integrating new keys and techniques into your workflow becomes a remarkably*iterative*process\.
Let’s being with something called an “editing goal”\. This is basically a description of the end result you want to arrive at\. For example, “change this string’s quote delimiters”, or “extract these lines of code into a separate function”\.
Most goals have multiple, equally valid ways to be achieved\. When you are tasked with an editing goal you haven’t encountered before, a set of unknown paths become available to you\. Your job is to “discover” one of those paths, based on the keys and techniques you already know\. If you’ve got the basics down, a basic, but inefficient path should always be available to you\.
Learning Kakoune is really about slowly integrating new techniques into your existing workflows to make them more efficient\. Let’s illustrate this principle with an example\. Suppose your goal is to swap the arguments in a Python function signature:
```
# before
def foo(first, second):
pass
```
```
# after
def foo(second, first):
pass
```
Let’s review the keys you’d need to discover the most basic editing path:
some basic keys
`x`selects the whole line:

`s`creates selections matching a regex:

`<a\-\)\>`rotates selections content \(note the plural\):

If you’ve learned the above keys, you can already form a simple game plan: select as one selection per argument, then rotate\. To execute this plan, you’d press`x`to select the line, select the parenthesis with`s\\\(\.\+\\\)<ret\>`, then “reduce” your selection to just the arguments with`s\\w\+<ret\>`, followed by a final`<a\-\)\>`\.

> ``` x s\(.+\)<ret> s\w+<ret> <a-)> ```
That’s not exactly the most*optimal*way, but my point is,*you can do it knowing only three keys*\. As you learn more keys, you can make edits like this more convenient\.
For example, you may replace the`s\\w\+<ret\>`with the much simpler`S,<space\><ret\>`, which*splits*your selection on regex matches \(in this case, just the literal`,`\):

> ``` x s\(.+\)<ret> H<a-;>L S,<space> <a-)> ```
The escaped parenthesis in that regex is kinda ugly, but luckily we can avoid that too\. By putting the cursor inside the parenthesis, we can select it all with`<a\-i\>\)`, thus simplifying the edit:

> ``` www <a-i>) S,<space><ret> <a-)> ```
But what if we want to do this for multiple functions at once? Just select them, then select the parenthesis and the inner words as*nested text objects*:

> ``` % <a-I>) :exec <space> -itersel <space> <a-I>w <a-)> ```
Note
We have to actually type part of this out using`:exec`because we need`\-itersel`, which runs a key sequence once per selection\. This is how we rotate the words within each line, as opposed to globally\!
In other words, you really don’t need to know that many keys to get started with Kakoune\. All the keys you learn can be composed together in ways that make sense, so you can learn new primitives at whatever pace suits you until you’ve got them all\. And in the meantime, if you really need something,`:doc keys`serves as an excellent resource\.
## [a server\-client editor](https://ficd.sh/blog/kakoune-is-a-text-editor/#a-server-client-editor)
Kakoune is designed with the Unix philosophy in mind:*do one thing, and do it well*\. Thus, its focus lies entirely with being a competent code editor; anything that*can*be outsourced to external tools*should*be\.
Like all modern editors, Kakoune can have multiple text buffers open for editing at once\. However,*unlike*most of its peers, Kakoune does not implement any window management\. A single client has no vertical or horizontal splits; you can only view one buffer at a time\.
However, Kakoune*does*have a solution to this, and I think it’s pretty elegant\. Notice how I said “client” earlier? That’s because Kakoune has a*server–client architecture*\. When you first launch Kakoune, besides starting the interface you see, it also spins up a session with a unique ID… which can be used to attach new clients to this session\!
Now, suppose we’ve started Kakoune with`kak \-s foobar`, which just sets a custom session ID\. If we want to see & edit two buffers side–by–side, we can simply attach a new client to the session with`kak \-c foobar`, and change its active buffer\.
This is what lets us outsource managing buffer windows to an actual window manager\. A Kakoune client is a separate process\. Thus, you can open new clients as tmux planes, separate terminal windows managed by your operating system, or however else you prefer to manage terminal applications\.
Speaking of tmux, a strong parallel exists here\. It could be helpful to think of Kakoune like tmux, except it handles text buffers instead of terminal panes\. Tmux allows for detaching from a session, allowing it to exist in the background and be reattached to later, even if you’ve closed the terminal window\. Kakoune also supports this detach\-attach workflow\. The`daemonize\-session`command prevents the session from terminating when the last client is closed, thus allowing your editing sessions to persist as long as the daemon isn’t killed\.
You can also control Kakoune sessions from outside using`kak \-p <name\>`\. This command reads commands from standard input and evaluates them in the context of the session you named\. For example, I can remotely kill the earlier session with`echo 'kill' \| kak \-p foobar`\. This makes it easy to script Kakoune from anywhere on your system\.
## [editing with pipes](https://ficd.sh/blog/kakoune-is-a-text-editor/#editing-with-pipes)
Any Linux user will tell you that in a shell, the`\|`key is incredibly powerful\. It can be used to compose commands together into*pipelines*by “piping” the output of one command into the input of another\.
As it turns out, Kakoune lets us integrate this same concept into our text editing with the`\|`key\. In short, the content of our selections is piped to the standard input of the command of our choice; the output replaces the original text\.
This capability has an important consequence: in Kakoune, you can*always*express a certain text transformation, because even if you can’t \(or don’t want to\) do it with Kakoune keys, you can do it with an external program\.
I often select a paragraph and reflow it with`\|fmt<ret\>`, or sort a list of numbers with`\|sort \-n<ret\>`\. You could also type some Python code, select it, and “evaluate” it inline with`\|python<ret\>`:

> ``` 4w 2W _ y o<ret>print()<esc> hP x|python<ret> ```
But piping is most interesting when you write your own programs to augment some aspect of your workflow\. For example, I often find myself needing to “increment” numbers and letters, so I wrote a small Python program and added it to my`$PATH`as`char\-inc`:
```
#!/usr/bin/env python3
import sys
# helper to safely get i-th arg from argv
def arg(i, default=1):
return int(sys.argv[i]) if i < len(sys.argv) else default
# read the input text we'll operate on from stdin
inp = sys.stdin.read()
# first arg is count
count = arg(1)
# second arg is direction: 1 for up, -1 for down
fac = arg(2)
# clamp the count
if count <= 0:
count = 1
# list of chars
out = []
for c in str(inp):
# only increment alphanumerics
if c.isalnum():
out.append(chr(ord(c) + count * fac))
else:
# unchanged
out.append(c)
print("".join(out), end="")
```
```
$ echo '1. a.' | char-inc
2. b.
$ echo '3. c.' | char-inc 2 -1 # optional <count> and <direction>
1. a.
```
Now I can refine my selection with regular Kakoune keys, then use my custom program to easily increment the selections\. Here’s an example of me updating an ordered list:

> ``` xy %<a-s> gh F: |char-inc<ret> ggP bcqud<esc> ```
## [command expansions](https://ficd.sh/blog/kakoune-is-a-text-editor/#command-expansions)
Kakoune can*expand*certain constructs when evaluating commands\. The results of these expansions are treated as normal strings, so they can be passed as parameters to other commands, substituted into longer strings, etc\. This is similar to parameter expansion in the shell, but it works a little differently, because there are multiple*kinds*of expansions\. For example,`val`gives access to read\-only internal data,`reg`lets us read[registers](https://ficd.sh/blog/kakoune-is-a-text-editor/#registers-marks), and`opt`can be used to read*options*, which are \(mostly\) like variables\. There are actually 7 expansion kinds in total… though I won’t list them all here, you can read more about them in`:doc expansions`\. Of all the expansion kinds,`sh`\(shell expansions\) are by far the most powerful\. We discuss them in a[later section](https://ficd.sh/blog/kakoune-is-a-text-editor/#shell-expansions)\.
Expansions can*only*be done using the`%`\-quotes[described earlier](https://ficd.sh/blog/kakoune-is-a-text-editor/#evaluating-commands)\. The*kind*goes after the`%`sign, and the`name`goes between the delimiters:`%kind\{name\}`\. We can use the`echo`command to experiment with them, since it just prints its arguments to the status line\. For example, we can see the current session ID with`echo %val\{session\}`, the content of register`a`with`echo %reg\[a\]`, the currently detected filetype with`echo %opt\|filetype\|`, and so on\.
## [writing plugins](https://ficd.sh/blog/kakoune-is-a-text-editor/#writing-plugins)
Besides being a joy to use interactively, Kakoune makes it easy to automate & script its behavior with macros, custom commands, hooks, key mapping, and more\. Let’s learn about it by writing a simple plugin: an auto\-formatter for Rust code\.
Even a task that doesn’t*seem*like it, is just a task of automating actions you can otherwise take interactively\. For example, we can directly format a Rust file with just a few keys: first,`%`to select the entire buffer, then`\|`to bring up a prompt for a shell command, typing`rustfmt`and pressing enter\.
This pipes the entire buffer into`rustfmt`and replaces it with the output\. In Kakoune key notation, the action is:`%\|rustfmt<ret\>`\. This would get annoying to do each time, though, so let’s use the`map`command to bind this to the equal key\. We can add it to our`kakrc`, which runs this command on session startup:
```
# bind to the equal key in normal mode,
# across whole session (global scope)
map global normal '=' '%|rustfmt<ret>'
```
So we’ve finished our first “level” of automation, which is binding a sequence of keys \(`%\|rustfmt<ret\>`\) to a single key \(`=`\)\. Think of this binding as a direct translation of keystrokes\. However, this feels like a waste of a key; it won’t be helpful in other filetypes, after all\! Instead, we can*define a custom command*\.
How about we create a command called`rustfmt`which executes this key sequence for us? There’s a difference in how`map`and`define\-command`work\. Where`map`translates a key into a sequence of keystrokes,`define\-command`maps a*command name*to some*Kakscript*\.
Because it expects commands and not keys, this won’t work:
```
define-command rustfmt %|rustfmt<ret>
```
```
Error: parse error: 1:26: unterminated string '%|...|'
```
Instead, we need to run these keystrokes from a command context\. The`execute\-keys`command, which we learned about earlier, is perfect for the job\.
```
execute-keys -draft '%|rustfmt<ret>'
```
The`\-draft`switch runs it in a “disposable context”, meaning our current selection state will be restored, and undo history won’t get clobbered\. There’s no need to use`\-save\-regs`because the sequence isn’t doing any yanking\. Nice\! Let’s put this command inside the body of`rustfmt`:
```
define-command rustfmt %{
execute-keys -draft '%|rustfmt<ret>'
}
```
---
OK, so we’ve got a custom command, and we can use it interactively with`:rustfmt<ret\>`\. We could also bind it to the same key as before, if we want:
```
map global normal '=' ':rustfmt<ret>'
```
That’s nice, but this isn’t really auto\-formatting, is it? Can we get this to happen automatically for Rust code? Yes, with the`hook`command\! This command lets us register*other*commands that will be evaluated when a certain hook triggers\. Available hooks and their parameters are documented in`:doc hooks`\.
In our case, we can use the`BufWritePre`hook\. This example triggers right before buffers whose filename ends with`\.rs`are written to the disk; when there’s a match, the`rustfmt`command is executed\.
```
hook global BufWritePre .*\.rs rustfmt
```
Hopefully this gave you an idea of how Kakoune’s hook & macro system can be used to automate behavior or implement certain functionality through some pretty simple components\!
## [shell expansions](https://ficd.sh/blog/kakoune-is-a-text-editor/#shell-expansions)
There’s one more piece to the Kakoune puzzle: shell expansions\. They allow us to spawn subshells that control Kakoune over standard output\. In other words, we can write shell scripts that “expand” within Kakscript\.`%sh\{\.\.\.\}`in Kakoune is analogous to`"$\(\.\.\.\)"`in shell\.
For example, the following two blocks are functionally equivalent; it’s just that one of them spawns a subshell to arrive at the same result:
```
evaluate-commands %sh{
printf 'echo "foobar!"\n'
}
```
Kakscript itself is very minimal and barely provides any programming capabilities \(there isn’t even an`if/else`\!\), but the available commands are capable enough when control flow and logic are handled by the shell, especially since Kakoune’s state can be read from using`$kak\_`prefixed environment variables\.
For example, here’s a small plugin that provides a command called`dyn\-theme`, which can dynamically set a color scheme based on the time of day\. Users can also set the`dyn\_theme\_enabled`and`dyn\_theme\_default`options to control its behavior\.
```
# whether theme should be dynamic
declare-option bool dyn_theme_enabled true
# default to use when dynamic is disabled
declare-option str dyn_theme_default "ashen"
define-command dyn-theme %{
colorscheme %sh{
if [ "$kak_opt_dyn_theme_enabled" = true ]; then
hour="$(date +%H")
# if before 6pm, use light theme
if [ "$hour" -lt 18 ]; then
echo "ashen-light"
# otherwise, use dark theme
else
echo "ashen"
fi
else
echo "$kak_opt_dyn_theme_default"
fi
}
}
# run it once automatically on startup
hook global KakBegin .* dyn-theme
```
If it’s currently 20:00, then the body of`dyn\-theme`expands to this:
Setting the options before calling the command results in a different expansion:
```
set-option global dyn_theme_enabled false
set-option global dyn_theme_default gruvbox-dark
# body expands to 'colorscheme gruvbox-dark'
dyn-theme
```
Actually, there’s no requirement for the core logic to be written in shell\. A “shell script” can be as simple as calling*another*program, so really, plugins can be written in any language\. Although POSIX sh is most common because it’s simple and portable,[Rust](https://github.com/kakoune-lsp/kakoune-lsp),[Python](https://git.jdugan6240.dev/jdugan6240/dippin-dotfiles/src/commit/69355d72dc4bf50b0702cebf39768c687d5db68d/.config/kak/utils/indent/indent.py),[C](https://github.com/eraserhd/kak-ansi)and[Perl](https://github.com/occivink/kakoune-sort-selections)are some other popular choices for Kakoune plugins\.
Kakoune plugins are nothing more than configuration & commands that you share with others\. As a consequence, you end up learning how to write plugins simply by customizing your own configuration\. You’ll define lots of custom commands, use the hook system, and automate common actions with custom keybindings\. These are all the same skills needed to write plugins\.
Personally, I’ve published over a dozen individual Kakoune plugins, one of which has even been[merged into Kakoune itself](https://github.com/mawww/kakoune/blob/master/rc/windowing/niri.kak)\. It’s also quite common for plugin authors to “publish” plugins simply as part of their public dotfiles\. I do this myself for plugins that don’t really warrant their own repository\.
Overall, the topic of shell expansions & plugin development is an entirely different can of worms\. I haven’t even touched on scopes, highlighters, and FIFOs\. Delving further into it is out of scope for this article\. My aim here is to share how this extension model works, and why it’s a good choice for Kakoune\.
## [conclusion](https://ficd.sh/blog/kakoune-is-a-text-editor/#conclusion)
Thank you for reading all the way until the end\. Becoming a Kakoune “power user” is a challenging but incredibly rewarding path\. I hope I was able to make it seem a bit more achievable\. Writing this took considerable time and effort, and it’s by no means exhaustive — there’s still much left to discuss\. You can expect more Kakoune content in future posts\.
### [acknowledgments](https://ficd.sh/blog/kakoune-is-a-text-editor/#acknowledgments)
I’m grateful to the Kakoune community for their support and advice\. Thanks in particular to[Screwtape](https://zork.net/~st/jottings/),[possumvibes](https://possumvibes.com/),[raiguard](https://raiguard.me/),[jdugan6240](https://jdugan6240.dev/)and[axlefublr](https://axlefublr.github.io/)for contributing their time & expertise to review my work\.
### [further reading](https://ficd.sh/blog/kakoune-is-a-text-editor/#further-reading)
- [Why Kakoune \- The quest for a better code editor](https://kakoune.org/why-kakoune/why-kakoune.html)
- [The Vim\-Inspired Editor with a Linguistic Twist](https://cosine.blue/2019-09-06-kakoune.html)
- [Kakoune, a Punk Rock Text Editor](https://zork.net/~st/jottings/kakoune-a-punk-rock-text-editor.html)
- [Intro to Kakoune highlighters](https://zork.net/~st/jottings/Intro_to_Kakoune_highlighters.html)
- [Intro to Kakoune completions](https://zork.net/~st/jottings/Intro_to_Kakoune_completions.html)
- [Understanding Kakoune’s Command Language](https://gist.github.com/lobre/4838c6859ff7d89e43447f07432cba7d)
- [The Kakoune Philosophy](https://strongly-typed-thoughts.net/blog/kakoune-philosophy)
### [automatically generating demo videos](https://ficd.sh/blog/kakoune-is-a-text-editor/#automatically-generating-demo-videos)
All demo videos were generated automatically using[VHS](https://github.com/charmbracelet/vhs)and a shell script\. It’ll get its own blog post eventually; for now, you can see an example below\.
Click to readFirst, I created a file`demo1/in`, to which I wrote the input\.
```
The quick brown fox jumped over the lazy dog.
```
Then, I created`demo1/tape`, which tells VHS what keys to press once the input buffer is open\. In this case, the instructions are very straightforward\.
```
Sleep 500ms
Type@250ms "wwwwwwwwww"
Sleep 1s
```
I complete the process by running`kak\-vhs ex15`, which creates a file`ex15\.webp`\. The script handles starting Kakoune with the correct configuration, opening the input file, executing the tape, and cleaning up after itself\.`kak\-vhs`is available[here](https://codeberg.org/ficd/kak-vhs)\.