# HG changeset patch # User Bram Moolenaar # Date 1592056804 -7200 # Node ID 2616c5a337e075269252a8b449b5a27025072c41 # Parent 0978840587194e53a7df1d3ab2d944a782e6036f patch 8.2.0970: terminal properties are not available in Vim script Commit: https://github.com/vim/vim/commit/0c0eddd3ddd266bcc2036362fae7b2b8b9d2c7bf Author: Bram Moolenaar Date: Sat Jun 13 15:47:25 2020 +0200 patch 8.2.0970: terminal properties are not available in Vim script Problem: Terminal properties are not available in Vim script. Solution: Add the terminalprops() function. diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -2194,7 +2194,8 @@ v:termresponse The escape sequence retur 'c', with only digits and ';' in between. When this option is set, the TermResponse autocommand event is fired, so that you can react to the response from the - terminal. + terminal. You can use |terminalprops()| to see what Vim + figured out about the terminal. The response from a new xterm is: "[> Pp ; Pv ; Pc c". Pp is the terminal type: 0 for vt100 and 1 for vt220. Pv is the patch level (since this was introduced in patch 95, it's @@ -2870,6 +2871,7 @@ term_setsize({buf}, {rows}, {cols}) none set the size of a terminal term_start({cmd} [, {options}]) Number open a terminal window and run a job term_wait({buf} [, {time}]) Number wait for screen to be updated +terminalprops() Dict properties of the terminal test_alloc_fail({id}, {countdown}, {repeat}) none make memory allocation fail test_autochdir() none enable 'autochdir' during startup @@ -10390,6 +10392,41 @@ tempname() *tempname()* *temp-file-n term_ functions are documented here: |terminal-function-details| + +terminalprops() *terminalprops()* + Returns a dictionary with properties of the terminal that Vim + detected from the response to |t_RV| request. See + |v:termresponse| for the response itself. If |v:termresponse| + is empty most values here will be 'u' for unknown. + cursor_style wether sending |t_RS| works ** + cursor_blink_mode wether sending |t_RC| works ** + underline_rgb whether |t_8u| works ** + mouse mouse type supported + + ** value 'u' for unknown, 'y' for yes, 'n' for no + + If the |+termresponse| feature is missing then the result is + an empty dictionary. + + If "cursor_style" is 'y' then |t_RS| will be send to request the + current cursor style. + If "cursor_blink_mode" is 'y' then |t_RC| will be send to + request the cursor blink status. + "cursor_style" and "cursor_blink_mode" are also set if |t_u7| + is not empty, Vim will detect the working of sending |t_RS| + and |t_RC| on startup. + + When "underline_rgb" is not 'y', then |t_8u| will be made empty. + This avoids sending it to xterm, which would clear the colors. + + For "mouse" the value 'u' is unknown + + Also see: + - 'ambiwidth' - detected by using |t_u7|. + - |v:termstyleresp| and |v:termblinkresp| for the response to + |t_RS| and |t_RC|. + + test_ functions are documented here: |test-functions-details| diff --git a/runtime/doc/testing.txt b/runtime/doc/testing.txt --- a/runtime/doc/testing.txt +++ b/runtime/doc/testing.txt @@ -165,6 +165,8 @@ test_override({name}, {val}) *test_ov terminals no_wait_return set the "no_wait_return" flag. Not restored with "ALL". + term_props reset all terminal properties when the version + string is detected ALL clear all overrides ({val} is not used) "starting" is to be used when a test should behave like diff --git a/runtime/doc/usr_41.txt b/runtime/doc/usr_41.txt --- a/runtime/doc/usr_41.txt +++ b/runtime/doc/usr_41.txt @@ -1148,6 +1148,7 @@ Various: *various-functions* getimstatus() check if IME status is active interrupt() interrupt script execution windowsversion() get MS-Windows version + terminalprops() properties of the terminal libcall() call a function in an external library libcallnr() idem, returning a number diff --git a/src/evalfunc.c b/src/evalfunc.c --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -944,6 +944,7 @@ static funcentry_T global_functions[] = {"term_setsize", 3, 3, FEARG_1, ret_void, TERM_FUNC(f_term_setsize)}, {"term_start", 1, 2, FEARG_1, ret_number, TERM_FUNC(f_term_start)}, {"term_wait", 1, 2, FEARG_1, ret_void, TERM_FUNC(f_term_wait)}, + {"terminalprops", 0, 0, 0, ret_dict_string, f_terminalprops}, {"test_alloc_fail", 3, 3, FEARG_1, ret_void, f_test_alloc_fail}, {"test_autochdir", 0, 0, 0, ret_void, f_test_autochdir}, {"test_feedinput", 1, 1, FEARG_1, ret_void, f_test_feedinput}, diff --git a/src/globals.h b/src/globals.h --- a/src/globals.h +++ b/src/globals.h @@ -1839,6 +1839,7 @@ EXTERN int disable_redraw_for_testing I EXTERN int ignore_redraw_flag_for_testing INIT(= FALSE); EXTERN int nfa_fail_for_testing INIT(= FALSE); EXTERN int no_query_mouse_for_testing INIT(= FALSE); +EXTERN int reset_term_props_on_termresponse INIT(= FALSE); EXTERN int in_free_unref_items INIT(= FALSE); #endif diff --git a/src/main.c b/src/main.c --- a/src/main.c +++ b/src/main.c @@ -407,6 +407,10 @@ main init_highlight(TRUE, FALSE); // set the default highlight groups TIME_MSG("init highlight"); +#if defined(FEAT_TERMRESPONSE) + init_term_props(TRUE); +#endif + #ifdef FEAT_EVAL // Set the break level after the terminal is initialized. debug_break_level = params.use_debug_break_level; diff --git a/src/proto/term.pro b/src/proto/term.pro --- a/src/proto/term.pro +++ b/src/proto/term.pro @@ -1,6 +1,8 @@ /* term.c */ guicolor_T termgui_get_color(char_u *name); guicolor_T termgui_mch_get_rgb(guicolor_T color); +void init_term_props(int all); +void f_terminalprops(typval_T *argvars, typval_T *rettv); void set_color_count(int nr); int set_termname(char_u *term); void getlinecol(long *cp, long *rp); diff --git a/src/term.c b/src/term.c --- a/src/term.c +++ b/src/term.c @@ -1470,7 +1470,7 @@ static termprop_T term_props[TPR_COUNT]; * When "all" is FALSE only set those that are detected from the version * response. */ - static void + void init_term_props(int all) { int i; @@ -1490,6 +1490,29 @@ init_term_props(int all) } #endif +#if defined(FEAT_EVAL) || defined(PROTO) + void +f_terminalprops(typval_T *argvars UNUSED, typval_T *rettv) +{ +# ifdef FEAT_TERMRESPONSE + int i; +# endif + + if (rettv_dict_alloc(rettv) != OK) + return; +# ifdef FEAT_TERMRESPONSE + for (i = 0; i < TPR_COUNT; ++i) + { + char_u value[2]; + + value[0] = term_props[i].tpr_status; + value[1] = NUL; + dict_add_string(rettv->vval.v_dict, term_props[i].tpr_name, value); + } +# endif +} +#endif + static struct builtin_term * find_builtin_term(char_u *term) { @@ -3676,8 +3699,6 @@ check_terminal_behavior(void) { int did_send = FALSE; - init_term_props(TRUE); - if (!can_get_termresponse() || starting != 0 || *T_U7 == NUL) return; @@ -4516,7 +4537,8 @@ handle_version_response(int first, int * // Reset terminal properties that are set based on the termresponse. // Mainly useful for tests that send the termresponse multiple times. - init_term_props(FALSE); + // For testing all props can be reset. + init_term_props(reset_term_props_on_termresponse); // If this code starts with CSI, you can bet that the // terminal uses 8-bit codes. diff --git a/src/testdir/test_termcodes.vim b/src/testdir/test_termcodes.vim --- a/src/testdir/test_termcodes.vim +++ b/src/testdir/test_termcodes.vim @@ -922,6 +922,7 @@ endfunc func Test_xx01_term_style_response() " Termresponse is only parsed when t_RV is not empty. set t_RV=x + call test_override('term_props', 1) " send the termresponse to trigger requesting the XT codes let seq = "\[>41;337;0c" @@ -932,7 +933,15 @@ func Test_xx01_term_style_response() call feedkeys(seq, 'Lx!') call assert_equal(seq, v:termstyleresp) + call assert_equal(#{ + \ cursor_style: 'u', + \ cursor_blink_mode: 'u', + \ underline_rgb: 'u', + \ mouse: 's' + \ }, terminalprops()) + set t_RV= + call test_override('term_props', 0) endfunc " This checks the iTerm2 version response. @@ -941,6 +950,7 @@ endfunc func Test_xx02_iTerm2_response() " Termresponse is only parsed when t_RV is not empty. set t_RV=x + call test_override('term_props', 1) " Old versions of iTerm2 used a different style term response. set ttymouse=xterm @@ -957,7 +967,15 @@ func Test_xx02_iTerm2_response() call assert_equal(seq, v:termresponse) call assert_equal('sgr', &ttymouse) + call assert_equal(#{ + \ cursor_style: 'n', + \ cursor_blink_mode: 'u', + \ underline_rgb: 'u', + \ mouse: 's' + \ }, terminalprops()) + set t_RV= + call test_override('term_props', 0) endfunc " This checks the libvterm version response. @@ -966,6 +984,7 @@ endfunc func Test_xx03_libvterm_response() " Termresponse is only parsed when t_RV is not empty. set t_RV=x + call test_override('term_props', 1) set ttymouse=xterm call test_option_not_set('ttymouse') @@ -974,7 +993,15 @@ func Test_xx03_libvterm_response() call assert_equal(seq, v:termresponse) call assert_equal('sgr', &ttymouse) + call assert_equal(#{ + \ cursor_style: 'n', + \ cursor_blink_mode: 'u', + \ underline_rgb: 'u', + \ mouse: 's' + \ }, terminalprops()) + set t_RV= + call test_override('term_props', 0) endfunc " This checks the Mac Terminal.app version response. @@ -983,6 +1010,7 @@ endfunc func Test_xx04_Mac_Terminal_response() " Termresponse is only parsed when t_RV is not empty. set t_RV=x + call test_override('term_props', 1) set ttymouse=xterm call test_option_not_set('ttymouse') @@ -991,10 +1019,18 @@ func Test_xx04_Mac_Terminal_response() call assert_equal(seq, v:termresponse) call assert_equal('sgr', &ttymouse) + call assert_equal(#{ + \ cursor_style: 'n', + \ cursor_blink_mode: 'u', + \ underline_rgb: 'y', + \ mouse: 's' + \ }, terminalprops()) + " Reset is_not_xterm and is_mac_terminal. set t_RV= set term=xterm set t_RV=x + call test_override('term_props', 0) endfunc " This checks the mintty version response. @@ -1003,6 +1039,7 @@ endfunc func Test_xx05_mintty_response() " Termresponse is only parsed when t_RV is not empty. set t_RV=x + call test_override('term_props', 1) set ttymouse=xterm call test_option_not_set('ttymouse') @@ -1011,7 +1048,15 @@ func Test_xx05_mintty_response() call assert_equal(seq, v:termresponse) call assert_equal('sgr', &ttymouse) + call assert_equal(#{ + \ cursor_style: 'n', + \ cursor_blink_mode: 'u', + \ underline_rgb: 'y', + \ mouse: 's' + \ }, terminalprops()) + set t_RV= + call test_override('term_props', 0) endfunc " This checks the screen version response. @@ -1020,6 +1065,7 @@ endfunc func Test_xx06_screen_response() " Termresponse is only parsed when t_RV is not empty. set t_RV=x + call test_override('term_props', 1) " Old versions of screen don't support SGR mouse mode. set ttymouse=xterm @@ -1037,7 +1083,15 @@ func Test_xx06_screen_response() call assert_equal(seq, v:termresponse) call assert_equal('sgr', &ttymouse) + call assert_equal(#{ + \ cursor_style: 'n', + \ cursor_blink_mode: 'n', + \ underline_rgb: 'y', + \ mouse: 's' + \ }, terminalprops()) + set t_RV= + call test_override('term_props', 0) endfunc " This checks the xterm version response. @@ -1046,6 +1100,7 @@ endfunc func Test_xx07_xterm_response() " Termresponse is only parsed when t_RV is not empty. set t_RV=x + call test_override('term_props', 1) " Do Terminal.app first to check that is_mac_terminal is reset. set ttymouse=xterm @@ -1066,6 +1121,13 @@ func Test_xx07_xterm_response() call assert_equal(seq, v:termresponse) call assert_equal('xterm', &ttymouse) + call assert_equal(#{ + \ cursor_style: 'n', + \ cursor_blink_mode: 'u', + \ underline_rgb: 'y', + \ mouse: 'u' + \ }, terminalprops()) + " xterm >= 95 < 277 "xterm2" set ttymouse=xterm call test_option_not_set('ttymouse') @@ -1074,6 +1136,13 @@ func Test_xx07_xterm_response() call assert_equal(seq, v:termresponse) call assert_equal('xterm2', &ttymouse) + call assert_equal(#{ + \ cursor_style: 'n', + \ cursor_blink_mode: 'u', + \ underline_rgb: 'u', + \ mouse: '2' + \ }, terminalprops()) + " xterm >= 277: "sgr" set ttymouse=xterm call test_option_not_set('ttymouse') @@ -1082,7 +1151,30 @@ func Test_xx07_xterm_response() call assert_equal(seq, v:termresponse) call assert_equal('sgr', &ttymouse) + call assert_equal(#{ + \ cursor_style: 'n', + \ cursor_blink_mode: 'u', + \ underline_rgb: 'u', + \ mouse: 's' + \ }, terminalprops()) + + " xterm >= 279: "sgr" and cursor_style not reset + set ttymouse=xterm + call test_option_not_set('ttymouse') + let seq = "\[>0;279;0c" + call feedkeys(seq, 'Lx!') + call assert_equal(seq, v:termresponse) + call assert_equal('sgr', &ttymouse) + + call assert_equal(#{ + \ cursor_style: 'u', + \ cursor_blink_mode: 'u', + \ underline_rgb: 'u', + \ mouse: 's' + \ }, terminalprops()) + set t_RV= + call test_override('term_props', 0) endfunc func Test_get_termcode() diff --git a/src/testing.c b/src/testing.c --- a/src/testing.c +++ b/src/testing.c @@ -854,6 +854,8 @@ f_test_override(typval_T *argvars, typva no_query_mouse_for_testing = val; else if (STRCMP(name, (char_u *)"no_wait_return") == 0) no_wait_return = val; + else if (STRCMP(name, (char_u *)"term_props") == 0) + reset_term_props_on_termresponse = val; else if (STRCMP(name, (char_u *)"ALL") == 0) { disable_char_avail_for_testing = FALSE; @@ -861,6 +863,7 @@ f_test_override(typval_T *argvars, typva ignore_redraw_flag_for_testing = FALSE; nfa_fail_for_testing = FALSE; no_query_mouse_for_testing = FALSE; + reset_term_props_on_termresponse = FALSE; if (save_starting >= 0) { starting = save_starting; diff --git a/src/version.c b/src/version.c --- 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 */ /**/ + 970, +/**/ 969, /**/ 968,