Skip to content

Commit fa1e90c

Browse files
committed
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.
1 parent d9eefe3 commit fa1e90c

7 files changed

Lines changed: 135 additions & 40 deletions

File tree

src/evalfunc.c

Lines changed: 7 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -5985,20 +5985,14 @@ f_getwinpos(typval_T *argvars UNUSED, typval_T *rettv)
59855985

59865986
if (rettv_list_alloc(rettv) == FAIL)
59875987
return;
5988-
#ifdef FEAT_GUI
5989-
if (gui.in_use)
5990-
(void)gui_mch_get_winpos(&x, &y);
5991-
# if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5992-
else
5993-
# endif
5994-
#endif
5995-
#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5988+
#if defined(FEAT_GUI) || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE))
59965989
{
59975990
varnumber_T timeout = 100;
59985991

59995992
if (argvars[0].v_type != VAR_UNKNOWN)
60005993
timeout = tv_get_number(&argvars[0]);
6001-
term_get_winpos(&x, &y, timeout);
5994+
5995+
(void)ui_get_winpos(&x, &y, timeout);
60025996
}
60035997
#endif
60045998
list_append_number(rettv->vval.v_list, (varnumber_T)x);
@@ -6013,21 +6007,11 @@ f_getwinpos(typval_T *argvars UNUSED, typval_T *rettv)
60136007
f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv)
60146008
{
60156009
rettv->vval.v_number = -1;
6016-
#ifdef FEAT_GUI
6017-
if (gui.in_use)
6018-
{
6019-
int x, y;
6020-
6021-
if (gui_mch_get_winpos(&x, &y) == OK)
6022-
rettv->vval.v_number = x;
6023-
return;
6024-
}
6025-
#endif
6026-
#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
6010+
#if defined(FEAT_GUI) || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE))
60276011
{
60286012
int x, y;
60296013

6030-
if (term_get_winpos(&x, &y, (varnumber_T)100) == OK)
6014+
if (ui_get_winpos(&x, &y, 100) == OK)
60316015
rettv->vval.v_number = x;
60326016
}
60336017
#endif
@@ -6040,21 +6024,11 @@ f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv)
60406024
f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv)
60416025
{
60426026
rettv->vval.v_number = -1;
6043-
#ifdef FEAT_GUI
6044-
if (gui.in_use)
6045-
{
6046-
int x, y;
6047-
6048-
if (gui_mch_get_winpos(&x, &y) == OK)
6049-
rettv->vval.v_number = y;
6050-
return;
6051-
}
6052-
#endif
6053-
#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
6027+
#if defined(FEAT_GUI) || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE))
60546028
{
60556029
int x, y;
60566030

6057-
if (term_get_winpos(&x, &y, (varnumber_T)100) == OK)
6031+
if (ui_get_winpos(&x, &y, 100) == OK)
60586032
rettv->vval.v_number = y;
60596033
}
60606034
#endif

src/libvterm/src/state.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -905,6 +905,7 @@ static int on_csi(const char *leader, const long args[], int argcount, const cha
905905
int leader_byte = 0;
906906
int intermed_byte = 0;
907907
VTermPos oldpos = state->pos;
908+
int handled = 1;
908909

909910
/* Some temporaries for later code */
910911
int count, val;
@@ -1416,6 +1417,10 @@ static int on_csi(const char *leader, const long args[], int argcount, const cha
14161417
case 8: /* CSI 8 ; rows ; cols t set size */
14171418
if (argcount == 3)
14181419
on_resize(CSI_ARG(args[1]), CSI_ARG(args[2]), state);
1420+
break;
1421+
default:
1422+
handled = 0;
1423+
break;
14191424
}
14201425
break;
14211426

@@ -1450,6 +1455,11 @@ static int on_csi(const char *leader, const long args[], int argcount, const cha
14501455
break;
14511456

14521457
default:
1458+
handled = 0;
1459+
break;
1460+
}
1461+
1462+
if (!handled) {
14531463
if(state->fallbacks && state->fallbacks->csi)
14541464
if((*state->fallbacks->csi)(leader, args, argcount, intermed, command, state->fbdata))
14551465
return 1;

src/proto/ui.pro

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ void suspend_shell(void);
1111
int ui_get_shellsize(void);
1212
void ui_set_shellsize(int mustset);
1313
void ui_new_shellsize(void);
14+
int ui_get_winpos(int *x, int *y, varnumber_T timeout);
1415
void ui_breakcheck(void);
1516
void ui_breakcheck_force(int force);
1617
void clip_init(int can_use);

src/terminal.c

Lines changed: 61 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3842,14 +3842,68 @@ parse_osc(const char *command, size_t cmdlen, void *user)
38423842
return 1;
38433843
}
38443844

3845+
/*
3846+
* Called by libvterm when it cannot recognize a CSI sequence.
3847+
* We recognize the window position report.
3848+
*/
3849+
static int
3850+
parse_csi(
3851+
const char *leader UNUSED,
3852+
const long args[],
3853+
int argcount,
3854+
const char *intermed UNUSED,
3855+
char command,
3856+
void *user)
3857+
{
3858+
term_T *term = (term_T *)user;
3859+
char buf[100];
3860+
int len;
3861+
int x = 0;
3862+
int y = 0;
3863+
win_T *wp;
3864+
3865+
// We recognize only CSI 13 t
3866+
if (command != 't' || argcount != 1 || args[0] != 13)
3867+
return 0; // not handled
3868+
3869+
// When getting the window position fails it results in zero/zero.
3870+
(void)ui_get_winpos(&x, &y, (varnumber_T)100);
3871+
3872+
FOR_ALL_WINDOWS(wp)
3873+
if (wp->w_buffer == term->tl_buffer)
3874+
break;
3875+
if (wp != NULL)
3876+
{
3877+
#ifdef FEAT_GUI
3878+
if (gui.in_use)
3879+
{
3880+
x += wp->w_wincol * gui.char_width;
3881+
y += W_WINROW(wp) * gui.char_height;
3882+
}
3883+
else
3884+
#endif
3885+
{
3886+
// We roughly estimate the position of the terminal window inside
3887+
// the Vim window by assuing a 10 x 7 character cell.
3888+
x += wp->w_wincol * 7;
3889+
y += W_WINROW(wp) * 10;
3890+
}
3891+
}
3892+
3893+
len = vim_snprintf(buf, 100, "\x1b[3;%d;%dt", x, y);
3894+
channel_send(term->tl_job->jv_channel, get_tty_part(term),
3895+
(char_u *)buf, len, NULL);
3896+
return 1;
3897+
}
3898+
38453899
static VTermParserCallbacks parser_fallbacks = {
3846-
NULL, /* text */
3847-
NULL, /* control */
3848-
NULL, /* escape */
3849-
NULL, /* csi */
3850-
parse_osc, /* osc */
3851-
NULL, /* dcs */
3852-
NULL /* resize */
3900+
NULL, // text
3901+
NULL, // control
3902+
NULL, // escape
3903+
parse_csi, // csi
3904+
parse_osc, // osc
3905+
NULL, // dcs
3906+
NULL // resize
38533907
};
38543908

38553909
/*

src/testdir/test_terminal.vim

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1887,3 +1887,36 @@ func Test_terminal_statusline()
18871887
au! BufLeave
18881888
set statusline=
18891889
endfunc
1890+
1891+
func Test_terminal_getwinpos()
1892+
" split, go to the bottom-right window
1893+
split
1894+
wincmd j
1895+
set splitright
1896+
1897+
call writefile([
1898+
\ 'echo getwinpos()',
1899+
\ ], 'XTest_getwinpos')
1900+
let buf = RunVimInTerminal('-S XTest_getwinpos', {'cols': 60})
1901+
call term_wait(buf)
1902+
1903+
" Find the output of getwinpos() in the bottom line.
1904+
let rows = term_getsize(buf)[0]
1905+
call WaitForAssert({-> assert_match('\[\d\+, \d\+\]', term_getline(buf, rows))})
1906+
let line = term_getline(buf, rows)
1907+
let xpos = str2nr(substitute(line, '\[\(\d\+\), \d\+\]', '\1', ''))
1908+
let ypos = str2nr(substitute(line, '\[\d\+, \(\d\+\)\]', '\1', ''))
1909+
1910+
" Position must be bigger than the getwinpos() result of Vim itself.
1911+
let [xroot, yroot] = getwinpos()
1912+
call assert_inrange(xroot + 2, xroot + 1000, xpos)
1913+
call assert_inrange(yroot + 2, yroot + 1000, ypos)
1914+
1915+
call term_wait(buf)
1916+
call term_sendkeys(buf, ":q\<CR>")
1917+
call StopVimInTerminal(buf)
1918+
call delete('XTest_getwinpos')
1919+
exe buf . 'bwipe!'
1920+
set splitright&
1921+
only!
1922+
endfunc

src/ui.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -627,6 +627,27 @@ ui_new_shellsize(void)
627627
}
628628
}
629629

630+
#if (defined(FEAT_EVAL) \
631+
&& (defined(FEAT_GUI) \
632+
|| (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)))) \
633+
|| defined(PROTO)
634+
/*
635+
* Get the window position in pixels, if possible.
636+
* Return FAIL when not possible.
637+
*/
638+
int
639+
ui_get_winpos(int *x, int *y, varnumber_T timeout)
640+
{
641+
# ifdef FEAT_GUI
642+
if (gui.in_use)
643+
return gui_mch_get_winpos(x, y);
644+
# endif
645+
# if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
646+
return term_get_winpos(x, y, timeout);
647+
# endif
648+
}
649+
#endif
650+
630651
void
631652
ui_breakcheck(void)
632653
{

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -771,6 +771,8 @@ static char *(features[]) =
771771

772772
static int included_patches[] =
773773
{ /* Add new patch number below this line */
774+
/**/
775+
1125,
774776
/**/
775777
1124,
776778
/**/

0 commit comments

Comments
 (0)