diff options
-rw-r--r-- | src/nvim/popupmenu.c | 70 | ||||
-rw-r--r-- | test/functional/ui/popupmenu_spec.lua | 105 |
2 files changed, 137 insertions, 38 deletions
diff --git a/src/nvim/popupmenu.c b/src/nvim/popupmenu.c index 75e5a52829..2b1dd22b1a 100644 --- a/src/nvim/popupmenu.c +++ b/src/nvim/popupmenu.c @@ -7,6 +7,7 @@ #include <stdint.h> #include <string.h> +#include "nvim/api/buffer.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" #include "nvim/ascii_defs.h" @@ -32,6 +33,7 @@ #include "nvim/highlight_defs.h" #include "nvim/insexpand.h" #include "nvim/keycodes.h" +#include "nvim/mark.h" #include "nvim/mbyte.h" #include "nvim/memline.h" #include "nvim/memory.h" @@ -787,36 +789,41 @@ void pum_redraw(void) } } -/// set info text to preview buffer. +/// Set the informational text in the preview buffer when the completion +/// item does not include a dedicated preview or popup window. +/// +/// @param[in] buf Buffer where the text will be set. +/// @param[in] info Informational text to display in the preview buffer. +/// @param[in] lnum Where to start the text. Incremented for each added line. +/// @param[out] max_width Maximum width of the displayed text. static void pum_preview_set_text(buf_T *buf, char *info, linenr_T *lnum, int *max_width) { - bcount_t inserted_bytes = 0; - for (char *p = info; *p != NUL;) { - int text_width = 0; - char *e = vim_strchr(p, '\n'); - if (e == NULL) { - ml_append_buf(buf, (*lnum)++, p, 0, false); - text_width = (int)mb_string2cells(p); - if (text_width > *max_width) { - *max_width = text_width; - } - break; - } - *e = NUL; - ml_append_buf(buf, (*lnum)++, p, (int)(e - p + 1), false); - inserted_bytes += (bcount_t)strlen(p) + 1; - text_width = (int)mb_string2cells(p); - if (text_width > *max_width) { - *max_width = text_width; - } - *e = '\n'; - p = e + 1; + Error err = ERROR_INIT; + Arena arena = ARENA_EMPTY; + Array replacement = ARRAY_DICT_INIT; + char *token = NULL; + char *line = os_strtok(info, "\n", &token); + buf->b_p_ma = true; + while (line != NULL) { + ADD(replacement, STRING_OBJ(cstr_to_string(line))); + (*lnum)++; + (*max_width) = MAX(*max_width, (int)mb_string2cells(line)); + line = os_strtok(NULL, "\n", &token); } - // delete the empty last line - ml_delete_buf(buf, buf->b_ml.ml_line_count, false); - if (get_cot_flags() & kOptCotFlagPopup) { - extmark_splice(buf, 1, 0, 1, 0, 0, buf->b_ml.ml_line_count, 0, inserted_bytes, kExtmarkNoUndo); + + int original_textlock = textlock; + if (textlock > 0) { + textlock = 0; + } + nvim_buf_set_lines(0, buf->handle, 0, -1, false, replacement, &arena, &err); + textlock = original_textlock; + if (ERROR_SET(&err)) { + emsg(err.msg); + api_clear_error(&err); } + arena_mem_free(arena_finish(&arena)); + api_free_array(replacement); + buf->b_p_ma = false; } /// adjust floating info preview window position @@ -866,14 +873,6 @@ win_T *pum_set_info(int selected, char *info) if (!wp) { return NULL; } - } else { - // clean exist buffer - linenr_T count = wp->w_buffer->b_ml.ml_line_count; - while (!buf_is_empty(wp->w_buffer)) { - ml_delete_buf(wp->w_buffer, 1, false); - } - bcount_t deleted_bytes = get_region_bytecount(wp->w_buffer, 1, count, 0, 0); - extmark_splice(wp->w_buffer, 1, 0, count, 0, deleted_bytes, 1, 0, 0, kExtmarkNoUndo); } linenr_T lnum = 0; int max_info_width = 0; @@ -1011,7 +1010,8 @@ static bool pum_set_selected(int n, int repeat) && (curbuf->b_nwindows == 1) && (curbuf->b_fname == NULL) && bt_nofile(curbuf) - && (curbuf->b_p_bh[0] == 'w')) { + && (curbuf->b_p_bh[0] == 'w') + && !use_float) { // Already a "wipeout" buffer, make it empty. while (!buf_is_empty(curbuf)) { ml_delete(1, false); diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua index d1228d3607..60d59190ce 100644 --- a/test/functional/ui/popupmenu_spec.lua +++ b/test/functional/ui/popupmenu_spec.lua @@ -1680,7 +1680,7 @@ describe('builtin popupmenu', function() end) end - describe('floating window preview #popup', function() + describe('floating window preview popup', function() it('pum popup preview', function() --row must > 10 screen:try_resize(40, 11) @@ -1693,14 +1693,29 @@ describe('builtin popupmenu', function() endfunc set omnifunc=Omni_test set completeopt=menu,popup - funct Set_info() let comp_info = complete_info() if comp_info['selected'] == 2 call nvim__complete_set(comp_info['selected'], {"info": "3info"}) endif endfunc - autocmd CompleteChanged * call Set_info() + funct TsHl() + let comp_info = complete_info() + if get(comp_info, 'previewbufnr', 0) > 0 + call v:lua.vim.treesitter.start(comp_info['preview_bufnr'], 'markdown') + endif + if comp_info['selected'] == 0 + call nvim__complete_set(comp_info['selected'], {"info": "```lua\nfunction test()\n print('foo')\nend\n```"}) + endif + endfunc + augroup Group + au! + autocmd CompleteChanged * :call Set_info() + augroup END + funct TestTs() + autocmd! Group + autocmd CompleteChanged * call TsHl() + endfunc ]]) feed('Gi<C-x><C-o>') --floating preview in right @@ -2004,6 +2019,90 @@ describe('builtin popupmenu', function() ]], } end + feed('<C-E><Esc>') + + -- works when scroll with treesitter highlight + command('call TestTs()') + feed('S<C-x><C-o>') + if multigrid then + screen:expect({ + grid = [[ + ## grid 1 + [2:----------------------------------------]|*10 + [3:----------------------------------------]| + ## grid 2 + one^ | + {1:~ }|*9 + ## grid 3 + {2:-- }{5:match 1 of 3} | + ## grid 5 + {s:one }| + {n:two }| + {n:looooooooooooooong }| + ## grid 9 + {n:```lua }| + {n:function test()}| + {n: print('foo') }| + {n:end }| + {n:``` }| + {n: }| + ]], + float_pos = { + [5] = { -1, 'NW', 2, 1, 0, false, 100 }, + [9] = { 1005, 'NW', 1, 1, 19, false, 50 }, + }, + win_viewport = { + [2] = { + win = 1000, + topline = 0, + botline = 2, + curline = 0, + curcol = 3, + linecount = 1, + sum_scroll_delta = 0, + }, + [9] = { + win = 1005, + topline = 0, + botline = 6, + curline = 0, + curcol = 0, + linecount = 5, + sum_scroll_delta = 0, + }, + }, + win_viewport_margins = { + [2] = { + bottom = 0, + left = 0, + right = 0, + top = 0, + win = 1000, + }, + [9] = { + bottom = 0, + left = 0, + right = 0, + top = 0, + win = 1005, + }, + }, + }) + else + screen:expect({ + grid = [[ + one^ | + {s:one }{n:```lua }{1: }| + {n:two function test()}{1: }| + {n:looooooooooooooong print('foo') }{1: }| + {1:~ }{n:end }{1: }| + {1:~ }{n:``` }{1: }| + {1:~ }{n: }{1: }| + {1:~ }|*3 + {2:-- }{5:match 1 of 3} | + ]], + }) + end end) end) |