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.
diff --git a/src/evalfunc.c b/src/evalfunc.c
index 83c4b94..0f126d7 100644
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -5985,20 +5985,14 @@
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_getwinposx(typval_T *argvars UNUSED, typval_T *rettv)
{
rettv->vval.v_number = -1;
-#ifdef FEAT_GUI
- if (gui.in_use)
+#if defined(FEAT_GUI) || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE))
{
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)
- {
- 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_getwinposy(typval_T *argvars UNUSED, typval_T *rettv)
{
rettv->vval.v_number = -1;
-#ifdef FEAT_GUI
- if (gui.in_use)
+#if defined(FEAT_GUI) || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE))
{
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)
- {
- 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 8b02093..a126145 100644
--- a/src/libvterm/src/state.c
+++ b/src/libvterm/src/state.c
@@ -905,6 +905,7 @@
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 @@
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 @@
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 774a308..26cfd47 100644
--- a/src/proto/ui.pro
+++ b/src/proto/ui.pro
@@ -11,6 +11,7 @@
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 26e3deb..34dea03 100644
--- a/src/terminal.c
+++ b/src/terminal.c
@@ -3842,14 +3842,68 @@
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 cae5439..4c84a43 100644
--- a/src/testdir/test_terminal.vim
+++ b/src/testdir/test_terminal.vim
@@ -1887,3 +1887,36 @@
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\<CR>")
+ 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 5c9077c..4432852 100644
--- a/src/ui.c
+++ b/src/ui.c
@@ -627,6 +627,27 @@
}
}
+#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 8e3e639..f9dd7cc 100644
--- a/src/version.c
+++ b/src/version.c
@@ -772,6 +772,8 @@
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 1125,
+/**/
1124,
/**/
1123,