aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/nvim/popupmenu.c70
-rw-r--r--test/functional/ui/popupmenu_spec.lua105
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)