]> granicus.if.org Git - vim/commitdiff
patch 8.1.1125: libvterm does not handle the window position report v8.1.1125
authorBram Moolenaar <Bram@vim.org>
Sat, 6 Apr 2019 15:47:40 +0000 (17:47 +0200)
committerBram Moolenaar <Bram@vim.org>
Sat, 6 Apr 2019 15:47:40 +0000 (17:47 +0200)
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
src/libvterm/src/state.c
src/proto/ui.pro
src/terminal.c
src/testdir/test_terminal.vim
src/ui.c
src/version.c

index 83c4b9447fb09bd22427305a9e082c1132147e65..0f126d7734f2c0f862bc81785a111333294d25a5 100644 (file)
@@ -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
index 8b02093bb907ce440176fd7c009c8e4e1233e065..a1261455f82b0134837ba23c7382f564fcdef47f 100644 (file)
@@ -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;
index 774a308966efc254d65c54c1bd4aec4657423425..26cfd4715ac6adb29f13db61815d46ef96b6f51f 100644 (file)
@@ -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);
index 26e3deb47bb3d366166488f1ecd5683b5e56a37f..34dea0312c327c353c1b9e131bcb788438e240ac 100644 (file)
@@ -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
 };
 
 /*
index cae5439b6a9d9070da08f83f904280970dcd3cbf..4c84a432aacfe6144c27c6a8d98c2f81e5d8f015 100644 (file)
@@ -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
index 5c9077c057d17aa289f0da4da9a35a17ddd205a3..44328521f5b52d9f30cd463ad90e46a7f6cae238 100644 (file)
--- 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)
 {
index 8e3e639739d1274b71ae3bb659a275718301ba1a..f9dd7cc215c7d01517a9bde490a973db6500c49b 100644 (file)
@@ -771,6 +771,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1125,
 /**/
     1124,
 /**/