Skip to content

Latest commit

 

History

History
87 lines (63 loc) · 3.78 KB

autoedit.asciidoc

File metadata and controls

87 lines (63 loc) · 3.78 KB

Edition auto insertion in Kakoune

It is a quite common feature for a code editor to help the programmer by automatically inserting some text in certain contexts. This document goal is to explain how this is done in Kakoune.

There is no special support in Kakoune for this task, hooks are expected to be used in order to manage that, and the normal Kakoune editing command are expected to be expressive enough so that relatively complex indentation can be written concisely.

The main hook is InsertChar, which gets called immediately after a character has been inserted in insertion mode due to the user pressing the corresponding key.

Previous line indentation

Let’s see a simple indent hook: preserving the previous line indentation.

Here is the Kakoune normal mode key list in order to do that:

k<a-x>      # 1. go to previous line and select it
s^\h+<ret>y # 2. select the leading spaces and copy them
j<a-h>P     # 3. go back to next line start and paste the spaces

Note that if nothing gets selected on phase 2., an error will be raised.

We want to do that each time the user jumps a line, just after the new line is inserted. So the hook would be:

:hook InsertChar \n %{ exec k<a-x> s^\h+<ret>y j<a-h>P }

(exec concatenates the keys for all argument, so the spaces will be ignored, allowing for clearer separation. either use <space> or quote the argument to use a space key)

That works, however if the phase 2. raises an error, the :exec will stop and the user will get its selections on the previous line. The solution is to use a draft context, instead of the one the user is interacting with.

:hook InsertChar \n %{ exec -draft k<a-x> s^\h+<ret>y j<a-h>P }

That way, exec is executed in a copy of the user’s context, which means it manipulates a copy of the user’s selections.

Increasing indentation

A little bit more complicated is to increase indentation whenever we insert a new line after a { or a (.

The complexity arises from the presence of a condition. We want to increase the indentation only if the previous line ends with { or (.

Fortunately, Kakoune provides us with a command for that: the <a-k> command, which keeps selections where a certain regex can be found.

Here is how we can do that:

k<a-x>             # 1. select the previous line
<a-k>[{(]\h*$<ret> # 2. keep selections that end with { or ( followed by blanks
j<a-gt>            # 3. go back to next line and indent it even if it is empty

Note that if no previous line ends with a { or (, the <a-k> command will raise an error, and stop the execution. This is what we want: it is similar to what would happen if we would continue with no selections; the following commands would have no effects.

However, the error would end up being caught by the hook execution code, and it will write information about it in the debug buffer, which we do not want, as this is actually expected. In order to prevent that, the exec should be wrapped in a try command. So we would have:

:hook InsertChar \n %[ try %[ exec -draft k<a-x> <a-k>[{(]\h*$<ret> j<a-gt> ] ]