2014-01-02 20:33:46 +01:00
|
|
|
Edition auto insertion in Kakoune
|
|
|
|
=================================
|
|
|
|
|
2020-05-28 18:37:26 +02:00
|
|
|
It is a quite common feature for a code editor to help the programmer
|
|
|
|
by automatically inserting some text in certain contexts. This document
|
2014-01-02 20:33:46 +01:00
|
|
|
goal is to explain how this is done in Kakoune.
|
|
|
|
|
2020-05-28 18:37:26 +02:00
|
|
|
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
|
2014-01-02 20:33:46 +01:00
|
|
|
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
|
|
|
|
----------------------------------------------------------------
|
|
|
|
|
2020-05-28 18:37:26 +02:00
|
|
|
Note that if nothing gets selected on phase *2.*, an error will be raised.
|
2014-01-02 20:33:46 +01:00
|
|
|
|
|
|
|
We want to do that each time the user jumps a line, just after the new line
|
|
|
|
is inserted. So the hook would be:
|
|
|
|
|
2015-02-03 14:56:55 +01:00
|
|
|
--------------------------------------------------------
|
|
|
|
: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)
|
2014-01-02 20:33:46 +01:00
|
|
|
|
|
|
|
That works, however if the phase *2.* raises an error, the +:exec+ will stop
|
2017-04-21 12:32:47 +02:00
|
|
|
and the user will get its selections on the previous line. The solution
|
2014-01-02 20:33:46 +01:00
|
|
|
is to use a *draft* context, instead of the one the user is interacting with.
|
|
|
|
|
2015-02-03 14:56:55 +01:00
|
|
|
---------------------------------------------------------------
|
|
|
|
:hook InsertChar \n %{ exec -draft k<a-x> s^\h+<ret>y j<a-h>P }
|
|
|
|
---------------------------------------------------------------
|
2014-01-02 20:33:46 +01:00
|
|
|
|
|
|
|
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
|
|
|
|
-------------------------------------------------------------------------------
|
|
|
|
|
2020-05-28 18:37:26 +02:00
|
|
|
Note that if no previous line ends with a +{+ or +(+, the +<a-k>+ command will
|
2014-01-02 20:33:46 +01:00
|
|
|
raise an error, and stop the execution. This is what we want: it is similar to
|
2016-04-08 18:00:24 +02:00
|
|
|
what would happen if we would continue with no selections; the following
|
2014-01-02 20:33:46 +01:00
|
|
|
commands would have no effects.
|
|
|
|
|
2016-04-08 18:00:24 +02:00
|
|
|
However, the error would end up being caught by the hook execution code, and
|
2020-05-28 18:37:26 +02:00
|
|
|
it will write information about it in the debug buffer, which we do not want,
|
2014-01-02 20:33:46 +01:00
|
|
|
as this is actually expected. In order to prevent that, the exec should be
|
|
|
|
wrapped in a try command. So we would have:
|
|
|
|
|
2015-02-03 14:56:55 +01:00
|
|
|
-------------------------------------------------------------------------------
|
|
|
|
:hook InsertChar \n %[ try %[ exec -draft k<a-x> <a-k>[{(]\h*$<ret> j<a-gt> ] ]
|
|
|
|
-------------------------------------------------------------------------------
|
2014-01-02 20:33:46 +01:00
|
|
|
|