892 lines
32 KiB
Markdown
892 lines
32 KiB
Markdown
> **⚠️️ this guide is written as of Kakoune v2022.10.31, future versions may not be compatible with parts of this guide anymore ⚠️**
|
||
|
||
|
||
When I first started seriously learning to program, I used a mixture of text-editors and IDE's and really whatever I could get my hands on. I didn't quite know what I was doing.
|
||
|
||
## A rough timeline of me first using text editors
|
||
|
||
- I used [Atom](https://atom.io) *(rest in peace, you were loved by some)*.
|
||
- I saw someone using [Sublime Text](https://www.sublimetext.com/) and thought it looked very pretty.
|
||
- Sublime costs money. Never-mind I'm broke.
|
||
- What's this, [Brackets](https://brackets.io/) is *gorgeous* (this is something I maintain to this day. Brackets is the most beautiful text editor but no one knows it).
|
||
- Oh, Brackets is unmaintained and doesn't work with new frameworks very well :\[ `EDIT: It is now maintained again, go check it out`
|
||
- Maybe I want to be an iOS developer? omg it takes seven hours to install [Xcode](https://developer.apple.com/xcode/) (5 of those are just opening the app)
|
||
- Never-mind, [Swift](https://www.swift.org/) isn't fun anymore, and Xcode serves no other purpose to me.
|
||
- Woah, this guy in this one YouTube tutorial is using *the terminal* to edit. How is that even possible?
|
||
- Oh! It must be [Nano](https://www.nano-editor.org/). Team Nano!
|
||
- Wait.. this looks different and there's no syntax highlighting :\[
|
||
- Never-mind, not team Nano anymore.
|
||
- Ohhh it was [Vim](https://www.vim.org/). Let's open it up, can't be too hard to use right?
|
||
- *One vim-quitting-induced OS reinstall later*
|
||
- Ok, let's not do that.
|
||
- What's this hot new thing? [VSCode](https://code.visualstudio.com/)? I've used [Visual Studio](https://visualstudio.microsoft.com/) before, but idk what this is. Let's try it, why not.
|
||
|
||
And there I was, yet another VSCode dev.
|
||
To be clear, there's absolutely nothing wrong with this. The themes are great, the editor runs smoothly (for me), extensions do all the hard work, it's a mostly good experience.
|
||
But something in me yearned for more, I needed something new.
|
||
|
||
## To [Vim](https://www.vim.org/), [Neovim](https://neovim.io), etc.
|
||
|
||
A video by [ThePrimeagen](https://www.youtube.com/@ThePrimeagen) on YouTube was the final catalyst for me, watching him duck and weave through files, never touching the mouse and editing at the speed of thought was inspiring.
|
||
- I set out to learn Vim.
|
||
- I quickly switched to [Neovim](https://neovim.io/), but eventually gave up and returned to VSCode
|
||
I wasn't quite ready for the world of configuration and text file customization. My sudden introduction to it scared me away.
|
||
|
||
Eventually, I stumbled across [Helix](https://helix-editor.com/) configuring Helix is dead-simple. In fact, here's my Helix config right here:
|
||
|
||
```toml
|
||
theme = "everforest_dark"
|
||
|
||
[editor]
|
||
middle-click-paste = false
|
||
line-number = "relative"
|
||
auto-save = true
|
||
auto-format = false
|
||
bufferline = "always"
|
||
color-modes = true
|
||
shell = ["zsh", "-c"]
|
||
|
||
[editor.statusline]
|
||
mode.normal = "NORMAL"
|
||
mode.insert = "INSERT"
|
||
mode.select = "SELECT"
|
||
left = ["mode", "file-name", "version-control"]
|
||
center = ["spinner", "position-percentage", "file-encoding"]
|
||
right = ["diagnostics", "primary-selection-length", "position", "file-type"]
|
||
|
||
[editor.lsp]
|
||
auto-signature-help = false
|
||
display-signature-help-docs = false
|
||
|
||
# Remaps
|
||
[keys.normal]
|
||
A-F = ":fmt"
|
||
esc = ["collapse_selection", "keep_primary_selection", ":w"]
|
||
C-r = [":reload"]
|
||
"{" = "goto_prev_paragraph"
|
||
"}" = "goto_next_paragraph"
|
||
|
||
[keys.normal.space]
|
||
space = "goto_next_buffer"
|
||
m = "goto_previous_buffer"
|
||
q = ":buffer-close"
|
||
|
||
[keys.select]
|
||
"{" = "goto_prev_paragraph"
|
||
"}" = "goto_next_paragraph"
|
||
|
||
[keys.insert]
|
||
A-F = ":fmt"
|
||
esc = ["normal_mode", ":w"]
|
||
```
|
||
> Not very complicated, all things considered
|
||
|
||
I used Helix for a while, I really liked it a lot.
|
||
Eventually, I got good at the keybindings and was a whizz at getting through files just like I had dreamt of.
|
||
But the 'batteries included' nature of Helix eventually got to me. It did nearly everything I needed, but the lack of customization via plugins really killed it for me eventually.
|
||
Not to mention, the beta software state meant that Helix had a lot of little quirks and bugs that sometimes made using it a pain in the ass.
|
||
|
||
## To [Kakoune](https://kakoune.org/)
|
||
|
||
I knew [Kakoune](https://kakoune.org/) was the inspiring editor for Helix, and I really did love the keybindings for Helix, so I decided to give it a try.
|
||
Well, it was damn good!
|
||
Using Kakoune was a much smoother experience, Kakoune was obviously more mature, thought out, and performance-wise I could feel noticeable lag going back to Helix.
|
||
The only problem; configuration.
|
||
Eventually, I figured it out. I used a combination of other people's config files, trial and error, and reading some of the source code for Kakoune, but eventually I understood the configuration layout well enough to write a config file of my own that serves me well.
|
||
|
||
## Small disclaimer
|
||
|
||
This guide is for those who already know keybindings in Kakoune, and want a nice configuration file. I'm not going to be going over actually using the editor in detail.
|
||
|
||
## Writing a nice configuration file
|
||
|
||
Here's what Kakoune looks like by default
|
||
![default kakrc](https://i.imgur.com/DArA8Jy.png)
|
||
|
||
> pretty damn ugly if I do say so myself
|
||
|
||
Here's what my current config looks like
|
||
![default kakrc](https://i.imgur.com/h3wlERq.png)
|
||
|
||
> That's a marked improvement for me at least
|
||
|
||
## Step-by-step
|
||
|
||
### The basic-basics
|
||
|
||
When ran, `kak` will search for the autoload folder(s) and recursively load all `.kak` files in it. The `autoload` dir is usually `~/.config/kak/autoload/`. Then, `kak` will search for a `kakrc` file in your configuration folder (usually `~/.config/kak/kakrc`), and load it up.
|
||
|
||
Let's set that up
|
||
|
||
```bash
|
||
mkdir -p ~/.config/kak
|
||
kak ~/.config/kak/kakrc
|
||
```
|
||
|
||
> yes, we're using Kakoune to edit it's own config
|
||
|
||
### Tips
|
||
|
||
Kakoune has a lot of detailed documentation, it's just not very easy to read.
|
||
The `:doc` command gives instant access to every article, it's just not super easy to find what you're for. All the actual docs files can be found on GitHub [here](https://github.com/mawww/kakoune/tree/master/doc)
|
||
|
||
### Color scheme
|
||
|
||
Obviously, the most important thing about a text-editor is it's themes. Let's get something nice going for Kakoune.
|
||
|
||
In Kakoune, the `colorscheme` command set's the terminal. You can type `:colorscheme ` and `<tab>` around to find something you like.
|
||
|
||
`kakrc`
|
||
|
||
```vim
|
||
colorscheme gruvbox-dark
|
||
```
|
||
|
||
> that should make things nicer
|
||
|
||
You can reload your `kakrc` by running `:source kakrc`. When that doesn't work, just `:wq` and open it right back up, no biggie.
|
||
*How's the new color-scheme look?*
|
||
|
||
**Let's take a quick detour to talk about scopes**
|
||
|
||
### Scopes
|
||
|
||
> `global/`
|
||
|
||
First, `:doc scopes`
|
||
|
||
According to the docs, there's three options for scopes.
|
||
`global`, `buffer`, and `window`
|
||
|
||
##### Global
|
||
|
||
The `global` scope refers to every linked instance of `kak` currently running (you can spawn new 'linked' instances of Kakoune with the `:new` command). Changes you make to the `global` scope will be available everywhere. If you edit your `kakrc`, changes will only be available in new session from then on.
|
||
|
||
##### Buffer
|
||
|
||
A buffer is in most cases, just the raw file that is opened. Kakoune has a neat feature called `:new` that I won't get into, but it allows multiple instances of the same file to be edited at the same time which is wicked cool.
|
||
Objects in the `buffer` scope will affect every instance of that file open in `kak`
|
||
|
||
##### Window
|
||
|
||
The `window` scope is the logical subset of the `buffer` scope. Where the `window` scope affects all instances of `kak` with that buffer open, `window` refers to *this* instance of *this* buffer open.
|
||
|
||
Make sure you understand this to the best of your abilities, `scopes` are *very* handy in Kakoune
|
||
|
||
### Line numbers
|
||
|
||
Something very useful in any sort of text editor is line numbers, fortunately Kakoune offers line numbers as a builtin feature.
|
||
|
||
Kakoune offers most visual customization through the `add-highlighter`command, the docs are at `:doc highlighters`.
|
||
|
||
#### Syntax
|
||
|
||
`add-highlighter [-override] <path>/<name> <type> <parameters> ...`
|
||
|
||
In Kakoune, you can think of highlighters as literal unique objects in the editor, each highlighter is a unique instance with it's own unique scope.
|
||
|
||
Here's how to add line numbers to Kakoune
|
||
|
||
|
||
```vim
|
||
add-highlighter global/ number-lines
|
||
```
|
||
|
||
Let's go over that word-by-word
|
||
|
||
- `add-highlighter` - the root command to add 'highlighters' to the editor
|
||
- `global/` - the scope of this command
|
||
- `number-lines` - the builtin highlighter to apply to the Kakoune look
|
||
|
||
But wait, did you notice that `global` has a trailing `/`?
|
||
That's actually another very neat feature of Kakoune.
|
||
|
||
In `kak` each `highlighter` is it's own unique object with it's own ID. This means that the alternate command `remove-highlighter` exists, you'll see how useful this can be later in this article.
|
||
How to use `remove-highlighter` is an exercise left to the reader for now (`:doc` is your friend).
|
||
|
||
#### Great, but what about `/`?
|
||
|
||
In Kakoune, you can set the name of a `highlighter` , or just let `kak` pick one for you automagically.
|
||
Setting a custom name in Kakoune is what the `/` is for. For example, here's the equivalent command but with a custom name:
|
||
|
||
```vim
|
||
add-highlighter global/number-lines-highlighter number-lines
|
||
```
|
||
|
||
In this case, our highlighter will be named `number-lines-highlighter` and that allows us to refer to it in the future.
|
||
Unless you know you'll need to refer to a `highlighter`, I recommend letting Kakoune pick names for you since it will eliminate the risk of accidental name collision.
|
||
|
||
The trailing `/` is how you tell Kakoune to pick a name for you.
|
||
|
||
#### Getting gnarly
|
||
|
||
In Kakoune, some `highlighters` have optional arguments that can be passed to them.
|
||
The `:docs` will always explain this.
|
||
Here's the options for `number-lines`:
|
||
```text
|
||
-relative
|
||
show line numbers relative to the main cursor line
|
||
|
||
-hlcursor
|
||
highlight the cursor line with a separate face
|
||
|
||
-separator <separator text>
|
||
specify a string to separate the line numbers column from the rest of the buffer (default is '|')
|
||
|
||
-cursor-separator <separator text>
|
||
identical to -separator but applies only to the line of the cursor (default is the same value passed to -separator)
|
||
|
||
-min-digits <num>
|
||
always reserve room for at least num digits, so text doesn’t jump around as lines are added or removed (default is 2)
|
||
```
|
||
|
||
Let's apply some of those;
|
||
|
||
```vim
|
||
add-highlighter global/ number-lines -hlcursor -relative -separator " " -cursor-separator " |"
|
||
```
|
||
|
||
Try adding each of those flags one at a time to see what happens. After that you can customize it to your liking.
|
||
|
||
#### Going deeper
|
||
|
||
To read a much more extensive and informative article on `highlighters`, see [here](https://zork.net/~st/jottings/Intro_to_Kakoune_highlighters.html)
|
||
|
||
### Matching braces
|
||
|
||
`kak` has another useful feature and that's to highlight matching brackets, braces, parentheses, quotes, etc.
|
||
|
||
The command is
|
||
|
||
```vim
|
||
add-highlighter global/ show-matching
|
||
```
|
||
|
||
Here's a before-and-after to illustrate what that does:
|
||
|
||
**Before**
|
||
|
||
![show-matching-before](https://i.imgur.com/oZotdaR.png)
|
||
|
||
**After**
|
||
|
||
![show-matching-before](https://i.imgur.com/5A6A4XY.png)
|
||
|
||
Notice how the other bracket was highlighted blue in the second photo.
|
||
This feature can be super useful in large codebases, or situations where there's nested blocks in your code.
|
||
|
||
### Pit Stop
|
||
|
||
Ok, here's our `kakrc` so far
|
||
|
||
```vim
|
||
# custom theme
|
||
colorscheme gruvbox-dark
|
||
|
||
## highlighting
|
||
# display line numbers
|
||
add-highlighter global/ number-lines -hlcursor -relative -separator " " -cursor-separator " |"
|
||
# show matching symbols
|
||
add-highlighter global/ show-matching
|
||
```
|
||
|
||
> pretty simple so far
|
||
|
||
### Set-option
|
||
|
||
`:doc options`
|
||
|
||
#### Syntax
|
||
|
||
`set-option [-add|-remove] <scope> <name> <values>...`
|
||
|
||
#### Tab-width
|
||
|
||
Most settings in `kak` can be accessed though the `set-options` command.
|
||
For example, I like my tabs to be 2 spaces wide, so I'm going to add that to my config like this:
|
||
|
||
```vim
|
||
#command #scope #name #value
|
||
set-option global tabstop 2
|
||
set-option global indentwidth 2
|
||
```
|
||
|
||
> Options don't get names in `kak`, that's why there's no `/` after the `global`scope.
|
||
|
||
#### Scroll-off
|
||
|
||
In Kakoune, you can specify a margin around the cursor. This is useful because it lets you see the text around a cursor even when editing text at the edges of the window.
|
||
|
||
```vim
|
||
# always keep eight lines and three columns displayed around the cursor
|
||
set-option global scrolloff 8,3
|
||
```
|
||
|
||
### Keybindings
|
||
|
||
`:doc mapping`
|
||
|
||
The `map` command is really quite simple. You tell it `key a`, and `keys b` and then whenever you type `key a`, Kakoune will just pretend you typed `keys b` instead. A bit like an alias.
|
||
|
||
#### Syntax
|
||
|
||
`map [switches] <scope> <mode> <key> <keys>`
|
||
|
||
Everything here should be straightforwards except possibly `<mode>`. I'm not going to get into `modes` here, since those are something you should already understand if you know `vim/kak` keybindings.
|
||
|
||
Here are the modes defined in `:doc mapping`
|
||
|
||
```text
|
||
insert
|
||
insert mode
|
||
|
||
normal
|
||
normal mode
|
||
|
||
prompt
|
||
prompts, such as when entering a command through :, or a regex through /
|
||
|
||
menu
|
||
mode entered when a menu is displayed with the 'menu' command
|
||
|
||
user
|
||
mode entered when the user prefix is hit (default: '<space>')
|
||
|
||
goto
|
||
mode entered when the goto key is hit (default: 'g')
|
||
|
||
view
|
||
mode entered when the view key is hit (default: 'v')
|
||
|
||
object
|
||
mode entered when an object selection is triggered (e.g. '<a-i>')
|
||
```
|
||
|
||
#### `normal` mode maps
|
||
|
||
##### `qwe`
|
||
|
||
Normally, to navigate word-by-word you'd use the `w`, `b`, and `e` keys to move around. However, I find it more convenient to remap the `b` to `q`. That way the keys are `qwe` and are next to each other on my keyboard.
|
||
Here's how to do that
|
||
|
||
```vim
|
||
# remap b to q
|
||
map global normal q b
|
||
# variations of b
|
||
map global normal Q B
|
||
map global normal <a-q> <a-b>
|
||
map global normal <a-Q> <a-B>
|
||
```
|
||
|
||
Kakoune doesn't have a `select` mode like Vim or Helix, so we only need to map from `normal` mode.
|
||
|
||
##### Clear selection on`<esc>`
|
||
|
||
In `kak`, pressing `<esc>` doesn't clear any highlighted text or collapse cursors which doesn't feel intuitive to me. Let's fix that;
|
||
|
||
```vim
|
||
# unselect on <esc>
|
||
map global normal <esc> ";,"
|
||
```
|
||
|
||
`;` un-highlights text, and `,` gets rid of multiple cursors.
|
||
|
||
##### Auto-comment lines
|
||
|
||
I like to map `<c-v>` (control+v) to the `:comment-line` command in Kakoune. This lets me toggle lines really quickly when debugging or refactoring code.
|
||
|
||
```vim
|
||
# comment lines
|
||
map global normal <c-v> ":comment-line<ret>"
|
||
```
|
||
|
||
> `<ret>` tells Kakoune to execute the commadn
|
||
|
||
Normally, I'd map `<c-c>` to this, but in Kakoune certain key-mappings don't work because of compatibility features (i think), and control+c is one of them. More info [here](https://github.com/mawww/kakoune/issues/797#issuecomment-649494417).
|
||
|
||
#### `user` mode maps
|
||
|
||
`user` mode is really neat, it allows you to setup a little menu of commands that you access by typing `<space>` and then the mapping.
|
||
|
||
##### Buffer control
|
||
|
||
Some utilities for navigating buffers
|
||
|
||
```vim
|
||
map -docstring "close current buffer" global user b ": db<ret>"
|
||
map -docstring "goto previous buffer" global user n ": bp<ret>"
|
||
map -docstring "goto next buffer" global user m ": bn<ret>"
|
||
```
|
||
|
||
> `-docstring` is just the help-text shown for the mapping in the menu
|
||
|
||
Now, by typing `<space>m`, `<space>n`, and `<space>b` I can go one buffer forwards, back, and close the current buffer respectively.
|
||
|
||
The more astute among you may have noticed that the commands in that mapping have a space separating the `:` colon and the actual command. In older versions Kakoune we did this when we didn't want the command saved in the history (access the history by typing `:` and pressing the up/down arrows). Current and future versions of Kakoune do this automatically, so we don't need to worry about the `<space>`.
|
||
|
||
##### Some more misc. mappings
|
||
|
||
```vim
|
||
# fancy insert newline
|
||
map -docstring "insert newline above" global user [ "O<esc>j"
|
||
map -docstring "insert newline below" global user ] "o<esc>k"
|
||
|
||
# spellcheck (requires aspell)
|
||
map -docstring "check document for spelling" global user w ": spell<ret>"
|
||
map -docstring "clear document spelling" global user q ": spell-clear<ret>"
|
||
```
|
||
|
||
##### And one more
|
||
|
||
```vim
|
||
# copy to system pboard [MAC ONLY]
|
||
map -docstring "copy to system pboard" global user y "<a-|> pbcopy<ret>"
|
||
```
|
||
- `<a-|>` - the *pipe-to* command
|
||
- `pbcopy` - a shell tool available on macs to manipulate the clipboard
|
||
|
||
#### Insert mode autosave
|
||
|
||
I like it when text-editors autosave. Neovim has this awesome autosave plugin that prints a little log message each time it saves and I want to implement something similar to that as a `map`.
|
||
|
||
First, the most basic
|
||
|
||
```vim
|
||
map -docstring "save current buffer" global user s ": w<ret>"
|
||
```
|
||
|
||
But there's no log :(
|
||
Also, later we're going to make this something that happens automatically when the user presses `<esc>` in `insert` mode.
|
||
|
||
So let's take a really quick detour to the `define-command` command, essentially functions in `kak`.
|
||
|
||
### Custom commands
|
||
|
||
`:doc commands declaring-new-commands`
|
||
|
||
```text
|
||
New commands can be defined using the define-command command:
|
||
|
||
define-command [<switches>] <command_name> <commands>
|
||
commands is a string containing the commands to execute, and switches can be any combination of the following parameters:
|
||
|
||
-params <num>
|
||
the command accepts a num parameter, which can be either a number, or of the form <min>..<max>, with both <min> and <max> omittable
|
||
|
||
-override
|
||
allow the new command to replace an existing one with the same name
|
||
|
||
-hidden
|
||
do not show the command in command name completions
|
||
|
||
-docstring
|
||
define the documentation string for the command
|
||
|
||
-menu
|
||
-file-completion
|
||
-client-completion
|
||
-buffer-completion
|
||
-command-completion
|
||
-shell-completion
|
||
-shell-script-completion
|
||
-shell-script-candidates
|
||
old-style command completion specification, function as-if the switch and its eventual parameter was passed to the complete-command command (See Configuring command completion)
|
||
|
||
The use of those switches is discouraged in favor of the complete-command command.
|
||
|
||
Using shell expansion allows defining complex commands or accessing Kakoune's state:
|
||
|
||
# create a directory for current buffer if it does not exist
|
||
define-command mkdir %{ nop %sh{ mkdir -p $(dirname $kak_buffile) } }
|
||
```
|
||
|
||
Overall, it's a lot like `map`. Define a command name, and then some other commands that will be ran.
|
||
|
||
#### Save-buffer
|
||
|
||
Here's my `save-buffer` command:
|
||
|
||
```vim
|
||
define-command save-buffer -docstring "save current buffer and show info" %{
|
||
write
|
||
info "file saved at %sh{date}"
|
||
}
|
||
```
|
||
|
||
- `write` - save the current buffer (the same thing as `:w`)
|
||
- `info - `info` logs a little snipped to the user, try `:info "hello, world!"` to see for yourself.
|
||
- `'file saved at %sh{date}'` - `kak` will first expand `%sh{date}` into the output of the `date` shell command, and then interpolate that with `file saved at ` before passing it to the `info` command.
|
||
|
||
The reason we don't need the `:` in the `%{}` block is that Kakoune treats the commands there as just that - commands.
|
||
The `map` command simulates those actual keypresses, so we need to tell the editor to go to `prompt` mode.
|
||
|
||
#### A more complicated example
|
||
|
||
```vim
|
||
# open tutor (needs curl)
|
||
define-command trampoline -docstring "open a tutorial" %{
|
||
evaluate-commands %sh{
|
||
tramp_file=$(mktemp -t "kakoune-trampoline.XXXXXXXX")
|
||
echo "edit -fifo $tramp_file *TRAMPOLINE*"
|
||
curl -s https://raw.githubusercontent.com/mawww/kakoune/master/contrib/TRAMPOLINE -o "$tramp_file"
|
||
}
|
||
}
|
||
```
|
||
|
||
> found on the [Kakoune forums](https://discuss.kakoune.com/)
|
||
|
||
Figuring out how this works is an exercise left to the reader.
|
||
|
||
### Plugins
|
||
|
||
The main reason I switched from Helix to Kakoune was plugins. Helix does not yet have support for plugins, where Kakoune has an incredible ecosystem. Albeit a much smaller one than Vim/Neovim, but personally, I think `kak` extensions are much easier to write,
|
||
|
||
In Kakoune, any `.kak` files in the `~/.config/kak/autoload` directory will be loaded, so one way to install extensions is to just clone git repos there.
|
||
|
||
**However**
|
||
|
||
Kakoune has an extremely well made package manager that I highly recommend.
|
||
It's called [plug.kak](https://github.com/andreyorst/plug.kak).
|
||
|
||
According to the site there's a few ways to install it, but here's how I like to do it:
|
||
|
||
```bash
|
||
mkdir -p $HOME/.config/kak/plugins
|
||
git clone https://github.com/andreyorst/plug.kak.git $HOME/.config/kak/plugins/plug.kak
|
||
```
|
||
|
||
Before we start using it, you should go read the `README` on the tool's [GitHub](https://github.com/andreyorst/plug.kak).
|
||
|
||
#### Initializing `plug.kak`
|
||
|
||
`plug.kak` has to be loaded by `plug.kak`! Kinda trippy I know.
|
||
Here's the line to do that:
|
||
|
||
```vim
|
||
source "%val{config}/plugins/plug.kak/rc/plug.kak"
|
||
plug "andreyorst/plug.kak" noload
|
||
```
|
||
|
||
This should go before your other plugins in your `kakrc`.
|
||
- `source` just tells `kak` where to find `plug.kak`
|
||
- `plug` is a special command that `plug.kak` provides that tells it to make that plugin available to Kakoune, among other things.
|
||
|
||
#### Loading plugins
|
||
|
||
Whenever you add a plugin, you need to reload your `kakrc`, then you can run the `:plug-install` command. Read the `plug.kak` [README](https://github.com/andreyorst/plug.kak) for a better explanation of all this.
|
||
|
||
#### Our first plugin - more themes
|
||
|
||
I like Gruvbox, I do, but I don't quite like running it 24/7, the colors hurt my eyes. Luckily, the amazing `anhsirk0` made a huge collection of amazing themes for Kakoune. Here's the repo for that [GitHub](https://github.com/anhsirk0/kakoune-themes).
|
||
Unfortunately, the structure of that repo makes it not work super well with `plug.kak`. Luckily, I made a fork of it that preserves all the themes and makes it work with `plug`. [Link here](https://github.com/secondary-smiles/kakoune-themes).
|
||
|
||
Now, let's get it 'installed'.
|
||
|
||
```vim
|
||
# themes
|
||
plug "secondary-smiles/kakoune-themes" theme config %{
|
||
colorscheme pastel
|
||
}
|
||
```
|
||
> Woah, there's a lot going on there.
|
||
|
||
- `plug "secondary-smiles/kakoune-themes"` - `plug.kak` will automagically search github for a plugin if you just provide a *username/repo* string.
|
||
- `theme` - this tells `plug.kak` that this extension is actually a pack of themes, or just one theme. It will treat the files differently because of that.
|
||
- `config` - this is some `Kakscript` that will be ran only once `plug.kak` has loaded this extension.
|
||
- `%{ colorscheme pastel }` - this will be run once `plug.kak` loads the extension, it works in a pair with the `config` keyword. (blocks in Kakoune are defined with `%[optional directive]{}`).
|
||
|
||
Well, try and reload your config now, see what you think!
|
||
|
||
Oh, we should probably remove that `colorscheme gruvbox-dark` from earlier too, we don't need two themes racing each-other to be dominant in the editor.
|
||
|
||
#### Auto-pairs
|
||
|
||
I might be the weird one out, but I really like auto-pairs when typing. That's where typing a matched character like `(`, `[`, `<`, etc. the editor automatically inserts the opposite character (`)`, `]`, `>`, etc.).
|
||
Luckily, a plugin exists for just that!
|
||
|
||
```vim
|
||
# autopairs
|
||
plug "alexherbo2/auto-pairs.kak" config %{
|
||
enable-auto-pairs
|
||
}
|
||
```
|
||
|
||
`enable-auto-pairs` is a command provided by `auto-pairs.kak`. You can, of course, disable it with `:disable-auto-pairs`.
|
||
|
||
#### Fuzzy-finder
|
||
|
||
Having a builtin file picker is really useful in any editor. [`fzf.kak`](https://github.com/andreyorst/fzf.kak) is a really superb implementation of this with a lot of customization abilities.
|
||
|
||
```vim
|
||
# fzf
|
||
plug "andreyorst/fzf.kak" config %{
|
||
require-module fzf
|
||
require-module fzf-grep
|
||
require-module fzf-file
|
||
} defer fzf %{
|
||
set-option global fzf_highlight_command "lat -r {}"
|
||
} defer fzf-file %{
|
||
set-option global fzf_file_command "fd . --no-ignore-vcs"
|
||
} defer fzf-grep %{
|
||
set-option global fzf_grep_command "fd"
|
||
}
|
||
```
|
||
|
||
If you read the `plug.kak` `README`, you'd already understand this.
|
||
Let's go over it anyways though.
|
||
|
||
`fzf.kak` provides several modules to further customize the plugin.
|
||
|
||
In the first `config` block, we `require` those modules so that they get loaded.
|
||
|
||
Then, we use the `defer <module-name>` block to run more commands only *after* that module is loaded by `plug.kak`. In this case, I'm using [`lat`](https://github.com/secondary-smiles/lat) (*shameless plug*) as my default file viewer, and [`fd`](https://github.com/sharkdp/fd) as my grepper.
|
||
|
||
I also like to set `<space>f` to enter fuzzy-finder mode:
|
||
|
||
```vim
|
||
map -docstring "open fzf" global user f ": fzf-mode<ret>"
|
||
```
|
||
|
||
#### Powerline
|
||
|
||
The default Kakoune status-bar leaves a lot to be desired. This plugin adds a lot more customizability.
|
||
|
||
Read the [README](https://github.com/andreyorst/powerline.kak) for more info on customization
|
||
|
||
```vim
|
||
plug "andreyorst/powerline.kak" defer kakoune-themes %{
|
||
powerline-theme pastel
|
||
} defer powerline %{
|
||
powerline-format global "git lsp bufname filetype mode_info lsp line_column position"
|
||
set-option global powerline_separator_thin ""
|
||
set-option global powerline_separator ""
|
||
} config %{
|
||
powerline-start
|
||
}
|
||
```
|
||
|
||
#### Enhanced selection
|
||
|
||
In Helix, pressing `x` will select the entire line. Subsequent `x`'s will keep expanding the selection line-by-line. In Kakoune, Subsequent `x`'s do nothing.
|
||
|
||
[byline.kak](https://github.com/evanrelf/byline.kak) does exactly that.
|
||
|
||
In fact, pressing `<shift>x` will shrink the selection by a line! Very useful.
|
||
|
||
```vim
|
||
plug "evanrelf/byline.kak" config %{
|
||
require-module "byline"
|
||
}
|
||
```
|
||
|
||
#### Luar
|
||
|
||
Some Kakoune plugins are written in Lua, this plugin will allow those ones to run. Adding this plugin is a nice future-proof against plugins randomly break because you forgot this one.
|
||
|
||
```vim
|
||
plug "gustavo-hms/luar" %{
|
||
require-module luar
|
||
}
|
||
```
|
||
|
||
#### LSP I
|
||
|
||
Kakoune has autocomplete out-of-the-box, but now that LSP's are standard, it makes a lot of sense to use them.
|
||
|
||
There's an extension for that!
|
||
|
||
```vim
|
||
plug "kak-lsp/kak-lsp" do %{
|
||
cargo install --locked --force --path .
|
||
# optional: if you want to use specific language servers
|
||
# mkdir -p ~/.config/kak-lsp
|
||
# cp -n kak-lsp.toml ~/.config/kak-lsp/
|
||
}
|
||
```
|
||
|
||
- The `do` directive tells `plug.kak` to run those shell commands only when first installing the plugin.
|
||
|
||
However, `kak-lsp` requires a bit more configuration to work properly.
|
||
|
||
First, read the `kak-lsp` [README](https://github.com/kak-lsp/kak-lsp) (always read the README for everything).
|
||
|
||
Before finishing `lsp`, let's learn about `hooks`;
|
||
|
||
### Hooks
|
||
|
||
`:doc hooks`
|
||
|
||
Hooks in `kak` are like Events in Javascript, or `autocmd` in Vim/Neovim.
|
||
Basically, you give Kakoune some commands to run, and a trigger. When `kak` detects that trigger happening, it'll run your commands.
|
||
|
||
#### Autosave
|
||
|
||
Let's finally finish that autosave feature we were working on.
|
||
|
||
Here's a simple hook to do that:
|
||
|
||
```vim
|
||
hook global ModeChange pop:insert:.* %{
|
||
save-buffer
|
||
}
|
||
```
|
||
|
||
- `ModeChange` - the hook for whenever the user goes from `user` to `insert` or any combination of other modes
|
||
- `ModeChange` accepts a string formatted as `[push|pop]:<old mode>:<new mode>`
|
||
- `pop:insert:.*` - this is the filter for the `ModeChange` hook, let's go over that
|
||
- `pop` - this is the *kind* of mode-change. The options here are `pop`, `push`, and `.*`.
|
||
- `pop` - refers to moving out of a mode and into the next one.
|
||
- `push` - *push*ing a command into a mode, for example, pressing `<alt>;` escapes `normal` mode for a single command.
|
||
- `.*` - wildcard for all
|
||
- `insert` - the **from** mode, or the mode that we're leaving.
|
||
- `.*` - the **to** mode, or the mode that we're going to. This is set to *any*, as we want to save anytime we exit `insert` mode
|
||
- `save-buffer` - our custom command to save the buffer and log the time.
|
||
|
||
#### Soft-wrap in markdown files
|
||
|
||
Another hook I have enabled is soft-wrapping text in `.md` files. I find that it makes it a lot easier to edit text (not code) when I can see everything at once and don't have to horizontally-scroll.
|
||
|
||
```vim
|
||
hook global WinSetOption filetype=markdown %{
|
||
add-highlighter -override global/markdown-wrap wrap -word
|
||
|
||
hook -once -always window WinSetOption filetype=.* %{
|
||
remove-highlighter global/markdown-wrap
|
||
}
|
||
}
|
||
```
|
||
|
||
> Yeah, you can nest `hooks` 😎
|
||
|
||
Figuring out what the nested `hook` does is an exercise left to the reader.
|
||
|
||
#### Lsp II
|
||
|
||
If you read the `kak-lsp` [README](https://github.com/kak-lsp/kak-lsp), then this part is going to make a lot of sense.
|
||
|
||
While it's possible to just blindly enable `kak-lsp` for everything, I prefer so set hooks for the specific filetypes that I want to be editing.
|
||
|
||
```vim
|
||
hook global WinSetOption filetype=(rust|javascript|typescript|c) %{
|
||
lsp-enable-window
|
||
lsp-inlay-diagnostics-enable global
|
||
}
|
||
|
||
## enable syntax highlighting for each lang
|
||
# c
|
||
hook global WinSetOption filetype=c %{
|
||
hook window -group semantic-tokens BufReload .* lsp-semantic-tokens
|
||
hook window -group semantic-tokens NormalIdle .* lsp-semantic-tokens
|
||
hook window -group semantic-tokens InsertIdle .* lsp-semantic-tokens
|
||
hook -once -always window WinSetOption filetype=.* %{
|
||
remove-hooks window semantic-tokens
|
||
}
|
||
}
|
||
|
||
# rust
|
||
hook global WinSetOption filetype=rust %{
|
||
hook window -group semantic-tokens BufReload .* lsp-semantic-tokens
|
||
hook window -group semantic-tokens NormalIdle .* lsp-semantic-tokens
|
||
hook window -group semantic-tokens InsertIdle .* lsp-semantic-tokens
|
||
hook -once -always window WinSetOption filetype=.* %{
|
||
remove-hooks window semantic-tokens
|
||
}
|
||
}
|
||
# typescript
|
||
hook global WinSetOption filetype=typescript %{
|
||
hook window -group semantic-tokens BufReload .* lsp-semantic-tokens
|
||
hook window -group semantic-tokens NormalIdle .* lsp-semantic-tokens
|
||
hook window -group semantic-tokens InsertIdle .* lsp-semantic-tokens
|
||
hook -once -always window WinSetOption filetype=.* %{
|
||
remove-hooks window semantic-tokens
|
||
}
|
||
}
|
||
|
||
# javascript
|
||
hook global WinSetOption filetype=javascript %{
|
||
hook window -group semantic-tokens BufReload .* lsp-semantic-tokens
|
||
hook window -group semantic-tokens NormalIdle .* lsp-semantic-tokens
|
||
hook window -group semantic-tokens InsertIdle .* lsp-semantic-tokens
|
||
hook -once -always window WinSetOption filetype=.* %{
|
||
remove-hooks window semantic-tokens
|
||
}
|
||
}
|
||
```
|
||
|
||
> If you read the comments, you'll also notice that we enabled better syntax highlighting for each of those filetypes as well.
|
||
|
||
I also like to set a mapping to `user` mode to let me access the `lsp` menu really quickly:
|
||
|
||
```vim
|
||
map -docstring "open lsp" global user l ": enter-user-mode lsp<ret>"
|
||
```
|
||
|
||
- Some extensions create their own special menus like the one that `<space>` creates. We access those with the `:enter-user-mode` command.
|
||
- Now, `<space>lf` will perform lsp-assisted formatting!
|
||
|
||
#### Tab completion
|
||
|
||
I don't like the `<c-n>`, `<c-p>` convention for selecting autocomplete items.
|
||
This is the recommended hook (according to the Kakoune wiki) for enabling `<tab>` and `<shift><tab>` selections.
|
||
|
||
```vim
|
||
# tabs for autocomplete
|
||
hook global InsertCompletionShow .* %{
|
||
try %{
|
||
# this command temporarily removes cursors preceded by whitespace;
|
||
# if there are no cursors left, it raises an error, does not
|
||
# continue to execute the mapping commands, and the error is eaten
|
||
# by the `try` command so no warning appears.
|
||
execute-keys -draft 'h<a-K>\h<ret>'
|
||
map window insert <tab> <c-n>
|
||
map window insert <s-tab> <c-p>
|
||
hook -once -always window InsertCompletionHide .* %{
|
||
unmap window insert <tab> <c-n>
|
||
unmap window insert <s-tab> <c-p>
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### LSP III
|
||
|
||
To learn more about creating custom completion tools in Kakoune see [here](https://zork.net/~st/jottings/Intro_to_Kakoune_completions.html).
|
||
|
||
### Goodbye clippy
|
||
|
||
You probably noticed that clippy appears a lot in Kakoune
|
||
|
||
```text
|
||
╭──╮
|
||
│ │
|
||
@ @ ╭
|
||
││ ││ │
|
||
││ ││ ╯
|
||
│╰─╯│
|
||
╰───╯
|
||
```
|
||
|
||
> this mf
|
||
|
||
Well, a not-so-secret easter egg in Kakoune is that it's possible to change the assistant!
|
||
|
||
Here's how to remove clippy altogether
|
||
|
||
```vim
|
||
set-option global ui_options terminal_assistant=none
|
||
```
|
||
|
||
> Available options are `clippy`, `dilbert`, `cat`, and `none`. Try setting each of those, something interesting might happen ;D
|
||
|
||
## Wrapping up
|
||
|
||
My current, mostly up-to-date `kakrc` can be found on my github [.dots](https://github.com/secondary-smiles/.dots/blob/main/pkg/kakoune/kakrc).
|
||
|
||
Kakoune is an incredible editor, I've really never had this much fun in a text editor, and for me it just feels so good using a [punk-rock editor](https://zork.net/~st/jottings/kakoune-a-punk-rock-text-editor.html).
|
||
|
||
This article isn't an introduction to terminal-editors, but if you're interested in the field, YouTube is a great starting place.
|
||
|
||
Also check out the [Kakoune Forums](https://discuss.kakoune.com/) for infinite `kak` tips and tricks.
|
||
|
||
Thanks for reading!
|