changeset 20778:6d5e233bac9c v8.2.0941

patch 8.2.0941: detecting terminal properties is unstructured Commit: https://github.com/vim/vim/commit/517f00f78893087d2f9d45768a5ba4dc48cb6856 Author: Bram Moolenaar <Bram@vim.org> Date: Wed Jun 10 12:15:51 2020 +0200 patch 8.2.0941: detecting terminal properties is unstructured Problem: Detecting terminal properties is unstructured. Solution: Add a table with terminal properties. Set properties when a terminal is detected.
author Bram Moolenaar <Bram@vim.org>
date Wed, 10 Jun 2020 12:30:04 +0200
parents 9e7672e41fba
children 0eb9578c85b1
files src/term.c src/version.c
diffstat 2 files changed, 168 insertions(+), 79 deletions(-) [+]
line wrap: on
line diff
--- a/src/term.c
+++ b/src/term.c
@@ -1431,8 +1431,63 @@ static int	need_gather = FALSE;	    // n
 static char_u	termleader[256 + 1];	    // for check_termcode()
 #ifdef FEAT_TERMRESPONSE
 static int	check_for_codes = FALSE;    // check for key code response
-static int	is_not_xterm = FALSE;	    // recognized not-really-xterm
-static int	xcc_test_failed = FALSE;    // xcc_status check failed
+
+/*
+ * Structure and table to store terminal features that can be detected by
+ * querying the terminal.  Either by inspecting the termresponse or a more
+ * specific request.  Besides this there are:
+ * t_colors - number of colors supported
+ */
+typedef struct {
+    char    *tpr_name;
+    int	    tpr_set_by_termresponse;
+    int	    tpr_status;
+} termprop_T;
+
+// Values for tpr_status.
+#define TPR_UNKNOWN	    'u'
+#define TPR_YES		    'y'
+#define TPR_NO		    'n'
+#define TPR_MOUSE_XTERM     'x'	// use "xterm" for 'ttymouse'
+#define TPR_MOUSE_XTERM2    '2'	// use "xterm2" for 'ttymouse'
+#define TPR_MOUSE_SGR	    's'	// use "sgr" for 'ttymouse'
+
+// can request the cursor style without messing up the display
+#define TPR_CURSOR_STYLE	    0
+// can request the cursor blink mode without messing up the display
+#define TPR_CURSOR_BLINK	    1
+// can set the underline color with t_8u without resetting other colors
+#define TPR_UNDERLINE_RGB	    2
+// mouse support - TPR_MOUSE_XTERM, TPR_MOUSE_XTERM2 or TPR_MOUSE_SGR
+#define TPR_MOUSE		    3
+// table size
+#define TPR_COUNT		    4
+
+static termprop_T term_props[TPR_COUNT];
+
+/*
+ * Initialize the term_props table.
+ * When "all" is FALSE only set those that are detected from the version
+ * response.
+ */
+    static void
+init_term_props(int all)
+{
+    int i;
+
+    term_props[TPR_CURSOR_STYLE].tpr_name = "cursor_style";
+    term_props[TPR_CURSOR_STYLE].tpr_set_by_termresponse = FALSE;
+    term_props[TPR_CURSOR_BLINK].tpr_name = "cursor_blink_mode";
+    term_props[TPR_CURSOR_BLINK].tpr_set_by_termresponse = FALSE;
+    term_props[TPR_UNDERLINE_RGB].tpr_name = "underline_rgb";
+    term_props[TPR_UNDERLINE_RGB].tpr_set_by_termresponse = TRUE;
+    term_props[TPR_MOUSE].tpr_name = "mouse";
+    term_props[TPR_MOUSE].tpr_set_by_termresponse = TRUE;
+
+    for (i = 0; i < TPR_COUNT; ++i)
+	if (all || term_props[i].tpr_set_by_termresponse)
+	    term_props[i].tpr_status = TPR_UNKNOWN;
+}
 #endif
 
     static struct builtin_term *
@@ -1958,8 +2013,9 @@ set_termname(char_u *term)
     term_is_xterm = vim_is_xterm(term);
 #endif
 #ifdef FEAT_TERMRESPONSE
-    is_not_xterm = FALSE;
-    is_mac_terminal = FALSE;
+    // Reset terminal properties that are set based on the termresponse, which
+    // will be sent out soon.
+    init_term_props(FALSE);
 #endif
 
 #if defined(UNIX) || defined(VMS)
@@ -3612,12 +3668,16 @@ may_req_termresponse(void)
 /*
  * Send sequences to the terminal and check with t_u7 how the cursor moves, to
  * find out properties of the terminal.
+ * Note that this goes out before T_CRV, so that the result can be used when
+ * the termresponse arrives.
  */
     void
 check_terminal_behavior(void)
 {
     int	    did_send = FALSE;
 
+    init_term_props(TRUE);
+
     if (!can_get_termresponse() || starting != 0 || *T_U7 == NUL)
 	return;
 
@@ -4424,28 +4484,40 @@ handle_u7_response(int *arg, char_u *tp 
     }
     else if (arg[0] == 3)
     {
+	int value;
+
 	LOG_TR(("Received compatibility test result: %s", tp));
+	xcc_status.tr_progress = STATUS_GOT;
+
 	// Third row: xterm compatibility test.
-	// If the cursor is not on the first column then the
-	// terminal is not xterm compatible.
-	if (arg[1] != 1)
-	    xcc_test_failed = TRUE;
-	xcc_status.tr_progress = STATUS_GOT;
+	// If the cursor is on the first column then the terminal can handle
+	// the request for cursor style and blinking.
+	value = arg[1] == 1 ? TPR_YES : TPR_NO;
+	term_props[TPR_CURSOR_STYLE].tpr_status = value;
+	term_props[TPR_CURSOR_BLINK].tpr_status = value;
     }
 }
 
 /*
- * Handle a response to T_CRV.
+ * Handle a response to T_CRV: {lead}{first}{x};{vers};{y}c
+ * Xterm and alikes use '>' for {first}.
+ * Rxvt sends "{lead}?1;2c".
  */
     static void
 handle_version_response(int first, int *arg, int argc, char_u *tp)
 {
+    // The xterm version.  It is set to zero when it can't be an actual xterm
+    // version.
     int version = arg[1];
 
     LOG_TR(("Received CRV response: %s", tp));
     crv_status.tr_progress = STATUS_GOT;
     did_cursorhold = TRUE;
 
+    // Reset terminal properties that are set based on the termresponse.
+    // Mainly useful for tests that send the termresponse multiple times.
+    init_term_props(FALSE);
+
     // If this code starts with CSI, you can bet that the
     // terminal uses 8-bit codes.
     if (tp[0] == CSI)
@@ -4458,19 +4530,21 @@ handle_version_response(int first, int *
     if (version > 20000)
 	version = 0;
 
+    // Figure out more if the reeponse is CSI > 99 ; 99 ; 99 c
     if (first == '>' && argc == 3)
     {
 	int need_flush = FALSE;
-	int is_iterm2 = FALSE;
-	int is_mintty = FALSE;
-	int is_screen = FALSE;
 
 	// mintty 2.9.5 sends 77;20905;0c.
 	// (77 is ASCII 'M' for mintty.)
 	if (arg[0] == 77)
-	    is_mintty = TRUE;
-
-	// if xterm version >= 141 try to get termcap codes
+	{
+	    // mintty can do SGR mouse reporting
+	    term_props[TPR_MOUSE].tpr_status = TPR_MOUSE_SGR;
+	}
+
+	// If xterm version >= 141 try to get termcap codes.  For other
+	// terminals the request should be ignored.
 	if (version >= 141)
 	{
 	    LOG_TR(("Enable checking for XT codes"));
@@ -4488,9 +4562,7 @@ handle_version_response(int first, int *
 	    if (mch_getenv((char_u *)"COLORS") == NULL)
 		may_adjust_color_count(256);
 	    // Libvterm can handle SGR mouse reporting.
-	    if (!option_was_set((char_u *)"ttym"))
-		set_option_value((char_u *)"ttym", 0L,
-					   (char_u *)"sgr", 0);
+	    term_props[TPR_MOUSE].tpr_status = TPR_MOUSE_SGR;
 	}
 
 	if (version == 95)
@@ -4498,99 +4570,118 @@ handle_version_response(int first, int *
 	    // Mac Terminal.app sends 1;95;0
 	    if (arg[0] == 1 && arg[2] == 0)
 	    {
-		is_not_xterm = TRUE;
-		is_mac_terminal = TRUE;
+		term_props[TPR_UNDERLINE_RGB].tpr_status = TPR_YES;
+		term_props[TPR_MOUSE].tpr_status = TPR_MOUSE_SGR;
 	    }
 	    // iTerm2 sends 0;95;0
 	    else if (arg[0] == 0 && arg[2] == 0)
-		is_iterm2 = TRUE;
+	    {
+		// iTerm2 can do SGR mouse reporting
+		term_props[TPR_MOUSE].tpr_status = TPR_MOUSE_SGR;
+	    }
 	    // old iTerm2 sends 0;95;
 	    else if (arg[0] == 0 && arg[2] == -1)
-		is_not_xterm = TRUE;
+		term_props[TPR_UNDERLINE_RGB].tpr_status = TPR_YES;
 	}
 
 	// screen sends 83;40500;0 83 is 'S' in ASCII.
 	if (arg[0] == 83)
-	    is_screen = TRUE;
-
-	// Only set 'ttymouse' automatically if it was not set
-	// by the user already.
-	if (!option_was_set((char_u *)"ttym"))
 	{
-	    // Xterm version 277 supports SGR.  Also support
-	    // Terminal.app, iTerm2, mintty, and screen 4.7+.
-	    if ((!is_screen && version >= 277)
-		    || is_iterm2
-		    || is_mac_terminal
-		    || is_mintty
-		    || (is_screen && arg[1] >= 40700))
-		set_option_value((char_u *)"ttym", 0L,
-					  (char_u *)"sgr", 0);
-	    // For xterm version >= 95 mouse dragging works.
+	    // screen supports SGR mouse codes since 4.7.0
+	    if (arg[1] >= 40700)
+		term_props[TPR_MOUSE].tpr_status = TPR_MOUSE_SGR;
+	    else
+		term_props[TPR_MOUSE].tpr_status = TPR_MOUSE_XTERM;
+	}
+
+	// If no recognized terminal has set mouse behavior, assume xterm.
+	if (term_props[TPR_MOUSE].tpr_status == TPR_UNKNOWN)
+	{
+	    // Xterm version 277 supports SGR.
+	    // Xterm version >= 95 supports mouse dragging.
+	    if (version >= 277)
+		term_props[TPR_MOUSE].tpr_status = TPR_MOUSE_SGR;
 	    else if (version >= 95)
-		set_option_value((char_u *)"ttym", 0L,
-				       (char_u *)"xterm2", 0);
+		term_props[TPR_MOUSE].tpr_status = TPR_MOUSE_XTERM2;
 	}
 
 	// Detect terminals that set $TERM to something like
 	// "xterm-256color" but are not fully xterm compatible.
-
+	//
 	// Gnome terminal sends 1;3801;0, 1;4402;0 or 1;2501;0.
 	// xfce4-terminal sends 1;2802;0.
 	// screen sends 83;40500;0
 	// Assuming any version number over 2500 is not an
 	// xterm (without the limit for rxvt and screen).
 	if (arg[1] >= 2500)
-	    is_not_xterm = TRUE;
-
-	// PuTTY sends 0;136;0
-	// vandyke SecureCRT sends 1;136;0
+	    term_props[TPR_UNDERLINE_RGB].tpr_status = TPR_YES;
+
 	else if (version == 136 && arg[2] == 0)
 	{
-	    is_not_xterm = TRUE;
-
-	    // PuTTY supports sgr-like mouse reporting, but
-	    // only set 'ttymouse' if it was not set by the
-	    // user already.
-	    if (arg[0] == 0
-			  && !option_was_set((char_u *)"ttym"))
-		set_option_value((char_u *)"ttym", 0L,
-					(char_u *)"sgr", 0);
+	    term_props[TPR_UNDERLINE_RGB].tpr_status = TPR_YES;
+
+	    // PuTTY sends 0;136;0
+	    if (arg[0] == 0)
+	    {
+		// supports sgr-like mouse reporting.
+		term_props[TPR_MOUSE].tpr_status = TPR_MOUSE_SGR;
+	    }
+	    // vandyke SecureCRT sends 1;136;0
 	}
 
 	// Konsole sends 0;115;0
 	else if (version == 115 && arg[0] == 0 && arg[2] == 0)
-	    is_not_xterm = TRUE;
+	    term_props[TPR_UNDERLINE_RGB].tpr_status = TPR_YES;
 
 	// GNU screen sends 83;30600;0, 83;40500;0, etc.
-	// 30600/40500 is a version number of GNU screen. DA2
-	// support is added on 3.6.  DCS string has a special
-	// meaning to GNU screen, but xterm compatibility
-	// checking does not detect GNU screen.
-	if (version >= 30600 && arg[0] == 83)
-	    xcc_test_failed = TRUE;
+	// 30600/40500 is a version number of GNU screen. DA2 support is added
+	// on 3.6.  DCS string has a special meaning to GNU screen, but xterm
+	// compatibility checking does not detect GNU screen.
+	if (arg[0] == 83 && arg[1] >= 30600)
+	{
+	    term_props[TPR_CURSOR_STYLE].tpr_status = TPR_NO;
+	    term_props[TPR_CURSOR_BLINK].tpr_status = TPR_NO;
+	}
 
 	// Xterm first responded to this request at patch level
-	// 95, so assume anything below 95 is not xterm.
+	// 95, so assume anything below 95 is not xterm and hopefully supports
+	// the underline RGB color sequence.
 	if (version < 95)
-	    is_not_xterm = TRUE;
-
-	// With the real Xterm setting the underline RGB color
-	// clears the background color, disable "t_8u".
-	if (!is_not_xterm && *T_8U != NUL)
+	    term_props[TPR_UNDERLINE_RGB].tpr_status = TPR_YES;
+
+	// Getting the cursor style is only supported properly by xterm since
+	// version 279 (otherwise it returns 0x18).
+	if (version < 279)
+	    term_props[TPR_CURSOR_STYLE].tpr_status = TPR_NO;
+
+	/*
+	 * Take action on the detected properties.
+	 */
+
+	// Unless the underline RGB color is expected to work, disable "t_8u".
+	// It does not work for the real Xterm, it resets the background color.
+	if (term_props[TPR_UNDERLINE_RGB].tpr_status == TPR_YES && *T_8U != NUL)
 	    T_8U = empty_option;
 
+	// Only set 'ttymouse' automatically if it was not set
+	// by the user already.
+	if (!option_was_set((char_u *)"ttym")
+		&& (term_props[TPR_MOUSE].tpr_status == TPR_MOUSE_XTERM2
+		    || term_props[TPR_MOUSE].tpr_status == TPR_MOUSE_SGR))
+	{
+	    set_option_value((char_u *)"ttym", 0L,
+		    term_props[TPR_MOUSE].tpr_status == TPR_MOUSE_SGR
+				    ? (char_u *)"sgr" : (char_u *)"xterm2", 0);
+	}
+
 	// Only request the cursor style if t_SH and t_RS are
 	// set. Only supported properly by xterm since version
 	// 279 (otherwise it returns 0x18).
-	// Only when the xcc_status was set, the test finished,
-	// and xcc_test_failed is FALSE;
+	// Only when getting the cursor style was detected to work.
 	// Not for Terminal.app, it can't handle t_RS, it
 	// echoes the characters to the screen.
 	if (rcs_status.tr_progress == STATUS_GET
-		&& xcc_status.tr_progress == STATUS_GOT
-		&& !xcc_test_failed
-		&& version >= 279
+		&& term_props[TPR_CURSOR_STYLE].tpr_status == TPR_YES
 		&& *T_CSH != NUL
 		&& *T_CRS != NUL)
 	{
@@ -4603,11 +4694,9 @@ handle_version_response(int first, int *
 	// Only request the cursor blink mode if t_RC set. Not
 	// for Gnome terminal, it can't handle t_RC, it
 	// echoes the characters to the screen.
-	// Only when the xcc_status was set, the test finished,
-	// and xcc_test_failed is FALSE;
+	// Only when getting the cursor style was detected to work.
 	if (rbm_status.tr_progress == STATUS_GET
-		&& xcc_status.tr_progress == STATUS_GOT
-		&& !xcc_test_failed
+		&& term_props[TPR_CURSOR_BLINK].tpr_status == TPR_YES
 		&& *T_CRC != NUL)
 	{
 	    LOG_TR(("Sending cursor blink mode request"));
@@ -4681,9 +4770,7 @@ handle_key_with_modifier(
 
 /*
  * Handle a CSI escape sequence.
- * - Xterm version string: {lead}>{x};{vers};{y}c
- *   Also eat other possible responses to t_RV, rxvt returns
- *   "{lead}?1;2c".
+ * - Xterm version string.
  *
  * - Cursor position report: {lead}{row};{col}R
  *   The final byte must be 'R'. It is used for checking the
--- a/src/version.c
+++ b/src/version.c
@@ -755,6 +755,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    941,
+/**/
     940,
 /**/
     939,