mawww / kakoune

mawww's experiment for a better code editor
http://kakoune.org
The Unlicense
9.85k stars 710 forks source link

Meaning of filtering regex in case of InsertCompletionHide hook. #3745

Open m-kru opened 3 years ago

m-kru commented 3 years ago

What is the meaning of <filtering_regex> in

hook [-group <group> | -once] <scope> <hook_name> <filtering_regex> <commands>

in case of InsertCompletionHide hook? I have always seen .* there.

I would like to trigger some action on InsertCompletionHide only if the last entered key was e. Is it possible? I have tried

    hook -group vhdl-indent window InsertCompletionHide 'e' vhdl-indent-on-completion-hide

but it does not trigger.

In the docs it is written:

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.

However, I do not understand it. When the completion hides you either did not choose anything or just choose one position from the list. What is the list of inserted completions?

Screwtapello commented 3 years ago

Every time a hook is called, it's called with a single string parameter. Every hook uses the string parameter differently, as described in :doc hooks. For example, BufOpenFile is called with the full path of the file that's opened, while WinResize is called with the new width and height. You can examine the hook parameter yourself by putting:

echo -debug Hook called with param: %val{hook_param}

...in your hook, triggering it, then checking the *debug* buffer.

The parameter to InsertCompletionHide is "the list of inserted completions text ranges". Because Kakoune supports multiple cursors, choosing a completion from the list can insert the selected text in multiple places. The hook parameter in this case is a list of those places.

Since the result is in the same format as the select command expects, something like this might work:

try %{
    # Use draft mode, so we don't mess with the user's actual selections
    eval -draft %{
        # Select the text that was inserted
        select %val{hook_param}

        # Search for trailing "e"
        exec se\z<ret>

        # If the previous line didn't throw an exception, there was a trailing e,
        # so we can do a thing.
    }
} catch %{
    # Something went wrong in the try block,
    # probably the `exec` failed to find a trailing "e".
}
m-kru commented 3 years ago

Ok, so how does the filtering_regex works in this case? I have printed hook_param and it is Hook called with param: 2.7,2.11 . Does it mean that the regex is applied to 2.7,2.11?

Screwtapello commented 3 years ago

Yes.

Note that the regex must match the entire hook_param, not just part of it - it's as though the regex were wrapped in ^ and $.

m-kru commented 3 years ago

Ok, it is all becoming a little bit complex, so maybe I will describe the problem.

I have hook for e, that decreases the indent of following lines: ^\h*else$. It works when user inserts each character. However, it does not work when user choose else keyword from completion list. It looks like inserting characters by completion mechanism is not the same as inserting them by hand.

Screwtapello commented 3 years ago

When you say "hook for e", you mean a RawKey hook? An InsertKey hook? It's reasonable that such a hook would not be triggered by completion, yes.

Assuming your hook checks to see if the current line matches ^\h*else$ before adjusting the indent, then having the hook filter regex be e is just an optimisation rather than required for correctness. Your InsertCompletionHide hook can do the same test and ignore the param.

m-kru commented 3 years ago

I mean InsertKey, however replacing it with RawKey makes no difference.

hook -group vhdl-indent window InsertChar 'e' vhdl-indent-on-e

define-command -hidden vhdl-indent-on-e %[
    evaluate-commands -itersel %[
        # Decrease indent after "else".
        try %[ execute-keys -draft <a-x> <a-k> (?i)(^\h+else$) <ret> <semicolon> <a-lt> ]
    ]
]

Making it work with InsertCompletionHide and then filtering if it should indent or not is really cumbersome. For example it triggers on <esc>, so typing else<esc> deindents twice.

Generally speaking, deindenting is much harder to implement then indenting, and it is less user friendly, as when done by hand you usually deident first, then type the word. In case of indenting it is reverse. You type the word, then indent (the by hand and automatic order is the same). I guess I will remove all auto deindenting rules.

language.kak files are not consistent in terms of deindenting. When I open different file types I never know what to expect.