changeset 16241:c1698187c482 v8.1.1125

patch 8.1.1125: libvterm does not handle the window position report commit https://github.com/vim/vim/commit/fa1e90cd4d1bebd66da22df4625f70963f091f17 Author: Bram Moolenaar <Bram@vim.org> Date: Sat Apr 6 17:47:40 2019 +0200 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.
author Bram Moolenaar <Bram@vim.org>
date Sat, 06 Apr 2019 18:00:05 +0200
parents 96666592655f
children eca5defefa66
files src/evalfunc.c src/libvterm/src/state.c src/proto/ui.pro src/terminal.c src/testdir/test_terminal.vim src/ui.c src/version.c
diffstat 7 files changed, 135 insertions(+), 40 deletions(-) [+]
line wrap: on
line diff
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -5985,20 +5985,14 @@ f_getwinpos(typval_T *argvars UNUSED, ty
 
     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, ty
 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_getwinposx(typval_T *argvars UNUSED, t
 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
--- a/src/libvterm/src/state.c
+++ b/src/libvterm/src/state.c
@@ -905,6 +905,7 @@ static int on_csi(const char *leader, co
   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, co
       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, co
     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;
--- 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);
--- a/src/terminal.c
+++ b/src/terminal.c
@@ -3842,14 +3842,68 @@ parse_osc(const char *command, size_t cm
     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
 };
 
 /*
--- 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\<CR>")
+  call StopVimInTerminal(buf)
+  call delete('XTest_getwinpos')
+  exe buf . 'bwipe!'
+  set splitright&
+  only!
+endfunc
--- 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)
 {
--- a/src/version.c
+++ b/src/version.c
@@ -772,6 +772,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    1125,
+/**/
     1124,
 /**/
     1123,