Skip to content

Commit 491ac28

Browse files
committed
patch 8.1.0062: popup menu broken if a callback changes the window layout
Problem: Popup menu broken if a callback changes the window layout. (Qiming Zhao) Solution: Recompute the popup menu position if needed. Redraw the ruler even when the popup menu is displayed.
1 parent 84a9308 commit 491ac28

File tree

4 files changed

+71
-20
lines changed

4 files changed

+71
-20
lines changed

src/popupmnu.c

Lines changed: 58 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,12 @@ static int pum_scrollbar; /* TRUE when scrollbar present */
2929
static int pum_row; /* top row of pum */
3030
static int pum_col; /* left column of pum */
3131

32+
static int pum_win_row;
33+
static int pum_win_height;
34+
static int pum_win_col;
35+
static int pum_win_wcol;
36+
static int pum_win_width;
37+
3238
static int pum_do_redraw = FALSE; /* do redraw anyway */
3339

3440
static int pum_set_selected(int n, int repeat);
@@ -81,7 +87,6 @@ pum_display(
8187
{
8288
int def_width;
8389
int max_width;
84-
int row;
8590
int context_lines;
8691
int cursor_col;
8792
int above_row;
@@ -103,7 +108,13 @@ pum_display(
103108
validate_cursor_col();
104109
pum_array = NULL;
105110

106-
row = curwin->w_wrow + W_WINROW(curwin);
111+
// Remember the essential parts of the window position and size, so we
112+
// can decide when to reposition the popup menu.
113+
pum_win_row = curwin->w_wrow + W_WINROW(curwin);
114+
pum_win_height = curwin->w_height;
115+
pum_win_col = curwin->w_wincol;
116+
pum_win_wcol = curwin->w_wcol;
117+
pum_win_width = curwin->w_width;
107118

108119
#if defined(FEAT_QUICKFIX)
109120
FOR_ALL_WINDOWS(pvwin)
@@ -128,28 +139,28 @@ pum_display(
128139
if (p_ph > 0 && pum_height > p_ph)
129140
pum_height = p_ph;
130141

131-
/* Put the pum below "row" if possible. If there are few lines decide
142+
/* Put the pum below "pum_win_row" if possible. If there are few lines decide
132143
* on where there is more room. */
133-
if (row + 2 >= below_row - pum_height
134-
&& row - above_row > (below_row - above_row) / 2)
144+
if (pum_win_row + 2 >= below_row - pum_height
145+
&& pum_win_row - above_row > (below_row - above_row) / 2)
135146
{
136-
/* pum above "row" */
147+
/* pum above "pum_win_row" */
137148

138149
/* Leave two lines of context if possible */
139150
if (curwin->w_wrow - curwin->w_cline_row >= 2)
140151
context_lines = 2;
141152
else
142153
context_lines = curwin->w_wrow - curwin->w_cline_row;
143154

144-
if (row >= size + context_lines)
155+
if (pum_win_row >= size + context_lines)
145156
{
146-
pum_row = row - size - context_lines;
157+
pum_row = pum_win_row - size - context_lines;
147158
pum_height = size;
148159
}
149160
else
150161
{
151162
pum_row = 0;
152-
pum_height = row - context_lines;
163+
pum_height = pum_win_row - context_lines;
153164
}
154165
if (p_ph > 0 && pum_height > p_ph)
155166
{
@@ -159,7 +170,7 @@ pum_display(
159170
}
160171
else
161172
{
162-
/* pum below "row" */
173+
/* pum below "pum_win_row" */
163174

164175
/* Leave two lines of context if possible */
165176
if (curwin->w_cline_row
@@ -169,7 +180,7 @@ pum_display(
169180
context_lines = curwin->w_cline_row
170181
+ curwin->w_cline_height - curwin->w_wrow;
171182

172-
pum_row = row + context_lines;
183+
pum_row = pum_win_row + context_lines;
173184
if (size > below_row - pum_row)
174185
pum_height = below_row - pum_row;
175186
else
@@ -822,6 +833,42 @@ pum_visible(void)
822833
return !pum_do_redraw && pum_array != NULL;
823834
}
824835

836+
/*
837+
* Reposition the popup menu to adjust for window layout changes.
838+
*/
839+
void
840+
pum_may_redraw(void)
841+
{
842+
pumitem_T *array = pum_array;
843+
int len = pum_size;
844+
int selected = pum_selected;
845+
846+
if (!pum_visible())
847+
return; // nothing to do
848+
849+
if (pum_win_row == curwin->w_wrow + W_WINROW(curwin)
850+
&& pum_win_height == curwin->w_height
851+
&& pum_win_col == curwin->w_wincol
852+
&& pum_win_width == curwin->w_width)
853+
{
854+
// window position didn't change, redraw in the same position
855+
pum_redraw();
856+
}
857+
else
858+
{
859+
int wcol = curwin->w_wcol;
860+
861+
// Window layout changed, recompute the position.
862+
// Use the remembered w_wcol value, the cursor may have moved when a
863+
// completion was inserted, but we want the menu in the same position.
864+
pum_undisplay();
865+
curwin->w_wcol = pum_win_wcol;
866+
curwin->w_valid |= VALID_WCOL;
867+
pum_display(array, len, selected);
868+
curwin->w_wcol = wcol;
869+
}
870+
}
871+
825872
/*
826873
* Return the height of the popup menu, the number of entries visible.
827874
* Only valid when pum_visible() returns TRUE!

src/proto/popupmnu.pro

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ void pum_redraw(void);
44
void pum_undisplay(void);
55
void pum_clear(void);
66
int pum_visible(void);
7+
void pum_may_redraw(void);
78
int pum_get_height(void);
89
int split_message(char_u *mesg, pumitem_T **array);
910
void ui_remove_balloon(void);

src/screen.c

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ static void redraw_win_toolbar(win_T *wp);
171171
static void win_redr_custom(win_T *wp, int draw_ruler);
172172
#endif
173173
#ifdef FEAT_CMDL_INFO
174-
static void win_redr_ruler(win_T *wp, int always);
174+
static void win_redr_ruler(win_T *wp, int always, int ignore_pum);
175175
#endif
176176

177177
/* Ugly global: overrule attribute used by screen_char() */
@@ -783,8 +783,7 @@ update_screen(int type_arg)
783783
#endif
784784
#ifdef FEAT_INS_EXPAND
785785
/* May need to redraw the popup menu. */
786-
if (pum_visible())
787-
pum_redraw();
786+
pum_may_redraw();
788787
#endif
789788

790789
/* Reset b_mod_set flags. Going through all windows is probably faster
@@ -7002,7 +7001,7 @@ win_redr_status(win_T *wp, int ignore_pum)
70027001
- 1 + wp->w_wincol), attr);
70037002

70047003
#ifdef FEAT_CMDL_INFO
7005-
win_redr_ruler(wp, TRUE);
7004+
win_redr_ruler(wp, TRUE, ignore_pum);
70067005
#endif
70077006
}
70087007

@@ -10455,7 +10454,7 @@ showmode(void)
1045510454
/* If the last window has no status line, the ruler is after the mode
1045610455
* message and must be redrawn */
1045710456
if (redrawing() && lastwin->w_status_height == 0)
10458-
win_redr_ruler(lastwin, TRUE);
10457+
win_redr_ruler(lastwin, TRUE, FALSE);
1045910458
#endif
1046010459
redraw_cmdline = FALSE;
1046110460
clear_cmdline = FALSE;
@@ -10874,6 +10873,7 @@ redraw_win_toolbar(win_T *wp)
1087410873
(int)wp->w_width, FALSE);
1087510874
}
1087610875
#endif
10876+
1087710877
/*
1087810878
* Show current status info in ruler and various other places
1087910879
* If always is FALSE, only show ruler if position has changed.
@@ -10899,7 +10899,7 @@ showruler(int always)
1089910899
else
1090010900
#endif
1090110901
#ifdef FEAT_CMDL_INFO
10902-
win_redr_ruler(curwin, always);
10902+
win_redr_ruler(curwin, always, FALSE);
1090310903
#endif
1090410904

1090510905
#ifdef FEAT_TITLE
@@ -10918,7 +10918,7 @@ showruler(int always)
1091810918

1091910919
#ifdef FEAT_CMDL_INFO
1092010920
static void
10921-
win_redr_ruler(win_T *wp, int always)
10921+
win_redr_ruler(win_T *wp, int always, int ignore_pum)
1092210922
{
1092310923
#define RULER_BUF_LEN 70
1092410924
char_u buffer[RULER_BUF_LEN];
@@ -10951,8 +10951,9 @@ win_redr_ruler(win_T *wp, int always)
1095110951
if (wp == lastwin && lastwin->w_status_height == 0)
1095210952
if (edit_submode != NULL)
1095310953
return;
10954-
/* Don't draw the ruler when the popup menu is visible, it may overlap. */
10955-
if (pum_visible())
10954+
// Don't draw the ruler when the popup menu is visible, it may overlap.
10955+
// Except when the popup menu will be redrawn anyway.
10956+
if (!ignore_pum && pum_visible())
1095610957
return;
1095710958
#endif
1095810959

src/version.c

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

762762
static int included_patches[] =
763763
{ /* Add new patch number below this line */
764+
/**/
765+
62,
764766
/**/
765767
61,
766768
/**/

0 commit comments

Comments
 (0)