aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/nvim/drawline.c4
-rw-r--r--src/nvim/insexpand.c6
-rw-r--r--src/nvim/popupmenu.c68
-rw-r--r--test/functional/ui/popupmenu_spec.lua21
-rw-r--r--test/old/testdir/test_popup.vim21
5 files changed, 76 insertions, 44 deletions
diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c
index 35a41f840d..3062b0f2a3 100644
--- a/src/nvim/drawline.c
+++ b/src/nvim/drawline.c
@@ -1495,7 +1495,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
ptr = line + v; // "line" may have been updated
}
- if ((State & MODE_INSERT) && in_curline && ins_compl_active()) {
+ if ((State & MODE_INSERT) && in_curline && ins_compl_win_active(wp)) {
area_highlighting = true;
}
@@ -1746,7 +1746,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
}
// Check if ComplMatchIns highlight is needed.
- if ((State & MODE_INSERT) && in_curline && ins_compl_active()) {
+ if ((State & MODE_INSERT) && in_curline && ins_compl_win_active(wp)) {
int ins_match_attr = ins_compl_col_range_attr((int)(ptr - line));
if (ins_match_attr > 0) {
search_attr = hl_combine_attr(search_attr, ins_match_attr);
diff --git a/src/nvim/insexpand.c b/src/nvim/insexpand.c
index aee3603d75..7245b0d6ce 100644
--- a/src/nvim/insexpand.c
+++ b/src/nvim/insexpand.c
@@ -1722,6 +1722,12 @@ bool ins_compl_active(void)
return compl_started;
}
+/// Return true when wp is the actual completion window
+bool ins_compl_win_active(win_T *wp)
+{
+ return ins_compl_active() && !(wp->w_p_pvw || wp->w_float_is_info);
+}
+
/// Selected one of the matches. When false the match was edited or using the
/// longest common string.
bool ins_compl_used_match(void)
diff --git a/src/nvim/popupmenu.c b/src/nvim/popupmenu.c
index 510736b2a0..75e5a52829 100644
--- a/src/nvim/popupmenu.c
+++ b/src/nvim/popupmenu.c
@@ -439,6 +439,7 @@ static int *pum_compute_text_attrs(char *text, hlf_T hlf, int user_hlattr)
const char *ptr = text;
int cell_idx = 0;
uint32_t char_pos = 0;
+ bool is_select = hlf == HLF_PSI;
while (*ptr != NUL) {
int new_attr = win_hl_attr(curwin, (int)hlf);
@@ -447,14 +448,14 @@ static int *pum_compute_text_attrs(char *text, hlf_T hlf, int user_hlattr)
// Handle fuzzy matching
for (int i = 0; i < ga->ga_len; i++) {
if (char_pos == ((uint32_t *)ga->ga_data)[i]) {
- new_attr = win_hl_attr(curwin, hlf == HLF_PSI ? HLF_PMSI : HLF_PMNI);
+ new_attr = win_hl_attr(curwin, is_select ? HLF_PMSI : HLF_PMNI);
new_attr = hl_combine_attr(win_hl_attr(curwin, HLF_PMNI), new_attr);
new_attr = hl_combine_attr(win_hl_attr(curwin, (int)hlf), new_attr);
break;
}
}
} else if (matched_start && ptr < text + leader_len) {
- new_attr = win_hl_attr(curwin, hlf == HLF_PSI ? HLF_PMSI : HLF_PMNI);
+ new_attr = win_hl_attr(curwin, is_select ? HLF_PMSI : HLF_PMNI);
new_attr = hl_combine_attr(win_hl_attr(curwin, HLF_PMNI), new_attr);
new_attr = hl_combine_attr(win_hl_attr(curwin, (int)hlf), new_attr);
}
@@ -520,6 +521,15 @@ static inline char *pum_get_item(int index, int type)
return NULL;
}
+static inline int pum_user_attr_combine(int idx, int type, int attr)
+{
+ int user_attr[] = {
+ pum_array[idx].pum_user_abbr_hlattr,
+ pum_array[idx].pum_user_kind_hlattr,
+ };
+ return user_attr[type] > 0 ? hl_combine_attr(attr, user_attr[type]) : attr;
+}
+
/// Redraw the popup menu, using "pum_first" and "pum_selected".
void pum_redraw(void)
{
@@ -583,19 +593,16 @@ void pum_redraw(void)
pum_row - row_off, pum_left_col, false, pum_grid.zindex);
}
+ int scroll_range = pum_size - pum_height;
// Never display more than we have
- if (pum_first > pum_size - pum_height) {
- pum_first = pum_size - pum_height;
- }
+ pum_first = MIN(pum_first, scroll_range);
if (pum_scrollbar) {
thumb_height = pum_height * pum_height / pum_size;
if (thumb_height == 0) {
thumb_height = 1;
}
- thumb_pos = (pum_first * (pum_height - thumb_height)
- + (pum_size - pum_height) / 2)
- / (pum_size - pum_height);
+ thumb_pos = (pum_first * (pum_height - thumb_height) + scroll_range / 2) / scroll_range;
}
for (int i = 0; i < pum_height; i++) {
@@ -633,13 +640,8 @@ void pum_redraw(void)
attr = win_hl_attr(curwin, (int)hlf);
attr = hl_combine_attr(win_hl_attr(curwin, HLF_PNI), attr);
orig_attr = attr;
- int user_abbr_hlattr = pum_array[idx].pum_user_abbr_hlattr;
- int user_kind_hlattr = pum_array[idx].pum_user_kind_hlattr;
- if (item_type == CPT_ABBR && user_abbr_hlattr > 0) {
- attr = hl_combine_attr(attr, user_abbr_hlattr);
- }
- if (item_type == CPT_KIND && user_kind_hlattr > 0) {
- attr = hl_combine_attr(attr, user_kind_hlattr);
+ if (item_type < 2) { // try combine attr with user custom
+ attr = pum_user_attr_combine(idx, item_type, attr);
}
int width = 0;
char *s = NULL;
@@ -667,7 +669,7 @@ void pum_redraw(void)
int *attrs = NULL;
if (item_type == CPT_ABBR) {
- attrs = pum_compute_text_attrs(st, hlf, user_abbr_hlattr);
+ attrs = pum_compute_text_attrs(st, hlf, pum_array[idx].pum_user_abbr_hlattr);
}
if (pum_rl) {
@@ -907,6 +909,7 @@ static bool pum_set_selected(int n, int repeat)
int prev_selected = pum_selected;
pum_selected = n;
+ int scroll_offset = pum_selected - pum_height;
unsigned cur_cot_flags = get_cot_flags();
bool use_float = (cur_cot_flags & kOptCotFlagPopup) != 0;
@@ -933,35 +936,24 @@ static bool pum_set_selected(int n, int repeat)
} else {
pum_first = pum_selected;
}
- } else if (pum_first < pum_selected - pum_height + 5) {
+ } else if (pum_first < scroll_offset + 5) {
// scroll up; when we did a jump it's probably a PageDown then
// scroll a whole page
- if (pum_first < pum_selected - pum_height + 1 + 2) {
- pum_first += pum_height - 2;
- if (pum_first < pum_selected - pum_height + 1) {
- pum_first = pum_selected - pum_height + 1;
- }
+ if (pum_first < scroll_offset + 3) {
+ pum_first = MAX(pum_first + pum_height - 2, scroll_offset + 1);
} else {
- pum_first = pum_selected - pum_height + 1;
+ pum_first = scroll_offset + 1;
}
}
// Give a few lines of context when possible.
- if (context > 3) {
- context = 3;
- }
+ context = MIN(context, 3);
if (pum_height > 2) {
if (pum_first > pum_selected - context) {
- // scroll down
- pum_first = pum_selected - context;
-
- if (pum_first < 0) {
- pum_first = 0;
- }
+ pum_first = MAX(pum_selected - context, 0); // scroll down
} else if (pum_first < pum_selected + context - pum_height + 1) {
- // scroll up
- pum_first = pum_selected + context - pum_height + 1;
+ pum_first = pum_selected + context - pum_height + 1; // up
}
}
// adjust for the number of lines displayed
@@ -1048,9 +1040,7 @@ static bool pum_set_selected(int n, int repeat)
// Increase the height of the preview window to show the
// text, but no more than 'previewheight' lines.
if (repeat == 0 && !use_float) {
- if (lnum > p_pvh) {
- lnum = (linenr_T)p_pvh;
- }
+ lnum = MIN(lnum, (linenr_T)p_pvh);
if (curwin->w_height < lnum) {
win_setheight((int)lnum);
@@ -1313,9 +1303,7 @@ static void pum_position_at_mouse(int min_width)
pum_width = max_col - pum_col;
}
- if (pum_width > pum_base_width + 1) {
- pum_width = pum_base_width + 1;
- }
+ pum_width = MIN(pum_width, pum_base_width + 1);
}
/// Select the pum entry at the mouse position.
diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua
index 75421c6998..d1228d3607 100644
--- a/test/functional/ui/popupmenu_spec.lua
+++ b/test/functional/ui/popupmenu_spec.lua
@@ -5567,11 +5567,15 @@ describe('builtin popupmenu', function()
-- oldtest: Test_pum_matchins_highlight()
it('with ComplMatchIns highlight', function()
exec([[
+ let g:change = 0
func Omni_test(findstart, base)
if a:findstart
return col(".")
endif
- return [#{word: "foo"}, #{word: "bar"}, #{word: "你好"}]
+ if g:change == 0
+ return [#{word: "foo"}, #{word: "bar"}, #{word: "你好"}]
+ endif
+ return [#{word: "foo", info: "info"}, #{word: "bar"}, #{word: "你好"}]
endfunc
set omnifunc=Omni_test
hi ComplMatchIns guifg=red
@@ -5663,6 +5667,21 @@ describe('builtin popupmenu', function()
{2:-- INSERT --} |
]])
feed('<Esc>')
+
+ feed(':let g:change=1<CR>S<C-X><C-O>')
+ screen:expect([[
+ info |
+ {1:~ }|*2
+ {3:[Scratch] [Preview] }|
+ {8:foo}^ |
+ {s:foo }{1: }|
+ {n:bar }{1: }|
+ {n:你好 }{1: }|
+ {1:~ }|*10
+ {4:[No Name] [+] }|
+ {2:-- }{5:match 1 of 3} |
+ ]])
+ feed('<Esc>')
end)
-- oldtest: Test_pum_matchins_highlight_combine()
diff --git a/test/old/testdir/test_popup.vim b/test/old/testdir/test_popup.vim
index f16a897b07..e902ea3bc2 100644
--- a/test/old/testdir/test_popup.vim
+++ b/test/old/testdir/test_popup.vim
@@ -1716,11 +1716,15 @@ endfunc
func Test_pum_matchins_highlight()
CheckScreendump
let lines =<< trim END
+ let g:change = 0
func Omni_test(findstart, base)
if a:findstart
return col(".")
endif
- return [#{word: "foo"}, #{word: "bar"}, #{word: "你好"}]
+ if g:change == 0
+ return [#{word: "foo"}, #{word: "bar"}, #{word: "你好"}]
+ endif
+ return [#{word: "foo", info: "info"}, #{word: "bar"}, #{word: "你好"}]
endfunc
set omnifunc=Omni_test
hi ComplMatchIns ctermfg=red
@@ -1767,6 +1771,10 @@ func Test_pum_matchins_highlight()
call VerifyScreenDump(buf, 'Test_pum_matchins_10', {})
call term_sendkeys(buf, "\<Esc>")
+ call term_sendkeys(buf, ":let g:change=1\<CR>S\<C-X>\<C-O>")
+ call VerifyScreenDump(buf, 'Test_pum_matchins_11', {})
+ call term_sendkeys(buf, "\<Esc>")
+
call StopVimInTerminal(buf)
endfunc
@@ -1812,4 +1820,15 @@ func Test_pum_matchins_highlight_combine()
call StopVimInTerminal(buf)
endfunc
+" this used to crash
+func Test_popup_completion_many_ctrlp()
+ new
+ let candidates=repeat(['a0'], 99)
+ call setline(1, candidates)
+ exe ":norm! VGg\<C-A>"
+ norm! G
+ call feedkeys("o" .. repeat("\<c-p>", 100), 'tx')
+ bw!
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab