Mercurial > vim
changeset 35643:610d9a6833c3 v9.1.0563
patch 9.1.0563: Cannot process any Key event
Commit: https://github.com/vim/vim/commit/83678849095abfa914f5405e8a5e5d23346b5917
Author: Shougo Matsushita <Shougo.Matsu@gmail.com>
Date: Thu Jul 11 22:05:12 2024 +0200
patch 9.1.0563: Cannot process any Key event
Problem: Cannot process any Key event
Solution: Add the KeyInputPre autocmd
(Shougo Matsushita)
closes: #15182
Co-authored-by: zeertzjq <zeertzjq@outlook.com>
Co-authored-by: K.Takata <kentkt@csc.jp>
Signed-off-by: Shougo Matsushita <Shougo.Matsu@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Thu, 11 Jul 2024 22:10:17 +0200 |
parents | f0e5c3d311a0 |
children | e478046e7f34 |
files | runtime/doc/autocmd.txt runtime/doc/eval.txt runtime/doc/tags runtime/doc/version9.txt src/autocmd.c src/getchar.c src/proto/autocmd.pro src/testdir/test_autocmd.vim src/version.c src/vim.h |
diffstat | 10 files changed, 182 insertions(+), 2 deletions(-) [+] |
line wrap: on
line diff
--- a/runtime/doc/autocmd.txt +++ b/runtime/doc/autocmd.txt @@ -1,4 +1,4 @@ -*autocmd.txt* For Vim version 9.1. Last change: 2024 Jul 09 +*autocmd.txt* For Vim version 9.1. Last change: 2024 Jul 11 VIM REFERENCE MANUAL by Bram Moolenaar @@ -439,6 +439,8 @@ Name triggered by ~ |CompleteDone| after Insert mode completion is done, after clearing info +|KeyInputPre| just before a key is processed + |User| to be used in combination with ":doautocmd" |SigUSR1| after the SIGUSR1 signal has been detected @@ -977,6 +979,21 @@ InsertLeavePre Just before leaving Ins *InsertLeave* InsertLeave Just after leaving Insert mode. Also when using CTRL-O |i_CTRL-O|. But not for |i_CTRL-C|. + *KeyInputPre* +KeyInputPre Just before a key is processed. The pattern is + matched against a string that indicates the + current mode, which is the same as what is + returned by `mode(1)`. + The |v:char| variable indicates the key typed + and can be changed during the event to process + a different key. When |v:char| is not a + single character or a special key, the first + character is used. + The following values of |v:event| are set: + typed The key is typed or not. + It is not allowed to change the text + |textlock| or the current mode. + {only with the +eval feature} *MenuPopup* MenuPopup Just before showing the popup menu (under the right mouse button). Useful for adjusting the
--- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -1995,7 +1995,8 @@ v:beval_winid The |window-ID| of the win *v:char* *char-variable* v:char Argument for evaluating 'formatexpr' and used for the typed character when using <expr> in an abbreviation |:map-<expr>|. - It is also used by the |InsertCharPre| and |InsertEnter| events. + It is also used by the |InsertCharPre|, |InsertEnter| and + |KeyInputPre| events. *v:charconvert_from* *charconvert_from-variable* v:charconvert_from
--- a/runtime/doc/tags +++ b/runtime/doc/tags @@ -5554,6 +5554,7 @@ Jobs eval.txt /*Jobs* K various.txt /*K* KDE gui_x11.txt /*KDE* KVim gui_x11.txt /*KVim* +KeyInputPre autocmd.txt /*KeyInputPre* Kibaale uganda.txt /*Kibaale* Korean mbyte.txt /*Korean* L motion.txt /*L*
--- a/runtime/doc/version9.txt +++ b/runtime/doc/version9.txt @@ -41607,6 +41607,7 @@ Functions: ~ Autocommands: ~ |CursorMovedC| after the cursor was moved in the comamnd-line +|KeyInputPre| process any Key event in any mode |SessionWritePost| after writing the session file |:mksession| |TermResponseAll| after the terminal response to |t_RV| and others is received
--- a/src/autocmd.c +++ b/src/autocmd.c @@ -155,6 +155,7 @@ static keyvalue_T event_tab[] = { KEYVALUE_ENTRY(EVENT_INSERTENTER, "InsertEnter"), KEYVALUE_ENTRY(EVENT_INSERTLEAVE, "InsertLeave"), KEYVALUE_ENTRY(EVENT_INSERTLEAVEPRE, "InsertLeavePre"), + KEYVALUE_ENTRY(EVENT_KEYINPUTPRE, "KeyInputPre"), KEYVALUE_ENTRY(EVENT_MENUPOPUP, "MenuPopup"), KEYVALUE_ENTRY(EVENT_MODECHANGED, "ModeChanged"), KEYVALUE_ENTRY(EVENT_OPTIONSET, "OptionSet"), @@ -2022,6 +2023,15 @@ has_insertcharpre(void) } /* + * Return TRUE when there is an KeyInputPre autocommand defined. + */ + int +has_keyinputpre(void) +{ + return (first_autopat[(int)EVENT_KEYINPUTPRE] != NULL); +} + +/* * Return TRUE when there is an CmdUndefined autocommand defined. */ int @@ -2256,6 +2266,7 @@ apply_autocmds_group( || event == EVENT_CMDWINLEAVE || event == EVENT_CMDUNDEFINED || event == EVENT_FUNCUNDEFINED + || event == EVENT_KEYINPUTPRE || event == EVENT_REMOTEREPLY || event == EVENT_SPELLFILEMISSING || event == EVENT_QUICKFIXCMDPRE
--- a/src/getchar.c +++ b/src/getchar.c @@ -96,6 +96,9 @@ static void closescript(void); static void updatescript(int c); static int vgetorpeek(int); static int inchar(char_u *buf, int maxlen, long wait_time); +#ifdef FEAT_EVAL +static int do_key_input_pre(int c); +#endif /* * Free and clear a buffer. @@ -2130,6 +2133,10 @@ vgetc(void) } #endif +#ifdef FEAT_EVAL + c = do_key_input_pre(c); +#endif + // Need to process the character before we know it's safe to do something // else. if (c != K_IGNORE) @@ -2138,6 +2145,74 @@ vgetc(void) return c; } +#ifdef FEAT_EVAL +/* + * Handle the InsertCharPre autocommand. + * "c" is the character that was typed. + * Return new input character. + */ + static int +do_key_input_pre(int c) +{ + int res = c; + char_u buf[MB_MAXBYTES + 1]; + char_u curr_mode[MODE_MAX_LENGTH]; + int save_State = State; + save_v_event_T save_v_event; + dict_T *v_event; + + // Return quickly when there is nothing to do. + if (!has_keyinputpre()) + return res; + + if (IS_SPECIAL(c)) + { + buf[0] = K_SPECIAL; + buf[1] = KEY2TERMCAP0(c); + buf[2] = KEY2TERMCAP1(c); + buf[3] = NUL; + } + else + buf[(*mb_char2bytes)(c, buf)] = NUL; + + get_mode(curr_mode); + + // Lock the text to avoid weird things from happening. + ++textlock; + set_vim_var_string(VV_CHAR, buf, -1); // set v:char + + v_event = get_v_event(&save_v_event); + (void)dict_add_bool(v_event, "typed", KeyTyped); + + if (apply_autocmds(EVENT_KEYINPUTPRE, curr_mode, curr_mode, FALSE, curbuf) + && STRCMP(buf, get_vim_var_str(VV_CHAR)) != 0) + { + // Get the value of v:char. It may be empty or more than one + // character. Only use it when changed, otherwise continue with the + // original character. + char_u *v_char; + + v_char = get_vim_var_str(VV_CHAR); + + // Convert special bytes when it is special string. + if (STRLEN(v_char) >= 3 && v_char[0] == K_SPECIAL) + res = TERMCAP2KEY(v_char[1], v_char[2]); + else if (STRLEN(v_char) > 0) + res = PTR2CHAR(v_char); + } + + restore_v_event(v_event, &save_v_event); + + set_vim_var_string(VV_CHAR, NULL, -1); // clear v:char + --textlock; + + // Restore the State, it may have been changed. + State = save_State; + + return res; +} +#endif + /* * Like vgetc(), but never return a NUL when called recursively, get a key * directly from the user (ignoring typeahead).
--- a/src/proto/autocmd.pro +++ b/src/proto/autocmd.pro @@ -26,6 +26,7 @@ int has_textchanged(void); int has_textchangedI(void); int has_textchangedP(void); int has_insertcharpre(void); +int has_keyinputpre(void); int has_cmdundefined(void); int has_textyankpost(void); int has_completechanged(void);
--- a/src/testdir/test_autocmd.vim +++ b/src/testdir/test_autocmd.vim @@ -4752,4 +4752,74 @@ func Test_BufEnter_botline() set hidden&vim endfunc +func Test_KeyInputPre() + " Consume previous keys + call feedkeys('', 'ntx') + + " KeyInputPre can record input keys. + let s:keys = [] + au KeyInputPre n call add(s:keys, v:char) + + call feedkeys('jkjkjjj', 'ntx') + call assert_equal( + \ ['j', 'k', 'j', 'k', 'j', 'j', 'j'], + \ s:keys) + + unlet s:keys + au! KeyInputPre + + " KeyInputPre can handle multibyte. + let s:keys = [] + au KeyInputPre * call add(s:keys, v:char) + edit Xxx1 + + call feedkeys("iあ\<ESC>", 'ntx') + call assert_equal(['i', "あ", "\<ESC>"], s:keys) + + bwipe! Xxx1 + unlet s:keys + au! KeyInputPre + + " KeyInputPre can change input keys. + au KeyInputPre i if v:char ==# 'a' | let v:char = 'b' | endif + edit Xxx1 + + call feedkeys("iaabb\<ESC>", 'ntx') + call assert_equal(getline('.'), 'bbbb') + + bwipe! Xxx1 + au! KeyInputPre + + " KeyInputPre returns multiple characters. + au KeyInputPre i if v:char ==# 'a' | let v:char = 'cccc' | endif + edit Xxx1 + + call feedkeys("iaabb\<ESC>", 'ntx') + call assert_equal(getline('.'), 'ccbb') + + bwipe! Xxx1 + au! KeyInputPre + + " KeyInputPre can use special keys. + au KeyInputPre i if v:char ==# 'a' | let v:char = "\<Ignore>" | endif + edit Xxx1 + + call feedkeys("iaabb\<ESC>", 'ntx') + call assert_equal(getline('.'), 'bb') + + bwipe! Xxx1 + au! KeyInputPre + + " Test for v:event.typed + au KeyInputPre n call assert_true(v:event.typed) + call feedkeys('j', 'ntx') + + au! KeyInputPre + + au KeyInputPre n call assert_false(v:event.typed) + call feedkeys('j', 'nx') + + au! KeyInputPre +endfunc + " vim: shiftwidth=2 sts=2 expandtab
--- a/src/version.c +++ b/src/version.c @@ -705,6 +705,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 563, +/**/ 562, /**/ 561,
--- a/src/vim.h +++ b/src/vim.h @@ -1397,6 +1397,7 @@ enum auto_event EVENT_INSERTENTER, // when entering Insert mode EVENT_INSERTLEAVEPRE, // just before leaving Insert mode EVENT_INSERTLEAVE, // just after leaving Insert mode + EVENT_KEYINPUTPRE, // before key input EVENT_MENUPOPUP, // just before popup menu is displayed EVENT_MODECHANGED, // after changing the mode EVENT_OPTIONSET, // option was set