Mode hooks and user modes


#1

Kakoune comes with a spell-checking script (spell.kak) but as is convention, it just defines a few commands and leaves the user to figure out how to incorporate them. It occurs to me that what I really want is:

  • declare a custom spell-checking mode
  • add spell-checking-related mappings in that mode
  • execute :spell<ret> on entering that mode
  • execute :spell-clear<ret> on exiting that mode

The first two items in the list are easy enough:

declare-user-mode spell
map global spell n ': spell-next' -docstring "next misspelling"

For the last two items, though, I’m a bit stuck. I clearly can’t use the InsertBegin/InsertEnd/NormalBegin/NormalEnd hooks, because they know nothing about my custom mode. The ModeChange hook is much more general, though, so I added:

hook global ModeChange .*:spell %{ spell }
hook global ModeChange spell:.* %{ spell-clear }

… and nothing happened. I got curious, so I added a new hook:

hook global ModeChange .* %{ echo -debug ModeChange %val{hook_param} }

… and started playing around. When I hit , to display the list of user modes, my debug log says:

ModeChange normal:next-key

… and when I type a mapping to enter a user-mode, it says:

ModeChange next-key:normal
ModeChange normal:prompt
ModeChange prompt:normal
ModeChange normal:next-key

In a way, that makes sense: the mapping is a normal-mode command, so Kakoune leaves the “next-key” mode and goes back to normal mode. The normal-mode command is : to open the prompt, it types an enter-user-mode command, and then we’re back in next-key mode again. But clearly trying to hook our user-mode by name is not going to work if Kakoune is only ever in next-key mode.

I guess strictly speaking we don’t need a special hook to run commands when entering a mode:

define-command enter-spell-mode %{
    spell
    enter-user-mode -lock spell
}
map global user s ': enter-spell-mode<ret>' -docstring spellcheck

… but the user can leave spell mode at any time with Esc, which I can’t write a mapping for (a good thing).

Alternatively, when entering the mode I could write a one-shot hook for ModeChange next-key:normal, except that Kakoune naturally fires that hook while executing commands within the mode, not just when exiting it.

But of course, that’s what the proposed ModePush and ModePop hooks are for, right? Surely that will let me distinguish “temporarily entering normal mode to run a command” from “permanently returning to normal mode”. As it turns out, no:

ModePush normal:next-key:2  # I hit , to enter the user-mode list
ModePop next-key:normal:2   # I hit s to trigger the "enter spell mode" mapping
ModePush normal:prompt:2    # the mapping runs in normal mode
ModePop prompt:normal:2
ModePush normal:next-key:2  # Kakoune actually enters spell mode
ModePop next-key:normal:2

It seems that “entering” a custom mode is not like entering normal mode from insert mode, it doesn’t add new stack modes, it just shuffles modes around at the same depth.

Is there some clever way I can get the “run commands on entering and exiting a user-mode” that I want, or should I start filing issues?


#2

I don’t think so. What I liked in Vim, is that spell checking works in background (sort of). I think if Kakoune will implement something like

  • User sets some boolean on
  • If it is on, upon switching to normal mode, spell command refreshes current buffer.
  • If user sets this boolean off, spell.kak executes spell-clear

I think, that for writers there’s no point to leave spell checking mode ever.

Also there should be a proper way to add words to dictionary or ignore some words.


#3

Apps like Microsoft Word (or this very forum) do spell-checking all the time because the “incorrect” marker is subtle (a red wavy underline), the user has a rich interface for interacting with it (right-click to open a menu with all kinds of options), and it’s efficient (each word can be checked individually as you type).

Kakoune is in a different category, at least at the moment. The ‘incorrect’ marker is very noisy (bright red background), the user has a very limited interface for interacting with the checker (by default, only :spell-next), and Kakoune has to pipe the entire document into the spell-checker every time.

I very definitely don’t want to have spell-checking enabled all the time while Kakoune has no way to add a word to the dictionary, or mark it as ignored.

It also occurred to me today that a feature like this would also be great for implementing something like git add -p inside Kakoune: enter “stage hunks” mode, automatically run “git show-diff”, have k and j jump between hunks, a to stage the currently-selected hunk, u to unstage it, and when the user hits Esc automatically run “git hide-diff”.


#4

I guess you want. But you also want a better spell checker with more features, commands etc.


#5

A bit off-topic but I just stumbled upon this nice flowchart of Vim modes:
https://rawgit.com/darcyparker/1886716/raw/vimModeStateDiagram.svg