]> granicus.if.org Git - vim/commitdiff
patch 9.0.0980: the keyboard state response may end up in a shell command v9.0.0980
authorBram Moolenaar <Bram@vim.org>
Thu, 1 Dec 2022 12:03:47 +0000 (12:03 +0000)
committerBram Moolenaar <Bram@vim.org>
Thu, 1 Dec 2022 12:03:47 +0000 (12:03 +0000)
Problem:    The keyboard state response may end up in a shell command.
Solution:   Only request the keyboard protocol state when the typeahead is
            empty, no more commands are following and not exiting.  Add the
            t_RK termcap entry for this.

12 files changed:
runtime/doc/map.txt
runtime/doc/term.txt
src/edit.c
src/ex_getln.c
src/main.c
src/normal.c
src/os_unix.c
src/proto/main.pro
src/proto/term.pro
src/term.c
src/termdefs.h
src/version.c

index e0c7106644ddb7ebff9dd89160e5c293b93cc2b6..3f4a37190f7ce269da51994a4de220ba7adde8a4 100644 (file)
@@ -1001,10 +1001,15 @@ mapping, see |map-bar|.
 WARNING: if you map <C-[> you may very well break any key codes that start
 with Esc.  Make sure it comes AFTER other mappings.
 
-Vim automatically detects if the modifyOtherKeys mode was enabled when it
-spots an escape sequence that must have been created by it.  To see if Vim
-detected such an escape sequence use `:verbose map`, the first line will then
-show "Seen modifyOtherKeys: true" (possibly translated).
+Starting with xterm version 377 Vim can detect the modifyOtherKeys state by
+requesting it.  For this the 't_RK' termcap entry is used.  When the response
+is found then Vim will know whether modifyOtherKeys level 2 is enabled, and
+handle mappings accordingly.
+
+Before version 377 Vim automatically detects if the modifyOtherKeys mode was
+enabled when it spots an escape sequence that must have been created by it.
+To see if Vim detected such an escape sequence use `:verbose map`, the first
+line will then show "Seen modifyOtherKeys: true" (possibly translated).
 
 This automatic detection depends on receiving an escape code starting with 
 "<1b>[27;".  This is the normal way xterm sends these key codes.  However, if
@@ -1016,6 +1021,9 @@ after the CTRL-V key.  This can be used to check whether modifyOtherKeys is
 enabled: In Insert mode type CTRL-SHIFT-V CTRL-V, if you get one byte then
 modifyOtherKeys is off, if you get <1b>[27;5;118~ then it is on.
 
+Note that xterm up to version 376 has a bug that makes Shift-Esc send a
+regular Esc code, the Shift modifier is dropped.
+
 When the 'esckeys' option is off, then modifyOtherKeys will be disabled in
 Insert mode to avoid every key with a modifier causing Insert mode to end.
 
index 2bd83c71252a5e947e9b076ea10c59aa8b81f1df..77d1ed388a7a482a325b7593ab56060807cb16fe 100644 (file)
@@ -90,6 +90,11 @@ Note: When 't_ti' is not empty, Vim assumes that it causes switching to the
 alternate screen.  This may slightly change what happens when executing a
 shell command or exiting Vim.  To avoid this use 't_TI' and 't_TE'.
 
+Vim will try to detect what keyboard protocol the terminal is using with the
+'t_RK' termcap entry.  This is sent after 't_TI', but only when there is no
+work to do (no typeahead and no pending commands).  That is to avoid the
+response to end up in a shell command or arrive after Vim exits.
+
                                                *xterm-bracketed-paste*
 When the 't_BE' option is set then 't_BE' will be sent to the
 terminal when entering "raw" mode and 't_BD' when leaving "raw" mode.  The
@@ -388,6 +393,8 @@ Added by Vim (there are no standard codes for these):
                xterm and other terminal emulators)  The
                response is stored in |v:termresponse| |xterm-8bit|
                |'ttymouse'| |xterm-codes|
+       t_RK    request terminal keyboard protocol state;       *t_RK* *'t_RK'*
+               sent after |t_TI|
        t_u7    request cursor position (for xterm)             *t_u7* *'t_u7'*
                see |'ambiwidth'|
                The response is stored in |v:termu7resp|
index 01e5cc2d3e36d9c1a9362ccc1944e9edcbdc2320..43f7d9abb0712c87b93802057aec301bbb75f816 100644 (file)
@@ -571,6 +571,8 @@ edit(
 #ifdef USE_ON_FLY_SCROLL
        dont_scroll = FALSE;            // allow scrolling here
 #endif
+       // May request the keyboard protocol state now.
+       may_send_t_RK();
 
        /*
         * Get a character for Insert mode.  Ignore K_IGNORE and K_NOP.
@@ -1479,7 +1481,8 @@ ins_redraw(int ready)         // not busy with something
        aco_save_T      aco;
        varnumber_T     tick = CHANGEDTICK(curbuf);
 
-       // save and restore curwin and curbuf, in case the autocmd changes them
+       // Save and restore curwin and curbuf, in case the autocmd changes
+       // them.
        aucmd_prepbuf(&aco, curbuf);
        apply_autocmds(EVENT_TEXTCHANGEDI, NULL, NULL, FALSE, curbuf);
        aucmd_restbuf(&aco);
@@ -1499,7 +1502,8 @@ ins_redraw(int ready)         // not busy with something
        aco_save_T      aco;
        varnumber_T     tick = CHANGEDTICK(curbuf);
 
-       // save and restore curwin and curbuf, in case the autocmd changes them
+       // Save and restore curwin and curbuf, in case the autocmd changes
+       // them.
        aucmd_prepbuf(&aco, curbuf);
        apply_autocmds(EVENT_TEXTCHANGEDP, NULL, NULL, FALSE, curbuf);
        aucmd_restbuf(&aco);
@@ -3706,7 +3710,7 @@ ins_esc(
        out_str(T_BE);
 
        // Re-enable modifyOtherKeys.
-       out_str(T_CTI);
+       out_str_t_TI();
     }
 #ifdef FEAT_CONCEAL
     // Check if the cursor line needs redrawing after changing State.  If
@@ -4384,6 +4388,7 @@ bracketed_paste(paste_mode_T mode, int drop, garray_T *gap)
        do
            c = vgetc();
        while (c == K_IGNORE || c == K_VER_SCROLLBAR || c == K_HOR_SCROLLBAR);
+
        if (c == NUL || got_int || (ex_normal_busy > 0 && c == Ctrl_C))
            // When CTRL-C was encountered the typeahead will be flushed and we
            // won't get the end sequence.  Except when using ":normal".
index 72f2a3aabf1a30fa6fdcc4d5464ee627ad1591ed..44049c7618e4e80b98e2f4f33f5c9af5f5ddcf50 100644 (file)
@@ -2908,6 +2908,9 @@ getexmodeline(
        long    sw;
        char_u *s;
 
+       // May request the keyboard protocol state now.
+       may_send_t_RK();
+
        if (ga_grow(&line_ga, 40) == FAIL)
            break;
 
index 90816576918d27254b4b6c6abd887944c168d7d1..477f3d619458aedcf65add15eca6f670beef01a9 100644 (file)
@@ -1133,14 +1133,14 @@ may_trigger_safestateagain(void)
        // of calling feedkeys(), we check if it's now safe again (all keys
        // were consumed).
        was_safe = is_safe_now();
-#ifdef FEAT_EVAL
+# ifdef FEAT_EVAL
        if (was_safe)
            ch_log(NULL, "SafeState: undo reset");
-#endif
+# endif
     }
     if (was_safe)
     {
-#ifdef FEAT_EVAL
+# ifdef FEAT_EVAL
        // Only do this message when another message was given, otherwise we
        // get lots of them.
        if ((did_repeated_msg & REPEATED_MSG_SAFESTATE) == 0)
@@ -1151,17 +1151,26 @@ may_trigger_safestateagain(void)
                      "SafeState: back to waiting, triggering SafeStateAgain");
            did_repeated_msg = did | REPEATED_MSG_SAFESTATE;
        }
-#endif
+# endif
        apply_autocmds(EVENT_SAFESTATEAGAIN, NULL, NULL, FALSE, curbuf);
     }
-#ifdef FEAT_EVAL
+# ifdef FEAT_EVAL
     else
        ch_log(NULL,
                  "SafeState: back to waiting, not triggering SafeStateAgain");
-#endif
+# endif
 }
 #endif
 
+/*
+ * Return TRUE if there is any typeahead, pending operator or command.
+ */
+    int
+work_pending(void)
+{
+    return op_pending() || !is_safe_now();
+}
+
 
 /*
  * Main loop: Execute Normal mode commands until exiting Vim.
@@ -1477,10 +1486,11 @@ main_loop(
            gui_mouse_correct();
 #endif
 
-       /*
-        * Update w_curswant if w_set_curswant has been set.
-        * Postponed until here to avoid computing w_virtcol too often.
-        */
+       // May request the keyboard protocol state now.
+       may_send_t_RK();
+
+       // Update w_curswant if w_set_curswant has been set.
+       // Postponed until here to avoid computing w_virtcol too often.
        update_curswant();
 
 #ifdef FEAT_EVAL
index 0d1eba759e698462fdf443d45831e2138a652234..3f48ad85a5565c57bc38fd833c7d184afbb82aff 100644 (file)
@@ -455,7 +455,7 @@ normal_cmd_get_more_chars(
 
            // Re-enable bracketed paste mode and modifyOtherKeys
            out_str(T_BE);
-           out_str(T_CTI);
+           out_str_t_TI();
        }
 
        if (langmap_active)
index 79d7f17d98bb0edd25a060d1b7f7b32f5cb9b609..bd75ccae14031ce3ecd0f83b3ecd9fe954fef51d 100644 (file)
@@ -5379,7 +5379,7 @@ finished:
 
                if (tmode == TMODE_RAW)
                    // possibly enables modifyOtherKeys again
-                   out_str(T_CTI);
+                   out_str_t_TI();
            }
 # endif
 
index f0f9b736039d26276349f367363a34eea9a0f615..307b6063c0fff53e45080d43ab8cc321f95ce479 100644 (file)
@@ -9,6 +9,7 @@ void may_trigger_safestate(int safe);
 void state_no_longer_safe(char *reason);
 int get_was_safe_state(void);
 void may_trigger_safestateagain(void);
+int work_pending(void);
 void main_loop(int cmdwin, int noexmode);
 void getout_preserve_modified(int exitval);
 void getout(int exitval);
index b1c691d80f6e96aa4b9a82cf8d2bd91f26286745..93edba1c0ebd38f80023adb41a494df45eb7da38 100644 (file)
@@ -48,6 +48,8 @@ void shell_resized(void);
 void shell_resized_check(void);
 void set_shellsize(int width, int height, int mustset);
 void out_str_t_TE(void);
+void out_str_t_TI(void);
+void may_send_t_RK(void);
 void settmode(tmode_T tmode);
 void starttermcap(void);
 void stoptermcap(void);
index 40728f2440e735ee911e84e748cd6503c13a416a..caffc355e05722de45ce7b704fcd71d48fe45a84 100644 (file)
@@ -452,7 +452,8 @@ static tcap_entry_T builtin_xterm[] = {
     {(int)KS_TI,       "\0337\033[?47h"},
     {(int)KS_TE,       "\033[?47l\0338"},
 #  endif
-    {(int)KS_CTI,      "\033[>4;2m\033[?4m"},  // see "builtin_mok2"
+    {(int)KS_CTI,      "\033[>4;2m"},
+    {(int)KS_CRK,      "\033[?4m"},  // see "builtin_mok2"
     {(int)KS_CTE,      "\033[>4;m"},
     {(int)KS_CIS,      "\033]1;"},
     {(int)KS_CIE,      "\007"},
@@ -593,10 +594,15 @@ static tcap_entry_T builtin_xterm[] = {
  * xterm.
  */
 static tcap_entry_T builtin_mok2[] = {
+    // t_TI enables modifyOtherKeys level 2
+    {(int)KS_CTI,      "\033[>4;2m"},
+
     // XTQMODKEYS was added in xterm version 377: "CSI ? 4 m" which should
     // return "{lead} > 4 ; Pv m".  Before version 377 we expect it to have no
     // effect.
-    {(int)KS_CTI,      "\033[>4;2m\033[?4m"},
+    {(int)KS_CRK,      "\033[?4m"},
+
+    // t_TE disables modifyOtherKeys
     {(int)KS_CTE,      "\033[>4;m"},
 
     {(int)KS_NAME,     NULL}  // end marker
@@ -606,11 +612,13 @@ static tcap_entry_T builtin_mok2[] = {
  * Additions for using the Kitty keyboard protocol.
  */
 static tcap_entry_T builtin_kitty[] = {
-    // t_TI enables the kitty keyboard protocol, requests the kitty keyboard
-    // protocol state and requests the version response.
-    {(int)KS_CTI,      "\033[=1;1u\033[?u\033[>c"},
+    // t_TI enables the kitty keyboard protocol.
+    {(int)KS_CTI,      "\033[=1;1u"},
+
+    // t_RK requests the kitty keyboard protocol state
+    {(int)KS_CRK,      "\033[?u"},
 
-    // t_TE also disabled modifyOtherKeys, because t_TI from xterm may already
+    // t_TE also disables modifyOtherKeys, because t_TI from xterm may already
     // have been used.
     {(int)KS_CTE,      "\033[>4;m\033[=0;1u"},
 
@@ -1685,7 +1693,7 @@ get_term_entries(int *height, int *width)
                        {KS_CM, "cm"}, {KS_SR, "sr"},
                        {KS_CRI,"RI"}, {KS_VB, "vb"}, {KS_KS, "ks"},
                        {KS_KE, "ke"}, {KS_TI, "ti"}, {KS_TE, "te"},
-                       {KS_CTI, "TI"}, {KS_CTE, "TE"},
+                       {KS_CTI, "TI"}, {KS_CRK, "RK"}, {KS_CTE, "TE"},
                        {KS_BC, "bc"}, {KS_CSB,"Sb"}, {KS_CSF,"Sf"},
                        {KS_CAB,"AB"}, {KS_CAF,"AF"}, {KS_CAU,"AU"},
                        {KS_LE, "le"},
@@ -3693,6 +3701,40 @@ out_str_t_TE(void)
        kitty_protocol_state = KKPS_AFTER_T_KE;
 }
 
+static int send_t_RK = FALSE;
+
+/*
+ * Output T_TI and setup for what follows.
+ */
+    void
+out_str_t_TI(void)
+{
+    out_str(T_CTI);
+
+    // Send t_RK when there is no more work to do.
+    send_t_RK = TRUE;
+}
+
+/*
+ * If t_TI was recently sent and there is no typeahead or work to do, now send
+ * t_RK.  This is postponed to avoid the response arriving in a shell command
+ * or after Vim exits.
+ */
+    void
+may_send_t_RK(void)
+{
+    if (send_t_RK
+           && !work_pending()
+           && !ex_normal_busy
+           && !in_feedkeys
+           && !exiting)
+    {
+       send_t_RK = FALSE;
+       out_str(T_CRK);
+       out_flush();
+    }
+}
+
 /*
  * Set the terminal to TMODE_RAW (for Normal mode) or TMODE_COOK (for external
  * commands and Ex mode).
@@ -3751,7 +3793,7 @@ settmode(tmode_T tmode)
                {
                    out_str(T_BE);      // enable bracketed paste mode (should
                                        // be before mch_settmode().
-                   out_str(T_CTI);     // possibly enables modifyOtherKeys
+                   out_str_t_TI();     // possibly enables modifyOtherKeys
                }
            }
            out_flush();
@@ -3775,7 +3817,7 @@ starttermcap(void)
        MAY_WANT_TO_LOG_THIS;
 
        out_str(T_TI);                  // start termcap mode
-       out_str(T_CTI);                 // start "raw" mode
+       out_str_t_TI();                 // start "raw" mode
        out_str(T_KS);                  // start "keypad transmit" mode
        out_str(T_BE);                  // enable bracketed paste mode
 
index 133641b5c0033fd59cca28bae418cf053439ec5c..9e9601f1a91861ad4ddbba9183ce29f05ddfcb17 100644 (file)
@@ -69,6 +69,7 @@ enum SpecialKey
     KS_KE,     // out of "keypad transmit" mode
     KS_TI,     // put terminal in termcap mode
     KS_CTI,    // put terminal in "raw" mode
+    KS_CRK,    // request keyboard protocol state
     KS_TE,     // end of termcap mode
     KS_CTE,    // end of "raw" mode
     KS_BC,     // backspace character (cursor left)
@@ -177,6 +178,7 @@ extern char_u *(term_strings[]);    // current terminal strings
 #define T_KE   (TERM_STR(KS_KE))       // out of "keypad transmit" mode
 #define T_TI   (TERM_STR(KS_TI))       // put terminal in termcap mode
 #define T_CTI  (TERM_STR(KS_CTI))      // put terminal in "raw" mode
+#define T_CRK  (TERM_STR(KS_CRK))      // request keyboard protocol status
 #define T_TE   (TERM_STR(KS_TE))       // end of termcap mode
 #define T_CTE  (TERM_STR(KS_CTE))      // end of "raw" mode
 #define T_BC   (TERM_STR(KS_BC))       // backspace character
index a04419ae523c4bf151709483460011991cb61c14..07086662eed303a895ac5053fc5557c8346f2dec 100644 (file)
@@ -695,6 +695,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    980,
 /**/
     979,
 /**/