Skip to content

Commit 2fd8e35

Browse files
committed
patch 8.1.1443: popup window padding and border not implemented yet
Problem: Popup window padding and border not implemented yet. Solution: Implement padding and border. Add core position and size to popup_getpos().
1 parent 8caaf82 commit 2fd8e35

7 files changed

Lines changed: 250 additions & 29 deletions

File tree

runtime/doc/popup.txt

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -90,11 +90,7 @@ Probably 2. is the best choice.
9090

9191
IMPLEMENTATION:
9292
- Code is in popupwin.c
93-
- Invoke filter with character before mapping?
94-
- Handle screen resize in screenalloc(). (Ben Jackson, #4467)
9593
- Why does 'nrformats' leak from the popup window buffer???
96-
- Implement padding
97-
- Implement border
9894
- Make redrawing more efficient and avoid flicker.
9995
Store popup info in a mask, use the mask in screen_line()
10096
Keep mask until next update_screen(), find differences and redraw affected
@@ -103,7 +99,8 @@ IMPLEMENTATION:
10399
Fix redrawing problem when scrolling non-current window
104100
Fix redrawing the statusline on top of a popup
105101
- Disable commands, feedkeys(), CTRL-W, etc. in a popup window.
106-
Use NOT_IN_POPUP_WINDOW.
102+
Use NOT_IN_POPUP_WINDOW for more commands.
103+
- Invoke filter with character before mapping?
107104
- Figure out the size and position better.
108105
if wrapping splits a double-wide character
109106
if wrapping inserts indent
@@ -255,12 +252,19 @@ popup_getpos({id}) *popup_getpos()*
255252
with these entries:
256253
col screen column of the popup, one-based
257254
line screen line of the popup, one-based
258-
width width of the popup in screen cells
259-
height height of the popup in screen cells
255+
width width of the whole popup in screen cells
256+
height height of the whole popup in screen cells
257+
core_col screen column of the text box
258+
core_line screen line of the text box
259+
core_width width of the text box in screen cells
260+
core_height height of the text box in screen cells
260261
visible one if the popup is displayed, zero if hidden
261262
Note that these are the actual screen positions. They differ
262263
from the values in `popup_getoptions()` for the sizing and
263264
positioning mechanism applied.
265+
266+
The "core_" values exclude the padding and border.
267+
264268
If popup window {id} is not found an empty Dict is returned.
265269

266270

@@ -361,11 +365,10 @@ The second argument of |popup_create()| is a dictionary with options:
361365
padding uses the 'wincolor' highlight; Example: [1, 2,
362366
1, 3] has 1 line of padding above, 2 columns on the
363367
right, 1 line below and 3 columns on the left
364-
{not implemented yet}
365368
border list with numbers, defining the border thickness
366369
above/right/below/left of the popup (similar to CSS);
370+
only values of zero and non-zero are recognized;
367371
an empty list uses a border of 1 all around
368-
{not implemented yet}
369372
borderhighlight highlight group name to use for the border
370373
{not implemented yet}
371374
borderchars list with characters, defining the character to use

src/popupwin.c

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,38 @@ get_pos_options(win_T *wp, dict_T *dict)
101101
}
102102
}
103103

104+
static void
105+
get_padding_border(dict_T *dict, int *array, char *name, int max_val)
106+
{
107+
dictitem_T *di;
108+
109+
vim_memset(array, 0, sizeof(int) * 4);
110+
di = dict_find(dict, (char_u *)name, -1);
111+
if (di != NULL)
112+
{
113+
if (di->di_tv.v_type != VAR_LIST)
114+
emsg(_(e_listreq));
115+
else
116+
{
117+
list_T *list = di->di_tv.vval.v_list;
118+
listitem_T *li;
119+
int i;
120+
int nr;
121+
122+
for (i = 0; i < 4; ++i)
123+
array[i] = 1;
124+
if (list != NULL)
125+
for (i = 0, li = list->lv_first; i < 4 && i < list->lv_len;
126+
++i, li = li->li_next)
127+
{
128+
nr = (int)tv_get_number(&li->li_tv);
129+
if (nr >= 0)
130+
array[i] = nr > max_val ? max_val : nr;
131+
}
132+
}
133+
}
134+
}
135+
104136
/*
105137
* Go through the options in "dict" and apply them to buffer "buf" displayed in
106138
* popup window "wp".
@@ -176,6 +208,9 @@ apply_options(win_T *wp, buf_T *buf UNUSED, dict_T *dict, int atcursor)
176208
if (callback.cb_name != NULL)
177209
set_callback(&wp->w_filter_cb, &callback);
178210
}
211+
212+
get_padding_border(dict, wp->w_popup_padding, "padding", 999);
213+
get_padding_border(dict, wp->w_popup_border, "border", 1);
179214
}
180215

181216
/*
@@ -700,16 +735,28 @@ f_popup_getpos(typval_T *argvars, typval_T *rettv)
700735
dict_T *dict;
701736
int id = (int)tv_get_number(argvars);
702737
win_T *wp = find_popup_win(id);
738+
int top_extra;
739+
int left_extra;
703740

704741
if (rettv_dict_alloc(rettv) == OK)
705742
{
706743
if (wp == NULL)
707744
return; // invalid {id}
745+
top_extra = wp->w_popup_border[0] + wp->w_popup_padding[0];
746+
left_extra = wp->w_popup_border[3] + wp->w_popup_padding[3];
747+
708748
dict = rettv->vval.v_dict;
749+
709750
dict_add_number(dict, "line", wp->w_winrow + 1);
710751
dict_add_number(dict, "col", wp->w_wincol + 1);
711-
dict_add_number(dict, "width", wp->w_width);
712-
dict_add_number(dict, "height", wp->w_height);
752+
dict_add_number(dict, "width", wp->w_width + left_extra + wp->w_popup_border[1] + wp->w_popup_padding[1]);
753+
dict_add_number(dict, "height", wp->w_height + top_extra + wp->w_popup_border[2] + wp->w_popup_padding[2]);
754+
755+
dict_add_number(dict, "core_line", wp->w_winrow + 1 + top_extra);
756+
dict_add_number(dict, "core_col", wp->w_wincol + 1 + left_extra);
757+
dict_add_number(dict, "core_width", wp->w_width);
758+
dict_add_number(dict, "core_height", wp->w_height);
759+
713760
dict_add_number(dict, "visible",
714761
(wp->w_popup_flags & POPF_HIDDEN) == 0);
715762
}

src/screen.c

Lines changed: 122 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -991,11 +991,46 @@ update_debug_sign(buf_T *buf, linenr_T lnum)
991991
}
992992
#endif
993993

994+
/*
995+
* Get 'wincolor' attribute for window "wp". If not set and "wp" is a popup
996+
* window then get the "Pmenu" highlight attribute.
997+
*/
998+
static int
999+
get_wcr_attr(win_T *wp)
1000+
{
1001+
int wcr_attr = 0;
1002+
1003+
if (*wp->w_p_wcr != NUL)
1004+
wcr_attr = syn_name2attr(wp->w_p_wcr);
9941005
#ifdef FEAT_TEXT_PROP
1006+
if (bt_popup(wp->w_buffer) && wcr_attr == 0)
1007+
wcr_attr = HL_ATTR(HLF_PNI);
1008+
#endif
1009+
return wcr_attr;
1010+
}
1011+
1012+
#ifdef FEAT_TEXT_PROP
1013+
/*
1014+
* Return a string of "len" spaces in IObuff.
1015+
*/
1016+
static char_u *
1017+
get_spaces(int len)
1018+
{
1019+
vim_memset(IObuff, ' ', (size_t)len);
1020+
IObuff[len] = NUL;
1021+
return IObuff;
1022+
}
1023+
9951024
static void
9961025
update_popups(void)
9971026
{
9981027
win_T *wp;
1028+
int top_off;
1029+
int left_off;
1030+
int total_width;
1031+
int total_height;
1032+
int popup_attr;
1033+
int row;
9991034

10001035
// Find the window with the lowest zindex that hasn't been updated yet,
10011036
// so that the window with a higher zindex is drawn later, thus goes on
@@ -1008,29 +1043,98 @@ update_popups(void)
10081043
if (wp->w_popup_last_changedtick != CHANGEDTICK(wp->w_buffer))
10091044
popup_adjust_position(wp);
10101045

1046+
// adjust w_winrow and w_wincol for border and padding, since
1047+
// win_update() doesn't handle them.
1048+
top_off = wp->w_popup_padding[0] + wp->w_popup_border[0];
1049+
left_off = wp->w_popup_padding[3] + wp->w_popup_border[3];
1050+
wp->w_winrow += top_off;
1051+
wp->w_wincol += left_off;
1052+
1053+
// Draw the popup text.
10111054
win_update(wp);
1055+
1056+
wp->w_winrow -= top_off;
1057+
wp->w_wincol -= left_off;
1058+
1059+
total_width = wp->w_popup_border[3] + wp->w_popup_padding[3]
1060+
+ wp->w_width + wp->w_popup_padding[1] + wp->w_popup_border[1];
1061+
total_height = wp->w_popup_border[0] + wp->w_popup_padding[0]
1062+
+ wp->w_height + wp->w_popup_padding[2] + wp->w_popup_border[2];
1063+
popup_attr = get_wcr_attr(wp);
1064+
1065+
if (wp->w_popup_border[0] > 0)
1066+
{
1067+
// top border
1068+
screen_fill(wp->w_winrow, wp->w_winrow + 1,
1069+
wp->w_wincol,
1070+
wp->w_wincol + total_width,
1071+
wp->w_popup_border[3] != 0 ? '+' : '-',
1072+
'-', popup_attr);
1073+
if (wp->w_popup_border[1] > 0)
1074+
screen_puts((char_u *)"+", wp->w_winrow,
1075+
wp->w_wincol + total_width - 1, popup_attr);
1076+
}
1077+
1078+
if (wp->w_popup_padding[0] > 0)
1079+
{
1080+
// top padding
1081+
row = wp->w_winrow + wp->w_popup_border[0];
1082+
screen_fill(row, row + wp->w_popup_padding[0],
1083+
wp->w_wincol + wp->w_popup_border[3],
1084+
wp->w_wincol + total_width - wp->w_popup_border[1],
1085+
' ', ' ', popup_attr);
1086+
}
1087+
1088+
for (row = wp->w_winrow + wp->w_popup_border[0];
1089+
row < wp->w_winrow + total_height - wp->w_popup_border[2];
1090+
++row)
1091+
{
1092+
// left border
1093+
if (wp->w_popup_border[3] > 0)
1094+
screen_puts((char_u *)"|", row, wp->w_wincol, popup_attr);
1095+
// left padding
1096+
if (wp->w_popup_padding[3] > 0)
1097+
screen_puts(get_spaces(wp->w_popup_padding[3]), row,
1098+
wp->w_wincol + wp->w_popup_border[3], popup_attr);
1099+
// right border
1100+
if (wp->w_popup_border[1] > 0)
1101+
screen_puts((char_u *)"|", row,
1102+
wp->w_wincol + total_width - 1, popup_attr);
1103+
// right padding
1104+
if (wp->w_popup_padding[1] > 0)
1105+
screen_puts(get_spaces(wp->w_popup_padding[1]), row,
1106+
wp->w_wincol + wp->w_popup_border[3]
1107+
+ wp->w_popup_padding[3] + wp->w_width, popup_attr);
1108+
}
1109+
1110+
if (wp->w_popup_padding[2] > 0)
1111+
{
1112+
// bottom padding
1113+
row = wp->w_winrow + wp->w_popup_border[0]
1114+
+ wp->w_popup_padding[0] + wp->w_height;
1115+
screen_fill(row, row + wp->w_popup_padding[2],
1116+
wp->w_wincol + wp->w_popup_border[3],
1117+
wp->w_wincol + total_width - wp->w_popup_border[1],
1118+
' ', ' ', popup_attr);
1119+
}
1120+
1121+
if (wp->w_popup_border[2] > 0)
1122+
{
1123+
// bottom border
1124+
row = wp->w_winrow + total_height - 1;
1125+
screen_fill(row , row + 1,
1126+
wp->w_wincol,
1127+
wp->w_wincol + total_width,
1128+
wp->w_popup_border[3] != 0 ? '+' : '-',
1129+
'-', popup_attr);
1130+
if (wp->w_popup_border[1] > 0)
1131+
screen_puts((char_u *)"+", row,
1132+
wp->w_wincol + total_width - 1, popup_attr);
1133+
}
10121134
}
10131135
}
10141136
#endif
10151137

1016-
/*
1017-
* Get 'wincolor' attribute for window "wp". If not set and "wp" is a popup
1018-
* window then get the "Pmenu" highlight attribute.
1019-
*/
1020-
static int
1021-
get_wcr_attr(win_T *wp)
1022-
{
1023-
int wcr_attr = 0;
1024-
1025-
if (*wp->w_p_wcr != NUL)
1026-
wcr_attr = syn_name2attr(wp->w_p_wcr);
1027-
#ifdef FEAT_TEXT_PROP
1028-
if (bt_popup(wp->w_buffer) && wcr_attr == 0)
1029-
wcr_attr = HL_ATTR(HLF_PNI);
1030-
#endif
1031-
return wcr_attr;
1032-
}
1033-
10341138
#if defined(FEAT_GUI) || defined(PROTO)
10351139
/*
10361140
* Update a single window, its status line and maybe the command line msg.

src/structs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2888,6 +2888,8 @@ struct window_S
28882888
int w_maxwidth; // "maxwidth" for popup window
28892889
int w_wantline; // "line" for popup window
28902890
int w_wantcol; // "col" for popup window
2891+
int w_popup_padding[4]; // popup padding top/right/bot/left
2892+
int w_popup_border[4]; // popup border top/right/bot/left
28912893
varnumber_T w_popup_last_changedtick; // b:changedtick when position was
28922894
// computed
28932895
callback_T w_filter_cb; // popup filter callback
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
>1+0&#ffffff0| @73
2+
|2| |++0#0000001#ffd7ff255|-@11|+| +0#0000000#ffffff0@5| +0#0000001#ffd7ff255@14| +0#0000000#ffffff0@4|++0#0000001#ffd7ff255|-@11|+| +0#0000000#ffffff0@18
3+
|3| ||+0#0000001#ffd7ff255|h|e|l@1|o| |b|o|r|d|e|r||| +0#0000000#ffffff0@5| +0#0000001#ffd7ff255|h|e|l@1|o| |p|a|d@1|i|n|g| | +0#0000000#ffffff0@4||+0#0000001#ffd7ff255| @11||| +0#0000000#ffffff0@18
4+
|4| |++0#0000001#ffd7ff255|-@11|+| +0#0000000#ffffff0@5| +0#0000001#ffd7ff255@14| +0#0000000#ffffff0@4||+0#0000001#ffd7ff255| |h|e|l@1|o| |b|o|t|h| ||| +0#0000000#ffffff0@18
5+
|5| @40||+0#0000001#ffd7ff255| @11||| +0#0000000#ffffff0@18
6+
|6| |++0#0000001#ffd7ff255|-@8| +0#0000000#ffffff0@9| +0#0000001#ffd7ff255@14| +0#0000000#ffffff0@4|++0#0000001#ffd7ff255|-@11|+| +0#0000000#ffffff0@18
7+
|7| ||+0#0000001#ffd7ff255|b|o|r|d|e|r| |T|L| +0#0000000#ffffff0@9| +0#0000001#ffd7ff255@3|p|a|d@1|i|n|g|s| @2| +0#0000000#ffffff0@37
8+
|8| @20| +0#0000001#ffd7ff255@14| +0#0000000#ffffff0@37
9+
|9| @20| +0#0000001#ffd7ff255@14| +0#0000000#ffffff0@37
10+
|1|0| @72
11+
|1@1| @72
12+
|1|2| @72
13+
|1|3| @72
14+
|1|4| @72
15+
@57|1|,|1| @10|T|o|p|

src/testdir/test_popupwin.vim

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,54 @@ func Test_simple_popup()
5656
call delete('XtestPopup')
5757
endfunc
5858

59+
func Test_popup_with_border_and_padding()
60+
if !CanRunVimInTerminal()
61+
return
62+
endif
63+
call writefile([
64+
\ "call setline(1, range(1, 100))",
65+
\ "call popup_create('hello border', {'line': 2, 'col': 3, 'border': []})",
66+
\ "call popup_create('hello padding', {'line': 2, 'col': 23, 'padding': []})",
67+
\ "call popup_create('hello both', {'line': 2, 'col': 43, 'border': [], 'padding': []})",
68+
\ "call popup_create('border TL', {'line': 6, 'col': 3, 'border': [1, 0, 0, 4]})",
69+
\ "call popup_create('paddings', {'line': 6, 'col': 23, 'padding': [1, 3, 2, 4]})",
70+
\], 'XtestPopupBorder')
71+
let buf = RunVimInTerminal('-S XtestPopupBorder', {'rows': 15})
72+
call VerifyScreenDump(buf, 'Test_popupwin_20', {})
73+
74+
" clean up
75+
call StopVimInTerminal(buf)
76+
call delete('XtestPopupBorder')
77+
78+
let with_border_or_padding = {
79+
\ 'line': 2,
80+
\ 'core_line': 3,
81+
\ 'col': 3,
82+
\ 'core_col': 4,
83+
\ 'width': 14,
84+
\ 'core_width': 12,
85+
\ 'height': 3,
86+
\ 'core_height': 1,
87+
\ 'visible': 1}
88+
let winid = popup_create('hello border', {'line': 2, 'col': 3, 'border': []})",
89+
call assert_equal(with_border_or_padding, popup_getpos(winid))
90+
91+
let winid = popup_create('hello paddng', {'line': 2, 'col': 3, 'padding': []})
92+
call assert_equal(with_border_or_padding, popup_getpos(winid))
93+
94+
let winid = popup_create('hello both', {'line': 3, 'col': 8, 'border': [], 'padding': []})
95+
call assert_equal({
96+
\ 'line': 3,
97+
\ 'core_line': 5,
98+
\ 'col': 8,
99+
\ 'core_col': 10,
100+
\ 'width': 14,
101+
\ 'core_width': 10,
102+
\ 'height': 5,
103+
\ 'core_height': 1,
104+
\ 'visible': 1}, popup_getpos(winid))
105+
endfunc
106+
59107
func Test_popup_with_syntax_win_execute()
60108
if !CanRunVimInTerminal()
61109
return

src/version.c

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

768768
static int included_patches[] =
769769
{ /* Add new patch number below this line */
770+
/**/
771+
1443,
770772
/**/
771773
1442,
772774
/**/

0 commit comments

Comments
 (0)