changeset 12170:1345621ecdfb v8.0.0965

patch 8.0.0965: not restoring cursor shape after it was set in a terminal commit https://github.com/vim/vim/commit/3eee06e7d4c3a8e2dbb2577a1eef0e0f108e0288 Author: Bram Moolenaar <Bram@vim.org> Date: Sat Aug 19 19:40:50 2017 +0200 patch 8.0.0965: not restoring cursor shape after it was set in a terminal 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.
author Christian Brabandt <cb@256bit.org>
date Sat, 19 Aug 2017 19:45:04 +0200
parents 28f606bb906c
children 72c158ee7bf4
files src/option.c src/term.c src/term.h src/terminal.c src/version.c
diffstat 5 files changed, 132 insertions(+), 48 deletions(-) [+]
line wrap: on
line diff
--- a/src/option.c
+++ b/src/option.c
@@ -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)
--- a/src/term.c
+++ b/src/term.c
@@ -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
 
 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_termc
     {(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)
     {
-	LOG_TR("Sending BG request");
-	out_str(T_RBG);
-	rbg_status = RBG_SENT;
+	/* 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)
+    {
 	/* 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
--- a/src/term.h
+++ b/src/term.h
@@ -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[]);    /* c
 #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 */
--- a/src/terminal.c
+++ b/src/terminal.c
@@ -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);
     }
 }
 
--- a/src/version.c
+++ b/src/version.c
@@ -770,6 +770,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    965,
+/**/
     964,
 /**/
     963,