1
0
forked from aniani/vim

patch 8.1.1645: cannot use a popup window for a balloon

Problem:    Cannot use a popup window for a balloon.
Solution:   Add popup_beval().  Add the "mousemoved" property.  Add the
            screenpos() function.
This commit is contained in:
Bram Moolenaar
2019-07-07 18:28:14 +02:00
parent 5b19e5b919
commit b3d17a20d2
18 changed files with 522 additions and 63 deletions

View File

@@ -2535,6 +2535,7 @@ or({expr}, {expr}) Number bitwise OR
pathshorten({expr}) String shorten directory names in a path pathshorten({expr}) String shorten directory names in a path
perleval({expr}) any evaluate |Perl| expression perleval({expr}) any evaluate |Perl| expression
popup_atcursor({what}, {options}) Number create popup window near the cursor 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_clear() none close all popup windows
popup_close({id} [, {result}]) none close popup window {id} popup_close({id} [, {result}]) none close popup window {id}
popup_create({what}, {options}) Number create a popup window popup_create({what}, {options}) Number create a popup window
@@ -2613,6 +2614,7 @@ screenattr({row}, {col}) Number attribute at screen position
screenchar({row}, {col}) Number character at screen position screenchar({row}, {col}) Number character at screen position
screenchars({row}, {col}) List List of characters at screen position screenchars({row}, {col}) List List of characters at screen position
screencol() Number current cursor column screencol() Number current cursor column
screenpos({winid}, {lnum}, {col}) Dict screen row and col of a text character
screenrow() Number current cursor row screenrow() Number current cursor row
screenstring({row}, {col}) String characters at screen position screenstring({row}, {col}) String characters at screen position
search({pattern} [, {flags} [, {stopline} [, {timeout}]]]) search({pattern} [, {flags} [, {stopline} [, {timeout}]]])
@@ -7907,6 +7909,23 @@ screencol() *screencol()*
nnoremap <expr> GG ":echom ".screencol()."\n" nnoremap <expr> GG ":echom ".screencol()."\n"
nnoremap <silent> GG :echom screencol()<CR> 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()* screenrow() *screenrow()*
The result is a Number, which is the current screen row of the The result is a Number, which is the current screen row of the
cursor. The top line has number one. cursor. The top line has number one.

View File

@@ -146,6 +146,8 @@ Creating a popup window:
|popup_create()| centered in the screen |popup_create()| centered in the screen
|popup_atcursor()| just above the cursor position, closes when |popup_atcursor()| just above the cursor position, closes when
the cursor moves away 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_notification()| show a notification for three seconds
|popup_dialog()| centered with padding and border |popup_dialog()| centered with padding and border
|popup_menu()| prompt for selecting an item from a list |popup_menu()| prompt for selecting an item from a list
@@ -184,6 +186,20 @@ popup_atcursor({what}, {options}) *popup_atcursor()*
< Use {options} to change the properties. < 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()*
popup_clear() Emergency solution to a misbehaving plugin: close all popup popup_clear() Emergency solution to a misbehaving plugin: close all popup
windows for the current tab and global popups. windows for the current tab and global popups.
@@ -276,8 +292,11 @@ popup_getoptions({id}) *popup_getoptions()*
A zero value means the option was not set. For "zindex" the A zero value means the option was not set. For "zindex" the
default value is returned, not zero. default value is returned, not zero.
The "moved" entry is a list with minimum and maximum column, The "moved" entry is a list with line number, minimum and
[0, 0] when not set. 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 "border" and "padding" are not included when all values are
zero. When all values are one then an empty list is included. zero. When all values are one then an empty list is included.
@@ -566,6 +585,7 @@ The second argument of |popup_create()| is a dictionary with options:
- "any": if the cursor moved at all - "any": if the cursor moved at all
- "word": if the cursor moved outside |<cword>| - "word": if the cursor moved outside |<cword>|
- "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}, {end}]: if the cursor moved before column
{start} or after {end} {start} or after {end}
The popup also closes if the cursor moves to another The popup also closes if the cursor moves to another
@@ -736,5 +756,45 @@ Extend popup_filter_menu() with shortcut keys: >
return popup_filter_menu(a:id, a:key) return popup_filter_menu(a:id, a:key)
endfunc 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:tw=78:ts=8:noet:ft=help:norl:

View File

@@ -720,6 +720,7 @@ Cursor and mark position: *cursor-functions* *mark-functions*
cursor() position the cursor at a line/column cursor() position the cursor at a line/column
screencol() get screen column of the cursor screencol() get screen column of the cursor
screenrow() get screen row 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 getcurpos() get position of the cursor
getpos() get position of cursor, mark, etc. getpos() get position of cursor, mark, etc.
setpos() set position of cursor, mark, etc. setpos() set position of cursor, mark, etc.
@@ -1046,6 +1047,8 @@ Popup window: *popup-window-functions*
popup_create() create popup centered in the screen popup_create() create popup centered in the screen
popup_atcursor() create popup just above the cursor position, popup_atcursor() create popup just above the cursor position,
closes when the cursor moves away 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_notification() show a notification for three seconds
popup_dialog() create popup centered with padding and border popup_dialog() create popup centered with padding and border
popup_menu() prompt for selecting an item from a list popup_menu() prompt for selecting an item from a list

View File

@@ -14,7 +14,7 @@
/* /*
* Get the text and position to be evaluated for "beval". * Get the text and position to be evaluated for "beval".
* If "getword" is true the returned text is not the whole line but the * If "getword" is TRUE the returned text is not the whole line but the
* relevant word in allocated memory. * relevant word in allocated memory.
* Returns OK or FAIL. * Returns OK or FAIL.
*/ */
@@ -27,12 +27,8 @@ get_beval_info(
char_u **textp, char_u **textp,
int *colp) int *colp)
{ {
win_T *wp;
int row, col; int row, col;
char_u *lbuf;
linenr_T lnum;
*textp = NULL;
# ifdef FEAT_BEVAL_TERM # ifdef FEAT_BEVAL_TERM
# ifdef FEAT_GUI # ifdef FEAT_GUI
if (!gui.in_use) if (!gui.in_use)
@@ -49,22 +45,68 @@ get_beval_info(
col = X_2_COL(beval->x); col = X_2_COL(beval->x);
} }
#endif #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); wp = mouse_find_win(&row, &col, FAIL_POPUP);
if (wp != NULL && row >= 0 && row < wp->w_height && col < wp->w_width) 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 // Found a window and the cursor is in the text. Now find the line
* number. */ // number.
if (!mouse_comp_pos(wp, &row, &col, &lnum)) if (!mouse_comp_pos(wp, &row, &col, &lnum))
{ {
/* Not past end of the file. */ // Not past end of the file.
lbuf = ml_get_buf(wp->w_buffer, lnum, FALSE); lbuf = ml_get_buf(wp->w_buffer, lnum, FALSE);
if (col <= win_linetabsize(wp, lbuf, (colnr_T)MAXCOL)) if (col <= win_linetabsize(wp, lbuf, (colnr_T)MAXCOL))
{ {
/* Not past end of line. */ // Not past end of line.
if (getword) if (getword)
{ {
/* For Netbeans we get the relevant part of the line // For Netbeans we get the relevant part of the line
* instead of the whole line. */ // instead of the whole line.
int len; int len;
pos_T *spos = NULL, *epos = NULL; pos_T *spos = NULL, *epos = NULL;
@@ -93,9 +135,9 @@ get_beval_info(
? col <= (int)epos->col ? col <= (int)epos->col
: lnum < epos->lnum)) : lnum < epos->lnum))
{ {
/* Visual mode and pointing to the line with the // Visual mode and pointing to the line with the
* Visual selection: return selected text, with a // Visual selection: return selected text, with a
* maximum of one line. */ // maximum of one line.
if (spos->lnum != epos->lnum || spos->col == epos->col) if (spos->lnum != epos->lnum || spos->col == epos->col)
return FAIL; return FAIL;
@@ -109,10 +151,10 @@ get_beval_info(
} }
else else
{ {
/* Find the word under the cursor. */ // Find the word under the cursor.
++emsg_off; ++emsg_off;
len = find_ident_at_pos(wp, lnum, (colnr_T)col, &lbuf, len = find_ident_at_pos(wp, lnum, (colnr_T)col, &lbuf,
FIND_IDENT + FIND_STRING + FIND_EVAL); flags);
--emsg_off; --emsg_off;
if (len == 0) if (len == 0)
return FAIL; return FAIL;
@@ -120,22 +162,16 @@ get_beval_info(
} }
} }
*winp = wp; if (winp != NULL)
*lnump = lnum; *winp = wp;
if (lnump != NULL)
*lnump = lnum;
*textp = lbuf; *textp = lbuf;
*colp = col; *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 OK;
} }
} }
} }
return FAIL; return FAIL;
} }

View File

@@ -771,6 +771,7 @@ static struct fst
#endif #endif
#ifdef FEAT_TEXT_PROP #ifdef FEAT_TEXT_PROP
{"popup_atcursor", 2, 2, f_popup_atcursor}, {"popup_atcursor", 2, 2, f_popup_atcursor},
{"popup_beval", 2, 2, f_popup_beval},
{"popup_clear", 0, 0, f_popup_clear}, {"popup_clear", 0, 0, f_popup_clear},
{"popup_close", 1, 2, f_popup_close}, {"popup_close", 1, 2, f_popup_close},
{"popup_create", 2, 2, f_popup_create}, {"popup_create", 2, 2, f_popup_create},
@@ -849,6 +850,7 @@ static struct fst
{"screenchar", 2, 2, f_screenchar}, {"screenchar", 2, 2, f_screenchar},
{"screenchars", 2, 2, f_screenchars}, {"screenchars", 2, 2, f_screenchars},
{"screencol", 0, 0, f_screencol}, {"screencol", 0, 0, f_screencol},
{"screenpos", 3, 3, f_screenpos},
{"screenrow", 0, 0, f_screenrow}, {"screenrow", 0, 0, f_screenrow},
{"screenstring", 2, 2, f_screenstring}, {"screenstring", 2, 2, f_screenstring},
{"search", 1, 4, f_search}, {"search", 1, 4, f_search},

View File

@@ -1189,6 +1189,96 @@ curs_columns(
curwin->w_valid |= VALID_WCOL|VALID_WROW|VALID_VIRTCOL; 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" * Scroll the current window down by "line_count" logical lines. "CTRL-Y"
*/ */

View File

@@ -2328,6 +2328,9 @@ do_mouse(
profile_setlimit(p_bdlay, &bevalexpr_due); profile_setlimit(p_bdlay, &bevalexpr_due);
bevalexpr_due_set = TRUE; bevalexpr_due_set = TRUE;
} }
#endif
#ifdef FEAT_TEXT_PROP
popup_handle_mouse_moved();
#endif #endif
return FALSE; return FALSE;
} }

View File

@@ -992,8 +992,6 @@ pum_position_at_mouse(int min_width)
# if defined(FEAT_BEVAL_TERM) || defined(PROTO) # if defined(FEAT_BEVAL_TERM) || defined(PROTO)
static pumitem_T *balloon_array = NULL; static pumitem_T *balloon_array = NULL;
static int balloon_arraysize; static int balloon_arraysize;
static int balloon_mouse_row = 0;
static int balloon_mouse_col = 0;
#define BALLOON_MIN_WIDTH 50 #define BALLOON_MIN_WIDTH 50
#define BALLOON_MIN_HEIGHT 10 #define BALLOON_MIN_HEIGHT 10
@@ -1209,8 +1207,9 @@ ui_post_balloon(char_u *mesg, list_T *list)
void void
ui_may_remove_balloon(void) ui_may_remove_balloon(void)
{ {
if (mouse_row != balloon_mouse_row || mouse_col != balloon_mouse_col) // For now: remove the balloon whenever the mouse moves to another screen
ui_remove_balloon(); // cell.
ui_remove_balloon();
} }
# endif # endif

View File

@@ -167,6 +167,35 @@ set_moved_columns(win_T *wp, int flags)
} }
} }
/*
* 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. * Return TRUE if "row"/"col" is on the border of the popup.
* The values are relative to the top-left corner. * The values are relative to the top-left corner.
@@ -335,6 +364,53 @@ apply_move_options(win_T *wp, dict_T *d)
get_pos_options(wp, d); get_pos_options(wp, d);
} }
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 static void
check_highlight(dict_T *dict, char *name, char_u **pval) check_highlight(dict_T *dict, char *name, char_u **pval)
{ {
@@ -541,31 +617,14 @@ apply_general_options(win_T *wp, dict_T *dict)
if (di != NULL) if (di != NULL)
{ {
set_moved_values(wp); set_moved_values(wp);
if (di->di_tv.v_type == VAR_STRING && di->di_tv.vval.v_string != NULL) handle_moved_argument(wp, di, FALSE);
{ }
char_u *s = di->di_tv.vval.v_string;
int flags = 0;
if (STRCMP(s, "word") == 0) di = dict_find(dict, (char_u *)"mousemoved", -1);
flags = FIND_IDENT | FIND_STRING; if (di != NULL)
else if (STRCMP(s, "WORD") == 0) {
flags = FIND_STRING; set_mousemoved_values(wp);
else if (STRCMP(s, "any") != 0) handle_moved_argument(wp, di, TRUE);
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); di = dict_find(dict, (char_u *)"filter", -1);
@@ -956,6 +1015,7 @@ typedef enum
{ {
TYPE_NORMAL, TYPE_NORMAL,
TYPE_ATCURSOR, TYPE_ATCURSOR,
TYPE_BEVAL,
TYPE_NOTIFICATION, TYPE_NOTIFICATION,
TYPE_DIALOG, TYPE_DIALOG,
TYPE_MENU TYPE_MENU
@@ -1137,17 +1197,33 @@ popup_create(typval_T *argvars, typval_T *rettv, create_type_T type)
{ {
wp->w_popup_pos = POPPOS_BOTLEFT; wp->w_popup_pos = POPPOS_BOTLEFT;
setcursor_mayforce(TRUE); setcursor_mayforce(TRUE);
wp->w_wantline = screen_screenrow(); wp->w_wantline = curwin->w_winrow + curwin->w_wrow;
if (wp->w_wantline == 0) // cursor in first line if (wp->w_wantline == 0) // cursor in first line
{ {
wp->w_wantline = 2; wp->w_wantline = 2;
wp->w_popup_pos = POPPOS_TOPLEFT; wp->w_popup_pos = POPPOS_TOPLEFT;
} }
wp->w_wantcol = screen_screencol() + 1; wp->w_wantcol = curwin->w_wincol + curwin->w_wcol + 1;
set_moved_values(wp); set_moved_values(wp);
set_moved_columns(wp, FIND_STRING); 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 // set default values
wp->w_zindex = POPUPWIN_DEFAULT_ZINDEX; wp->w_zindex = POPUPWIN_DEFAULT_ZINDEX;
wp->w_popup_close = POPCLOSE_NONE; wp->w_popup_close = POPCLOSE_NONE;
@@ -1275,6 +1351,15 @@ f_popup_atcursor(typval_T *argvars, typval_T *rettv)
popup_create(argvars, rettv, TYPE_ATCURSOR); popup_create(argvars, rettv, TYPE_ATCURSOR);
} }
/*
* 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". * Invoke the close callback for window "wp" with value "result".
* Careful: The callback may make "wp" invalid! * Careful: The callback may make "wp" invalid!
@@ -1334,6 +1419,48 @@ popup_close_for_mouse_click(win_T *wp)
popup_close_and_callback(wp, &res); 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 * In a filter: check if the typed key is a mouse event that is used for
* dragging the popup. * dragging the popup.
@@ -1821,7 +1948,7 @@ get_borderchars(dict_T *dict, win_T *wp)
} }
/* /*
* For popup_getoptions(): add a "moved" entry to "dict". * For popup_getoptions(): add a "moved" and "mousemoved" entry to "dict".
*/ */
static void static void
get_moved_list(dict_T *dict, win_T *wp) get_moved_list(dict_T *dict, win_T *wp)
@@ -1832,9 +1959,18 @@ get_moved_list(dict_T *dict, win_T *wp)
if (list != NULL) if (list != NULL)
{ {
dict_add_list(dict, "moved", list); 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_mincol);
list_append_number(list, wp->w_popup_maxcol); 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);
}
} }
/* /*

View File

@@ -1,5 +1,6 @@
/* beval.c */ /* beval.c */
int get_beval_info(BalloonEval *beval, int getword, win_T **winp, linenr_T *lnump, char_u **textp, int *colp); 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); void post_balloon(BalloonEval *beval, char_u *mesg, list_T *list);
int can_use_beval(void); int can_use_beval(void);
void general_beval_cb(BalloonEval *beval, int state); void general_beval_cb(BalloonEval *beval, int state);

View File

@@ -27,6 +27,7 @@ int curwin_col_off(void);
int win_col_off2(win_T *wp); int win_col_off2(win_T *wp);
int curwin_col_off2(void); int curwin_col_off2(void);
void curs_columns(int may_scroll); void curs_columns(int may_scroll);
void f_screenpos(typval_T *argvars, typval_T *rettv);
void scrolldown(long line_count, int byfold); void scrolldown(long line_count, int byfold);
void scrollup(long line_count, int byfold); void scrollup(long line_count, int byfold);
void check_topfill(win_T *wp, int down); void check_topfill(win_T *wp, int down);

View File

@@ -11,7 +11,9 @@ void popup_adjust_position(win_T *wp);
void f_popup_clear(typval_T *argvars, typval_T *rettv); void f_popup_clear(typval_T *argvars, typval_T *rettv);
void f_popup_create(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_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_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_menu(typval_T *argvars, typval_T *rettv);
void f_popup_filter_yesno(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); void f_popup_dialog(typval_T *argvars, typval_T *rettv);

View File

@@ -0,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|

View File

@@ -0,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|

View File

@@ -0,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|

View File

@@ -72,3 +72,31 @@ func Test_curswant_with_cursorline()
call assert_equal(6, winsaveview().curswant) call assert_equal(6, winsaveview().curswant)
quit! quit!
endfunc 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

View File

@@ -1005,6 +1005,53 @@ func Test_popup_atcursor()
bwipe! bwipe!
endfunc 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() func Test_popup_filter()
new new
call setline(1, 'some text') call setline(1, 'some text')
@@ -1413,7 +1460,7 @@ func Test_popup_moved()
let winid = popup_atcursor('text', {'moved': 'any'}) let winid = popup_atcursor('text', {'moved': 'any'})
redraw redraw
call assert_equal(1, popup_getpos(winid).visible) call assert_equal(1, popup_getpos(winid).visible)
call assert_equal([4, 4], popup_getoptions(winid).moved) call assert_equal([1, 4, 4], popup_getoptions(winid).moved)
" trigger the check for last_cursormoved by going into insert mode " trigger the check for last_cursormoved by going into insert mode
call feedkeys("li\<Esc>", 'xt') call feedkeys("li\<Esc>", 'xt')
call assert_equal({}, popup_getpos(winid)) call assert_equal({}, popup_getpos(winid))
@@ -1423,7 +1470,7 @@ func Test_popup_moved()
let winid = popup_atcursor('text', {'moved': 'word'}) let winid = popup_atcursor('text', {'moved': 'word'})
redraw redraw
call assert_equal(1, popup_getpos(winid).visible) call assert_equal(1, popup_getpos(winid).visible)
call assert_equal([4, 7], popup_getoptions(winid).moved) call assert_equal([1, 4, 7], popup_getoptions(winid).moved)
call feedkeys("hi\<Esc>", 'xt') call feedkeys("hi\<Esc>", 'xt')
call assert_equal({}, popup_getpos(winid)) call assert_equal({}, popup_getpos(winid))
call popup_clear() call popup_clear()
@@ -1432,7 +1479,7 @@ func Test_popup_moved()
let winid = popup_atcursor('text', {'moved': 'word'}) let winid = popup_atcursor('text', {'moved': 'word'})
redraw redraw
call assert_equal(1, popup_getpos(winid).visible) call assert_equal(1, popup_getpos(winid).visible)
call assert_equal([4, 7], popup_getoptions(winid).moved) call assert_equal([1, 4, 7], popup_getoptions(winid).moved)
call feedkeys("li\<Esc>", 'xt') call feedkeys("li\<Esc>", 'xt')
call assert_equal(1, popup_getpos(winid).visible) call assert_equal(1, popup_getpos(winid).visible)
call feedkeys("ei\<Esc>", 'xt') call feedkeys("ei\<Esc>", 'xt')
@@ -1446,7 +1493,7 @@ func Test_popup_moved()
let winid = popup_atcursor('text', {}) let winid = popup_atcursor('text', {})
redraw redraw
call assert_equal(1, popup_getpos(winid).visible) call assert_equal(1, popup_getpos(winid).visible)
call assert_equal([2, 15], popup_getoptions(winid).moved) call assert_equal([2, 2, 15], popup_getoptions(winid).moved)
call feedkeys("eli\<Esc>", 'xt') call feedkeys("eli\<Esc>", 'xt')
call assert_equal(1, popup_getpos(winid).visible) call assert_equal(1, popup_getpos(winid).visible)
call feedkeys("wi\<Esc>", 'xt') call feedkeys("wi\<Esc>", 'xt')

View File

@@ -777,6 +777,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
1645,
/**/ /**/
1644, 1644,
/**/ /**/