Understanding a hook with exec -draft

Hello, I am new to kakoune – learning little by little, starting with a mininal setup (no symlink to the system-wise scripts, adding scripts only one by one to my personal autoload path) and trying to understand how things work. I am afraid I will pester the list with questions and comments.

For now I have trouble understanding how some hooks work. This hook for converting tabs to spaces:

:hook buffer InsertChar \t %{exec -draft h@ }

works (it is mentioned on the Wiki), but I would like to understand the role of ‘-draft’ here. I am told that -draft works on a “copy” of the buffer, but what is its exact role here?

Related: I would like to know why the following hook, which should be equivalent, does not work:

:hook buffer InsertChar \t %{exec <esc>@a }

The first (leave Insert for Normal mode with <esc>) and third (enter Insert mode after the current selection with a) steps do seem to be executed correcty, but the second step (converting tabs to spaces in the current selection with @) seems to be skipped, which means that the tab is not converted to spaces.

Any help in understanding these isssues would be appreciated.

To reply to my own query about the second hook:

Things get better if I insert h before @, although it is now difficult to exit from the selection and reposition the cursor to the right of it.

I guess my trouble comes from the fact that I don’t understand what happens to the “selection” (cursor) when typing in Insert mode (is the “selection” identical to the “newline” positioned at the end of the line? or is the “selection” nothing at all?) and when moving from Insert to Normal mode with <esc>. When pressing <esc> manually, the “selection” moves back one space to become the last typed char, but perhaps this happens after a delay, so that the hook does not detect it.

1 Like

Kakoune’s cursor is always one character wide and sits on a character, not in between two. This means that there is always a valid selection that is at least one character long.

So if you enter insert mode and type Hello World, your buffer should look like the following:

Hello World█

The cursor is on the newline character, which is also the current selection. If you press <esc> to exit insert mode then a to enter text after the current selection your buffer should look like:

Hello World▓

The cursor is on the first character of the second line, and the current selection is now two characters long. It contains the newline from the first line and the newline from the second line.

Try the following hook to print the content of the current selection to the status bar every time you press a key. See what the current selection contains as you enter and leave insert mode and add and delete text.

hook global RawKey . %{
    echo selection %val{selection}

About the draft thing you can think it as executing the commands in another client. If you do new and select something in client2 it won’t be reflected in client1, but if you do a change in client2 a diff will be applied to the selections of client1.

1 Like

Thanks for your feedback, before posting I had read the docs about -draft but it still didn’t click. Before reading your answer I did find mawww’s comments in:


They were similar to your reply and quite helpful.

Another issue that became clear to me concerned the use of exec -draft in a hook called from Insert mode. When called from Insert mode, the keys following exec without -draft are just inserted in the document. The only way to quit Insert mode is to use <esc> as first key and then move back to insert mode at the end of the command being executed (with i). The whole thing may be unreliable, as shown in my example (the one that didn’t work, I think for timing issues related to the selection). Using exec -draft avoids the whole mess by

(a) executing commands as if they were typed in Normal mode
(b) leaving the selection intact, and thus not worrying about it.

All good to me :slight_smile: