How to implement NormalKey hook

So, I’m trying to fix Add more key bindings to the `*spelling*` buffer · Issue #11 · dmerejkowsky/kak-spell · GitHub

Here’s what I’ve got so far:

First, the kak-spell script generates a *spelling* scratch buffer containing one selection per line, like this:

1.3,1.5 kak
3.1,3.9 PyEnchant

Then it calls the following commands:

hook buffer -group kak-spell NormalKey <ret> kak-spell-jump
hook buffer -group kak-spell NormalKey a 'kak-spell-add-from-spelling-buffer en_US'

The idea is that can you press ‘enter’ while in the *spelling* buffer to jump to the error, and ‘a’ to add the word from the line into the personal dictionary.

The kak-spell-jump command works fine:

define-command kak-spell-jump -hidden %{
  execute-keys '
    <esc>
    :edit -existing *spelling* <ret>
    gi <a-E> <esc>
    :set-option global kak_spell_current_error %val{selection} <ret>
    ga
    :select %opt{kak_spell_current_error} <ret>
  '
}

But I did not manage to make kak-spell-add-from-spelling-buffer work.

I tried this:

define-command -hidden kak-spell-add-from-spelling-buffer -params 1 %{
  execute-keys '
    <esc>
    gi <a-w> l Gl
  '
  nop %sh{ kak-spell --lang $1 add $kak_selection }

But the problem is that the a command still gets executed, and I end up with this:

1
    .3,1.5 kak
3.1,3.9 PyEnchant

which breaks everything else because the buffer is no longer formatted properly.

I’ve tried using -draft with -save-reg but to no avail.

What am I doing wrong ?

Update: I’ve also tried using -draft

define-command -hidden kak-spell-add-from-spelling-buffer -params 1 %{
  execute-keys -draft '
    <esc>
    gi <a-w> l Gl
    :set-option global kak_spell_word_to_add %val{selection} <ret>
  '

  nop %sh{ kak-spell --lang $1 add $kak_opt_kak_spell_word_to_add }
  execute-keys '
    <esc>
    ga
    :kak-spell<ret>
    :kak-spell-list<ret>
  '
}

But for some reason I end up adding several words instead of just the one from the line under the cursor …

Update: I got the answer by looking at plug.kak implementation.

Things that helped:

One, using <map buffer normal> instead of <hook buffer NormalKey>. That way I don’t need to “undo” what pressing “a” does.

Two, using this pattern:

  evaluate-commands -save-regs t %{
    execute-keys -save-regs '' "gi <a-w> l Gl"
    set-register t %val{selection}
    evaluate-commands %sh{
         word="${kak_reg_t%:*}"
         # Now we are ready to add $word with for lang $1"
    }
}

The trick is we need to keep the $1 param of the command, execute some keys to select the word from the line, and access the selection from the execute-keys call.

Note that this destroys whatever was on the t register.

Please tell me if you see a better way to do this.

It seems like you’ve already figured some of this out yourself but I’m just going to go through point by point.

First the execute-keys command takes a list of strings and execute all keys in them. Commonly you might see something like.
execute-keys <esc> <lt> x s ^.* <ret>
this is a list of space seperated strings. Comparatively,
execute-keys "<esc> <lt> x s ^.* <ret>"
is a single string where the whitespace is interpreted as the space key, or <space>.

The idiomatic way to write your kak-spell-jump is

define-command kak-spell-jump -hidden %{
  edit -existing *spelling*
  execute-keys gi <a-E>
  set-option global kak_spell_current_error %val{selection}
  execute-keys ga
  select %opt{kak_spell_current_error}
}

where commands are written as statements rather than as key presses with : and <ret>. As you figured out when your hook executes after the a key you’re in insert mode and the exec keys inserts all those spaces in your strings into the buffer as if you typed them.

I believe your -save-regs is unnecessary in that command. You can simply go.

exec gi <a-w> l Gl
eval %sh{
    word="$kak_val_selection"
    #...
}

One more point. Normally when you execute a command in kakscript you want to write it as : edit ... <ret> or s abc<ret> with the space between a key that creates a prompt (: or s). Doing this means the prompt entry is not added to the history to pollute it.

1 Like

Wow. This was really useful feedback! The thing is, this kind of advice is really hard to find - maybe we should write a 'kak script best practices" somewhere …

Anyway, thanks a bunch!