Intro to Kakoune completers

One of the best things about Kakoune is how eager it is to provide hints and completions at every opportunity; another one is how easy it is to write your own completion plugins. Unfortunately, although the documentation does contain pretty much everything you need to know, it takes some effort to collect the puzzle-pieces and figure out how to put them together.

To help you write your first completion plugin, I’ve written an article that walks you through each step of the process, explaining what each part does and why it’s there:

https://zork.net/~st/jottings/Intro_to_Kakoune_completions.html

Like my “Intro to Kakoune highlighters” article, there’s also a skeleton at the end you can use as a starting point for your own completion plugin!

Please let me know if you have any questions or comments.

12 Likes

For some reason when pasting in the

set-option window my_custom_completions \
    "%val{cursor_line}.%val{cursor_column}@%val{timestamp}" \
    "fish|info -style menu Fish of the day is trout a la creme|fish" \
    "frog||frog {MenuInfo}Fried with garlic"

block I was getting every single word in the quoted text as suggestions, i.e. my completion menu looked something like

fish
Fish
Fried
info
MenuInfo

But I was on WSL at work so I will try again when I’m at home.

I think the example would be a lot more beneficial if it gave an example of dynamically calling some external tool (which is what most custom completions will do) rather than completing a static word with static suggestions.

A simple but powerful example would be to just use the output of

cat /usr/share/dict/words | grep %var{selection} | awk '/.*/ {print$0"||"$0}'

A tool like https://github.com/laurikari/tre that supports fuzzy matching might be more useful for producing completions if you wanted to go the extra mile and have a genuinely useful little plugin at the end of it.

Great article though, and much needed as the completions format is a difficult to grasp from the documentation alone and I couldn’t find any good explanations online back when I looked into it.

That’s weird. Perhaps there was something weird in the quoting — try joining the lines together and removing the backslashes?

The trouble is that every external tool does things in a different way, so the story gets hung up on the details of how a particular external tool works and the details of Kakoune-quoting. All of that stuff is generic to all Kakoune scripting, not specific to completions, so I wanted to avoid it. By writing out the completions individually:

set-option -add window my_custom_completions "fish||fish"
set-option -add window my_custom_completions "frog||frog"

…I hoped to make it obvious that you could do this kind of thing in a shell expansion:

eval %sh{
    for food in fish frog feta flan; do
        echo set-option -add window my_custom_completions "$food||$food"
    done
}

…and from there it should be straight-forward to figure out how to massage your favourite completion engine’s output into Kakoune’s input format.

That’s a reasonable idea, but I think it makes a bad example of a custom completer because it’s a lot easier to do that with just the static_words option:

evaluate-commands set-option window static_words %sh{
    sed -e "s/'/''/; s/.*/'&'/" /usr/share/dict/words |
    tr '\n' ' '
}

Also, in practice using /usr/share/dict/words as a completion source is a terrible idea, because the word you want is always buried beneath a million archaic and variant spellings. Phone keyboards get away with it because they heavily weight completions by word-frequency based on studying enormous corpuses, but Kakoune doesn’t support any kind of weighting so it’s only useful for completions with maybe a dozen candidates at most.

Thanks for your feedback, though!

1 Like

Thanks Screwtape your blog was invaluable. Here is what I went with:

# ref: https://bitbucket.org/KJ_Duncan/kakoune-java.kak/src/master/rc/javaInheritanceHierarchy.kak
# a snippet block for brevity.
[...]
hook -group your-completers window InsertCompletionShow .* %{
  try %{
                           # this was a good idea, 
                           # thanks again screwtape.
    execute-keys -draft 2b s \A^import<space>\z<ret>

    evaluate-commands -draft %{
      execute-keys h <a-i>w <a-semicolon>

      set-option window your_completions \
        "%val{cursor_line}.%val{cursor_column}+%val{selection_length}@%val{timestamp}"
    }

   evaluate-commands %sh{
      # list of completers 
      goes='here and there'

      print_completers() {

        format=' %s\;||%s'

        for import in "$@"
        do
          printf "$format" "$import" "$import"
        done

      }

      printf "set-option -add window your_completions "

      print_completers $goes

      printf "\n"
  }
[...]

Bye :star_struck: