= Hooks

== Description

Commands can be registered to be executed when certain events arise. To
register a hook use the following command:

------------------------------------------------------------------
hook [<switches>] <scope> <hook_name> <filtering_regex> <commands>
------------------------------------------------------------------

*scope* can be one of *global*, *buffer* or *window* (See
<<scopes#,`:doc scopes`>>).

*hook_name* must be one of the hook names in the list below, like `InsertKey`
or `BufSetOption`.

*filtering_regex* must match the entire parameter string in order for the
commands to be executed.

*command* is a string containing the commands to execute when the hook
is called.

For *switches*, see <<commands#hooks,`:doc commands hooks`>>.

If a hook is registered with the `-group` switch, it can later be removed with
the `remove-hooks` command:

----------------------------
remove-hooks <scope> <group>
----------------------------

This command removes all hooks originally registered in *scope* whose
`-group` switch matches the regex *group*.

For example to automatically use line numbering with .cc files, use the
following command:

--------------------------------------------------------------
hook global WinCreate .*\.cc %{ add-highlighter number-lines }
--------------------------------------------------------------

== Default hooks

The parameter string associated with each hook is described after the hook
name. Hooks with no description will always use an empty string.

*NormalIdle*::
    a certain duration has passed since the last keypress in normal mode

*NormalKey* `key`::
    a key is received in normal mode. This hook will not trigger when the user
    presses a key on the left-hand side of a normal-mode mapping (see
    <<mapping#,`:doc mapping`>>), but will trigger for keys on the right-hand
    side. See also `RawKey` below.

*InsertIdle*::
    a certain duration has passed since the last keypress in insert mode

*InsertKey* `key`::
    a key is received in insert mode. This hook will not trigger when the user
    presses a key on the left-hand side of a insert-mode mapping (see
    <<mapping#,`:doc mapping`>>), but will trigger for keys on the right-hand
    side. See also `RawKey` below.

*InsertChar* `char`::
    a character is received in insert mode

*InsertDelete* `deleted char`::
    a character is deleted in insert mode

*InsertMove* `move key`::
    the cursor moved (without inserting) in insert mode

*PromptIdle*::
    a certain duration has passed since the last keypress in prompt mode

*WinCreate* `buffer name`::
    a window was created. This hook is executed in draft context, so any
    changes to selections or input state will be discarded.

*WinClose* `buffer name`::
    a window was destroyed. This hook is executed in a draft context, so any
    changes to selections or input state will be discarded.

*WinResize* `<line>.<column>`::
    a window was resized. This hook is executed in a draft context, so any
    changes to selections or input state will be discarded.

*WinDisplay* `buffer name`::
    a client switched to displaying the given buffer.

*WinSetOption* `<option_name>=<new_value>`::
    an option was set in a window context. This hook is executed in a draft
    context, so any changes to selections or input state will be discarded.

*GlobalSetOption* `<option_name>=<new_value>`::
    an option was set at the global scope

*BufSetOption* `<option_name>=<new_value>`::
    an option was set in a buffer context

*BufNewFile* `filename`::
    a buffer for a new file has been created

*BufOpenFile* `filename`::
    a buffer for an existing file has been created

*BufCreate* `filename`::
    a buffer has been created

*BufWritePre* `filename`::
    executed just before a buffer is written

*BufWritePost* `filename`::
    executed just after a buffer is written

*BufReload* `filename`::
    executed after a buffer reload has been triggered by an external
    modification to its file

*BufClose* `buffer name`::
    executed when a buffer is deleted, while it is still valid

*BufOpenFifo* `buffer name`::
    executed when a buffer opens a fifo

*BufReadFifo* `<start line>.<start column>,<end line>.<end column>`::
    executed after some data has been read from a fifo and inserted in
    the buffer. The hook param contains the range of text that was just
    inserted, in a format compatible with the `select` command.

*BufCloseFifo*::
    executed when a fifo buffer closes its fifo file descriptor either
    because the buffer is being deleted or the writing end has been closed

*ClientCreate* `client name`::
    executed when a new client is created.

*ClientClose* `client name`::
    executed when a client is closed, after it was removed from the client
    list.
    
*ClientRenamed* `<old name>:<new name>`::
    executed when a client is renamed using the `rename-client` command

*SessionRenamed* `<old name>:<new name>`::
    executed when a session is renamed using the `rename-session` command

*RuntimeError* `error message`::
    an error was encountered while executing a user command

*ModeChange* `[push|pop]:<old mode>:<new mode>`::
    Triggered whenever a mode is pushed or removed from the mode stack.
    The mode name can be things like 'normal' or 'insert' for regular
    interactive modes, or 'next-key[<name>]' for sub-modes where Kakoune
    prompts for a key. For example, `g` in normal mode pushes 'next-key[goto]'
    mode, the `enter-user-mode foo` command pushes 'next-key[user.foo]' mode,
    and the `on-key -mode-name bar` command pushes 'next-key[bar]' mode.

*KakBegin* `session name`::
    Kakoune has started, this hook is called just after reading the user
    configuration files

*KakEnd*::
    Kakoune is quitting

*FocusIn* `client name`::
    on supported clients, triggered when the client gets focused

*FocusOut* `client name`::
    on supported clients, triggered when the client gets unfocused

*InsertCompletionShow*::
    Triggered when the insert completion menu gets displayed

*InsertCompletionHide* `completion`::
    Triggered when the insert completion menu gets hidden, the list of
    inserted completions text ranges is passed as filtering text, in the
    same format the `select` command expects.

*RawKey* `key`::
    Triggered whenever a key is pressed by the user, regardless of what mode
    Kakoune is in, or what mappings are present (see
    <<mapping#,`:doc mapping`>>). It cannot be triggered by `execute-keys`,
    even with the `-with-hooks` option (see
    <<execeval#execute-keys-specific-switches,`:doc execeval execute-keys-specific-switches`>>).

*RegisterModified* `register`::
    Triggered after a register has been written to.

*ModuleLoaded* `module`::
    Triggered after a module is evaluated by the first `require-module` call

*User* `param`::
    Triggered  via the `trigger-user-hook` command. Provides a way for plugins
    to introduce custom hooks by specifying what *param* would be.

Note that some hooks will not consider underlying scopes depending on what
context they are bound to be run into, e.g. the `BufWritePost` hook is a buffer
hook, and will not consider the `window` scope.

While defining hook commands with a `%sh{}` block, some additional env
vars are available:

* `kak_hook_param`: filtering text passed to the currently executing hook

* `kak_hook_param_capture_N`: text captured by the hook filter regex capturing
    group N, N can either be the capturing group number, or its name
    (See <<regex#groups,`:doc regex groups`>>).

== Disabling Hooks

Hooks can be disabled temporarily by prefixing any normal mode command by `\`
(see <<keys#,`:doc keys`>>) and permanently by setting the `disabled_hooks` option
which accepts a regex describing which hooks won't be executed. For example
indentation hooks can be disabled with '.*-indent'.

Finally, hook execution can be disabled while using the `execute-keys` or
`evaluate-commands` commands by using the `-no-hooks` switch.
(See <<execeval#,`:doc execeval`>>)

As an exception to these rules, hooks declared with the `-always` switch
are triggered no matter what. A good use case is doing some cleanup on `BufCloseFifo`.
