From fa1e90cd4d1bebd66da22df4625f70963f091f17 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 6 Apr 2019 17:47:40 +0200 Subject: [PATCH] patch 8.1.1125: libvterm does not handle the window position report Problem: Libvterm does not handle the window position report. Solution: Let libvterm call the fallback CSI handler when not handling CSI sequence. Handle the window position report in Vim. --- src/evalfunc.c | 40 ++++----------------- src/libvterm/src/state.c | 10 ++++++ src/proto/ui.pro | 1 + src/terminal.c | 68 +++++++++++++++++++++++++++++++---- src/testdir/test_terminal.vim | 33 +++++++++++++++++ src/ui.c | 21 +++++++++++ src/version.c | 2 ++ 7 files changed, 135 insertions(+), 40 deletions(-) diff --git a/src/evalfunc.c b/src/evalfunc.c index 83c4b9447..0f126d773 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -5985,20 +5985,14 @@ f_getwinpos(typval_T *argvars UNUSED, typval_T *rettv) if (rettv_list_alloc(rettv) == FAIL) return; -#ifdef FEAT_GUI - if (gui.in_use) - (void)gui_mch_get_winpos(&x, &y); -# if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE) - else -# endif -#endif -#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE) +#if defined(FEAT_GUI) || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) { varnumber_T timeout = 100; if (argvars[0].v_type != VAR_UNKNOWN) timeout = tv_get_number(&argvars[0]); - term_get_winpos(&x, &y, timeout); + + (void)ui_get_winpos(&x, &y, timeout); } #endif list_append_number(rettv->vval.v_list, (varnumber_T)x); @@ -6013,21 +6007,11 @@ f_getwinpos(typval_T *argvars UNUSED, typval_T *rettv) f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv) { rettv->vval.v_number = -1; -#ifdef FEAT_GUI - if (gui.in_use) - { - int x, y; - - if (gui_mch_get_winpos(&x, &y) == OK) - rettv->vval.v_number = x; - return; - } -#endif -#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE) +#if defined(FEAT_GUI) || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) { int x, y; - if (term_get_winpos(&x, &y, (varnumber_T)100) == OK) + if (ui_get_winpos(&x, &y, 100) == OK) rettv->vval.v_number = x; } #endif @@ -6040,21 +6024,11 @@ f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv) f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv) { rettv->vval.v_number = -1; -#ifdef FEAT_GUI - if (gui.in_use) - { - int x, y; - - if (gui_mch_get_winpos(&x, &y) == OK) - rettv->vval.v_number = y; - return; - } -#endif -#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE) +#if defined(FEAT_GUI) || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) { int x, y; - if (term_get_winpos(&x, &y, (varnumber_T)100) == OK) + if (ui_get_winpos(&x, &y, 100) == OK) rettv->vval.v_number = y; } #endif diff --git a/src/libvterm/src/state.c b/src/libvterm/src/state.c index 8b02093bb..a1261455f 100644 --- a/src/libvterm/src/state.c +++ b/src/libvterm/src/state.c @@ -905,6 +905,7 @@ static int on_csi(const char *leader, const long args[], int argcount, const cha int leader_byte = 0; int intermed_byte = 0; VTermPos oldpos = state->pos; + int handled = 1; /* Some temporaries for later code */ int count, val; @@ -1416,6 +1417,10 @@ static int on_csi(const char *leader, const long args[], int argcount, const cha case 8: /* CSI 8 ; rows ; cols t set size */ if (argcount == 3) on_resize(CSI_ARG(args[1]), CSI_ARG(args[2]), state); + break; + default: + handled = 0; + break; } break; @@ -1450,6 +1455,11 @@ static int on_csi(const char *leader, const long args[], int argcount, const cha break; default: + handled = 0; + break; + } + + if (!handled) { if(state->fallbacks && state->fallbacks->csi) if((*state->fallbacks->csi)(leader, args, argcount, intermed, command, state->fbdata)) return 1; diff --git a/src/proto/ui.pro b/src/proto/ui.pro index 774a30896..26cfd4715 100644 --- a/src/proto/ui.pro +++ b/src/proto/ui.pro @@ -11,6 +11,7 @@ void suspend_shell(void); int ui_get_shellsize(void); void ui_set_shellsize(int mustset); void ui_new_shellsize(void); +int ui_get_winpos(int *x, int *y, varnumber_T timeout); void ui_breakcheck(void); void ui_breakcheck_force(int force); void clip_init(int can_use); diff --git a/src/terminal.c b/src/terminal.c index 26e3deb47..34dea0312 100644 --- a/src/terminal.c +++ b/src/terminal.c @@ -3842,14 +3842,68 @@ parse_osc(const char *command, size_t cmdlen, void *user) return 1; } +/* + * Called by libvterm when it cannot recognize a CSI sequence. + * We recognize the window position report. + */ + static int +parse_csi( + const char *leader UNUSED, + const long args[], + int argcount, + const char *intermed UNUSED, + char command, + void *user) +{ + term_T *term = (term_T *)user; + char buf[100]; + int len; + int x = 0; + int y = 0; + win_T *wp; + + // We recognize only CSI 13 t + if (command != 't' || argcount != 1 || args[0] != 13) + return 0; // not handled + + // When getting the window position fails it results in zero/zero. + (void)ui_get_winpos(&x, &y, (varnumber_T)100); + + FOR_ALL_WINDOWS(wp) + if (wp->w_buffer == term->tl_buffer) + break; + if (wp != NULL) + { +#ifdef FEAT_GUI + if (gui.in_use) + { + x += wp->w_wincol * gui.char_width; + y += W_WINROW(wp) * gui.char_height; + } + else +#endif + { + // We roughly estimate the position of the terminal window inside + // the Vim window by assuing a 10 x 7 character cell. + x += wp->w_wincol * 7; + y += W_WINROW(wp) * 10; + } + } + + len = vim_snprintf(buf, 100, "\x1b[3;%d;%dt", x, y); + channel_send(term->tl_job->jv_channel, get_tty_part(term), + (char_u *)buf, len, NULL); + return 1; +} + static VTermParserCallbacks parser_fallbacks = { - NULL, /* text */ - NULL, /* control */ - NULL, /* escape */ - NULL, /* csi */ - parse_osc, /* osc */ - NULL, /* dcs */ - NULL /* resize */ + NULL, // text + NULL, // control + NULL, // escape + parse_csi, // csi + parse_osc, // osc + NULL, // dcs + NULL // resize }; /* diff --git a/src/testdir/test_terminal.vim b/src/testdir/test_terminal.vim index cae5439b6..4c84a432a 100644 --- a/src/testdir/test_terminal.vim +++ b/src/testdir/test_terminal.vim @@ -1887,3 +1887,36 @@ func Test_terminal_statusline() au! BufLeave set statusline= endfunc + +func Test_terminal_getwinpos() + " split, go to the bottom-right window + split + wincmd j + set splitright + + call writefile([ + \ 'echo getwinpos()', + \ ], 'XTest_getwinpos') + let buf = RunVimInTerminal('-S XTest_getwinpos', {'cols': 60}) + call term_wait(buf) + + " Find the output of getwinpos() in the bottom line. + let rows = term_getsize(buf)[0] + call WaitForAssert({-> assert_match('\[\d\+, \d\+\]', term_getline(buf, rows))}) + let line = term_getline(buf, rows) + let xpos = str2nr(substitute(line, '\[\(\d\+\), \d\+\]', '\1', '')) + let ypos = str2nr(substitute(line, '\[\d\+, \(\d\+\)\]', '\1', '')) + + " Position must be bigger than the getwinpos() result of Vim itself. + let [xroot, yroot] = getwinpos() + call assert_inrange(xroot + 2, xroot + 1000, xpos) + call assert_inrange(yroot + 2, yroot + 1000, ypos) + + call term_wait(buf) + call term_sendkeys(buf, ":q\") + call StopVimInTerminal(buf) + call delete('XTest_getwinpos') + exe buf . 'bwipe!' + set splitright& + only! +endfunc diff --git a/src/ui.c b/src/ui.c index 5c9077c05..44328521f 100644 --- a/src/ui.c +++ b/src/ui.c @@ -627,6 +627,27 @@ ui_new_shellsize(void) } } +#if (defined(FEAT_EVAL) \ + && (defined(FEAT_GUI) \ + || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)))) \ + || defined(PROTO) +/* + * Get the window position in pixels, if possible. + * Return FAIL when not possible. + */ + int +ui_get_winpos(int *x, int *y, varnumber_T timeout) +{ +# ifdef FEAT_GUI + if (gui.in_use) + return gui_mch_get_winpos(x, y); +# endif +# if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE) + return term_get_winpos(x, y, timeout); +# endif +} +#endif + void ui_breakcheck(void) { diff --git a/src/version.c b/src/version.c index 8e3e63973..f9dd7cc21 100644 --- a/src/version.c +++ b/src/version.c @@ -771,6 +771,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1125, /**/ 1124, /**/ -- 2.50.1