changeset 12076:ca4931a20f8c v8.0.0918

patch 8.0.0918: cannot get terminal window cursor shape or attributes commit https://github.com/vim/vim/commit/3cd43ccccb03b2e68df9c8a344a87e51c007c656 Author: Bram Moolenaar <Bram@vim.org> Date: Sat Aug 12 19:51:41 2017 +0200 patch 8.0.0918: cannot get terminal window cursor shape or attributes Problem: Cannot get terminal window cursor shape or attributes. Solution: Support cursor shape, attributes and color.
author Christian Brabandt <cb@256bit.org>
date Sat, 12 Aug 2017 20:00:05 +0200
parents 488c6139c881
children 7323503da3ee
files runtime/doc/eval.txt src/feature.h src/libvterm/include/vterm.h src/libvterm/src/state.c src/libvterm/src/vterm.c src/option.c src/proto/term.pro src/proto/ui.pro src/term.c src/term.h src/terminal.c src/ui.c src/version.c
diffstat 13 files changed, 197 insertions(+), 32 deletions(-) [+]
line wrap: on
line diff
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -7939,13 +7939,19 @@ term_getattr({attr}, {what})				*term_ge
 
 term_getcursor({buf})					*term_getcursor()*
 		Get the cursor position of terminal {buf}. Returns a list with
-		three numbers: [rows, cols, visible].  "rows" and "cols" are
-		one based, the first screen cell is row 1, column 1.
-		"visible" is one when the cursor is visible, zero when it is
-		hidden.
-
-		This is the cursor position of the terminal itself, not of the
-		Vim window.
+		two numbers and a dictionary: [rows, cols, dict].
+
+		"rows" and "cols" are one based, the first screen cell is row
+		1, column 1.  This is the cursor position of the terminal
+		itself, not of the Vim window.
+
+		"dict" can have these members:
+		   "visible"	one when the cursor is visible, zero when it
+				is hidden.
+		   "blink"	one when the cursor is visible, zero when it
+				is hidden.
+		   "shape"	1 for a block cursor, 2 for underline and 3
+				for a vertical bar.
 
 		{buf} must be the buffer number of a terminal window. If the
 		buffer does not exist or is not a terminal window, an empty
@@ -8035,7 +8041,7 @@ term_scrape({buf}, {row})				*term_scrap
 		    "fg"	foreground color as #rrggbb
 		    "bg"	background color as #rrggbb
 		    "attr"	attributes of the cell, use |term_getattr()|
-		    		to get the individual flags
+				to get the individual flags
 		    "width"	cell width: 1 or 2
 		{only available when compiled with the |+terminal| feature}
 
@@ -8075,7 +8081,7 @@ term_start({cmd}, {options})				*term_st
 		   "term_rows"	     vertical size to use for the terminal,
 				     instead of using 'termsize'
 		   "term_cols"	     horizontal size to use for the terminal,
-		   		     instead of using 'termsize'
+				     instead of using 'termsize'
 		   "vertical"	     split the window vertically
 		   "curwin"	     use the current window, do not split the
 				     window; fails if the current buffer
@@ -8165,7 +8171,7 @@ test_override({name}, {val})				*test_ov
 		in a way that the test doesn't work properly.
 		When using: >
 			call test_override('starting', 1)
-< 		The value of "starting" is saved.  It is restored by: >
+<		The value of "starting" is saved.  It is restored by: >
 			call test_override('starting', 0)
 
 test_settime({expr})					*test_settime()*
--- a/src/feature.h
+++ b/src/feature.h
@@ -1273,6 +1273,9 @@
 #if !defined(FEAT_JOB_CHANNEL) && defined(FEAT_TERMINAL)
 # undef FEAT_TERMINAL
 #endif
+#if defined(FEAT_TERMINAL) && !defined(CURSOR_SHAPE)
+# define CURSOR_SHAPE
+#endif
 
 /*
  * +signs		Allow signs to be displayed to the left of text lines.
--- a/src/libvterm/include/vterm.h
+++ b/src/libvterm/include/vterm.h
@@ -120,7 +120,8 @@ typedef enum {
   VTERM_PROP_ICONNAME,          /* string */
   VTERM_PROP_REVERSE,           /* bool */
   VTERM_PROP_CURSORSHAPE,       /* number */
-  VTERM_PROP_MOUSE              /* number */
+  VTERM_PROP_MOUSE,             /* number */
+  VTERM_PROP_CURSORCOLOR        /* string */
 } VTermProp;
 
 enum {
--- a/src/libvterm/src/state.c
+++ b/src/libvterm/src/state.c
@@ -1504,6 +1504,10 @@ static int on_osc(const char *command, s
     settermprop_string(state, VTERM_PROP_TITLE, command + 2, cmdlen - 2);
     return 1;
   }
+  else if(strneq(command, "12;", 3)) {
+    settermprop_string(state, VTERM_PROP_CURSORCOLOR, command + 3, cmdlen - 3);
+    return 1;
+  }
   else if(state->fallbacks && state->fallbacks->osc)
     if((*state->fallbacks->osc)(command, cmdlen, state->fbdata))
       return 1;
@@ -1819,6 +1823,7 @@ int vterm_state_set_termprop(VTermState 
   switch(prop) {
   case VTERM_PROP_TITLE:
   case VTERM_PROP_ICONNAME:
+  case VTERM_PROP_CURSORCOLOR:
     /* we don't store these, just transparently pass through */
     return 1;
   case VTERM_PROP_CURSORVISIBLE:
--- a/src/libvterm/src/vterm.c
+++ b/src/libvterm/src/vterm.c
@@ -294,6 +294,7 @@ VTermValueType vterm_get_prop_type(VTerm
     case VTERM_PROP_REVERSE:       return VTERM_VALUETYPE_BOOL;
     case VTERM_PROP_CURSORSHAPE:   return VTERM_VALUETYPE_INT;
     case VTERM_PROP_MOUSE:         return VTERM_VALUETYPE_INT;
+    case VTERM_PROP_CURSORCOLOR:   return VTERM_VALUETYPE_STRING;
   }
   return 0; /* UNREACHABLE */
 }
--- a/src/option.c
+++ b/src/option.c
@@ -3162,6 +3162,9 @@ static struct vimoption options[] =
     p_term("t_EI", T_CEI)
     p_term("t_fs", T_FS)
     p_term("t_IE", T_CIE)
+    p_term("t_SC", T_CSC)
+    p_term("t_EC", T_CEC)
+    p_term("t_SH", T_CSH)
     p_term("t_IS", T_CIS)
     p_term("t_ke", T_KE)
     p_term("t_ks", T_KS)
--- a/src/proto/term.pro
+++ b/src/proto/term.pro
@@ -51,7 +51,10 @@ int mouse_model_popup(void);
 void scroll_start(void);
 void cursor_on(void);
 void cursor_off(void);
-void term_cursor_shape(void);
+void term_cursor_mode(int forced);
+void term_cursor_color(char_u *color);
+void term_cursor_blink(int blink);
+void term_cursor_shape(int shape, int blink);
 void scroll_region_set(win_T *wp, int off);
 void scroll_region_reset(void);
 void clear_termcodes(void);
--- a/src/proto/ui.pro
+++ b/src/proto/ui.pro
@@ -47,6 +47,7 @@ void trash_input_buf(void);
 int read_from_input_buf(char_u *buf, long maxlen);
 void fill_input_buf(int exit_on_error);
 void read_error_exit(void);
+void ui_cursor_shape_forced(int forced);
 void ui_cursor_shape(void);
 int check_col(int col);
 int check_row(int row);
--- a/src/term.c
+++ b/src/term.c
@@ -817,6 +817,14 @@ static struct builtin_term builtin_termc
     {(int)KS_MS,	"y"},
     {(int)KS_UT,	"y"},
     {(int)KS_LE,	"\b"},
+    {(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")},
+#  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
 #  ifdef TERMINFO
     {(int)KS_CM,	IF_EB("\033[%i%p1%d;%p2%dH",
 						  ESC_STR "[%i%p1%d;%p2%dH")},
@@ -840,6 +848,8 @@ static struct builtin_term builtin_termc
     {(int)KS_CIE,	"\007"},
     {(int)KS_TS,	IF_EB("\033]2;", ESC_STR "]2;")},
     {(int)KS_FS,	"\007"},
+    {(int)KS_CSC,	IF_EB("\033]12;", ESC_STR "]12;")},
+    {(int)KS_CEC,	"\007"},
 #  ifdef TERMINFO
     {(int)KS_CWS,	IF_EB("\033[8;%p1%d;%p2%dt",
 						  ESC_STR "[8;%p1%d;%p2%dt")},
@@ -1142,6 +1152,8 @@ static struct builtin_term builtin_termc
     {(int)KS_TE,	"[TE]"},
     {(int)KS_CIS,	"[CIS]"},
     {(int)KS_CIE,	"[CIE]"},
+    {(int)KS_CSC,	"[CSC]"},
+    {(int)KS_CEC,	"[CEC]"},
     {(int)KS_TS,	"[TS]"},
     {(int)KS_FS,	"[FS]"},
 #  ifdef TERMINFO
@@ -1569,6 +1581,7 @@ set_termname(char_u *term)
 				{KS_CAB,"AB"}, {KS_CAF,"AF"}, {KS_LE, "le"},
 				{KS_ND, "nd"}, {KS_OP, "op"}, {KS_CRV, "RV"},
 				{KS_CIS, "IS"}, {KS_CIE, "IE"},
+				{KS_CSC, "SC"}, {KS_CEC, "EC"},
 				{KS_TS, "ts"}, {KS_FS, "fs"},
 				{KS_CWP, "WP"}, {KS_CWS, "WS"},
 				{KS_CSI, "SI"}, {KS_CEI, "EI"},
@@ -2283,8 +2296,8 @@ term_is_8bit(char_u *name)
 
 /*
  * Translate terminal control chars from 7-bit to 8-bit:
- * <Esc>[ -> CSI
- * <Esc>] -> <M-C-]>
+ * <Esc>[ -> CSI  <M_C_[>
+ * <Esc>] -> OSC  <M-C-]>
  * <Esc>O -> <M-C-O>
  */
     static int
@@ -3655,7 +3668,7 @@ cursor_off(void)
  * Set cursor shape to match Insert or Replace mode.
  */
     void
-term_cursor_shape(void)
+term_cursor_mode(int forced)
 {
     static int showing_mode = NORMAL;
     char_u *p;
@@ -3667,7 +3680,7 @@ term_cursor_shape(void)
 
     if ((State & REPLACE) == REPLACE)
     {
-	if (showing_mode != REPLACE)
+	if (forced || showing_mode != REPLACE)
 	{
 	    if (*T_CSR != NUL)
 		p = T_CSR;	/* Replace mode cursor */
@@ -3682,18 +3695,55 @@ term_cursor_shape(void)
     }
     else if (State & INSERT)
     {
-	if (showing_mode != INSERT && *T_CSI != NUL)
+	if ((forced || showing_mode != INSERT) && *T_CSI != NUL)
 	{
 	    out_str(T_CSI);	    /* Insert mode cursor */
 	    showing_mode = INSERT;
 	}
     }
-    else if (showing_mode != NORMAL)
+    else if (forced || showing_mode != NORMAL)
     {
 	out_str(T_CEI);		    /* non-Insert mode cursor */
 	showing_mode = NORMAL;
     }
 }
+
+# if defined(FEAT_TERMINAL) || defined(PROTO)
+    void
+term_cursor_color(char_u *color)
+{
+    if (*T_CSC != NUL)
+    {
+	out_str(T_CSC);			/* set cursor color start */
+	out_str_nf(color);
+	out_str(T_CEC);			/* set cursor color end */
+	out_flush();
+    }
+}
+
+    void
+term_cursor_blink(int blink)
+{
+    if (blink)
+	out_str(T_VS);
+    else
+	out_str(T_VE);
+    out_flush();
+}
+
+/*
+ * "shape" == 1: block, "shape" == 2: underline, "shape" == 3: vertical bar
+ */
+    void
+term_cursor_shape(int shape, int blink)
+{
+    if (*T_CSH != NUL)
+    {
+	OUT_STR(tgoto((char *)T_CSH, 0, shape * 2 - blink));
+	out_flush();
+    }
+}
+# endif
 #endif
 
 /*
--- a/src/term.h
+++ b/src/term.h
@@ -40,6 +40,7 @@ enum SpecialKey
     KS_VI,	/* cursor invisible */
     KS_VE,	/* cursor visible */
     KS_VS,	/* cursor very visible */
+    KS_CSH,	/* cursor shape */
     KS_ME,	/* normal mode */
     KS_MR,	/* reverse mode */
     KS_MD,	/* bold mode */
@@ -74,6 +75,8 @@ enum SpecialKey
     KS_ND,	/* cursor right */
     KS_CIS,	/* set icon text start */
     KS_CIE,	/* set icon text end */
+    KS_CSC,	/* set cursor color start */
+    KS_CEC,	/* set cursor color end */
     KS_TS,	/* set window title start (to status line)*/
     KS_FS,	/* set window title end (from status line) */
     KS_CWP,	/* set window position in pixels */
@@ -128,6 +131,7 @@ extern char_u *(term_strings[]);    /* c
 #define T_VI	(TERM_STR(KS_VI))	/* cursor invisible */
 #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_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 */
@@ -164,6 +168,8 @@ extern char_u *(term_strings[]);    /* c
 #define T_CIE	(TERM_STR(KS_CIE))	/* set icon text end */
 #define T_TS	(TERM_STR(KS_TS))	/* set window title start */
 #define T_FS	(TERM_STR(KS_FS))	/* set window title end */
+#define T_CSC	(TERM_STR(KS_CSC))	/* set cursor color start */
+#define T_CEC	(TERM_STR(KS_CEC))	/* set cursor color end */
 #define T_CWP	(TERM_STR(KS_CWP))	/* set window position */
 #define T_CGP	(TERM_STR(KS_CGP))	/* get window position */
 #define T_CWS	(TERM_STR(KS_CWS))	/* window size */
--- a/src/terminal.c
+++ b/src/terminal.c
@@ -36,9 +36,7 @@
  * that buffer, attributes come from the scrollback buffer tl_scrollback.
  *
  * TODO:
- * - support different cursor shapes, colors and attributes
- * - make term_getcursor() return type (none/block/bar/underline) and
- *   attributes (color, blink, etc.)
+ * - cursor shape/color/blink in the GUI
  * - Make argument list work on MS-Windows. #1954
  * - MS-Windows: no redraw for 'updatetime'  #1915
  * - To set BS correctly, check get_stty(); Pass the fd of the pty.
@@ -143,6 +141,9 @@ struct terminal_S {
 
     VTermPos	tl_cursor_pos;
     int		tl_cursor_visible;
+    int		tl_cursor_blink;
+    int		tl_cursor_shape;  /* 1: block, 2: underline, 3: bar */
+    char_u	*tl_cursor_color; /* NULL or allocated */
 
     int		tl_using_altscreen;
 };
@@ -155,6 +156,8 @@ struct terminal_S {
  */
 static term_T *first_term = NULL;
 
+/* Terminal active in terminal_loop(). */
+static term_T *in_terminal_loop = NULL;
 
 #define MAX_ROW 999999	    /* used for tl_dirty_row_end to update all rows */
 #define KEY_BUF_LEN 200
@@ -256,6 +259,7 @@ term_start(char_u *cmd, jobopt_T *opt, i
 	return;
     term->tl_dirty_row_end = MAX_ROW;
     term->tl_cursor_visible = TRUE;
+    term->tl_cursor_shape = VTERM_PROP_CURSORSHAPE_BLOCK;
     term->tl_finish = opt->jo_term_finish;
     ga_init2(&term->tl_scrollback, sizeof(sb_line_T), 300);
 
@@ -517,6 +521,7 @@ free_terminal(buf_T *buf)
     vim_free(term->tl_title);
     vim_free(term->tl_status_text);
     vim_free(term->tl_opencmd);
+    vim_free(term->tl_cursor_color);
     vim_free(term);
     buf->b_term = NULL;
 }
@@ -1158,6 +1163,35 @@ term_paste_register(int prev_c UNUSED)
     }
 }
 
+static int did_change_cursor = FALSE;
+
+    static void
+may_set_cursor_props(term_T *term)
+{
+    if (in_terminal_loop == term)
+    {
+	if (term->tl_cursor_color != NULL)
+	    term_cursor_color(term->tl_cursor_color);
+	else
+	    term_cursor_color((char_u *)"");
+	/* do both blink and shape+blink, in case setting shape does not work */
+	term_cursor_blink(term->tl_cursor_blink);
+	term_cursor_shape(term->tl_cursor_shape, term->tl_cursor_blink);
+    }
+}
+
+    static void
+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);
+    }
+}
+
 /*
  * Returns TRUE if the current window contains a terminal and we are sending
  * keys to the job.
@@ -1185,10 +1219,14 @@ terminal_loop(void)
 {
     int		c;
     int		termkey = 0;
+    int		ret;
+
+    in_terminal_loop = curbuf->b_term;
 
     if (*curwin->w_p_tk != NUL)
 	termkey = string_to_key(curwin->w_p_tk, TRUE);
     position_cursor(curwin, &curbuf->b_term->tl_cursor_pos);
+    may_set_cursor_props(curbuf->b_term);
 
     for (;;)
     {
@@ -1235,7 +1273,8 @@ terminal_loop(void)
 		{
 		    /* CTRL-\ CTRL-N : go to Terminal-Normal mode. */
 		    term_enter_normal_mode();
-		    return FAIL;
+		    ret = FAIL;
+		    goto theend;
 		}
 		/* Send both keys to the terminal. */
 		send_keys_to_term(curbuf->b_term, prev_c, TRUE);
@@ -1249,7 +1288,8 @@ terminal_loop(void)
 	    {
 		/* CTRL-W N : go to Terminal-Normal mode. */
 		term_enter_normal_mode();
-		return FAIL;
+		ret = FAIL;
+		goto theend;
 	    }
 	    else if (c == '"')
 	    {
@@ -1260,13 +1300,22 @@ terminal_loop(void)
 	    {
 		stuffcharReadbuff(Ctrl_W);
 		stuffcharReadbuff(c);
-		return OK;
+		ret = OK;
+		goto theend;
 	    }
 	}
 	if (send_keys_to_term(curbuf->b_term, c, TRUE) != OK)
-	    return OK;
+	{
+	    ret = OK;
+	    goto theend;
+	}
     }
-    return FAIL;
+    ret = FAIL;
+
+theend:
+    in_terminal_loop = NULL;
+    may_restore_cursor_props();
+    return ret;
 }
 
 /*
@@ -1303,7 +1352,7 @@ term_job_ended(job_T *job)
     static void
 may_toggle_cursor(term_T *term)
 {
-    if (curbuf == term->tl_buffer)
+    if (in_terminal_loop == term)
     {
 	if (term->tl_cursor_visible)
 	    cursor_on();
@@ -1385,6 +1434,22 @@ handle_settermprop(
 	    out_flush();
 	    break;
 
+	case VTERM_PROP_CURSORBLINK:
+	    term->tl_cursor_blink = value->boolean;
+	    may_set_cursor_props(term);
+	    break;
+
+	case VTERM_PROP_CURSORSHAPE:
+	    term->tl_cursor_shape = value->number;
+	    may_set_cursor_props(term);
+	    break;
+
+	case VTERM_PROP_CURSORCOLOR:
+	    vim_free(term->tl_cursor_color);
+	    term->tl_cursor_color = vim_strsave((char_u *)value->string);
+	    may_set_cursor_props(term);
+	    break;
+
 	case VTERM_PROP_ALTSCREEN:
 	    /* TODO: do anything else? */
 	    term->tl_using_altscreen = value->boolean;
@@ -2076,17 +2141,30 @@ f_term_getattr(typval_T *argvars, typval
 f_term_getcursor(typval_T *argvars, typval_T *rettv)
 {
     buf_T	*buf = term_get_buf(argvars);
+    term_T	*term;
     list_T	*l;
+    dict_T	*d;
 
     if (rettv_list_alloc(rettv) == FAIL)
 	return;
     if (buf == NULL)
 	return;
+    term = buf->b_term;
 
     l = rettv->vval.v_list;
-    list_append_number(l, buf->b_term->tl_cursor_pos.row + 1);
-    list_append_number(l, buf->b_term->tl_cursor_pos.col + 1);
-    list_append_number(l, buf->b_term->tl_cursor_visible);
+    list_append_number(l, term->tl_cursor_pos.row + 1);
+    list_append_number(l, term->tl_cursor_pos.col + 1);
+
+    d = dict_alloc();
+    if (d != NULL)
+    {
+	dict_add_nr_str(d, "visible", term->tl_cursor_visible, NULL);
+	dict_add_nr_str(d, "blink", term->tl_cursor_blink, NULL);
+	dict_add_nr_str(d, "shape", term->tl_cursor_shape, NULL);
+	dict_add_nr_str(d, "color", 0L, term->tl_cursor_color == NULL
+				       ? (char_u *)"" : term->tl_cursor_color);
+	list_append_dict(l, d);
+    }
 }
 
 /*
--- a/src/ui.c
+++ b/src/ui.c
@@ -1942,14 +1942,14 @@ read_error_exit(void)
  * May update the shape of the cursor.
  */
     void
-ui_cursor_shape(void)
+ui_cursor_shape_forced(int forced)
 {
 # ifdef FEAT_GUI
     if (gui.in_use)
 	gui_update_cursor_later();
     else
 # endif
-	term_cursor_shape();
+	term_cursor_mode(forced);
 
 # ifdef MCH_CURSOR_SHAPE
     mch_update_cursor();
@@ -1959,6 +1959,12 @@ ui_cursor_shape(void)
     conceal_check_cursur_line();
 # endif
 }
+
+    void
+ui_cursor_shape(void)
+{
+    ui_cursor_shape_forced(FALSE);
+}
 #endif
 
 #if defined(FEAT_CLIPBOARD) || defined(FEAT_GUI) || defined(FEAT_RIGHTLEFT) \
--- 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 */
 /**/
+    918,
+/**/
     917,
 /**/
     916,