kakoune/doc/autoedit.asciidoc
2020-05-28 18:37:26 +02:00

88 lines
3.8 KiB
Plaintext

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> ] ]
-------------------------------------------------------------------------------