patch 9.1.0563: Cannot process any Key event

Commit: 
https://github.com/vim/vim/commit/83678849095abfa914f5405e8a5e5d23346b5917
Author: Shougo Matsushita <shougo.ma...@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 <zeert...@outlook.com>
    Co-authored-by: K.Takata <ken...@csc.jp>
    Signed-off-by: Shougo Matsushita <shougo.ma...@gmail.com>
    Signed-off-by: Christian Brabandt <c...@256bit.org>

diff --git a/runtime/doc/autocmd.txt b/runtime/doc/autocmd.txt
index 23f1cbf92..1e9c89654 100644
--- 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 
Insert mode.  Also when
                                                        *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
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index 18cd2c123..eddafd078 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -1995,7 +1995,8 @@ v:beval_winid     The |window-ID| of the window, over 
which the mouse pointer
                                        *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
diff --git a/runtime/doc/tags b/runtime/doc/tags
index 1238a9c8a..b3761e88e 100644
--- 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*
diff --git a/runtime/doc/version9.txt b/runtime/doc/version9.txt
index ed1cd4308..cfeb28c7b 100644
--- 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
diff --git a/src/autocmd.c b/src/autocmd.c
index e60eac794..00f41bddd 100644
--- 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"),
@@ -2021,6 +2022,15 @@ has_insertcharpre(void)
     return (first_autopat[(int)EVENT_INSERTCHARPRE] != NULL);
 }
 
+/*
+ * 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.
  */
@@ -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
diff --git a/src/getchar.c b/src/getchar.c
index 1c544da63..0a37b7b11 100644
--- 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).
diff --git a/src/proto/autocmd.pro b/src/proto/autocmd.pro
index 4a502da62..920987a8c 100644
--- 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);
diff --git a/src/testdir/test_autocmd.vim b/src/testdir/test_autocmd.vim
index bcbddf978..5ad1730c4 100644
--- 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
diff --git a/src/version.c b/src/version.c
index 39c29b064..ff654844f 100644
--- a/src/version.c
+++ b/src/version.c
@@ -704,6 +704,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    563,
 /**/
     562,
 /**/
diff --git a/src/vim.h b/src/vim.h
index ae7458ad7..a35916246 100644
--- 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

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to vim_dev+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/E1sS07N-000PKG-4r%40256bit.org.

Raspunde prin e-mail lui