diff options
-rw-r--r-- | runtime/doc/lua.txt | 6 | ||||
-rw-r--r-- | runtime/lua/vim/_editor.lua | 5 | ||||
-rw-r--r-- | runtime/lua/vim/lsp/client.lua | 2 | ||||
-rw-r--r-- | src/mpack/lmpack.c | 4 | ||||
-rw-r--r-- | src/nvim/api/ui.c | 101 | ||||
-rw-r--r-- | src/nvim/extmark.c | 6 | ||||
-rw-r--r-- | src/nvim/ui_defs.h | 1 | ||||
-rw-r--r-- | src/nvim/undo.c | 4 | ||||
-rw-r--r-- | test/functional/api/buffer_updates_spec.lua | 14 | ||||
-rw-r--r-- | test/functional/api/server_notifications_spec.lua | 2 | ||||
-rw-r--r-- | test/functional/api/server_requests_spec.lua | 14 | ||||
-rw-r--r-- | test/functional/autocmd/cmdline_spec.lua | 2 | ||||
-rw-r--r-- | test/functional/core/exit_spec.lua | 2 | ||||
-rw-r--r-- | test/functional/core/job_spec.lua | 2 | ||||
-rw-r--r-- | test/functional/ex_cmds/dict_notifications_spec.lua | 2 | ||||
-rw-r--r-- | test/functional/lua/vim_spec.lua | 2 | ||||
-rw-r--r-- | test/functional/provider/define_spec.lua | 2 | ||||
-rw-r--r-- | test/functional/ui/decorations_spec.lua | 38 | ||||
-rw-r--r-- | test/functional/ui/hlstate_spec.lua | 279 | ||||
-rw-r--r-- | test/functional/vimscript/wait_spec.lua | 2 |
20 files changed, 410 insertions, 80 deletions
diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt index c2f5941a5c..6a1d94d34b 100644 --- a/runtime/doc/lua.txt +++ b/runtime/doc/lua.txt @@ -1622,9 +1622,9 @@ vim.on_key({fn}, {ns_id}) *vim.on_key()* • {fn} will receive the keys after mappings have been evaluated Parameters: ~ - • {fn} (`fun(key: string)`) Function invoked on every key press. - |i_CTRL-V| Returning nil removes the callback associated with - namespace {ns_id}. + • {fn} (`fun(key: string)?`) Function invoked on every key press. + |i_CTRL-V| Passing in nil when {ns_id} is specified removes + the callback associated with namespace {ns_id}. • {ns_id} (`integer?`) Namespace ID. If nil or 0, generates and returns a new |nvim_create_namespace()| id. diff --git a/runtime/lua/vim/_editor.lua b/runtime/lua/vim/_editor.lua index c130eb1958..c5a6e65e86 100644 --- a/runtime/lua/vim/_editor.lua +++ b/runtime/lua/vim/_editor.lua @@ -652,8 +652,9 @@ local on_key_cbs = {} ---@note {fn} will not be cleared by |nvim_buf_clear_namespace()| ---@note {fn} will receive the keys after mappings have been evaluated --- ----@param fn fun(key: string) Function invoked on every key press. |i_CTRL-V| ---- Returning nil removes the callback associated with namespace {ns_id}. +---@param fn fun(key: string)? Function invoked on every key press. |i_CTRL-V| +--- Passing in nil when {ns_id} is specified removes the +--- callback associated with namespace {ns_id}. ---@param ns_id integer? Namespace ID. If nil or 0, generates and returns a --- new |nvim_create_namespace()| id. --- diff --git a/runtime/lua/vim/lsp/client.lua b/runtime/lua/vim/lsp/client.lua index 58db4387b6..a279be55e9 100644 --- a/runtime/lua/vim/lsp/client.lua +++ b/runtime/lua/vim/lsp/client.lua @@ -79,6 +79,7 @@ local validate = vim.validate --- Track this so that we can escalate automatically if we've already tried a --- graceful shutdown --- @field private _graceful_shutdown_failed true? +--- @field private commands table --- --- @field dynamic_capabilities lsp.DynamicCapabilities --- @@ -270,6 +271,7 @@ function Client.start(config) attached_buffers = {}, server_capabilities = {}, dynamic_capabilities = vim.lsp._dynamic.new(id), + commands = config.commands, -- Remove in Nvim 0.11 --- Contains $/progress report messages. --- They have the format {token: integer|string, value: any} diff --git a/src/mpack/lmpack.c b/src/mpack/lmpack.c index ff21e29789..4ce4b5f3e5 100644 --- a/src/mpack/lmpack.c +++ b/src/mpack/lmpack.c @@ -882,7 +882,9 @@ static int lmpack_session_receive(lua_State *L) luaL_argcheck(L, (size_t)startpos <= len, 3, "start position must be less than or equal to the input string length"); - str += (size_t)startpos - 1; + size_t offset = (size_t)startpos - 1 ; + str += offset; + len -= offset; if (session->unpacker != LUA_REFNIL) { lmpack_geti(L, session->reg, session->unpacker); diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c index 5c8ebfb861..c7280253c2 100644 --- a/src/nvim/api/ui.c +++ b/src/nvim/api/ui.c @@ -584,7 +584,6 @@ static inline int write_cb(void *vdata, const char *buf, size_t len) data->pack_totlen += len; if (!data->temp_buf && UI_BUF_SIZE - BUF_POS(data) < len) { - data->buf_overflow = true; return 0; } @@ -594,14 +593,42 @@ static inline int write_cb(void *vdata, const char *buf, size_t len) return 0; } -static bool prepare_call(UI *ui, const char *name) +static inline int size_cb(void *vdata, const char *buf, size_t len) +{ + UIData *data = (UIData *)vdata; + if (!buf) { + return 0; + } + + data->pack_totlen += len; + return 0; +} + +static void prepare_call(UI *ui, const char *name, size_t size_needed) { UIData *data = ui->data; + size_t name_len = strlen(name); + const size_t overhead = name_len + 20; + bool oversized_message = size_needed + overhead > UI_BUF_SIZE; - if (BUF_POS(data) > UI_BUF_SIZE - EVENT_BUF_SIZE) { + if (oversized_message || BUF_POS(data) > UI_BUF_SIZE - size_needed - overhead) { remote_ui_flush_buf(ui); } + if (oversized_message) { + // TODO(bfredl): manually testable by setting UI_BUF_SIZE to 1024 (mode_info_set) + data->temp_buf = xmalloc(20 + name_len + size_needed); + data->buf_wptr = data->temp_buf; + char **buf = &data->buf_wptr; + mpack_array(buf, 3); + mpack_uint(buf, 2); + mpack_str(buf, S_LEN("redraw")); + mpack_array(buf, 1); + mpack_array(buf, 2); + mpack_str(buf, name, name_len); + return; + } + // To optimize data transfer(especially for "grid_line"), we bundle adjacent // calls to same method together, so only add a new call entry if the last // method call is different from "name" @@ -614,64 +641,42 @@ static bool prepare_call(UI *ui, const char *name) mpack_str(buf, name, strlen(name)); data->nevents++; data->ncalls = 1; - return true; + return; } +} - return false; +static void send_oversized_message(UIData *data) +{ + if (data->temp_buf) { + size_t size = (size_t)(data->buf_wptr - data->temp_buf); + WBuffer *buf = wstream_new_buffer(data->temp_buf, size, 1, xfree); + rpc_write_raw(data->channel_id, buf); + data->temp_buf = NULL; + data->buf_wptr = data->buf; + data->nevents_pos = NULL; + } } /// Pushes data into UI.UIData, to be consumed later by remote_ui_flush(). static void push_call(UI *ui, const char *name, Array args) { UIData *data = ui->data; - bool pending = data->nevents_pos; - char *buf_pos_save = data->buf_wptr; - - bool new_event = prepare_call(ui, name); msgpack_packer pac; data->pack_totlen = 0; - data->buf_overflow = false; + // First determine the needed size + msgpack_packer_init(&pac, data, size_cb); + msgpack_rpc_from_array(args, &pac); + // Then send the actual message + prepare_call(ui, name, data->pack_totlen); msgpack_packer_init(&pac, data, write_cb); msgpack_rpc_from_array(args, &pac); - if (data->buf_overflow) { - data->buf_wptr = buf_pos_save; - if (new_event) { - data->cur_event = NULL; - data->nevents--; - } - if (pending) { - remote_ui_flush_buf(ui); - } - size_t name_len = strlen(name); - if (data->pack_totlen > UI_BUF_SIZE - name_len - 20) { - // TODO(bfredl): manually testable by setting UI_BUF_SIZE to 1024 (mode_info_set) - data->temp_buf = xmalloc(20 + name_len + data->pack_totlen); - data->buf_wptr = data->temp_buf; - char **buf = &data->buf_wptr; - mpack_array(buf, 3); - mpack_uint(buf, 2); - mpack_str(buf, S_LEN("redraw")); - mpack_array(buf, 1); - mpack_array(buf, 2); - mpack_str(buf, name, name_len); - } else { - prepare_call(ui, name); - } - data->pack_totlen = 0; - data->buf_overflow = false; - msgpack_rpc_from_array(args, &pac); - - if (data->temp_buf) { - size_t size = (size_t)(data->buf_wptr - data->temp_buf); - WBuffer *buf = wstream_new_buffer(data->temp_buf, size, 1, xfree); - rpc_write_raw(data->channel_id, buf); - data->temp_buf = NULL; - data->buf_wptr = data->buf; - data->nevents_pos = NULL; - } + // Oversized messages need to be sent immediately + if (data->temp_buf) { + send_oversized_message(data); } + data->ncalls++; } @@ -866,7 +871,7 @@ void remote_ui_raw_line(UI *ui, Integer grid, Integer row, Integer startcol, Int { UIData *data = ui->data; if (ui->ui_ext[kUILinegrid]) { - prepare_call(ui, "grid_line"); + prepare_call(ui, "grid_line", EVENT_BUF_SIZE); data->ncalls++; char **buf = &data->buf_wptr; @@ -895,7 +900,7 @@ void remote_ui_raw_line(UI *ui, Integer grid, Integer row, Integer startcol, Int mpack_bool(buf, false); remote_ui_flush_buf(ui); - prepare_call(ui, "grid_line"); + prepare_call(ui, "grid_line", EVENT_BUF_SIZE); data->ncalls++; mpack_array(buf, 5); mpack_uint(buf, (uint32_t)grid); diff --git a/src/nvim/extmark.c b/src/nvim/extmark.c index 0f9e7749f1..e753ad199a 100644 --- a/src/nvim/extmark.c +++ b/src/nvim/extmark.c @@ -116,6 +116,12 @@ static void extmark_setraw(buf_T *buf, uint64_t mark, int row, colnr_T col, bool return; } + // Only the position before undo needs to be redrawn here, + // as the position after undo should be marked as changed. + if (!invalid && mt_decor_any(key) && key.pos.row != row) { + decor_redraw(buf, key.pos.row, key.pos.row, key.pos.col, mt_decor(key)); + } + int row1 = 0; int row2 = 0; if (invalid) { diff --git a/src/nvim/ui_defs.h b/src/nvim/ui_defs.h index 2245575306..a2071782b6 100644 --- a/src/nvim/ui_defs.h +++ b/src/nvim/ui_defs.h @@ -46,7 +46,6 @@ typedef struct { // state for write_cb, while packing a single arglist to msgpack. This // might fail due to buffer overflow. size_t pack_totlen; - bool buf_overflow; char *temp_buf; // We start packing the two outermost msgpack arrays before knowing the total diff --git a/src/nvim/undo.c b/src/nvim/undo.c index 547ac605e7..6081268e53 100644 --- a/src/nvim/undo.c +++ b/src/nvim/undo.c @@ -2390,9 +2390,7 @@ static void u_undoredo(bool undo, bool do_buf_event) // When text has been changed, possibly the start of the next line // may have SpellCap that should be removed or it needs to be // displayed. Schedule the next line for redrawing just in case. - // Also just in case the line had a sign which needs to be removed. - if ((spell_check_window(curwin) || buf_meta_total(curbuf, kMTMetaSignText)) - && bot <= curbuf->b_ml.ml_line_count) { + if (spell_check_window(curwin) && bot <= curbuf->b_ml.ml_line_count) { redrawWinline(curwin, bot); } diff --git a/test/functional/api/buffer_updates_spec.lua b/test/functional/api/buffer_updates_spec.lua index d68c60e54c..262ca40e28 100644 --- a/test/functional/api/buffer_updates_spec.lua +++ b/test/functional/api/buffer_updates_spec.lua @@ -482,7 +482,7 @@ describe('API: buffer events:', function() end) it('does not get confused if enabled/disabled many times', function() - local channel = api.nvim_get_api_info()[1] + local channel = api.nvim_get_chan_info(0).id local b, tick = editoriginal(false) -- Enable buffer events many times. @@ -564,7 +564,7 @@ describe('API: buffer events:', function() -- make sure there are no other pending nvim_buf_lines_event messages going to -- channel 1 - local channel1 = request(1, 'nvim_get_api_info')[1] + local channel1 = request(1, 'nvim_get_chan_info', 0).id eval('rpcnotify(' .. channel1 .. ', "Hello")') wantn(1, 'Hello', {}) @@ -576,14 +576,14 @@ describe('API: buffer events:', function() -- make sure there are no other pending nvim_buf_lines_event messages going to -- channel 1 - channel1 = request(1, 'nvim_get_api_info')[1] + channel1 = request(1, 'nvim_get_chan_info', 0).id eval('rpcnotify(' .. channel1 .. ', "Hello Again")') wantn(1, 'Hello Again', {}) end) it('works with :diffput and :diffget', function() local b1, tick1 = editoriginal(true, { 'AAA', 'BBB' }) - local channel = api.nvim_get_api_info()[1] + local channel = api.nvim_get_chan_info(0).id command('diffthis') command('rightbelow vsplit') local b2, tick2 = open(true, { 'BBB', 'CCC' }) @@ -700,7 +700,7 @@ describe('API: buffer events:', function() it('detaches if the buffer is closed', function() local b, tick = editoriginal(true, { 'AAA' }) - local channel = api.nvim_get_api_info()[1] + local channel = api.nvim_get_chan_info(0).id -- Test that buffer events are working. command('normal! x') @@ -739,7 +739,7 @@ describe('API: buffer events:', function() it(':enew! does not detach hidden buffer', function() local b, tick = editoriginal(true, { 'AAA', 'BBB' }) - local channel = api.nvim_get_api_info()[1] + local channel = api.nvim_get_chan_info(0).id command('set undoreload=1 hidden') command('normal! x') @@ -753,7 +753,7 @@ describe('API: buffer events:', function() it('stays attached if the buffer is hidden', function() local b, tick = editoriginal(true, { 'AAA' }) - local channel = api.nvim_get_api_info()[1] + local channel = api.nvim_get_chan_info(0).id -- Test that buffer events are working. command('normal! x') diff --git a/test/functional/api/server_notifications_spec.lua b/test/functional/api/server_notifications_spec.lua index f6058b14ee..d1608a951c 100644 --- a/test/functional/api/server_notifications_spec.lua +++ b/test/functional/api/server_notifications_spec.lua @@ -14,7 +14,7 @@ describe('notify', function() before_each(function() clear() - channel = api.nvim_get_api_info()[1] + channel = api.nvim_get_chan_info(0).id end) after_each(function() diff --git a/test/functional/api/server_requests_spec.lua b/test/functional/api/server_requests_spec.lua index 5e508e7513..298dbac217 100644 --- a/test/functional/api/server_requests_spec.lua +++ b/test/functional/api/server_requests_spec.lua @@ -18,18 +18,18 @@ describe('server -> client', function() before_each(function() clear() - cid = api.nvim_get_api_info()[1] + cid = api.nvim_get_chan_info(0).id end) it('handles unexpected closed stream while preparing RPC response', function() source([[ let g:_nvim_args = [v:progpath, '--embed', '--headless', '-n', '-u', 'NONE', '-i', 'NONE', ] let ch1 = jobstart(g:_nvim_args, {'rpc': v:true}) - let child1_ch = rpcrequest(ch1, "nvim_get_api_info")[0] + let child1_ch = rpcrequest(ch1, "nvim_get_chan_info", 0).id call rpcnotify(ch1, 'nvim_eval', 'rpcrequest('.child1_ch.', "nvim_get_api_info")') let ch2 = jobstart(g:_nvim_args, {'rpc': v:true}) - let child2_ch = rpcrequest(ch2, "nvim_get_api_info")[0] + let child2_ch = rpcrequest(ch2, "nvim_get_chan_info", 0).id call rpcnotify(ch2, 'nvim_eval', 'rpcrequest('.child2_ch.', "nvim_get_api_info")') call jobstop(ch1) @@ -231,7 +231,7 @@ describe('server -> client', function() describe('jobstart()', function() local jobid before_each(function() - local channel = api.nvim_get_api_info()[1] + local channel = api.nvim_get_chan_info(0).id api.nvim_set_var('channel', channel) source([[ function! s:OnEvent(id, data, event) @@ -292,7 +292,7 @@ describe('server -> client', function() ok(id > 0) fn.rpcrequest(id, 'nvim_set_current_line', 'hello') - local client_id = fn.rpcrequest(id, 'nvim_get_api_info')[1] + local client_id = fn.rpcrequest(id, 'nvim_get_chan_info', 0).id set_session(server) eq(serverpid, fn.getpid()) @@ -300,7 +300,7 @@ describe('server -> client', function() -- method calls work both ways fn.rpcrequest(client_id, 'nvim_set_current_line', 'howdy!') - eq(id, fn.rpcrequest(client_id, 'nvim_get_api_info')[1]) + eq(id, fn.rpcrequest(client_id, 'nvim_get_chan_info', 0).id) set_session(client) eq(clientpid, fn.getpid()) @@ -378,7 +378,7 @@ describe('server -> client', function() eq('hello', api.nvim_get_current_line()) eq(serverpid, fn.rpcrequest(id, 'nvim_eval', 'getpid()')) - eq(id, fn.rpcrequest(id, 'nvim_get_api_info')[1]) + eq(id, fn.rpcrequest(id, 'nvim_get_chan_info', 0).id) end) end) end) diff --git a/test/functional/autocmd/cmdline_spec.lua b/test/functional/autocmd/cmdline_spec.lua index 5a5b16b438..7428456656 100644 --- a/test/functional/autocmd/cmdline_spec.lua +++ b/test/functional/autocmd/cmdline_spec.lua @@ -14,7 +14,7 @@ describe('cmdline autocommands', function() local channel before_each(function() clear() - channel = api.nvim_get_api_info()[1] + channel = api.nvim_get_chan_info(0).id api.nvim_set_var('channel', channel) command("autocmd CmdlineEnter * call rpcnotify(g:channel, 'CmdlineEnter', v:event)") command("autocmd CmdlineLeave * call rpcnotify(g:channel, 'CmdlineLeave', v:event)") diff --git a/test/functional/core/exit_spec.lua b/test/functional/core/exit_spec.lua index b74ebb2367..d9e3cc3f31 100644 --- a/test/functional/core/exit_spec.lua +++ b/test/functional/core/exit_spec.lua @@ -18,7 +18,7 @@ describe('v:exiting', function() before_each(function() helpers.clear() - cid = helpers.api.nvim_get_api_info()[1] + cid = helpers.api.nvim_get_chan_info(0).id end) it('defaults to v:null', function() diff --git a/test/functional/core/job_spec.lua b/test/functional/core/job_spec.lua index c6885d0b7c..318730fbb1 100644 --- a/test/functional/core/job_spec.lua +++ b/test/functional/core/job_spec.lua @@ -42,7 +42,7 @@ describe('jobs', function() before_each(function() clear() - channel = api.nvim_get_api_info()[1] + channel = api.nvim_get_chan_info(0).id api.nvim_set_var('channel', channel) source([[ function! Normalize(data) abort diff --git a/test/functional/ex_cmds/dict_notifications_spec.lua b/test/functional/ex_cmds/dict_notifications_spec.lua index 15fbb750f6..fc7714d16b 100644 --- a/test/functional/ex_cmds/dict_notifications_spec.lua +++ b/test/functional/ex_cmds/dict_notifications_spec.lua @@ -14,7 +14,7 @@ describe('Vimscript dictionary notifications', function() before_each(function() clear() - channel = api.nvim_get_api_info()[1] + channel = api.nvim_get_chan_info(0).id api.nvim_set_var('channel', channel) end) diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 10a2437ba2..c7490756d4 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -3363,7 +3363,7 @@ describe('lua stdlib', function() describe('returns -2 when interrupted', function() before_each(function() - local channel = api.nvim_get_api_info()[1] + local channel = api.nvim_get_chan_info(0).id api.nvim_set_var('channel', channel) end) diff --git a/test/functional/provider/define_spec.lua b/test/functional/provider/define_spec.lua index a1109935d2..657f1a0d8a 100644 --- a/test/functional/provider/define_spec.lua +++ b/test/functional/provider/define_spec.lua @@ -362,7 +362,7 @@ local function function_specs_for(fn, sync, first_arg_factory, init) end local function channel() - return api.nvim_get_api_info()[1] + return api.nvim_get_chan_info(0).id end local function host() diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua index 9f38c05757..951188614b 100644 --- a/test/functional/ui/decorations_spec.lua +++ b/test/functional/ui/decorations_spec.lua @@ -2230,6 +2230,44 @@ describe('extmark decorations', function() ]]} end) + it('virtual text is drawn correctly after delete and undo #27368', function() + insert('aaa\nbbb\nccc\nddd\neee') + command('vsplit') + api.nvim_buf_set_extmark(0, ns, 2, 0, { virt_text = {{'EOL'}} }) + feed('3gg') + screen:expect{grid=[[ + aaa │aaa | + bbb │bbb | + ^ccc EOL │ccc EOL | + ddd │ddd | + eee │eee | + {1:~ }│{1:~ }|*8 + {41:[No Name] [+] }{40:[No Name] [+] }| + | + ]]} + feed('dd') + screen:expect{grid=[[ + aaa │aaa | + bbb │bbb | + ^ddd EOL │ddd EOL | + eee │eee | + {1:~ }│{1:~ }|*9 + {41:[No Name] [+] }{40:[No Name] [+] }| + | + ]]} + command('silent undo') + screen:expect{grid=[[ + aaa │aaa | + bbb │bbb | + ^ccc EOL │ccc EOL | + ddd │ddd | + eee │eee | + {1:~ }│{1:~ }|*8 + {41:[No Name] [+] }{40:[No Name] [+] }| + | + ]]} + end) + it('works with both hl_group and sign_hl_group', function() screen:try_resize(screen._width, 3) insert('abcdefghijklmn') diff --git a/test/functional/ui/hlstate_spec.lua b/test/functional/ui/hlstate_spec.lua index 278e6e5272..8b36ad5431 100644 --- a/test/functional/ui/hlstate_spec.lua +++ b/test/functional/ui/hlstate_spec.lua @@ -309,4 +309,283 @@ describe('ext_hlstate detailed highlights', function() {3: }| ]]) end) + + it('combines deleted extmark highlights', function() + insert([[ + line1 + line2 + line3 + line4 + line5 + line6]]) + + screen:expect { + grid = [[ + line1 | + line2 | + line3 | + line4 | + line5 | + line^6 | + {1:~ }| + {2: }| + ]], + attr_ids = { + [1] = { + { foreground = Screen.colors.Blue, bold = true }, + { { ui_name = 'EndOfBuffer', hi_name = 'NonText', kind = 'ui' } }, + }, + [2] = { {}, { { ui_name = 'MsgArea', hi_name = 'MsgArea', kind = 'ui' } } }, + }, + } + + local ns = api.nvim_create_namespace('test') + + local add_indicator = function(line, col) + api.nvim_buf_set_extmark(0, ns, line, col, { + hl_mode = 'combine', + priority = 2, + right_gravity = false, + virt_text = { { '|', 'Delimiter' } }, + virt_text_win_col = 0, + virt_text_pos = 'overlay', + }) + end + + add_indicator(1, 0) + add_indicator(2, 0) + add_indicator(3, 0) + add_indicator(4, 0) + + screen:expect { + grid = [[ + line1 | + {1:|} line2 | + {1:|} line3 | + {1:|} line4 | + {1:|} line5 | + line^6 | + {2:~ }| + {3: }| + ]], + attr_ids = { + [1] = { + { foreground = Screen.colors.SlateBlue }, + { { hi_name = 'Special', kind = 'syntax' } }, + }, + [2] = { + { bold = true, foreground = Screen.colors.Blue }, + { { ui_name = 'EndOfBuffer', kind = 'ui', hi_name = 'NonText' } }, + }, + [3] = { {}, { { ui_name = 'MsgArea', kind = 'ui', hi_name = 'MsgArea' } } }, + }, + } + + helpers.feed('3ggV2jd') + --screen:redraw_debug() + screen:expect { + grid = [[ + line1 | + {1:|} line2 | + {2:^|}ine6 | + {3:~ }|*4 + {4:3 fewer lines }| + ]], + attr_ids = { + [1] = { + { foreground = Screen.colors.SlateBlue }, + { { kind = 'syntax', hi_name = 'Special' } }, + }, + [2] = { { foreground = Screen.colors.SlateBlue }, { 1, 1, 1 } }, + [3] = { + { bold = true, foreground = Screen.colors.Blue }, + { { kind = 'ui', ui_name = 'EndOfBuffer', hi_name = 'NonText' } }, + }, + [4] = { {}, { { kind = 'ui', ui_name = 'MsgArea', hi_name = 'MsgArea' } } }, + }, + } + end) + + it('removes deleted extmark highlights with invalidate', function() + insert([[ + line1 + line2 + line3 + line4 + line5 + line6]]) + + screen:expect { + grid = [[ + line1 | + line2 | + line3 | + line4 | + line5 | + line^6 | + {1:~ }| + {2: }| + ]], + attr_ids = { + [1] = { + { foreground = Screen.colors.Blue, bold = true }, + { { ui_name = 'EndOfBuffer', hi_name = 'NonText', kind = 'ui' } }, + }, + [2] = { {}, { { ui_name = 'MsgArea', hi_name = 'MsgArea', kind = 'ui' } } }, + }, + } + + local ns = api.nvim_create_namespace('test') + + local add_indicator = function(line, col) + api.nvim_buf_set_extmark(0, ns, line, col, { + hl_mode = 'combine', + priority = 2, + right_gravity = false, + virt_text = { { '|', 'Delimiter' } }, + virt_text_win_col = 0, + virt_text_pos = 'overlay', + invalidate = true, + }) + end + + add_indicator(1, 0) + add_indicator(2, 0) + add_indicator(3, 0) + add_indicator(4, 0) + + screen:expect { + grid = [[ + line1 | + {1:|} line2 | + {1:|} line3 | + {1:|} line4 | + {1:|} line5 | + line^6 | + {2:~ }| + {3: }| + ]], + attr_ids = { + [1] = { + { foreground = Screen.colors.SlateBlue }, + { { hi_name = 'Special', kind = 'syntax' } }, + }, + [2] = { + { bold = true, foreground = Screen.colors.Blue }, + { { ui_name = 'EndOfBuffer', kind = 'ui', hi_name = 'NonText' } }, + }, + [3] = { {}, { { ui_name = 'MsgArea', kind = 'ui', hi_name = 'MsgArea' } } }, + }, + } + + helpers.feed('3ggV2jd') + --screen:redraw_debug() + screen:expect { + grid = [[ + line1 | + {1:|} line2 | + ^line6 | + {2:~ }|*4 + {3:3 fewer lines }| + ]], + attr_ids = { + [1] = { + { foreground = Screen.colors.SlateBlue }, + { { kind = 'syntax', hi_name = 'Special' } }, + }, + [2] = { + { foreground = Screen.colors.Blue, bold = true }, + { { kind = 'ui', ui_name = 'EndOfBuffer', hi_name = 'NonText' } }, + }, + [3] = { {}, { { kind = 'ui', ui_name = 'MsgArea', hi_name = 'MsgArea' } } }, + }, + } + end) + + it('does not hang when combining too many highlights', function() + local num_lines = 500 + insert('first line\n') + for _ = 1, num_lines do + insert([[ + line + ]]) + end + insert('last line') + + helpers.feed('gg') + screen:expect { + grid = [[ + ^first line | + line |*6 + {1: }| + ]], + attr_ids = { + [1] = { {}, { { kind = 'ui', hi_name = 'MsgArea', ui_name = 'MsgArea' } } }, + }, + } + local ns = api.nvim_create_namespace('test') + + local add_indicator = function(line, col) + api.nvim_buf_set_extmark(0, ns, line, col, { + hl_mode = 'combine', + priority = 2, + right_gravity = false, + virt_text = { { '|', 'Delimiter' } }, + virt_text_win_col = 0, + virt_text_pos = 'overlay', + }) + end + + for i = 1, num_lines do + add_indicator(i, 0) + end + + screen:expect { + grid = [[ + ^first line | + {1:|} line |*6 + {2: }| + ]], + attr_ids = { + [1] = { + { foreground = Screen.colors.SlateBlue }, + { { kind = 'syntax', hi_name = 'Special' } }, + }, + [2] = { {}, { { kind = 'ui', ui_name = 'MsgArea', hi_name = 'MsgArea' } } }, + }, + } + + helpers.feed(string.format('3ggV%ijd', num_lines - 2)) + --screen:redraw_debug(nil, nil, 100000) + + local expected_ids = {} + for i = 1, num_lines - 1 do + expected_ids[i] = 1 + end + screen:expect { + grid = string.format( + [[ + first line | + {1:|} line | + {2:^|}ast line | + {3:~ }|*4 + {4:%-40s}| + ]], + tostring(num_lines - 1) .. ' fewer lines' + ), + attr_ids = { + [1] = { + { foreground = Screen.colors.SlateBlue }, + { { kind = 'syntax', hi_name = 'Special' } }, + }, + [2] = { { foreground = Screen.colors.SlateBlue }, expected_ids }, + [3] = { + { foreground = Screen.colors.Blue, bold = true }, + { { kind = 'ui', hi_name = 'NonText', ui_name = 'EndOfBuffer' } }, + }, + [4] = { {}, { { kind = 'ui', hi_name = 'MsgArea', ui_name = 'MsgArea' } } }, + }, + timeout = 100000, + } + end) end) diff --git a/test/functional/vimscript/wait_spec.lua b/test/functional/vimscript/wait_spec.lua index 4ee3b183b3..50cdb2cfb4 100644 --- a/test/functional/vimscript/wait_spec.lua +++ b/test/functional/vimscript/wait_spec.lua @@ -13,7 +13,7 @@ local pcall_err = helpers.pcall_err before_each(function() clear() - local channel = api.nvim_get_api_info()[1] + local channel = api.nvim_get_chan_info(0).id api.nvim_set_var('channel', channel) end) |