summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2017-08-12 19:51:41 +0200
committerBram Moolenaar <Bram@vim.org>2017-08-12 19:51:41 +0200
commit3cd43ccccb03b2e68df9c8a344a87e51c007c656 (patch)
tree51e41f2ba0520be2c6f4b0753538259545feca05
parent589b1109c55409baf27f79920d8ffc95111eaa01 (diff)
downloadvim-git-3cd43ccccb03b2e68df9c8a344a87e51c007c656.tar.gz
patch 8.0.0918: cannot get terminal window cursor shape or attributesv8.0.0918
Problem: Cannot get terminal window cursor shape or attributes. Solution: Support cursor shape, attributes and color.
-rw-r--r--runtime/doc/eval.txt24
-rw-r--r--src/feature.h3
-rw-r--r--src/libvterm/include/vterm.h3
-rw-r--r--src/libvterm/src/state.c5
-rw-r--r--src/libvterm/src/vterm.c1
-rw-r--r--src/option.c3
-rw-r--r--src/proto/term.pro5
-rw-r--r--src/proto/ui.pro1
-rw-r--r--src/term.c62
-rw-r--r--src/term.h6
-rw-r--r--src/terminal.c102
-rw-r--r--src/ui.c10
-rw-r--r--src/version.c2
13 files changed, 196 insertions, 31 deletions
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index bf8bae4f2..de142ee80 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -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()*
diff --git a/src/feature.h b/src/feature.h
index f77ffd6fe..ae3859b81 100644
--- 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.
diff --git a/src/libvterm/include/vterm.h b/src/libvterm/include/vterm.h
index cd7b1f772..50a840a31 100644
--- 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 {
diff --git a/src/libvterm/src/state.c b/src/libvterm/src/state.c
index 8f8909e2f..88c259c34 100644
--- a/src/libvterm/src/state.c
+++ b/src/libvterm/src/state.c
@@ -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:
diff --git a/src/libvterm/src/vterm.c b/src/libvterm/src/vterm.c
index 2931e5202..b2a7240ff 100644
--- a/src/libvterm/src/vterm.c
+++ b/src/libvterm/src/vterm.c
@@ -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 */
}
diff --git a/src/option.c b/src/option.c
index 3b2949c34..55f0ad137 100644
--- 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)
diff --git a/src/proto/term.pro b/src/proto/term.pro
index 57188e1da..63e644890 100644
--- 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);
diff --git a/src/proto/ui.pro b/src/proto/ui.pro
index 47c0fef68..4cf87b44f 100644
--- 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);
diff --git a/src/term.c b/src/term.c
index 1fa9dfde6..80545ad81 100644
--- a/src/term.c
+++ b/src/term.c
@@ -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
/*
diff --git a/src/term.h b/src/term.h
index be01cb5ad..66ad4c66c 100644
--- 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[]); /* 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 */
diff --git a/src/terminal.c b/src/terminal.c
index e8727ee6e..fe1d5da2f 100644
--- 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, 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);
+ }
}
/*
diff --git a/src/ui.c b/src/ui.c
index 90e961cac..907390e6b 100644
--- 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) \
diff --git a/src/version.c b/src/version.c
index 3bd461af0..c3918a2dd 100644
--- 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,