0
0
mirror of https://github.com/vim/vim.git synced 2025-09-23 03:43:49 -04:00

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.
This commit is contained in:
Bram Moolenaar
2017-08-12 19:51:41 +02:00
parent 589b1109c5
commit 3cd43ccccb
13 changed files with 196 additions and 31 deletions

View 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()*

View File

@@ -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.

View 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 {

View 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:

View 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 */
}

View 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)

View 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);

View 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);

View 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
/*

View 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 */

View 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);
}
}
/*

View File

@@ -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

View File

@@ -769,6 +769,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
918,
/**/
917,
/**/