diff options
-rw-r--r-- | src/nvim/popupmenu.c | 114 | ||||
-rw-r--r-- | test/functional/ui/popupmenu_spec.lua | 146 |
2 files changed, 174 insertions, 86 deletions
diff --git a/src/nvim/popupmenu.c b/src/nvim/popupmenu.c index 4ce4f9632f..8ca4b28f3f 100644 --- a/src/nvim/popupmenu.c +++ b/src/nvim/popupmenu.c @@ -658,6 +658,7 @@ void pum_redraw(void) // Do this 3 times and order from p_cia int grid_col = col_off; int totwidth = 0; + bool need_ellipsis = false; int order[3]; int items_width_array[3] = { pum_base_width, pum_kind_width, pum_extra_width }; pum_align_order(order); @@ -710,9 +711,10 @@ void pum_redraw(void) char *rt = reverse_text(st); char *rt_start = rt; int cells = vim_strsize(rt); - bool need_ellipsis = p_pmw > ellipsis_width - && pum_width == p_pmw - && grid_col - cells < col_off - pum_width; + if (p_pmw > ellipsis_width && pum_width == p_pmw + && grid_col - cells < col_off - pum_width) { + need_ellipsis = true; + } if (grid_col - cells < col_off - pum_width) { do { @@ -720,41 +722,7 @@ void pum_redraw(void) MB_PTR_ADV(rt); } while (grid_col - cells < col_off - pum_width); - if (need_ellipsis) { - char *orig_rt = rt; - int used_cells = 0; - char *last_char = NULL; - while (*orig_rt != NUL) { - int char_cells = utf_ptr2cells(orig_rt); - if (used_cells + char_cells > ellipsis_width) { - break; - } - used_cells += char_cells; - MB_PTR_ADV(orig_rt); - last_char = orig_rt; - } - - if (last_char != NULL) { - int over_cell = 0; - if (used_cells < ellipsis_width) { - over_cell = ellipsis_width - used_cells; - MB_PTR_ADV(orig_rt); - last_char = orig_rt; - } - size_t kept_len = strlen(last_char); - char *new_str = xmalloc((size_t)ellipsis_width + (size_t)over_cell - + kept_len + 1); - memset(new_str, '.', (size_t)ellipsis_width); - if (over_cell > 0) { - memset(new_str + ellipsis_width, ' ', (size_t)over_cell); - } - memcpy(new_str + ellipsis_width + over_cell, last_char, kept_len); - new_str[(size_t)ellipsis_width + kept_len + (size_t)over_cell] = NUL; - char *old_rt = rt_start; - rt = rt_start = new_str; - xfree(old_rt); - } - } else if (grid_col - cells > col_off - pum_width) { + if (grid_col - cells > col_off - pum_width) { // Most left character requires 2-cells but only 1 cell is available on // screen. Put a '<' on the left of the pum item. *(--rt) = '<'; @@ -772,57 +740,16 @@ void pum_redraw(void) xfree(st); grid_col -= width; } else { - size_t size = strlen(st); - int cells = (int)mb_string2cells_len(st, size); - bool need_ellipsis = p_pmw > ellipsis_width - && pum_width == p_pmw - && grid_col + cells > col_off + pum_width; - - // Add '...' indicator if truncated due to p_pmw - if (need_ellipsis) { - while (size > 0 && grid_col + cells > col_off + pum_width) { - size--; - size -= (size_t)utf_head_off(st, st + size); - cells -= utf_ptr2cells(st + size); - } - char *st_end = st + size; - int used_cells = 0; - char *last_char = NULL; - while (st_end > st) { - int char_cells = utf_ptr2cells(st_end); - if (used_cells + char_cells > ellipsis_width) { - break; - } - used_cells += char_cells; - MB_PTR_BACK(st, st_end); - last_char = st_end; - } - - if (last_char != NULL) { - int over_cell = 0; - if (used_cells < ellipsis_width) { - MB_PTR_BACK(st, st_end); - last_char = st_end; - over_cell = ellipsis_width - used_cells; - } - size_t kept_len = (size_t)(last_char - st); - char *new_str = xmalloc((size_t)ellipsis_width + (size_t)over_cell - + kept_len + 1); - memcpy(new_str, st, kept_len); - if (over_cell > 0) { - memset(new_str + kept_len, ' ', (size_t)over_cell); - } - memset(new_str + kept_len + over_cell, '.', (size_t)ellipsis_width); - new_str[kept_len + (size_t)ellipsis_width + (size_t)over_cell] = NUL; - xfree(st); - st = new_str; - } + int cells = (int)mb_string2cells(st); + if (p_pmw > ellipsis_width && pum_width == p_pmw + && grid_col + cells > col_off + pum_width) { + need_ellipsis = true; } if (attrs == NULL) { grid_line_puts(grid_col, st, -1, attr); } else { - pum_grid_puts_with_attrs(grid_col, vim_strsize(st), st, -1, attrs); + pum_grid_puts_with_attrs(grid_col, cells, st, -1, attrs); } xfree(st); @@ -881,9 +808,24 @@ void pum_redraw(void) } if (pum_rl) { - grid_line_fill(col_off - pum_width + 1, grid_col + 1, schar_from_ascii(' '), orig_attr); + const int lcol = col_off - pum_width + 1; + grid_line_fill(lcol, grid_col + 1, schar_from_ascii(' '), orig_attr); + if (need_ellipsis) { + bool over_wide = pum_width > ellipsis_width && linebuf_char[lcol + ellipsis_width] == NUL; + grid_line_fill(lcol, lcol + ellipsis_width, schar_from_ascii('.'), orig_attr); + if (over_wide) { + grid_line_put_schar(lcol + ellipsis_width, schar_from_ascii(' '), orig_attr); + } + } } else { - grid_line_fill(grid_col, col_off + pum_width, schar_from_ascii(' '), orig_attr); + const int rcol = col_off + pum_width; + grid_line_fill(grid_col, rcol, schar_from_ascii(' '), orig_attr); + if (need_ellipsis) { + if (pum_width > ellipsis_width && linebuf_char[rcol - ellipsis_width] == NUL) { + grid_line_put_schar(rcol - ellipsis_width - 1, schar_from_ascii(' '), orig_attr); + } + grid_line_fill(rcol - ellipsis_width, rcol, schar_from_ascii('.'), orig_attr); + } } if (pum_scrollbar > 0) { diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua index d82c24bb83..6404feb9cd 100644 --- a/test/functional/ui/popupmenu_spec.lua +++ b/test/functional/ui/popupmenu_spec.lua @@ -5796,6 +5796,152 @@ describe('builtin popupmenu', function() feed('<Esc>') end) + it([['pummaxwidth' works with "kind" and "menu"]], function() + exec([[ + func Omni_test(findstart, base) + if a:findstart + return col(".") + endif + return [ + \ #{word: "foo", menu: "fooMenu", kind: "fooKind"}, + \ #{word: "bar", menu: "barMenu", kind: "barKind"}, + \ #{word: "baz", menu: "bazMenu", kind: "bazKind"}, + \ ] + endfunc + set omnifunc=Omni_test + ]]) + + command('set pummaxwidth=14') + feed('S<C-X><C-O>') + if multigrid then + screen:expect({ + grid = [[ + ## grid 1 + [2:--------------------------------]|*19 + [3:--------------------------------]| + ## grid 2 + foo^ | + {1:~ }|*18 + ## grid 3 + {2:-- }{5:match 1 of 3} | + ## grid 4 + {s:foo fooKind...}| + {n:bar barKind...}| + {n:baz bazKind...}| + ]], + float_pos = { [4] = { -1, 'NW', 2, 1, 0, false, 100 } }, + }) + else + screen:expect([[ + foo^ | + {s:foo fooKind...}{1: }| + {n:bar barKind...}{1: }| + {n:baz bazKind...}{1: }| + {1:~ }|*15 + {2:-- }{5:match 1 of 3} | + ]]) + end + feed('<Esc>') + + command('set rightleft') + feed('S<C-X><C-O>') + if multigrid then + screen:expect({ + grid = [[ + ## grid 1 + [2:--------------------------------]|*19 + [3:--------------------------------]| + ## grid 2 + ^ oof| + {1: ~}|*18 + ## grid 3 + {2:-- }{5:match 1 of 3} | + ## grid 4 + {s:...dniKoof oof}| + {n:...dniKrab rab}| + {n:...dniKzab zab}| + ]], + float_pos = { [4] = { -1, 'NW', 2, 1, 18, false, 100 } }, + }) + else + screen:expect([[ + ^ oof| + {1: }{s:...dniKoof oof}| + {1: }{n:...dniKrab rab}| + {1: }{n:...dniKzab zab}| + {1: ~}|*15 + {2:-- }{5:match 1 of 3} | + ]]) + end + feed('<Esc>') + command('set norightleft') + + command('set pummaxwidth=13') + feed('S<C-X><C-O>') + if multigrid then + screen:expect({ + grid = [[ + ## grid 1 + [2:--------------------------------]|*19 + [3:--------------------------------]| + ## grid 2 + foo^ | + {1:~ }|*18 + ## grid 3 + {2:-- }{5:match 1 of 3} | + ## grid 4 + {s:foo fooKin...}| + {n:bar barKin...}| + {n:baz bazKin...}| + ]], + float_pos = { [4] = { -1, 'NW', 2, 1, 0, false, 100 } }, + }) + else + screen:expect([[ + foo^ | + {s:foo fooKin...}{1: }| + {n:bar barKin...}{1: }| + {n:baz bazKin...}{1: }| + {1:~ }|*15 + {2:-- }{5:match 1 of 3} | + ]]) + end + feed('<Esc>') + + command('set rightleft') + feed('S<C-X><C-O>') + if multigrid then + screen:expect({ + grid = [[ + ## grid 1 + [2:--------------------------------]|*19 + [3:--------------------------------]| + ## grid 2 + ^ oof| + {1: ~}|*18 + ## grid 3 + {2:-- }{5:match 1 of 3} | + ## grid 4 + {s:...niKoof oof}| + {n:...niKrab rab}| + {n:...niKzab zab}| + ]], + float_pos = { [4] = { -1, 'NW', 2, 1, 19, false, 100 } }, + }) + else + screen:expect([[ + ^ oof| + {1: }{s:...niKoof oof}| + {1: }{n:...niKrab rab}| + {1: }{n:...niKzab zab}| + {1: ~}|*15 + {2:-- }{5:match 1 of 3} | + ]]) + end + feed('<Esc>') + command('set norightleft') + end) + it('does not crash when displayed in last column with rightleft #12032', function() local col = 30 local items = { 'word', 'choice', 'text', 'thing' } |