Patch 8.1.1645

37 views
Skip to first unread message

Bram Moolenaar

unread,
Jul 7, 2019, 12:29:17 PM7/7/19
to vim...@googlegroups.com

Patch 8.1.1645
Problem: Cannot use a popup window for a balloon.
Solution: Add popup_beval(). Add the "mousemoved" property. Add the
screenpos() function.
Files: src/popupwin.c, src/proto/popupwin.pro, src/move.c,
src/proto/move.pro, src/beval.c, src/proto/beval.pro,
src/evalfunc.c, src/popupmnu.c, src/normal.c,
src/testdir/test_popupwin.vim, src/testdir/test_cursor_func.vim,
runtime/doc/popup.txt, runtime/doc/eval.txt,
runtime/doc/usr_41.txt,
src/testdir/dumps/Test_popupwin_beval_1.dump,
src/testdir/dumps/Test_popupwin_beval_2.dump,
src/testdir/dumps/Test_popupwin_beval_3.dump


*** ../vim-8.1.1644/src/popupwin.c 2019-07-05 20:17:18.928510171 +0200
--- src/popupwin.c 2019-07-07 16:59:37.333487332 +0200
***************
*** 168,173 ****
--- 168,202 ----
}

/*
+ * Used when popup options contain "mousemoved": set default moved values.
+ */
+ static void
+ set_mousemoved_values(win_T *wp)
+ {
+ wp->w_popup_mouse_row = mouse_row;
+ wp->w_popup_mouse_mincol = mouse_col;
+ wp->w_popup_mouse_maxcol = mouse_col;
+ }
+
+ /*
+ * Used when popup options contain "moved" with "word" or "WORD".
+ */
+ static void
+ set_mousemoved_columns(win_T *wp, int flags)
+ {
+ char_u *text;
+ int col;
+
+ if (find_word_under_cursor(mouse_row, mouse_col, TRUE, flags,
+ NULL, NULL, &text, &col) == OK)
+ {
+ wp->w_popup_mouse_mincol = col;
+ wp->w_popup_mouse_maxcol = col + STRLEN(text) - 1;
+ vim_free(text);
+ }
+ }
+
+ /*
* Return TRUE if "row"/"col" is on the border of the popup.
* The values are relative to the top-left corner.
*/
***************
*** 336,341 ****
--- 365,417 ----
}

static void
+ handle_moved_argument(win_T *wp, dictitem_T *di, int mousemoved)
+ {
+ if (di->di_tv.v_type == VAR_STRING && di->di_tv.vval.v_string != NULL)
+ {
+ char_u *s = di->di_tv.vval.v_string;
+ int flags = 0;
+
+ if (STRCMP(s, "word") == 0)
+ flags = FIND_IDENT | FIND_STRING;
+ else if (STRCMP(s, "WORD") == 0)
+ flags = FIND_STRING;
+ else if (STRCMP(s, "expr") == 0)
+ flags = FIND_IDENT | FIND_STRING | FIND_EVAL;
+ else if (STRCMP(s, "any") != 0)
+ semsg(_(e_invarg2), s);
+ if (flags != 0)
+ {
+ if (mousemoved)
+ set_mousemoved_columns(wp, flags);
+ else
+ set_moved_columns(wp, flags);
+ }
+ }
+ else if (di->di_tv.v_type == VAR_LIST
+ && di->di_tv.vval.v_list != NULL
+ && di->di_tv.vval.v_list->lv_len == 2)
+ {
+ list_T *l = di->di_tv.vval.v_list;
+ int mincol = tv_get_number(&l->lv_first->li_tv);
+ int maxcol = tv_get_number(&l->lv_first->li_next->li_tv);
+
+ if (mousemoved)
+ {
+ wp->w_popup_mouse_mincol = mincol;
+ wp->w_popup_mouse_maxcol = maxcol;
+ }
+ else
+ {
+ wp->w_popup_mincol = mincol;
+ wp->w_popup_maxcol = maxcol;
+ }
+ }
+ else
+ semsg(_(e_invarg2), tv_get_string(&di->di_tv));
+ }
+
+ static void
check_highlight(dict_T *dict, char *name, char_u **pval)
{
dictitem_T *di;
***************
*** 541,571 ****
if (di != NULL)
{
set_moved_values(wp);
! if (di->di_tv.v_type == VAR_STRING && di->di_tv.vval.v_string != NULL)
! {
! char_u *s = di->di_tv.vval.v_string;
! int flags = 0;
!
! if (STRCMP(s, "word") == 0)
! flags = FIND_IDENT | FIND_STRING;
! else if (STRCMP(s, "WORD") == 0)
! flags = FIND_STRING;
! else if (STRCMP(s, "any") != 0)
! semsg(_(e_invarg2), s);
! if (flags != 0)
! set_moved_columns(wp, flags);
! }
! else if (di->di_tv.v_type == VAR_LIST
! && di->di_tv.vval.v_list != NULL
! && di->di_tv.vval.v_list->lv_len == 2)
! {
! list_T *l = di->di_tv.vval.v_list;

! wp->w_popup_mincol = tv_get_number(&l->lv_first->li_tv);
! wp->w_popup_maxcol = tv_get_number(&l->lv_first->li_next->li_tv);
! }
! else
! semsg(_(e_invarg2), tv_get_string(&di->di_tv));
}

di = dict_find(dict, (char_u *)"filter", -1);
--- 617,630 ----
if (di != NULL)
{
set_moved_values(wp);
! handle_moved_argument(wp, di, FALSE);
! }

! di = dict_find(dict, (char_u *)"mousemoved", -1);
! if (di != NULL)
! {
! set_mousemoved_values(wp);
! handle_moved_argument(wp, di, TRUE);
}

di = dict_find(dict, (char_u *)"filter", -1);
***************
*** 956,961 ****
--- 1015,1021 ----
{
TYPE_NORMAL,
TYPE_ATCURSOR,
+ TYPE_BEVAL,
TYPE_NOTIFICATION,
TYPE_DIALOG,
TYPE_MENU
***************
*** 1137,1153 ****
{
wp->w_popup_pos = POPPOS_BOTLEFT;
setcursor_mayforce(TRUE);
! wp->w_wantline = screen_screenrow();
if (wp->w_wantline == 0) // cursor in first line
{
wp->w_wantline = 2;
wp->w_popup_pos = POPPOS_TOPLEFT;
}
! wp->w_wantcol = screen_screencol() + 1;
set_moved_values(wp);
set_moved_columns(wp, FIND_STRING);
}

// set default values
wp->w_zindex = POPUPWIN_DEFAULT_ZINDEX;
wp->w_popup_close = POPCLOSE_NONE;
--- 1197,1229 ----
{
wp->w_popup_pos = POPPOS_BOTLEFT;
setcursor_mayforce(TRUE);
! wp->w_wantline = curwin->w_winrow + curwin->w_wrow;
if (wp->w_wantline == 0) // cursor in first line
{
wp->w_wantline = 2;
wp->w_popup_pos = POPPOS_TOPLEFT;
}
! wp->w_wantcol = curwin->w_wincol + curwin->w_wcol + 1;
set_moved_values(wp);
set_moved_columns(wp, FIND_STRING);
}

+ if (type == TYPE_BEVAL)
+ {
+ wp->w_popup_pos = POPPOS_BOTLEFT;
+
+ // by default use the mouse position
+ wp->w_wantline = mouse_row;
+ if (wp->w_wantline <= 0) // mouse on first line
+ {
+ wp->w_wantline = 2;
+ wp->w_popup_pos = POPPOS_TOPLEFT;
+ }
+ wp->w_wantcol = mouse_col + 1;
+ set_mousemoved_values(wp);
+ set_mousemoved_columns(wp, FIND_IDENT + FIND_STRING + FIND_EVAL);
+ }
+
// set default values
wp->w_zindex = POPUPWIN_DEFAULT_ZINDEX;
wp->w_popup_close = POPCLOSE_NONE;
***************
*** 1276,1281 ****
--- 1352,1366 ----
}

/*
+ * popup_beval({text}, {options})
+ */
+ void
+ f_popup_beval(typval_T *argvars, typval_T *rettv)
+ {
+ popup_create(argvars, rettv, TYPE_BEVAL);
+ }
+
+ /*
* Invoke the close callback for window "wp" with value "result".
* Careful: The callback may make "wp" invalid!
*/
***************
*** 1334,1339 ****
--- 1419,1466 ----
popup_close_and_callback(wp, &res);
}

+ static void
+ check_mouse_moved(win_T *wp, win_T *mouse_wp)
+ {
+ // Close the popup when all if these are true:
+ // - the mouse is not on this popup
+ // - "mousemoved" was used
+ // - the mouse is no longer on the same screen row or the mouse column is
+ // outside of the relevant text
+ if (wp != mouse_wp
+ && wp->w_popup_mouse_row != 0
+ && (wp->w_popup_mouse_row != mouse_row
+ || mouse_col < wp->w_popup_mouse_mincol
+ || mouse_col > wp->w_popup_mouse_maxcol))
+ {
+ typval_T res;
+
+ res.v_type = VAR_NUMBER;
+ res.vval.v_number = -2;
+ popup_close_and_callback(wp, &res);
+ }
+ }
+
+ /*
+ * Called when the mouse moved: may close a popup with "mousemoved".
+ */
+ void
+ popup_handle_mouse_moved(void)
+ {
+ win_T *wp;
+ win_T *mouse_wp;
+ int row = mouse_row;
+ int col = mouse_col;
+
+ // find the window where the mouse is in
+ mouse_wp = mouse_find_win(&row, &col, FIND_POPUP);
+
+ for (wp = first_popupwin; wp != NULL; wp = wp->w_next)
+ check_mouse_moved(wp, mouse_wp);
+ for (wp = curtab->tp_first_popupwin; wp != NULL; wp = wp->w_next)
+ check_mouse_moved(wp, mouse_wp);
+ }
+
/*
* In a filter: check if the typed key is a mouse event that is used for
* dragging the popup.
***************
*** 1821,1827 ****
}

/*
! * For popup_getoptions(): add a "moved" entry to "dict".
*/
static void
get_moved_list(dict_T *dict, win_T *wp)
--- 1948,1954 ----
}

/*
! * For popup_getoptions(): add a "moved" and "mousemoved" entry to "dict".
*/
static void
get_moved_list(dict_T *dict, win_T *wp)
***************
*** 1832,1840 ****
--- 1959,1976 ----
if (list != NULL)
{
dict_add_list(dict, "moved", list);
+ list_append_number(list, wp->w_popup_lnum);
list_append_number(list, wp->w_popup_mincol);
list_append_number(list, wp->w_popup_maxcol);
}
+ list = list_alloc();
+ if (list != NULL)
+ {
+ dict_add_list(dict, "mousemoved", list);
+ list_append_number(list, wp->w_popup_mouse_row);
+ list_append_number(list, wp->w_popup_mouse_mincol);
+ list_append_number(list, wp->w_popup_mouse_maxcol);
+ }
}

/*
*** ../vim-8.1.1644/src/proto/popupwin.pro 2019-06-30 18:04:53.793559360 +0200
--- src/proto/popupwin.pro 2019-07-06 17:06:06.122751209 +0200
***************
*** 11,17 ****
--- 11,19 ----
void f_popup_clear(typval_T *argvars, typval_T *rettv);
void f_popup_create(typval_T *argvars, typval_T *rettv);
void f_popup_atcursor(typval_T *argvars, typval_T *rettv);
+ void f_popup_beval(typval_T *argvars, typval_T *rettv);
void popup_close_for_mouse_click(win_T *wp);
+ void popup_handle_mouse_moved(void);
void f_popup_filter_menu(typval_T *argvars, typval_T *rettv);
void f_popup_filter_yesno(typval_T *argvars, typval_T *rettv);
void f_popup_dialog(typval_T *argvars, typval_T *rettv);
*** ../vim-8.1.1644/src/move.c 2019-03-30 18:46:57.356077354 +0100
--- src/move.c 2019-07-07 17:02:20.284693207 +0200
***************
*** 1189,1194 ****
--- 1189,1284 ----
curwin->w_valid |= VALID_WCOL|VALID_WROW|VALID_VIRTCOL;
}

+ #if defined(FEAT_EVAL) || defined(PROTO)
+ /*
+ * Compute the screen position of text character at "pos" in window "wp"
+ * The resulting values are one-based, zero when character is not visible.
+ */
+ static void
+ textpos2screenpos(
+ win_T *wp,
+ pos_T *pos,
+ int *rowp, // screen row
+ int *scolp, // start screen column
+ int *ccolp, // cursor screen column
+ int *ecolp) // end screen column
+ {
+ colnr_T scol = 0, ccol = 0, ecol = 0;
+ int row = 0;
+ int rowoff = 0;
+ colnr_T coloff = 0;
+
+ if (pos->lnum >= wp->w_topline && pos->lnum < wp->w_botline)
+ {
+ colnr_T off;
+ colnr_T col;
+ int width;
+
+ row = plines_m_win(wp, wp->w_topline, pos->lnum - 1) + 1;
+ getvcol(wp, pos, &scol, &ccol, &ecol);
+
+ // similar to what is done in validate_cursor_col()
+ col = scol;
+ off = win_col_off(wp);
+ col += off;
+ width = wp->w_width - off + win_col_off2(wp);
+
+ /* long line wrapping, adjust row */
+ if (wp->w_p_wrap
+ && col >= (colnr_T)wp->w_width
+ && width > 0)
+ {
+ /* use same formula as what is used in curs_columns() */
+ rowoff = ((col - wp->w_width) / width + 1);
+ col -= rowoff * width;
+ }
+ col -= wp->w_leftcol;
+ if (col >= width)
+ col = -1;
+ if (col >= 0)
+ coloff = col - scol + wp->w_wincol + 1;
+ else
+ // character is left or right of the window
+ row = scol = ccol = ecol = 0;
+ }
+ *rowp = wp->w_winrow + row + rowoff;
+ *scolp = scol + coloff;
+ *ccolp = ccol + coloff;
+ *ecolp = ecol + coloff;
+ }
+
+ /*
+ * "screenpos({winid}, {lnum}, {col})" function
+ */
+ void
+ f_screenpos(typval_T *argvars UNUSED, typval_T *rettv)
+ {
+ dict_T *dict;
+ win_T *wp;
+ pos_T pos;
+ int row = 0;
+ int scol = 0, ccol = 0, ecol = 0;
+
+ if (rettv_dict_alloc(rettv) != OK)
+ return;
+ dict = rettv->vval.v_dict;
+
+ wp = find_win_by_nr_or_id(&argvars[0]);
+ if (wp == NULL)
+ return;
+
+ pos.lnum = tv_get_number(&argvars[1]);
+ pos.col = tv_get_number(&argvars[2]) - 1;
+ pos.coladd = 0;
+ textpos2screenpos(wp, &pos, &row, &scol, &ccol, &ecol);
+
+ dict_add_number(dict, "row", row);
+ dict_add_number(dict, "col", scol);
+ dict_add_number(dict, "curscol", ccol);
+ dict_add_number(dict, "endcol", ecol);
+ }
+ #endif
+
/*
* Scroll the current window down by "line_count" logical lines. "CTRL-Y"
*/
*** ../vim-8.1.1644/src/proto/move.pro 2019-01-31 13:22:28.068543628 +0100
--- src/proto/move.pro 2019-07-07 17:02:26.788661232 +0200
***************
*** 27,32 ****
--- 27,33 ----
int win_col_off2(win_T *wp);
int curwin_col_off2(void);
void curs_columns(int may_scroll);
+ void f_screenpos(typval_T *argvars, typval_T *rettv);
void scrolldown(long line_count, int byfold);
void scrollup(long line_count, int byfold);
void check_topfill(win_T *wp, int down);
*** ../vim-8.1.1644/src/beval.c 2019-06-12 20:21:57.737817533 +0200
--- src/beval.c 2019-07-07 16:31:17.941627410 +0200
***************
*** 14,20 ****

/*
* Get the text and position to be evaluated for "beval".
! * If "getword" is true the returned text is not the whole line but the
* relevant word in allocated memory.
* Returns OK or FAIL.
*/
--- 14,20 ----

/*
* Get the text and position to be evaluated for "beval".
! * If "getword" is TRUE the returned text is not the whole line but the
* relevant word in allocated memory.
* Returns OK or FAIL.
*/
***************
*** 27,38 ****
char_u **textp,
int *colp)
{
- win_T *wp;
int row, col;
- char_u *lbuf;
- linenr_T lnum;

- *textp = NULL;
# ifdef FEAT_BEVAL_TERM
# ifdef FEAT_GUI
if (!gui.in_use)
--- 27,34 ----
***************
*** 49,70 ****
col = X_2_COL(beval->x);
}
#endif
wp = mouse_find_win(&row, &col, FAIL_POPUP);
if (wp != NULL && row >= 0 && row < wp->w_height && col < wp->w_width)
{
! /* Found a window and the cursor is in the text. Now find the line
! * number. */
if (!mouse_comp_pos(wp, &row, &col, &lnum))
{
! /* Not past end of the file. */
lbuf = ml_get_buf(wp->w_buffer, lnum, FALSE);
if (col <= win_linetabsize(wp, lbuf, (colnr_T)MAXCOL))
{
! /* Not past end of line. */
if (getword)
{
! /* For Netbeans we get the relevant part of the line
! * instead of the whole line. */
int len;
pos_T *spos = NULL, *epos = NULL;

--- 45,112 ----
col = X_2_COL(beval->x);
}
#endif
+ if (find_word_under_cursor(row, col, getword,
+ FIND_IDENT + FIND_STRING + FIND_EVAL,
+ winp, lnump, textp, colp) == OK)
+ {
+ #ifdef FEAT_VARTABS
+ vim_free(beval->vts);
+ beval->vts = tabstop_copy((*winp)->w_buffer->b_p_vts_array);
+ if ((*winp)->w_buffer->b_p_vts_array != NULL && beval->vts == NULL)
+ {
+ if (getword)
+ vim_free(*textp);
+ return FAIL;
+ }
+ #endif
+ beval->ts = (*winp)->w_buffer->b_p_ts;
+ return OK;
+ }
+
+ return FAIL;
+ }
+
+ /*
+ * Find text under the mouse position "row" / "col".
+ * If "getword" is TRUE the returned text in "*textp" is not the whole line but
+ * the relevant word in allocated memory.
+ * Return OK if found.
+ * Return FAIL if not found, no text at the mouse position.
+ */
+ int
+ find_word_under_cursor(
+ int mouserow,
+ int mousecol,
+ int getword,
+ int flags, // flags for find_ident_at_pos()
+ win_T **winp, // can be NULL
+ linenr_T *lnump, // can be NULL
+ char_u **textp,
+ int *colp)
+ {
+ int row = mouserow;
+ int col = mousecol;
+ win_T *wp;
+ char_u *lbuf;
+ linenr_T lnum;
+
+ *textp = NULL;
wp = mouse_find_win(&row, &col, FAIL_POPUP);
if (wp != NULL && row >= 0 && row < wp->w_height && col < wp->w_width)
{
! // Found a window and the cursor is in the text. Now find the line
! // number.
if (!mouse_comp_pos(wp, &row, &col, &lnum))
{
! // Not past end of the file.
lbuf = ml_get_buf(wp->w_buffer, lnum, FALSE);
if (col <= win_linetabsize(wp, lbuf, (colnr_T)MAXCOL))
{
! // Not past end of line.
if (getword)
{
! // For Netbeans we get the relevant part of the line
! // instead of the whole line.
int len;
pos_T *spos = NULL, *epos = NULL;

***************
*** 93,101 ****
? col <= (int)epos->col
: lnum < epos->lnum))
{
! /* Visual mode and pointing to the line with the
! * Visual selection: return selected text, with a
! * maximum of one line. */
if (spos->lnum != epos->lnum || spos->col == epos->col)
return FAIL;

--- 135,143 ----
? col <= (int)epos->col
: lnum < epos->lnum))
{
! // Visual mode and pointing to the line with the
! // Visual selection: return selected text, with a
! // maximum of one line.
if (spos->lnum != epos->lnum || spos->col == epos->col)
return FAIL;

***************
*** 109,118 ****
}
else
{
! /* Find the word under the cursor. */
++emsg_off;
len = find_ident_at_pos(wp, lnum, (colnr_T)col, &lbuf,
! FIND_IDENT + FIND_STRING + FIND_EVAL);
--emsg_off;
if (len == 0)
return FAIL;
--- 151,160 ----
}
else
{
! // Find the word under the cursor.
++emsg_off;
len = find_ident_at_pos(wp, lnum, (colnr_T)col, &lbuf,
! flags);
--emsg_off;
if (len == 0)
return FAIL;
***************
*** 120,141 ****
}
}

! *winp = wp;
! *lnump = lnum;
*textp = lbuf;
*colp = col;
- #ifdef FEAT_VARTABS
- vim_free(beval->vts);
- beval->vts = tabstop_copy(wp->w_buffer->b_p_vts_array);
- if (wp->w_buffer->b_p_vts_array != NULL && beval->vts == NULL)
- return FAIL;
- #endif
- beval->ts = wp->w_buffer->b_p_ts;
return OK;
}
}
}
-
return FAIL;
}

--- 162,177 ----
}
}

! if (winp != NULL)
! *winp = wp;
! if (lnump != NULL)
! *lnump = lnum;
*textp = lbuf;
*colp = col;
return OK;
}
}
}
return FAIL;
}

*** ../vim-8.1.1644/src/proto/beval.pro 2018-05-17 13:52:56.000000000 +0200
--- src/proto/beval.pro 2019-07-07 16:04:03.689341355 +0200
***************
*** 1,5 ****
--- 1,6 ----
/* beval.c */
int get_beval_info(BalloonEval *beval, int getword, win_T **winp, linenr_T *lnump, char_u **textp, int *colp);
+ int find_word_under_cursor(int mouserow, int mousecol, int getword, int flags, win_T **winp, linenr_T *lnump, char_u **textp, int *colp);
void post_balloon(BalloonEval *beval, char_u *mesg, list_T *list);
int can_use_beval(void);
void general_beval_cb(BalloonEval *beval, int state);
*** ../vim-8.1.1644/src/evalfunc.c 2019-07-04 15:39:23.823385977 +0200
--- src/evalfunc.c 2019-07-06 15:58:24.308858997 +0200
***************
*** 771,776 ****
--- 771,777 ----
#endif
#ifdef FEAT_TEXT_PROP
{"popup_atcursor", 2, 2, f_popup_atcursor},
+ {"popup_beval", 2, 2, f_popup_beval},
{"popup_clear", 0, 0, f_popup_clear},
{"popup_close", 1, 2, f_popup_close},
{"popup_create", 2, 2, f_popup_create},
***************
*** 849,854 ****
--- 850,856 ----
{"screenchar", 2, 2, f_screenchar},
{"screenchars", 2, 2, f_screenchars},
{"screencol", 0, 0, f_screencol},
+ {"screenpos", 3, 3, f_screenpos},
{"screenrow", 0, 0, f_screenrow},
{"screenstring", 2, 2, f_screenstring},
{"search", 1, 4, f_search},
*** ../vim-8.1.1644/src/popupmnu.c 2019-06-15 19:37:11.680608505 +0200
--- src/popupmnu.c 2019-07-06 16:41:49.828506031 +0200
***************
*** 992,999 ****
# if defined(FEAT_BEVAL_TERM) || defined(PROTO)
static pumitem_T *balloon_array = NULL;
static int balloon_arraysize;
- static int balloon_mouse_row = 0;
- static int balloon_mouse_col = 0;

#define BALLOON_MIN_WIDTH 50
#define BALLOON_MIN_HEIGHT 10
--- 992,997 ----
***************
*** 1209,1216 ****
void
ui_may_remove_balloon(void)
{
! if (mouse_row != balloon_mouse_row || mouse_col != balloon_mouse_col)
! ui_remove_balloon();
}
# endif

--- 1207,1215 ----
void
ui_may_remove_balloon(void)
{
! // For now: remove the balloon whenever the mouse moves to another screen
! // cell.
! ui_remove_balloon();
}
# endif

*** ../vim-8.1.1644/src/normal.c 2019-06-30 22:16:06.931821750 +0200
--- src/normal.c 2019-07-06 16:43:04.132100090 +0200
***************
*** 2329,2334 ****
--- 2329,2337 ----
bevalexpr_due_set = TRUE;
}
#endif
+ #ifdef FEAT_TEXT_PROP
+ popup_handle_mouse_moved();
+ #endif
return FALSE;
}

*** ../vim-8.1.1644/src/testdir/test_popupwin.vim 2019-07-05 21:53:14.939268472 +0200
--- src/testdir/test_popupwin.vim 2019-07-07 18:18:14.652578345 +0200
***************
*** 1005,1010 ****
--- 1005,1057 ----
bwipe!
endfunc

+ func Test_popup_beval()
+ if !CanRunVimInTerminal()
+ throw 'Skipped: cannot make screendumps'
+ endif
+
+ let lines =<< trim END
+ call setline(1, range(1, 20))
+ call setline(5, 'here is some text to hover over')
+ set balloonevalterm
+ set balloonexpr=BalloonExpr()
+ set balloondelay=100
+ func BalloonExpr()
+ let s:winid = popup_beval([v:beval_text], {})
+ return ''
+ endfunc
+ func Hover()
+ call test_setmouse(5, 15)
+ call feedkeys("\<MouseMove>\<Ignore>", "xt")
+ sleep 100m
+ endfunc
+ func MoveOntoPopup()
+ call test_setmouse(4, 17)
+ call feedkeys("\<F4>\<MouseMove>\<Ignore>", "xt")
+ endfunc
+ func MoveAway()
+ call test_setmouse(5, 13)
+ call feedkeys("\<F5>\<MouseMove>\<Ignore>", "xt")
+ endfunc
+ END
+ call writefile(lines, 'XtestPopupBeval')
+ let buf = RunVimInTerminal('-S XtestPopupBeval', {'rows': 10})
+ call term_wait(buf, 100)
+ call term_sendkeys(buf, 'j')
+ call term_sendkeys(buf, ":call Hover()\<CR>")
+ call VerifyScreenDump(buf, 'Test_popupwin_beval_1', {})
+
+ call term_sendkeys(buf, ":call MoveOntoPopup()\<CR>")
+ call VerifyScreenDump(buf, 'Test_popupwin_beval_2', {})
+
+ call term_sendkeys(buf, ":call MoveAway()\<CR>")
+ call VerifyScreenDump(buf, 'Test_popupwin_beval_3', {})
+
+ " clean up
+ call StopVimInTerminal(buf)
+ call delete('XtestPopupBeval')
+ endfunc
+
func Test_popup_filter()
new
call setline(1, 'some text')
***************
*** 1413,1419 ****
let winid = popup_atcursor('text', {'moved': 'any'})
redraw
call assert_equal(1, popup_getpos(winid).visible)
! call assert_equal([4, 4], popup_getoptions(winid).moved)
" trigger the check for last_cursormoved by going into insert mode
call feedkeys("li\<Esc>", 'xt')
call assert_equal({}, popup_getpos(winid))
--- 1460,1466 ----
let winid = popup_atcursor('text', {'moved': 'any'})
redraw
call assert_equal(1, popup_getpos(winid).visible)
! call assert_equal([1, 4, 4], popup_getoptions(winid).moved)
" trigger the check for last_cursormoved by going into insert mode
call feedkeys("li\<Esc>", 'xt')
call assert_equal({}, popup_getpos(winid))
***************
*** 1423,1429 ****
let winid = popup_atcursor('text', {'moved': 'word'})
redraw
call assert_equal(1, popup_getpos(winid).visible)
! call assert_equal([4, 7], popup_getoptions(winid).moved)
call feedkeys("hi\<Esc>", 'xt')
call assert_equal({}, popup_getpos(winid))
call popup_clear()
--- 1470,1476 ----
let winid = popup_atcursor('text', {'moved': 'word'})
redraw
call assert_equal(1, popup_getpos(winid).visible)
! call assert_equal([1, 4, 7], popup_getoptions(winid).moved)
call feedkeys("hi\<Esc>", 'xt')
call assert_equal({}, popup_getpos(winid))
call popup_clear()
***************
*** 1432,1438 ****
let winid = popup_atcursor('text', {'moved': 'word'})
redraw
call assert_equal(1, popup_getpos(winid).visible)
! call assert_equal([4, 7], popup_getoptions(winid).moved)
call feedkeys("li\<Esc>", 'xt')
call assert_equal(1, popup_getpos(winid).visible)
call feedkeys("ei\<Esc>", 'xt')
--- 1479,1485 ----
let winid = popup_atcursor('text', {'moved': 'word'})
redraw
call assert_equal(1, popup_getpos(winid).visible)
! call assert_equal([1, 4, 7], popup_getoptions(winid).moved)
call feedkeys("li\<Esc>", 'xt')
call assert_equal(1, popup_getpos(winid).visible)
call feedkeys("ei\<Esc>", 'xt')
***************
*** 1446,1452 ****
let winid = popup_atcursor('text', {})
redraw
call assert_equal(1, popup_getpos(winid).visible)
! call assert_equal([2, 15], popup_getoptions(winid).moved)
call feedkeys("eli\<Esc>", 'xt')
call assert_equal(1, popup_getpos(winid).visible)
call feedkeys("wi\<Esc>", 'xt')
--- 1493,1499 ----
let winid = popup_atcursor('text', {})
redraw
call assert_equal(1, popup_getpos(winid).visible)
! call assert_equal([2, 2, 15], popup_getoptions(winid).moved)
call feedkeys("eli\<Esc>", 'xt')
call assert_equal(1, popup_getpos(winid).visible)
call feedkeys("wi\<Esc>", 'xt')
*** ../vim-8.1.1644/src/testdir/test_cursor_func.vim 2019-05-16 22:24:52.403017783 +0200
--- src/testdir/test_cursor_func.vim 2019-07-07 14:42:25.107175433 +0200
***************
*** 72,74 ****
--- 72,102 ----
call assert_equal(6, winsaveview().curswant)
quit!
endfunc
+
+ func Test_screenpos()
+ rightbelow new
+ rightbelow 20vsplit
+ call setline(1, ["\tsome text", "long wrapping line here", "next line"])
+ redraw
+ let winid = win_getid()
+ let [winrow, wincol] = win_screenpos(winid)
+ call assert_equal({'row': winrow,
+ \ 'col': wincol + 0,
+ \ 'curscol': wincol + 7,
+ \ 'endcol': wincol + 7}, screenpos(winid, 1, 1))
+ call assert_equal({'row': winrow,
+ \ 'col': wincol + 13,
+ \ 'curscol': wincol + 13,
+ \ 'endcol': wincol + 13}, screenpos(winid, 1, 7))
+ call assert_equal({'row': winrow + 2,
+ \ 'col': wincol + 1,
+ \ 'curscol': wincol + 1,
+ \ 'endcol': wincol + 1}, screenpos(winid, 2, 22))
+ setlocal number
+ call assert_equal({'row': winrow + 3,
+ \ 'col': wincol + 9,
+ \ 'curscol': wincol + 9,
+ \ 'endcol': wincol + 9}, screenpos(winid, 2, 22))
+ close
+ bwipe!
+ endfunc
*** ../vim-8.1.1644/runtime/doc/popup.txt 2019-07-04 16:53:21.369654166 +0200
--- runtime/doc/popup.txt 2019-07-07 17:12:34.957616704 +0200
***************
*** 146,151 ****
--- 146,153 ----
|popup_create()| centered in the screen
|popup_atcursor()| just above the cursor position, closes when
the cursor moves away
+ |popup_beval()| at the position indicated by v:beval_
+ variables, closes when the mouse moves away
|popup_notification()| show a notification for three seconds
|popup_dialog()| centered with padding and border
|popup_menu()| prompt for selecting an item from a list
***************
*** 184,189 ****
--- 186,205 ----
< Use {options} to change the properties.


+ popup_beval({what}, {options}) *popup_beval()*
+ Show the {what} above the position from 'ballooneval' and
+ close it when the mouse moves. This works like: >
+ let pos = screenpos(v:beval_winnr, v:beval_lnum, v:beval_col)
+ call popup_create({what}, {
+ \ 'pos': 'botleft',
+ \ 'line': pos.lnum - 1,
+ \ 'col': pos.col,
+ \ 'mousemoved': 'WORD',
+ \ })
+ < Use {options} to change the properties.
+ See |popup_beval_example| for an example use.
+
+
*popup_clear()*
popup_clear() Emergency solution to a misbehaving plugin: close all popup
windows for the current tab and global popups.
***************
*** 276,283 ****
A zero value means the option was not set. For "zindex" the
default value is returned, not zero.

! The "moved" entry is a list with minimum and maximum column,
! [0, 0] when not set.

"border" and "padding" are not included when all values are
zero. When all values are one then an empty list is included.
--- 292,302 ----
A zero value means the option was not set. For "zindex" the
default value is returned, not zero.

! The "moved" entry is a list with line number, minimum and
! maximum column, [0, 0, 0] when not set.
!
! The "mousemoved" entry is a list with screen row, minimum and
! maximum screen column, [0, 0, 0] when not set.

"border" and "padding" are not included when all values are
zero. When all values are one then an empty list is included.
***************
*** 566,571 ****
--- 585,591 ----
- "any": if the cursor moved at all
- "word": if the cursor moved outside |<cword>|
- "WORD": if the cursor moved outside |<cWORD>|
+ - "expr": if the cursor moved outside |<cexpr>|
- [{start}, {end}]: if the cursor moved before column
{start} or after {end}
The popup also closes if the cursor moves to another
***************
*** 736,740 ****
--- 756,800 ----
return popup_filter_menu(a:id, a:key)
endfunc
<
+ *popup_beval_example*
+ Example for using a popup window for 'ballooneval': >
+
+ set ballooneval balloonevalterm
+ set balloonexpr=BalloonExpr()
+ let s:winid = 0
+
+ func BalloonExpr()
+ if s:winid
+ call popup_close(s:winid)
+ let s:winid = 0
+ endif
+ let s:winid = popup_beval([bufname(v:beval_bufnr), v:beval_text], {})
+ return ''
+ endfunc
+ <
+ If the text has to be obtained asynchronously return an empty string from the
+ expression function and call popup_beval() once the text is available. In
+ this example similated with a timer callback: >
+
+ set ballooneval balloonevalterm
+ set balloonexpr=BalloonExpr()
+ let s:winid = 0
+
+ func BalloonExpr()
+ if s:winid
+ call popup_close(s:winid)
+ let s:winid = 0
+ endif
+ " simulate an asynchronous loopup for the text to display
+ let s:balloonFile = bufname(v:beval_bufnr)
+ let s:balloonWord = v:beval_text
+ call timer_start(100, 'ShowPopup')
+ return ''
+ endfunc
+
+ func ShowPopup(id)
+ let s:winid = popup_beval([s:balloonFile, s:balloonWord], {})
+ endfunc
+ <

vim:tw=78:ts=8:noet:ft=help:norl:
*** ../vim-8.1.1644/runtime/doc/eval.txt 2019-07-04 17:11:16.799440884 +0200
--- runtime/doc/eval.txt 2019-07-07 14:41:25.071768307 +0200
***************
*** 2534,2539 ****
--- 2535,2541 ----
pathshorten({expr}) String shorten directory names in a path
perleval({expr}) any evaluate |Perl| expression
popup_atcursor({what}, {options}) Number create popup window near the cursor
+ popup_beval({what}, {options}) Number create popup window for 'ballooneval'
popup_clear() none close all popup windows
popup_close({id} [, {result}]) none close popup window {id}
popup_create({what}, {options}) Number create a popup window
***************
*** 2612,2617 ****
--- 2614,2620 ----
screenchar({row}, {col}) Number character at screen position
screenchars({row}, {col}) List List of characters at screen position
screencol() Number current cursor column
+ screenpos({winid}, {lnum}, {col}) Dict screen row and col of a text character
screenrow() Number current cursor row
screenstring({row}, {col}) String characters at screen position
search({pattern} [, {flags} [, {stopline} [, {timeout}]]])
***************
*** 7906,7911 ****
--- 7909,7931 ----
nnoremap <expr> GG ":echom ".screencol()."\n"
nnoremap <silent> GG :echom screencol()<CR>
<
+ screenpos({winid}, {lnum}, {col}) *screenpos()*
+ The result is a Dict with the screen position of the text
+ character in window {winid} at buffer line {lnum} and column
+ {col}. {col} is a one-based byte index.
+ The Dict has these members:
+ row screen row
+ col first screen column
+ endcol last screen column
+ curscol cursor screen column
+ If the specified position is not visible, all values are zero.
+ The "endcol" value differs from "col" when the character
+ occupies more than one screen cell. E.g. for a Tab "col" can
+ be 1 and "endcol" can be 8.
+ The "curscol" value is where the cursor would be placed. For
+ a Tab it would be the same as "endcol", while for a double
+ width character it would be the same as "col".
+
screenrow() *screenrow()*
The result is a Number, which is the current screen row of the
cursor. The top line has number one.
*** ../vim-8.1.1644/runtime/doc/usr_41.txt 2019-07-04 16:53:21.373654143 +0200
--- runtime/doc/usr_41.txt 2019-07-06 15:16:12.426341319 +0200
***************
*** 720,725 ****
--- 720,726 ----
cursor() position the cursor at a line/column
screencol() get screen column of the cursor
screenrow() get screen row of the cursor
+ screenpos() screen row and col of a text character
getcurpos() get position of the cursor
getpos() get position of cursor, mark, etc.
setpos() set position of cursor, mark, etc.
***************
*** 1046,1051 ****
--- 1047,1054 ----
popup_create() create popup centered in the screen
popup_atcursor() create popup just above the cursor position,
closes when the cursor moves away
+ popup_beval() at the position indicated by v:beval_
+ variables, closes when the mouse moves away
popup_notification() show a notification for three seconds
popup_dialog() create popup centered with padding and border
popup_menu() prompt for selecting an item from a list
*** ../vim-8.1.1644/src/testdir/dumps/Test_popupwin_beval_1.dump 2019-07-07 18:22:04.315270748 +0200
--- src/testdir/dumps/Test_popupwin_beval_1.dump 2019-07-07 18:15:51.053411015 +0200
***************
*** 0 ****
--- 1,10 ----
+ |1+0&#ffffff0| @73
+ >2| @73
+ |3| @73
+ |4| @12|t+0#0000001#ffd7ff255|e|x|t| +0#0000000#ffffff0@56
+ |h|e|r|e| |i|s| |s|o|m|e| |t|e|x|t| |t|o| |h|o|v|e|r| |o|v|e|r| @43
+ |6| @73
+ |7| @73
+ |8| @73
+ |9| @73
+ |:|c|a|l@1| |H|o|v|e|r|(|)| @43|2|,|1| @10|T|o|p|
*** ../vim-8.1.1644/src/testdir/dumps/Test_popupwin_beval_2.dump 2019-07-07 18:22:04.319270725 +0200
--- src/testdir/dumps/Test_popupwin_beval_2.dump 2019-07-07 18:18:55.720342601 +0200
***************
*** 0 ****
--- 1,10 ----
+ |1+0&#ffffff0| @73
+ >2| @73
+ |3| @73
+ |4| @12|t+0#0000001#ffd7ff255|e|x|t| +0#0000000#ffffff0@56
+ |h|e|r|e| |i|s| |s|o|m|e| |t|e|x|t| |t|o| |h|o|v|e|r| |o|v|e|r| @43
+ |6| @73
+ |7| @73
+ |8| @73
+ |9| @73
+ |:|c|a|l@1| |M|o|v|e|O|n|t|o|P|o|p|u|p|(|)| @35|2|,|1| @10|T|o|p|
*** ../vim-8.1.1644/src/testdir/dumps/Test_popupwin_beval_3.dump 2019-07-07 18:22:04.323270704 +0200
--- src/testdir/dumps/Test_popupwin_beval_3.dump 2019-07-07 18:16:43.881103039 +0200
***************
*** 0 ****
--- 1,10 ----
+ |1+0&#ffffff0| @73
+ >2| @73
+ |3| @73
+ |4| @73
+ |h|e|r|e| |i|s| |s|o|m|e| |t|e|x|t| |t|o| |h|o|v|e|r| |o|v|e|r| @43
+ |6| @73
+ |7| @73
+ |8| @73
+ |9| @73
+ |:|c|a|l@1| |M|o|v|e|A|w|a|y|(|)| @40|2|,|1| @10|T|o|p|
*** ../vim-8.1.1644/src/version.c 2019-07-07 15:12:08.765146251 +0200
--- src/version.c 2019-07-07 18:19:47.056049202 +0200
***************
*** 779,780 ****
--- 779,782 ----
{ /* Add new patch number below this line */
+ /**/
+ 1645,
/**/

--
ARTHUR: Well, I can't just call you `Man'.
DENNIS: Well, you could say `Dennis'.
ARTHUR: Well, I didn't know you were called `Dennis.'
DENNIS: Well, you didn't bother to find out, did you?
The Quest for the Holy Grail (Monty Python)

/// Bram Moolenaar -- Br...@Moolenaar.net -- http://www.Moolenaar.net \\\
/// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\ an exciting new programming language -- http://www.Zimbu.org ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///

Paul Jolly

unread,
Jul 7, 2019, 4:26:22 PM7/7/19
to Vim Dev Mailing List
Hi Bram - this is outstanding, thank you.

One small thing I noticed is that the popup window "balloon" is shown
botleft (see problem_1.png, attached). Is this intentional?

I was expecting the "balloon" to appear below and to the right of the
mouse, and hence that popup create option to be topleft?


Paul
> --
> --
> You received this message from the "vim_dev" maillist.
> Do not top-post! Type your reply below the text you are replying to.
> For more information, visit http://www.vim.org/maillist.php
>
> ---
> You received this message because you are subscribed to the Google Groups "vim_dev" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to vim_dev+u...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/vim_dev/201907071629.x67GT85H010977%40masaka.moolenaar.net.
> For more options, visit https://groups.google.com/d/optout.
problem_1.png

Bram Moolenaar

unread,
Jul 7, 2019, 5:10:40 PM7/7/19
to vim...@googlegroups.com, Paul Jolly

Paul Jolly wrote:

> Hi Bram - this is outstanding, thank you.
>
> One small thing I noticed is that the popup window "balloon" is shown
> botleft (see problem_1.png, attached). Is this intentional?

Yep, the default is to show the balloon above the text and to the right.
This can be changed with the "pos" argument.

> I was expecting the "balloon" to appear below and to the right of the
> mouse, and hence that popup create option to be topleft?

There is no perfect choice. The help at popup_beval() give a hint on
how to pass arguments if you want a different position.

--
`When any government, or any church for that matter, undertakes to say to
its subjects, "This you may not read, this you must not see, this you are
forbidden to know," the end result is tyranny and oppression no matter how
holy the motives' -- Robert A Heinlein, "If this goes on --"

Paul Jolly

unread,
Jul 7, 2019, 5:23:26 PM7/7/19
to Bram Moolenaar, Vim Dev Mailing List
> > One small thing I noticed is that the popup window "balloon" is shown
> > botleft (see problem_1.png, attached). Is this intentional?
>
> Yep, the default is to show the balloon above the text and to the right.
> This can be changed with the "pos" argument.
>
> > I was expecting the "balloon" to appear below and to the right of the
> > mouse, and hence that popup create option to be topleft?
>
> There is no perfect choice. The help at popup_beval() give a hint on
> how to pass arguments if you want a different position.

Thanks. My question here was only based on how balloons currently
work; they are shown below and to the right.

Per your suggestion, I already have a custom popup_create call that is
positioning things as I expect.

Thanks again for the quick turnaround on this.


Paul

Paul Jolly

unread,
Jul 8, 2019, 3:40:22 AM7/8/19
to Bram Moolenaar, Vim Dev Mailing List
One other small issue I've spotted is that in gvim, when a popup is
used instead of a balloon, the cursor sometimes appears to jump to the
bottom right of the popup window:

https://www.youtube.com/watch?v=TN2iGTlvvxc

The cursor itself hasn't actually moved, because if I move the cursor
via any movement, it's actually in its original place and so the
movement is as expected.

Bram Moolenaar

unread,
Jul 8, 2019, 7:02:28 AM7/8/19
to vim...@googlegroups.com, Paul Jolly

> > > One small thing I noticed is that the popup window "balloon" is shown
> > > botleft (see problem_1.png, attached). Is this intentional?
> >
> > Yep, the default is to show the balloon above the text and to the right.
> > This can be changed with the "pos" argument.
> >
> > > I was expecting the "balloon" to appear below and to the right of the
> > > mouse, and hence that popup create option to be topleft?
> >
> > There is no perfect choice. The help at popup_beval() give a hint on
> > how to pass arguments if you want a different position.
>
> Thanks. My question here was only based on how balloons currently
> work; they are shown below and to the right.

It depends on the position and the content. One difference is that the
balloon tries to show all of its text, while the popup window is
(currently) keeping the same position and tries to fit the text inside
the available space.

> Per your suggestion, I already have a custom popup_create call that is
> positioning things as I expect.

OK. And that's using the mechanism to close the popup when the mouse
moves away?

> Thanks again for the quick turnaround on this.

It's good to get quick feedback on these new features.

--
WOMAN: I didn't know we had a king. I thought we were an autonomous
collective.
DENNIS: You're fooling yourself. We're living in a dictatorship. A
self-perpetuating autocracy in which the working classes--
WOMAN: Oh there you go, bringing class into it again.
DENNIS: That's what it's all about if only people would--
The Quest for the Holy Grail (Monty Python)

Bram Moolenaar

unread,
Jul 8, 2019, 7:02:28 AM7/8/19
to vim...@googlegroups.com, Paul Jolly

Paul Jolly wrote:

> One other small issue I've spotted is that in gvim, when a popup is
> used instead of a balloon, the cursor sometimes appears to jump to the
> bottom right of the popup window:
>
> https://www.youtube.com/watch?v=TN2iGTlvvxc
>
> The cursor itself hasn't actually moved, because if I move the cursor
> via any movement, it's actually in its original place and so the
> movement is as expected.

Sound like restoring the cursor position after drawing some text might
be missing. Do you have a simple script to show the problem?

--
There are 2 kinds of people in my world: those who know Unix, Perl, Vim, GNU,
Linux, etc, and those who know COBOL. It gets very difficult for me at
parties, not knowing which group to socialise with :-)
Sitaram Chamarty

Paul Jolly

unread,
Jul 8, 2019, 7:20:45 AM7/8/19
to Bram Moolenaar, Vim Dev Mailing List
> Sound like restoring the cursor position after drawing some text might
> be missing. Do you have a simple script to show the problem?

Repro at the end of this message. Couple of things to note:

* I've had to add redraws in order to reliably draw the popup (compare
popup_beval_example)
* 'help popup_beval()' I think has a slight error; it references
pos.lnum, but this should be pos.row

To repro in gvim:

gvim -u repro.vim repro.vim

Then hover the mouse over any text such that the popup window itself
overlaps some text. Might require some random attempts - I'm not quite
sure what conditions cause this.

You should see the described behaviour.

Thanks

========

set nocompatible
set nobackup
set nowritebackup
set noswapfile
set mouse=a
set ttymouse=sgr
set balloondelay=250
set ballooneval balloonevalterm
set balloonexpr=BalloonExpr()
set balloondelay=250
let s:winid = 0

func BalloonExpr()
if s:winid
call popup_close(s:winid)
let s:winid = 0
redraw
endif
let pos = screenpos(v:beval_winnr, v:beval_lnum, v:beval_col)
let s:winid = popup_create(["hello"], {
\ "pos": "topleft",
\ "line": pos.row + 1,
\ "col": pos.col,
\ "mousemoved": "WORD",
\ "moved":"any"
\})
redraw
return ''
endfunc

Paul Jolly

unread,
Jul 8, 2019, 7:24:20 AM7/8/19
to Bram Moolenaar, Vim Dev Mailing List
> > Per your suggestion, I already have a custom popup_create call that is
> > positioning things as I expect.
>
> OK. And that's using the mechanism to close the popup when the mouse
> moves away?

Yes, that's correct.

I'm also using a command to trigger the exact same hover "balloon"
using the cursor position. This has a really nice symmetry to it from
the user's perspective (if you don't want to move off the keys).

> > Thanks again for the quick turnaround on this.
>
> It's good to get quick feedback on these new features.

Next steps from my perspective:

* display error messages (from gopls, the LSP server) in popups
* use popup windows for function/method signature information
(currently blocked on gopls telling me the signature position)

This popup stuff is going to be transformative, particular when used
with an LSP like gopls. Thanks again for all your work on it.

Bram Moolenaar

unread,
Jul 8, 2019, 5:30:47 PM7/8/19
to vim...@googlegroups.com, Paul Jolly

Paul Jolly wrote:

> > Sound like restoring the cursor position after drawing some text might
> > be missing. Do you have a simple script to show the problem?
>
> Repro at the end of this message. Couple of things to note:
>
> * I've had to add redraws in order to reliably draw the popup (compare
> popup_beval_example)

That should no longer be needed after 8.1.1654. That also fixes the
cursor showing up in the wrong place.

> * 'help popup_beval()' I think has a slight error; it references
> pos.lnum, but this should be pos.row

Right, I'll fix that.

> To repro in gvim:
>
> gvim -u repro.vim repro.vim
>
> Then hover the mouse over any text such that the popup window itself
> overlaps some text. Might require some random attempts - I'm not quite
> sure what conditions cause this.
>
> You should see the described behaviour.

Thanks for the reproducible example. It mostly works now.

I do notice that in the terminal the popup doesn't show on every hover,
apparently need to move to the right a bit.
In the GUI 'ballloonexpr' is evaluated again even though still within
the same word.

--
Q: How does a UNIX Guru pick up a girl?
A: look; grep; which; eval; nice; uname; talk; date;

Paul Jolly

unread,
Jul 9, 2019, 5:47:23 AM7/9/19
to Bram Moolenaar, Vim Dev Mailing List
<snip>

Thanks for the various updates. A govim user just reported an issue
that I raised as https://github.com/vim/vim/issues/4637
Reply all
Reply to author
Forward
0 new messages