Skip to content

Commit b3d17a2

Browse files
committed
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.
1 parent 5b19e5b commit b3d17a2

18 files changed

Lines changed: 522 additions & 63 deletions

runtime/doc/eval.txt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2535,6 +2535,7 @@ or({expr}, {expr}) Number bitwise OR
25352535
pathshorten({expr}) String shorten directory names in a path
25362536
perleval({expr}) any evaluate |Perl| expression
25372537
popup_atcursor({what}, {options}) Number create popup window near the cursor
2538+
popup_beval({what}, {options}) Number create popup window for 'ballooneval'
25382539
popup_clear() none close all popup windows
25392540
popup_close({id} [, {result}]) none close popup window {id}
25402541
popup_create({what}, {options}) Number create a popup window
@@ -2613,6 +2614,7 @@ screenattr({row}, {col}) Number attribute at screen position
26132614
screenchar({row}, {col}) Number character at screen position
26142615
screenchars({row}, {col}) List List of characters at screen position
26152616
screencol() Number current cursor column
2617+
screenpos({winid}, {lnum}, {col}) Dict screen row and col of a text character
26162618
screenrow() Number current cursor row
26172619
screenstring({row}, {col}) String characters at screen position
26182620
search({pattern} [, {flags} [, {stopline} [, {timeout}]]])
@@ -7907,6 +7909,23 @@ screencol() *screencol()*
79077909
nnoremap <expr> GG ":echom ".screencol()."\n"
79087910
nnoremap <silent> GG :echom screencol()<CR>
79097911
<
7912+
screenpos({winid}, {lnum}, {col}) *screenpos()*
7913+
The result is a Dict with the screen position of the text
7914+
character in window {winid} at buffer line {lnum} and column
7915+
{col}. {col} is a one-based byte index.
7916+
The Dict has these members:
7917+
row screen row
7918+
col first screen column
7919+
endcol last screen column
7920+
curscol cursor screen column
7921+
If the specified position is not visible, all values are zero.
7922+
The "endcol" value differs from "col" when the character
7923+
occupies more than one screen cell. E.g. for a Tab "col" can
7924+
be 1 and "endcol" can be 8.
7925+
The "curscol" value is where the cursor would be placed. For
7926+
a Tab it would be the same as "endcol", while for a double
7927+
width character it would be the same as "col".
7928+
79107929
screenrow() *screenrow()*
79117930
The result is a Number, which is the current screen row of the
79127931
cursor. The top line has number one.

runtime/doc/popup.txt

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,8 @@ Creating a popup window:
146146
|popup_create()| centered in the screen
147147
|popup_atcursor()| just above the cursor position, closes when
148148
the cursor moves away
149+
|popup_beval()| at the position indicated by v:beval_
150+
variables, closes when the mouse moves away
149151
|popup_notification()| show a notification for three seconds
150152
|popup_dialog()| centered with padding and border
151153
|popup_menu()| prompt for selecting an item from a list
@@ -184,6 +186,20 @@ popup_atcursor({what}, {options}) *popup_atcursor()*
184186
< Use {options} to change the properties.
185187

186188

189+
popup_beval({what}, {options}) *popup_beval()*
190+
Show the {what} above the position from 'ballooneval' and
191+
close it when the mouse moves. This works like: >
192+
let pos = screenpos(v:beval_winnr, v:beval_lnum, v:beval_col)
193+
call popup_create({what}, {
194+
\ 'pos': 'botleft',
195+
\ 'line': pos.lnum - 1,
196+
\ 'col': pos.col,
197+
\ 'mousemoved': 'WORD',
198+
\ })
199+
< Use {options} to change the properties.
200+
See |popup_beval_example| for an example use.
201+
202+
187203
*popup_clear()*
188204
popup_clear() Emergency solution to a misbehaving plugin: close all popup
189205
windows for the current tab and global popups.
@@ -276,8 +292,11 @@ popup_getoptions({id}) *popup_getoptions()*
276292
A zero value means the option was not set. For "zindex" the
277293
default value is returned, not zero.
278294

279-
The "moved" entry is a list with minimum and maximum column,
280-
[0, 0] when not set.
295+
The "moved" entry is a list with line number, minimum and
296+
maximum column, [0, 0, 0] when not set.
297+
298+
The "mousemoved" entry is a list with screen row, minimum and
299+
maximum screen column, [0, 0, 0] when not set.
281300

282301
"border" and "padding" are not included when all values are
283302
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:
566585
- "any": if the cursor moved at all
567586
- "word": if the cursor moved outside |<cword>|
568587
- "WORD": if the cursor moved outside |<cWORD>|
588+
- "expr": if the cursor moved outside |<cexpr>|
569589
- [{start}, {end}]: if the cursor moved before column
570590
{start} or after {end}
571591
The popup also closes if the cursor moves to another
@@ -736,5 +756,45 @@ Extend popup_filter_menu() with shortcut keys: >
736756
return popup_filter_menu(a:id, a:key)
737757
endfunc
738758
<
759+
*popup_beval_example*
760+
Example for using a popup window for 'ballooneval': >
761+
762+
set ballooneval balloonevalterm
763+
set balloonexpr=BalloonExpr()
764+
let s:winid = 0
765+
766+
func BalloonExpr()
767+
if s:winid
768+
call popup_close(s:winid)
769+
let s:winid = 0
770+
endif
771+
let s:winid = popup_beval([bufname(v:beval_bufnr), v:beval_text], {})
772+
return ''
773+
endfunc
774+
<
775+
If the text has to be obtained asynchronously return an empty string from the
776+
expression function and call popup_beval() once the text is available. In
777+
this example similated with a timer callback: >
778+
779+
set ballooneval balloonevalterm
780+
set balloonexpr=BalloonExpr()
781+
let s:winid = 0
782+
783+
func BalloonExpr()
784+
if s:winid
785+
call popup_close(s:winid)
786+
let s:winid = 0
787+
endif
788+
" simulate an asynchronous loopup for the text to display
789+
let s:balloonFile = bufname(v:beval_bufnr)
790+
let s:balloonWord = v:beval_text
791+
call timer_start(100, 'ShowPopup')
792+
return ''
793+
endfunc
794+
795+
func ShowPopup(id)
796+
let s:winid = popup_beval([s:balloonFile, s:balloonWord], {})
797+
endfunc
798+
<
739799

740800
vim:tw=78:ts=8:noet:ft=help:norl:

runtime/doc/usr_41.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -720,6 +720,7 @@ Cursor and mark position: *cursor-functions* *mark-functions*
720720
cursor() position the cursor at a line/column
721721
screencol() get screen column of the cursor
722722
screenrow() get screen row of the cursor
723+
screenpos() screen row and col of a text character
723724
getcurpos() get position of the cursor
724725
getpos() get position of cursor, mark, etc.
725726
setpos() set position of cursor, mark, etc.
@@ -1046,6 +1047,8 @@ Popup window: *popup-window-functions*
10461047
popup_create() create popup centered in the screen
10471048
popup_atcursor() create popup just above the cursor position,
10481049
closes when the cursor moves away
1050+
popup_beval() at the position indicated by v:beval_
1051+
variables, closes when the mouse moves away
10491052
popup_notification() show a notification for three seconds
10501053
popup_dialog() create popup centered with padding and border
10511054
popup_menu() prompt for selecting an item from a list

src/beval.c

Lines changed: 62 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
/*
1616
* Get the text and position to be evaluated for "beval".
17-
* If "getword" is true the returned text is not the whole line but the
17+
* If "getword" is TRUE the returned text is not the whole line but the
1818
* relevant word in allocated memory.
1919
* Returns OK or FAIL.
2020
*/
@@ -27,12 +27,8 @@ get_beval_info(
2727
char_u **textp,
2828
int *colp)
2929
{
30-
win_T *wp;
3130
int row, col;
32-
char_u *lbuf;
33-
linenr_T lnum;
3431

35-
*textp = NULL;
3632
# ifdef FEAT_BEVAL_TERM
3733
# ifdef FEAT_GUI
3834
if (!gui.in_use)
@@ -49,22 +45,68 @@ get_beval_info(
4945
col = X_2_COL(beval->x);
5046
}
5147
#endif
48+
if (find_word_under_cursor(row, col, getword,
49+
FIND_IDENT + FIND_STRING + FIND_EVAL,
50+
winp, lnump, textp, colp) == OK)
51+
{
52+
#ifdef FEAT_VARTABS
53+
vim_free(beval->vts);
54+
beval->vts = tabstop_copy((*winp)->w_buffer->b_p_vts_array);
55+
if ((*winp)->w_buffer->b_p_vts_array != NULL && beval->vts == NULL)
56+
{
57+
if (getword)
58+
vim_free(*textp);
59+
return FAIL;
60+
}
61+
#endif
62+
beval->ts = (*winp)->w_buffer->b_p_ts;
63+
return OK;
64+
}
65+
66+
return FAIL;
67+
}
68+
69+
/*
70+
* Find text under the mouse position "row" / "col".
71+
* If "getword" is TRUE the returned text in "*textp" is not the whole line but
72+
* the relevant word in allocated memory.
73+
* Return OK if found.
74+
* Return FAIL if not found, no text at the mouse position.
75+
*/
76+
int
77+
find_word_under_cursor(
78+
int mouserow,
79+
int mousecol,
80+
int getword,
81+
int flags, // flags for find_ident_at_pos()
82+
win_T **winp, // can be NULL
83+
linenr_T *lnump, // can be NULL
84+
char_u **textp,
85+
int *colp)
86+
{
87+
int row = mouserow;
88+
int col = mousecol;
89+
win_T *wp;
90+
char_u *lbuf;
91+
linenr_T lnum;
92+
93+
*textp = NULL;
5294
wp = mouse_find_win(&row, &col, FAIL_POPUP);
5395
if (wp != NULL && row >= 0 && row < wp->w_height && col < wp->w_width)
5496
{
55-
/* Found a window and the cursor is in the text. Now find the line
56-
* number. */
97+
// Found a window and the cursor is in the text. Now find the line
98+
// number.
5799
if (!mouse_comp_pos(wp, &row, &col, &lnum))
58100
{
59-
/* Not past end of the file. */
101+
// Not past end of the file.
60102
lbuf = ml_get_buf(wp->w_buffer, lnum, FALSE);
61103
if (col <= win_linetabsize(wp, lbuf, (colnr_T)MAXCOL))
62104
{
63-
/* Not past end of line. */
105+
// Not past end of line.
64106
if (getword)
65107
{
66-
/* For Netbeans we get the relevant part of the line
67-
* instead of the whole line. */
108+
// For Netbeans we get the relevant part of the line
109+
// instead of the whole line.
68110
int len;
69111
pos_T *spos = NULL, *epos = NULL;
70112

@@ -93,9 +135,9 @@ get_beval_info(
93135
? col <= (int)epos->col
94136
: lnum < epos->lnum))
95137
{
96-
/* Visual mode and pointing to the line with the
97-
* Visual selection: return selected text, with a
98-
* maximum of one line. */
138+
// Visual mode and pointing to the line with the
139+
// Visual selection: return selected text, with a
140+
// maximum of one line.
99141
if (spos->lnum != epos->lnum || spos->col == epos->col)
100142
return FAIL;
101143

@@ -109,33 +151,27 @@ get_beval_info(
109151
}
110152
else
111153
{
112-
/* Find the word under the cursor. */
154+
// Find the word under the cursor.
113155
++emsg_off;
114156
len = find_ident_at_pos(wp, lnum, (colnr_T)col, &lbuf,
115-
FIND_IDENT + FIND_STRING + FIND_EVAL);
157+
flags);
116158
--emsg_off;
117159
if (len == 0)
118160
return FAIL;
119161
lbuf = vim_strnsave(lbuf, len);
120162
}
121163
}
122164

123-
*winp = wp;
124-
*lnump = lnum;
165+
if (winp != NULL)
166+
*winp = wp;
167+
if (lnump != NULL)
168+
*lnump = lnum;
125169
*textp = lbuf;
126170
*colp = col;
127-
#ifdef FEAT_VARTABS
128-
vim_free(beval->vts);
129-
beval->vts = tabstop_copy(wp->w_buffer->b_p_vts_array);
130-
if (wp->w_buffer->b_p_vts_array != NULL && beval->vts == NULL)
131-
return FAIL;
132-
#endif
133-
beval->ts = wp->w_buffer->b_p_ts;
134171
return OK;
135172
}
136173
}
137174
}
138-
139175
return FAIL;
140176
}
141177

src/evalfunc.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -771,6 +771,7 @@ static struct fst
771771
#endif
772772
#ifdef FEAT_TEXT_PROP
773773
{"popup_atcursor", 2, 2, f_popup_atcursor},
774+
{"popup_beval", 2, 2, f_popup_beval},
774775
{"popup_clear", 0, 0, f_popup_clear},
775776
{"popup_close", 1, 2, f_popup_close},
776777
{"popup_create", 2, 2, f_popup_create},
@@ -849,6 +850,7 @@ static struct fst
849850
{"screenchar", 2, 2, f_screenchar},
850851
{"screenchars", 2, 2, f_screenchars},
851852
{"screencol", 0, 0, f_screencol},
853+
{"screenpos", 3, 3, f_screenpos},
852854
{"screenrow", 0, 0, f_screenrow},
853855
{"screenstring", 2, 2, f_screenstring},
854856
{"search", 1, 4, f_search},

0 commit comments

Comments
 (0)