]> granicus.if.org Git - vim/commitdiff
patch 8.0.0918: cannot get terminal window cursor shape or attributes v8.0.0918
authorBram Moolenaar <Bram@vim.org>
Sat, 12 Aug 2017 17:51:41 +0000 (19:51 +0200)
committerBram Moolenaar <Bram@vim.org>
Sat, 12 Aug 2017 17:51:41 +0000 (19:51 +0200)
Problem:    Cannot get terminal window cursor shape or attributes.
Solution:   Support cursor shape, attributes and color.

13 files changed:
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

index bf8bae4f2083107e70f2e985e97374a2904aac0e..de142ee8024e8c7f2361a25e08c737d0c0d9deae 100644 (file)
@@ -7939,13 +7939,19 @@ term_getattr({attr}, {what})                            *term_getattr()*
 
 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.
+               two numbers and a dictionary: [rows, cols, dict].
 
-               This is the cursor position of the terminal itself, not of the
-               Vim window.
+               "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_scrape()*
                    "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_start()*
                   "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_override()*
                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()*
index f77ffd6fe0fea491ab5dceb377b4a460bbbc5b41..ae3859b8153ae147ea70a179ae87520df47966a6 100644 (file)
 #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.
index cd7b1f77211ff0f9b648780392de336f01c10164..50a840a316f4bbd7485c963746ab9f3cecf231b2 100644 (file)
@@ -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 {
index 8f8909e2ff765d3a5b090bbf4d54aa7291f883c6..88c259c34e3d90a36b6ec6b583951d983c220c1c 100644 (file)
@@ -1504,6 +1504,10 @@ static int on_osc(const char *command, size_t cmdlen, void *user)
     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 *state, VTermProp prop, VTermValue *val)
   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:
index 2931e5202d2ab2277959d7ef7b0c76af848ca38c..b2a7240ffce187e1ed4a20390d852cc8b11627bf 100644 (file)
@@ -294,6 +294,7 @@ VTermValueType vterm_get_prop_type(VTermProp prop)
     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 */
 }
index 3b2949c347a4290a0d0b391ca5a469028cd2e454..55f0ad137101e2538aa5a5669ec4362629951878 100644 (file)
@@ -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)
index 57188e1daa23a7386f8cff0e680f2d29aad345cf..63e64489059c7bebb9ea173bafd52a57d782ab88 100644 (file)
@@ -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);
index 47c0fef684c62743b69debe014f04e9a85fb254d..4cf87b44f7577bf7a4a9c5a639fc65a5459ba564 100644 (file)
@@ -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);
index 1fa9dfde66a9f49b18fb2111a2db43bc7561d0b9..80545ad81b3ee69b3a164aa355d7434058eea082 100644 (file)
@@ -817,6 +817,14 @@ static struct builtin_term builtin_termcaps[] =
     {(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_termcaps[] =
     {(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_termcaps[] =
     {(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
 
 /*
index be01cb5ad6413cf0b5e876d87ee4b8a69920203a..66ad4c66c5ae7a49307f09dcd72477a67881019b 100644 (file)
@@ -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[]);    /* current terminal strings */
 #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[]);    /* current terminal strings */
 #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 */
index e8727ee6e5d7a189fc0848d837aa0490398279fb..fe1d5da2f546750bac315b9e95022e8e3e59b5c6 100644 (file)
@@ -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, int forceit)
        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_T *rettv)
 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);
+    }
 }
 
 /*
index 90e961cac210624224814a6d58d4ea64a1bb383c..907390e6b8c48bc68b878a04eff4ca68938c075a 100644 (file)
--- 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();
@@ -1958,6 +1958,12 @@ ui_cursor_shape(void)
 # ifdef FEAT_CONCEAL
     conceal_check_cursur_line();
 # endif
+}
+
+    void
+ui_cursor_shape(void)
+{
+    ui_cursor_shape_forced(FALSE);
 }
 #endif
 
index 3bd461af07f9c56514cc9aa47911cef2be1eb18a..c3918a2dd5fdcb7596f077c73cded7e1fa21edef 100644 (file)
@@ -769,6 +769,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    918,
 /**/
     917,
 /**/