]> granicus.if.org Git - vim/commitdiff
patch 8.0.0965: not restoring cursor shape after it was set in a terminal v8.0.0965
authorBram Moolenaar <Bram@vim.org>
Sat, 19 Aug 2017 17:40:50 +0000 (19:40 +0200)
committerBram Moolenaar <Bram@vim.org>
Sat, 19 Aug 2017 17:40:50 +0000 (19:40 +0200)
Problem:    The cursor shape is not reset after it was changed in a terminal.
Solution:   Request the original cursor shape and restore it.  Add t_RS.
            Do not add t_SH for now, it does not work properly.

src/option.c
src/term.c
src/term.h
src/terminal.c
src/version.c

index 0bcf21692d4c9ad0463af35e0a63e6bccd319eec..a65149785a4a2764bef024d0ebe941c87eda554a 100644 (file)
@@ -3179,6 +3179,7 @@ static struct vimoption options[] =
     p_term("t_SC", T_CSC)
     p_term("t_EC", T_CEC)
     p_term("t_SH", T_CSH)
+    p_term("t_RS", T_CRS)
     p_term("t_IS", T_CIS)
     p_term("t_ke", T_KE)
     p_term("t_ks", T_KS)
index d72f58c32df492b67c0f76c4b0a63cee9ebc8327..f5265448e8051c2c81767197b67b276f53b10f99 100644 (file)
@@ -114,21 +114,22 @@ char              *tgetstr(char *, char **);
 #  else
 #   define LOG_TR(msg)
 #  endif
+
+#  define STATUS_GET   1       /* send request when switching to RAW mode */
+#  define STATUS_SENT  2       /* did send request, waiting for response */
+#  define STATUS_GOT   3       /* received response */
+
 /* Request Terminal Version status: */
-#  define CRV_GET      1       /* send T_CRV when switched to RAW mode */
-#  define CRV_SENT     2       /* did send T_CRV, waiting for answer */
-#  define CRV_GOT      3       /* received T_CRV response */
-static int crv_status = CRV_GET;
+static int crv_status = STATUS_GET;
+
 /* Request Cursor position report: */
-#  define U7_GET       1       /* send T_U7 when switched to RAW mode */
-#  define U7_SENT      2       /* did send T_U7, waiting for answer */
-#  define U7_GOT       3       /* received T_U7 response */
-static int u7_status = U7_GET;
+static int u7_status = STATUS_GET;
+
 /* Request background color report: */
-#  define RBG_GET      1       /* send T_RBG when switched to RAW mode */
-#  define RBG_SENT     2       /* did send T_RBG, waiting for answer */
-#  define RBG_GOT      3       /* received T_RBG response */
-static int rbg_status = RBG_GET;
+static int rbg_status = STATUS_GET;
+
+/* Request cursor mode report: */
+static int rcm_status = STATUS_GET;
 # endif
 
 /*
@@ -160,6 +161,12 @@ static char_u *vim_tgetstr(char *s, char_u **pp);
 
 static int  detected_8bit = FALSE;     /* detected 8-bit terminal */
 
+/* When the cursor shape was detected these values are used:
+ * 1: block, 2: underline, 3: vertical bar
+ * initial_cursor_blink is only valid when initial_cursor_shape is not zero. */
+static int initial_cursor_shape = 0;
+static int initial_cursor_blink = FALSE;
+
 static struct builtin_term builtin_termcaps[] =
 {
 
@@ -820,11 +827,16 @@ static struct builtin_term builtin_termcaps[] =
     {(int)KS_VI,       IF_EB("\033[?25l", ESC_STR "[?25l")},
     {(int)KS_VE,       IF_EB("\033[?25h", ESC_STR "[?25h")},
     {(int)KS_VS,       IF_EB("\033[?12h", ESC_STR "[?12h")},
+#if 0
+    /* This is currently disabled, because we cannot reliably restore the
+     * cursor because of what appears to be an xterm bug. */
 #  ifdef TERMINFO
     {(int)KS_CSH,      IF_EB("\033[%p1%d q", ESC_STR "[%p1%d q")},
 #  else
     {(int)KS_CSH,      IF_EB("\033[%d q", ESC_STR "[%d q")},
 #  endif
+#endif
+    {(int)KS_CRS,      IF_EB("\033P$q q\033\\", ESC_STR "P$q q" ESC_STR "\\")},
 #  ifdef TERMINFO
     {(int)KS_CM,       IF_EB("\033[%i%p1%d;%p2%dH",
                                                  ESC_STR "[%i%p1%d;%p2%dH")},
@@ -1803,9 +1815,9 @@ set_termname(char_u *term)
  * is being used.
  * Don't do this when the GUI is active, it uses "t_kb" and "t_kD" directly.
  */
-#ifdef FEAT_GUI
+# ifdef FEAT_GUI
     if (!gui.in_use)
-#endif
+# endif
        get_stty();
 #endif
 
@@ -1906,8 +1918,8 @@ set_termname(char_u *term)
     full_screen = TRUE;                /* we can use termcap codes from now on */
     set_term_defaults();       /* use current values as defaults */
 #ifdef FEAT_TERMRESPONSE
-    LOG_TR("setting crv_status to CRV_GET");
-    crv_status = CRV_GET;      /* Get terminal version later */
+    LOG_TR("setting crv_status to STATUS_GET");
+    crv_status = STATUS_GET;   /* Get terminal version later */
 #endif
 
     /*
@@ -3298,9 +3310,10 @@ settmode(int tmode)
                /* May need to check for T_CRV response and termcodes, it
                 * doesn't work in Cooked mode, an external program may get
                 * them. */
-               if (tmode != TMODE_RAW && (crv_status == CRV_SENT
-                                        || u7_status == U7_SENT
-                                        || rbg_status == RBG_SENT))
+               if (tmode != TMODE_RAW && (crv_status == STATUS_SENT
+                                        || u7_status == STATUS_SENT
+                                        || rbg_status == STATUS_SENT
+                                        || rcm_status == STATUS_SENT))
                    (void)vpeekc_nomap();
                check_for_codes_from_term();
            }
@@ -3347,7 +3360,7 @@ starttermcap(void)
            may_req_termresponse();
            /* Immediately check for a response.  If t_Co changes, we don't
             * want to redraw with wrong colors first. */
-           if (crv_status == CRV_SENT)
+           if (crv_status == STATUS_SENT)
                check_for_codes_from_term();
        }
 #endif
@@ -3367,8 +3380,10 @@ stoptermcap(void)
 # endif
        {
            /* May need to discard T_CRV, T_U7 or T_RBG response. */
-           if (crv_status == CRV_SENT || u7_status == U7_SENT
-                                                    || rbg_status == RBG_SENT)
+           if (crv_status == STATUS_SENT
+                   || u7_status == STATUS_SENT
+                   || rbg_status == STATUS_SENT
+                   || rcm_status == STATUS_SENT)
            {
 # ifdef UNIX
                /* Give the terminal a chance to respond. */
@@ -3414,14 +3429,14 @@ stoptermcap(void)
     void
 may_req_termresponse(void)
 {
-    if (crv_status == CRV_GET
+    if (crv_status == STATUS_GET
            && can_get_termresponse()
            && starting == 0
            && *T_CRV != NUL)
     {
-       LOG_TR("Sending CRV");
+       LOG_TR("Sending CRV request");
        out_str(T_CRV);
-       crv_status = CRV_SENT;
+       crv_status = STATUS_SENT;
        /* check for the characters now, otherwise they might be eaten by
         * get_keystroke() */
        out_flush();
@@ -3442,7 +3457,7 @@ may_req_termresponse(void)
     void
 may_req_ambiguous_char_width(void)
 {
-    if (u7_status == U7_GET
+    if (u7_status == STATUS_GET
            && can_get_termresponse()
            && starting == 0
            && *T_U7 != NUL
@@ -3457,7 +3472,7 @@ may_req_ambiguous_char_width(void)
         buf[mb_char2bytes(0x25bd, buf)] = 0;
         out_str(buf);
         out_str(T_U7);
-        u7_status = U7_SENT;
+        u7_status = STATUS_SENT;
         out_flush();
 
         /* This overwrites a few characters on the screen, a redraw is needed
@@ -3477,19 +3492,40 @@ may_req_ambiguous_char_width(void)
 /*
  * Similar to requesting the version string: Request the terminal background
  * color when it is the right moment.
+ * Also request the cursor shape, if possible.
  */
     void
 may_req_bg_color(void)
 {
-    if (rbg_status == RBG_GET
-           && can_get_termresponse()
-           && starting == 0
-           && *T_RBG != NUL
-           && !option_was_set((char_u *)"bg"))
+    int done = FALSE;
+
+    if (can_get_termresponse() && starting == 0)
+    {
+       /* Only request background if t_RB is set and 'background' wasn't
+        * changed. */
+       if (rbg_status == STATUS_GET
+               && *T_RBG != NUL
+               && !option_was_set((char_u *)"bg"))
+       {
+           LOG_TR("Sending BG request");
+           out_str(T_RBG);
+           rbg_status = STATUS_SENT;
+           done = TRUE;
+       }
+
+       /* Only request the cursor shape if t_SH and t_RS are set. */
+       if (rcm_status == STATUS_GET
+               && *T_CSH != NUL
+               && *T_CRS != NUL)
+       {
+           LOG_TR("Sending cursor shape request");
+           out_str(T_CRS);
+           rcm_status = STATUS_SENT;
+           done = TRUE;
+       }
+    }
+    if (done)
     {
-       LOG_TR("Sending BG request");
-       out_str(T_RBG);
-       rbg_status = RBG_SENT;
        /* check for the characters now, otherwise they might be eaten by
         * get_keystroke() */
        out_flush();
@@ -3676,7 +3712,12 @@ term_cursor_mode(int forced)
     /* Only do something when redrawing the screen and we can restore the
      * mode. */
     if (!full_screen || *T_CEI == NUL)
+    {
+       if (forced && initial_cursor_shape > 0)
+           /* Restore to initial values. */
+           term_cursor_shape(initial_cursor_shape, initial_cursor_blink);
        return;
+    }
 
     if ((State & REPLACE) == REPLACE)
     {
@@ -4290,7 +4331,8 @@ check_termcode(
                        {
                            /* Skip over the digits, the final char must
                             * follow. */
-                           for (j = slen - 2; j < len && (isdigit(tp[j]) || tp[j] == ';'); ++j)
+                           for (j = slen - 2; j < len && (isdigit(tp[j])
+                                                        || tp[j] == ';'); ++j)
                                ;
                            ++j;
                            if (len < j)        /* got a partial sequence */
@@ -4394,7 +4436,7 @@ check_termcode(
                        char *aw = NULL;
 
                        LOG_TR("Received U7 status");
-                       u7_status = U7_GOT;
+                       u7_status = STATUS_GOT;
 # ifdef FEAT_AUTOCMD
                        did_cursorhold = TRUE;
 # endif
@@ -4433,8 +4475,8 @@ check_termcode(
                /* eat it when at least one digit and ending in 'c' */
                if (*T_CRV != NUL && i > 2 + (tp[0] != CSI) && tp[i] == 'c')
                {
-                   LOG_TR("Received CRV");
-                   crv_status = CRV_GOT;
+                   LOG_TR("Received CRV response");
+                   crv_status = STATUS_GOT;
 # ifdef FEAT_AUTOCMD
                    did_cursorhold = TRUE;
 # endif
@@ -4566,8 +4608,8 @@ check_termcode(
                            char *newval = (3 * '6' < tp[j+7] + tp[j+12]
                                                + tp[j+17]) ? "light" : "dark";
 
-                           LOG_TR("Received RBG");
-                           rbg_status = RBG_GOT;
+                           LOG_TR("Received RBG response");
+                           rbg_status = STATUS_GOT;
                            if (STRCMP(p_bg, newval) != 0)
                            {
                                /* value differs, apply it */
@@ -4592,24 +4634,33 @@ check_termcode(
            }
 
            /* Check for key code response from xterm:
-            *
             * {lead}{flag}+r<hex bytes><{tail}
             *
             * {lead} can be <Esc>P or DCS
             * {flag} can be '0' or '1'
             * {tail} can be Esc>\ or STERM
             *
-            * Consume any code that starts with "{lead}.+r".
+            * Check for cursor shape response from xterm:
+            * {lead}1$r<number> q{tail}
+            *
+            * {lead} can be <Esc>P or DCS
+            * {tail} can be Esc>\ or STERM
+            *
+            * Consume any code that starts with "{lead}.+r" or "{lead}.$r".
             */
-           else if (check_for_codes
+           else if ((check_for_codes || rcm_status == STATUS_SENT)
                    && ((tp[0] == ESC && len >= 2 && tp[1] == 'P')
                        || tp[0] == DCS))
            {
                j = 1 + (tp[0] == ESC);
-               if (len >= j + 3 && (argp[1] != '+' || argp[2] != 'r'))
+               if (len < j + 3)
+                   i = len; /* need more chars */
+               else if ((argp[1] != '+' && argp[1] != '$') || argp[2] != 'r')
                  i = 0; /* no match */
-               else
+               else if (argp[1] == '+')
+                 /* key code response */
                  for (i = j; i < len; ++i)
+                 {
                    if ((tp[i] == ESC && i + 1 < len && tp[i + 1] == '\\')
                            || tp[i] == STERM)
                    {
@@ -4620,6 +4671,32 @@ check_termcode(
                        slen = i + 1 + (tp[i] == ESC);
                        break;
                    }
+                 }
+               else if ((len >= j + 6 && isdigit(argp[3]))
+                       && argp[4] == ' '
+                       && argp[5] == 'q')
+               {
+                   /* cursor shape response */
+                   i = j + 6;
+                   if ((tp[i] == ESC && i + 1 < len && tp[i + 1] == '\\')
+                           || tp[i] == STERM)
+                   {
+                       int number = argp[3] - '0';
+
+                       /* 0, 1 = block blink, 2 = block
+                        * 3 = underline blink, 4 = underline
+                        * 5 = vertical bar blink, 6 = vertical bar */
+                       number = number == 0 ? 1 : number;
+                       initial_cursor_shape = (number + 1) / 2;
+                       initial_cursor_blink = (number & 1) ? TRUE : FALSE;
+                       rcm_status = STATUS_GOT;
+                       LOG_TR("Received cursor shape response");
+
+                       key_name[0] = (int)KS_EXTRA;
+                       key_name[1] = (int)KE_IGNORE;
+                       slen = i + 1 + (tp[i] == ESC);
+                   }
+               }
 
                if (i == len)
                {
@@ -5837,7 +5914,7 @@ gather_termleader(void)
        termleader[len++] = CSI;    /* the GUI codes are not in termcodes[] */
 #endif
 #ifdef FEAT_TERMRESPONSE
-    if (check_for_codes)
+    if (check_for_codes || *T_CRS != NUL)
        termleader[len++] = DCS;    /* the termcode response starts with DCS
                                       in 8-bit mode */
 #endif
index 66ad4c66c5ae7a49307f09dcd72477a67881019b..00e3c96aa2da0c62ca6ca584b87cc0cd77d41f0d 100644 (file)
@@ -41,6 +41,7 @@ enum SpecialKey
     KS_VE,     /* cursor visible */
     KS_VS,     /* cursor very visible */
     KS_CSH,    /* cursor shape */
+    KS_CRS,    /* request cursor shape */
     KS_ME,     /* normal mode */
     KS_MR,     /* reverse mode */
     KS_MD,     /* bold mode */
@@ -132,6 +133,7 @@ extern char_u *(term_strings[]);    /* current terminal strings */
 #define T_VE   (TERM_STR(KS_VE))       /* cursor visible */
 #define T_VS   (TERM_STR(KS_VS))       /* cursor very visible */
 #define T_CSH  (TERM_STR(KS_CSH))      /* cursor shape */
+#define T_CRS  (TERM_STR(KS_CRS))      /* request cursor shape */
 #define T_ME   (TERM_STR(KS_ME))       /* normal mode */
 #define T_MR   (TERM_STR(KS_MR))       /* reverse mode */
 #define T_MD   (TERM_STR(KS_MD))       /* bold mode */
index 8d15d3a99162400dc27df3ce6cfa71b64b9f1659..6b401beee85993621f3223aa165dfa76ff3a512b 100644 (file)
@@ -38,6 +38,7 @@
  * in tl_scrollback are no longer used.
  *
  * TODO:
+ * - help index for winptydll, optwin entry for winptydll
  * - make [range]terminal pipe [range] lines to the terminal
  * - implement term_setsize()
  * - add test for giving error for invalid 'termsize' value.
@@ -1287,9 +1288,10 @@ may_restore_cursor_props(void)
     if (did_change_cursor)
     {
        did_change_cursor = FALSE;
-       ui_cursor_shape_forced(TRUE);
        term_cursor_color((char_u *)"");
        term_cursor_blink(FALSE);
+       /* this will restore the initial cursor style, if possible */
+       ui_cursor_shape_forced(TRUE);
     }
 }
 
index 291ccdff830575f3a651e94ac24162d2bba8a59c..6af9a8f65effc63136ce094abea44a594fb7a5a6 100644 (file)
@@ -769,6 +769,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    965,
 /**/
     964,
 /**/