diff options
-rw-r--r-- | runtime/doc/lsp.txt | 4 | ||||
-rw-r--r-- | runtime/lua/vim/lsp.lua | 34 | ||||
-rw-r--r-- | runtime/lua/vim/lsp/util.lua | 159 | ||||
-rw-r--r-- | runtime/lua/vim/shared.lua | 14 | ||||
-rw-r--r-- | src/nvim/edit.c | 2 | ||||
-rw-r--r-- | src/nvim/eval.c | 24 | ||||
-rw-r--r-- | src/nvim/eval/funcs.c | 3 | ||||
-rw-r--r-- | src/nvim/eval/typval.h | 5 | ||||
-rw-r--r-- | src/nvim/ex_getln.c | 2 | ||||
-rw-r--r-- | src/nvim/lua/vim.lua | 11 | ||||
-rw-r--r-- | src/nvim/memline.c | 4 | ||||
-rw-r--r-- | src/nvim/normal.c | 2 | ||||
-rw-r--r-- | src/nvim/os/input.c | 20 | ||||
-rw-r--r-- | src/nvim/screen.c | 2 | ||||
-rw-r--r-- | src/nvim/state.c | 28 | ||||
-rw-r--r-- | src/nvim/terminal.c | 2 | ||||
-rw-r--r-- | src/nvim/testdir/test_cursor_func.vim | 5 | ||||
-rw-r--r-- | test/functional/fixtures/fake-lsp-server.lua | 8 | ||||
-rw-r--r-- | test/functional/lua/vim_spec.lua | 5 | ||||
-rw-r--r-- | test/functional/plugin/lsp_spec.lua | 16 | ||||
-rw-r--r-- | test/functional/ui/input_spec.lua | 38 |
21 files changed, 317 insertions, 71 deletions
diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt index d2d88fb9ba..24f9dd7a69 100644 --- a/runtime/doc/lsp.txt +++ b/runtime/doc/lsp.txt @@ -751,8 +751,8 @@ start_client({config}) *vim.lsp.start_client()* table. > - -- In attach function for the client, you can do: - local custom_attach = function(client) + -- In init function for the client, you can do: + local custom_init = function(client) if client.config.flags then client.config.flags.allow_incremental_sync = true end diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua index 841c365cbe..6c5c2c5062 100644 --- a/runtime/lua/vim/lsp.lua +++ b/runtime/lua/vim/lsp.lua @@ -262,6 +262,13 @@ end --@param bufnr (Number) Number of the buffer, or 0 for current --@param client Client object local function text_document_did_open_handler(bufnr, client) + local allow_incremental_sync = if_nil(client.config.flags.allow_incremental_sync, false) + if allow_incremental_sync then + if not client._cached_buffers then + client._cached_buffers = {} + end + client._cached_buffers[bufnr] = nvim_buf_get_lines(bufnr, 0, -1, true) + end if not client.resolved_capabilities.text_document_open_close then return end @@ -808,7 +815,6 @@ end --- Notify all attached clients that a buffer has changed. local text_document_did_change_handler do - local encoding_index = { ["utf-8"] = 1; ["utf-16"] = 2; ["utf-32"] = 3; } text_document_did_change_handler = function(_, bufnr, changedtick, firstline, lastline, new_lastline, old_byte_size, old_utf32_size, old_utf16_size) @@ -827,23 +833,12 @@ do util.buf_versions[bufnr] = changedtick -- Lazy initialize these because clients may not even need them. local incremental_changes = once(function(client) - local size_index = encoding_index[client.offset_encoding] - local length = select(size_index, old_byte_size, old_utf16_size, old_utf32_size) - local lines = nvim_buf_get_lines(bufnr, firstline, new_lastline, true) - - -- This is necessary because we are specifying the full line including the - -- newline in range. Therefore, we must replace the newline as well. - if #lines > 0 then - table.insert(lines, '') - end - return { - range = { - start = { line = firstline, character = 0 }; - ["end"] = { line = lastline, character = 0 }; - }; - rangeLength = length; - text = table.concat(lines, '\n'); - }; + local lines = nvim_buf_get_lines(bufnr, 0, -1, true) + local startline = math.min(firstline + 1, math.min(#client._cached_buffers[bufnr], #lines)) + local endline = math.min(-(#lines - new_lastline), 0) + local incremental_change = vim.lsp.util.compute_diff(client._cached_buffers[bufnr], lines, startline, endline) + client._cached_buffers[bufnr] = lines + return incremental_change end) local full_changes = once(function() return { @@ -931,6 +926,9 @@ function lsp.buf_attach_client(bufnr, client_id) if client.resolved_capabilities.text_document_open_close then client.notify('textDocument/didClose', params) end + if client._cached_buffers then + client._cached_buffers[bufnr] = nil + end end) util.buf_versions[bufnr] = nil all_buffer_active_clients[bufnr] = nil diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index 6fb9f09c99..88a5fb468f 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -226,6 +226,165 @@ end -- function M.glob_to_regex(glob) -- end +--@private +--- Finds the first line and column of the difference between old and new lines +--@param old_lines table list of lines +--@param new_lines table list of lines +--@returns (int, int) start_line_idx and start_col_idx of range +local function first_difference(old_lines, new_lines, start_line_idx) + local line_count = math.min(#old_lines, #new_lines) + if line_count == 0 then return 1, 1 end + if not start_line_idx then + for i = 1, line_count do + start_line_idx = i + if old_lines[start_line_idx] ~= new_lines[start_line_idx] then + break + end + end + end + local old_line = old_lines[start_line_idx] + local new_line = new_lines[start_line_idx] + local length = math.min(#old_line, #new_line) + local start_col_idx = 1 + while start_col_idx <= length do + if string.sub(old_line, start_col_idx, start_col_idx) ~= string.sub(new_line, start_col_idx, start_col_idx) then + break + end + start_col_idx = start_col_idx + 1 + end + return start_line_idx, start_col_idx +end + + +--@private +--- Finds the last line and column of the differences between old and new lines +--@param old_lines table list of lines +--@param new_lines table list of lines +--@param start_char integer First different character idx of range +--@returns (int, int) end_line_idx and end_col_idx of range +local function last_difference(old_lines, new_lines, start_char, end_line_idx) + local line_count = math.min(#old_lines, #new_lines) + if line_count == 0 then return 0,0 end + if not end_line_idx then + end_line_idx = -1 + end + for i = end_line_idx, -line_count, -1 do + if old_lines[#old_lines + i + 1] ~= new_lines[#new_lines + i + 1] then + end_line_idx = i + break + end + end + local old_line + local new_line + if end_line_idx <= -line_count then + end_line_idx = -line_count + old_line = string.sub(old_lines[#old_lines + end_line_idx + 1], start_char) + new_line = string.sub(new_lines[#new_lines + end_line_idx + 1], start_char) + else + old_line = old_lines[#old_lines + end_line_idx + 1] + new_line = new_lines[#new_lines + end_line_idx + 1] + end + local old_line_length = #old_line + local new_line_length = #new_line + local length = math.min(old_line_length, new_line_length) + local end_col_idx = -1 + while end_col_idx >= -length do + local old_char = string.sub(old_line, old_line_length + end_col_idx + 1, old_line_length + end_col_idx + 1) + local new_char = string.sub(new_line, new_line_length + end_col_idx + 1, new_line_length + end_col_idx + 1) + if old_char ~= new_char then + break + end + end_col_idx = end_col_idx - 1 + end + return end_line_idx, end_col_idx + +end + +--@private +--- Get the text of the range defined by start and end line/column +--@param lines table list of lines +--@param start_char integer First different character idx of range +--@param end_char integer Last different character idx of range +--@param start_line integer First different line idx of range +--@param end_line integer Last different line idx of range +--@returns string text extracted from defined region +local function extract_text(lines, start_line, start_char, end_line, end_char) + if start_line == #lines + end_line + 1 then + if end_line == 0 then return '' end + local line = lines[start_line] + local length = #line + end_char - start_char + return string.sub(line, start_char, start_char + length + 1) + end + local result = string.sub(lines[start_line], start_char) .. '\n' + for line_idx = start_line + 1, #lines + end_line do + result = result .. lines[line_idx] .. '\n' + end + if end_line ~= 0 then + local line = lines[#lines + end_line + 1] + local length = #line + end_char + 1 + result = result .. string.sub(line, 1, length) + end + return result +end + +--@private +--- Compute the length of the substituted range +--@param lines table list of lines +--@param start_char integer First different character idx of range +--@param end_char integer Last different character idx of range +--@param start_line integer First different line idx of range +--@param end_line integer Last different line idx of range +--@returns (int, int) end_line_idx and end_col_idx of range +local function compute_length(lines, start_line, start_char, end_line, end_char) + local adj_end_line = #lines + end_line + 1 + local adj_end_char + if adj_end_line > #lines then + adj_end_char = end_char - 1 + else + adj_end_char = #lines[adj_end_line] + end_char + end + if start_line == adj_end_line then + return adj_end_char - start_char + 1 + end + local result = #lines[start_line] - start_char + 1 + for line = start_line + 1, adj_end_line -1 do + result = result + #lines[line] + 1 + end + result = result + adj_end_char + 1 + return result +end + +--- Returns the range table for the difference between old and new lines +--@param old_lines table list of lines +--@param new_lines table list of lines +--@returns table start_line_idx and start_col_idx of range +function M.compute_diff(old_lines, new_lines, start_line_idx, end_line_idx) + local start_line, start_char = first_difference(old_lines, new_lines, start_line_idx) + local end_line, end_char = last_difference(vim.list_slice(old_lines, start_line, #old_lines), + vim.list_slice(new_lines, start_line, #new_lines), start_char, end_line_idx) + local text = extract_text(new_lines, start_line, start_char, end_line, end_char) + local length = compute_length(old_lines, start_line, start_char, end_line, end_char) + + local adj_end_line = #old_lines + end_line + local adj_end_char + if end_line == 0 then + adj_end_char = 0 + else + adj_end_char = #old_lines[#old_lines + end_line + 1] + end_char + 1 + end + + local result = { + range = { + start = { line = start_line - 1, character = start_char - 1}, + ["end"] = { line = adj_end_line, character = adj_end_char} + }, + text = text, + rangeLength = length + 1, + } + + return result +end + --- Can be used to extract the completion items from a --- `textDocument/completion` request, which may return one of --- `CompletionItem[]`, `CompletionList` or null. diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua index 998e04f568..0a663628a5 100644 --- a/runtime/lua/vim/shared.lua +++ b/runtime/lua/vim/shared.lua @@ -400,6 +400,20 @@ function vim.tbl_count(t) return count end +--- Creates a copy of a table containing only elements from start to end (inclusive) +--- +--@param list table table +--@param start integer Start range of slice +--@param finish integer End range of slice +--@returns Copy of table sliced from start to finish (inclusive) +function vim.list_slice(list, start, finish) + local new_list = {} + for i = start or 1, finish or #list do + new_list[#new_list+1] = list[i] + end + return new_list +end + --- Trim whitespace (Lua pattern "%s") from both sides of a string. --- --@see https://www.lua.org/pil/20.2.html diff --git a/src/nvim/edit.c b/src/nvim/edit.c index 53717229f6..68c7438ea3 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -1024,7 +1024,7 @@ static int insert_handle_key(InsertState *s) break; case K_EVENT: // some event - multiqueue_process_events(main_loop.events); + state_handle_k_event(); goto check_pum; case K_COMMAND: // some command diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 6d97310c1c..63d5216cc4 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -5280,14 +5280,10 @@ bool set_ref_in_item(typval_T *tv, int copyID, ht_stack_T **ht_stack, if (ht_stack == NULL) { abort = set_ref_in_ht(&dd->dv_hashtab, copyID, list_stack); } else { - ht_stack_T *newitem = try_malloc(sizeof(ht_stack_T)); - if (newitem == NULL) { - abort = true; - } else { - newitem->ht = &dd->dv_hashtab; - newitem->prev = *ht_stack; - *ht_stack = newitem; - } + ht_stack_T *const newitem = xmalloc(sizeof(ht_stack_T)); + newitem->ht = &dd->dv_hashtab; + newitem->prev = *ht_stack; + *ht_stack = newitem; } QUEUE *w = NULL; @@ -5308,14 +5304,10 @@ bool set_ref_in_item(typval_T *tv, int copyID, ht_stack_T **ht_stack, if (list_stack == NULL) { abort = set_ref_in_list(ll, copyID, ht_stack); } else { - list_stack_T *newitem = try_malloc(sizeof(list_stack_T)); - if (newitem == NULL) { - abort = true; - } else { - newitem->list = ll; - newitem->prev = *list_stack; - *list_stack = newitem; - } + list_stack_T *const newitem = xmalloc(sizeof(list_stack_T)); + newitem->list = ll; + newitem->prev = *list_stack; + *list_stack = newitem; } } break; diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 8c8e0d568b..60229e1ebc 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -3029,10 +3029,11 @@ static void f_getchar(typval_T *argvars, typval_T *rettv, FunPtr fptr) if (argvars[0].v_type == VAR_UNKNOWN) { // getchar(): blocking wait. + // TODO(bfredl): deduplicate shared logic with state_enter ? if (!(char_avail() || using_script() || input_available())) { (void)os_inchar(NULL, 0, -1, 0, main_loop.events); if (!multiqueue_empty(main_loop.events)) { - multiqueue_process_events(main_loop.events); + state_handle_k_event(); continue; } } diff --git a/src/nvim/eval/typval.h b/src/nvim/eval/typval.h index 6fcb01aace..531b17cb59 100644 --- a/src/nvim/eval/typval.h +++ b/src/nvim/eval/typval.h @@ -341,8 +341,9 @@ struct ufunc { ///< used for s: variables int uf_refcount; ///< reference count, see func_name_refcount() funccall_T *uf_scoped; ///< l: local variables for closure - char_u uf_name[]; ///< Name of function; can start with <SNR>123_ - ///< (<SNR> is K_SPECIAL KS_EXTRA KE_SNR) + char_u uf_name[]; ///< Name of function (actual size equals name); + ///< can start with <SNR>123_ + ///< (<SNR> is K_SPECIAL KS_EXTRA KE_SNR) }; struct partial_S { diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index d470bfb418..5979f4d3a0 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -935,7 +935,7 @@ static int command_line_execute(VimState *state, int key) if (s->c == K_EVENT || s->c == K_COMMAND) { if (s->c == K_EVENT) { - multiqueue_process_events(main_loop.events); + state_handle_k_event(); } else { do_cmdline(NULL, getcmdkeycmd, NULL, DOCMD_NOWAIT); } diff --git a/src/nvim/lua/vim.lua b/src/nvim/lua/vim.lua index e13b9745a8..eb54ff28ee 100644 --- a/src/nvim/lua/vim.lua +++ b/src/nvim/lua/vim.lua @@ -263,8 +263,15 @@ end -- vim.fn.{func}(...) vim.fn = setmetatable({}, { __index = function(t, key) - local function _fn(...) - return vim.call(key, ...) + local _fn + if vim.api[key] ~= nil then + _fn = function() + error(string.format("Tried to call API function with vim.fn: use vim.api.%s instead", key)) + end + else + _fn = function(...) + return vim.call(key, ...) + end end t[key] = _fn return _fn diff --git a/src/nvim/memline.c b/src/nvim/memline.c index 293a4d01db..34d8eb0ffe 100644 --- a/src/nvim/memline.c +++ b/src/nvim/memline.c @@ -3859,8 +3859,8 @@ static void ml_updatechunk(buf_T *buf, linenr_T line, long len, int updtype) /* May resize here so we don't have to do it in both cases below */ if (buf->b_ml.ml_usedchunks + 1 >= buf->b_ml.ml_numchunks) { buf->b_ml.ml_numchunks = buf->b_ml.ml_numchunks * 3 / 2; - buf->b_ml.ml_chunksize = (chunksize_T *) - xrealloc(buf->b_ml.ml_chunksize, + buf->b_ml.ml_chunksize = xrealloc( + buf->b_ml.ml_chunksize, sizeof(chunksize_T) * buf->b_ml.ml_numchunks); } diff --git a/src/nvim/normal.c b/src/nvim/normal.c index 4d8b11f832..0b4e2e1f23 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -8103,7 +8103,7 @@ static void nv_event(cmdarg_T *cap) // lists or dicts being used. may_garbage_collect = false; bool may_restart = (restart_edit != 0); - multiqueue_process_events(main_loop.events); + state_handle_k_event(); finish_op = false; if (may_restart) { // Tricky: if restart_edit was set before the handler we are in ctrl-o mode, diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c index 9d6518841a..eca245650a 100644 --- a/src/nvim/os/input.c +++ b/src/nvim/os/input.c @@ -159,16 +159,28 @@ bool os_char_avail(void) return inbuf_poll(0, NULL) == kInputAvail; } -// Check for CTRL-C typed by reading all available characters. +/// Poll for fast events. `got_int` will be set to `true` if CTRL-C was typed. +/// +/// This invokes a full libuv loop iteration which can be quite costly. +/// Prefer `line_breakcheck()` if called in a busy inner loop. +/// +/// Caller must at least check `got_int` before calling this function again. +/// checking for other low-level input state like `input_available()` might +/// also be relevant (i e to throttle idle processing when user input is +/// available) void os_breakcheck(void) { + if (got_int) { + return; + } + int save_us = updating_screen; // We do not want screen_resize() to redraw here. + // TODO(bfredl): we are already special casing redraw events, is this + // hack still needed? updating_screen++; - if (!got_int) { - loop_poll_events(&main_loop, 0); - } + loop_poll_events(&main_loop, 0); updating_screen = save_us; } diff --git a/src/nvim/screen.c b/src/nvim/screen.c index c15d7f74ea..aa3a7ae7ed 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -2658,7 +2658,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, // already be in use. xfree(p_extra_free); p_extra_free = xmalloc(MAX_MCO * fdc + 1); - n_extra = fill_foldcolumn(p_extra_free, wp, foldinfo, lnum); + n_extra = (int)fill_foldcolumn(p_extra_free, wp, foldinfo, lnum); p_extra_free[n_extra] = NUL; p_extra = p_extra_free; c_extra = NUL; diff --git a/src/nvim/state.c b/src/nvim/state.c index b195c1d96b..a3c74789d1 100644 --- a/src/nvim/state.c +++ b/src/nvim/state.c @@ -75,6 +75,34 @@ getkey: } } +/// process events on main_loop, but interrupt if input is available +/// +/// This should be used to handle K_EVENT in states accepting input +/// otherwise bursts of events can block break checking indefinitely. +void state_handle_k_event(void) +{ + while (true) { + Event event = multiqueue_get(main_loop.events); + if (event.handler) { + event.handler(event.argv); + } + + if (multiqueue_empty(main_loop.events)) { + // don't breakcheck before return, caller should return to main-loop + // and handle input already. + return; + } + + // TODO(bfredl): as an further micro-optimization, we could check whether + // event.handler already checked input. + os_breakcheck(); + if (input_available() || got_int) { + return; + } + } +} + + /// Return true if in the current mode we need to use virtual. bool virtual_active(void) { diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c index 642c443318..f6995cddb6 100644 --- a/src/nvim/terminal.c +++ b/src/nvim/terminal.c @@ -457,7 +457,7 @@ static int terminal_execute(VimState *state, int key) case K_EVENT: // We cannot let an event free the terminal yet. It is still needed. s->term->refcount++; - multiqueue_process_events(main_loop.events); + state_handle_k_event(); s->term->refcount--; if (s->term->buf_handle == 0) { s->close = true; diff --git a/src/nvim/testdir/test_cursor_func.vim b/src/nvim/testdir/test_cursor_func.vim index 2e190911b2..53b7da517e 100644 --- a/src/nvim/testdir/test_cursor_func.vim +++ b/src/nvim/testdir/test_cursor_func.vim @@ -92,6 +92,11 @@ func Test_screenpos() \ 'endcol': wincol + 9}, screenpos(winid, 2, 22)) close bwipe! + + call assert_equal({'col': 1, 'row': 1, 'endcol': 1, 'curscol': 1}, screenpos(win_getid(), 1, 1)) + nmenu WinBar.TEST : + call assert_equal({'col': 1, 'row': 2, 'endcol': 1, 'curscol': 1}, screenpos(win_getid(), 1, 1)) + nunmenu WinBar.TEST endfunc func Test_screenpos_number() diff --git a/test/functional/fixtures/fake-lsp-server.lua b/test/functional/fixtures/fake-lsp-server.lua index 3bbb4c4517..1b1fc2589f 100644 --- a/test/functional/fixtures/fake-lsp-server.lua +++ b/test/functional/fixtures/fake-lsp-server.lua @@ -402,11 +402,11 @@ function tests.basic_check_buffer_open_and_change_incremental() contentChanges = { { range = { - start = { line = 1; character = 0; }; - ["end"] = { line = 2; character = 0; }; + start = { line = 1; character = 3; }; + ["end"] = { line = 1; character = 3; }; }; - rangeLength = 4; - text = "boop\n"; + rangeLength = 0; + text = "boop"; }; } }) diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index e253db5297..9bf00b594b 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -715,6 +715,11 @@ describe('lua stdlib', function() eq({false, 'Vim:E714: List required'}, exec_lua([[return {pcall(vim.fn.add, "aa", "bb")}]])) end) + it('vim.fn should error when calling API function', function() + eq('Error executing lua: vim.lua:0: Tried to call API function with vim.fn: use vim.api.nvim_get_current_line instead', + pcall_err(exec_lua, "vim.fn.nvim_get_current_line()")) + end) + it('vim.rpcrequest and vim.rpcnotify', function() exec_lua([[ chan = vim.fn.jobstart({'cat'}, {rpc=true}) diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index 8ac81daeef..cdc3017323 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -27,10 +27,10 @@ teardown(function() os.remove(fake_lsp_logfile) end) -local function fake_lsp_server_setup(test_name, timeout_ms) +local function fake_lsp_server_setup(test_name, timeout_ms, options) exec_lua([=[ lsp = require('vim.lsp') - local test_name, fixture_filename, logfile, timeout = ... + local test_name, fixture_filename, logfile, timeout, options = ... TEST_RPC_CLIENT_ID = lsp.start_client { cmd_env = { NVIM_LOG_FILE = logfile; @@ -52,18 +52,19 @@ local function fake_lsp_server_setup(test_name, timeout_ms) on_init = function(client, result) TEST_RPC_CLIENT = client vim.rpcrequest(1, "init", result) + client.config.flags.allow_incremental_sync = options.allow_incremental_sync or false end; on_exit = function(...) vim.rpcnotify(1, "exit", ...) end; } - ]=], test_name, fake_lsp_code, fake_lsp_logfile, timeout_ms or 1e3) + ]=], test_name, fake_lsp_code, fake_lsp_logfile, timeout_ms or 1e3, options or {}) end local function test_rpc_server(config) if config.test_name then clear() - fake_lsp_server_setup(config.test_name, config.timeout_ms or 1e3) + fake_lsp_server_setup(config.test_name, config.timeout_ms or 1e3, config.options) end local client = setmetatable({}, { __index = function(_, name) @@ -257,6 +258,7 @@ describe('LSP', function() eq(0, client.resolved_capabilities().text_document_did_change) client.request('shutdown') client.notify('exit') + client.stop() end; on_exit = function(code, signal) eq(0, code, "exit code", fake_lsp_logfile) @@ -680,8 +682,7 @@ describe('LSP', function() } end) - -- TODO(askhan) we don't support full for now, so we can disable these tests. - pending('should check the body and didChange incremental', function() + it('should check the body and didChange incremental', function() local expected_callbacks = { {NIL, "shutdown", {}, 1}; {NIL, "finish", {}, 1}; @@ -690,6 +691,7 @@ describe('LSP', function() local client test_rpc_server { test_name = "basic_check_buffer_open_and_change_incremental"; + options = { allow_incremental_sync = true }; on_setup = function() exec_lua [[ BUFFER = vim.api.nvim_create_buf(false, true) @@ -716,7 +718,7 @@ describe('LSP', function() if method == 'start' then exec_lua [[ vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, { - "boop"; + "123boop"; }) ]] client.notify('finish') diff --git a/test/functional/ui/input_spec.lua b/test/functional/ui/input_spec.lua index 9313a35708..ea8968a653 100644 --- a/test/functional/ui/input_spec.lua +++ b/test/functional/ui/input_spec.lua @@ -1,16 +1,18 @@ local helpers = require('test.functional.helpers')(after_each) -local clear, feed_command, nvim = helpers.clear, helpers.feed_command, helpers.nvim +local clear, feed_command = helpers.clear, helpers.feed_command local feed, next_msg, eq = helpers.feed, helpers.next_msg, helpers.eq local command = helpers.command local expect = helpers.expect +local meths = helpers.meths +local exec_lua = helpers.exec_lua local write_file = helpers.write_file local Screen = require('test.functional.ui.screen') -describe('mappings', function() - local cid +before_each(clear) +describe('mappings', function() local add_mapping = function(mapping, send) - local cmd = "nnoremap "..mapping.." :call rpcnotify("..cid..", 'mapped', '" + local cmd = "nnoremap "..mapping.." :call rpcnotify(1, 'mapped', '" ..send:gsub('<', '<lt>').."')<cr>" feed_command(cmd) end @@ -21,8 +23,6 @@ describe('mappings', function() end before_each(function() - clear() - cid = nvim('get_api_info')[1] add_mapping('<C-L>', '<C-L>') add_mapping('<C-S-L>', '<C-S-L>') add_mapping('<s-up>', '<s-up>') @@ -115,7 +115,6 @@ describe('mappings', function() end) describe('input utf sequences that contain CSI/K_SPECIAL', function() - before_each(clear) it('ok', function() feed('i…<esc>') expect('…') @@ -129,7 +128,6 @@ describe('input non-printable chars', function() it("doesn't crash when echoing them back", function() write_file("Xtest-overwrite", [[foobar]]) - clear() local screen = Screen.new(60,8) screen:set_default_attr_ids({ [1] = {bold = true, foreground = Screen.colors.Blue1}, @@ -215,3 +213,27 @@ describe('input non-printable chars', function() ]]) end) end) + +describe("event processing and input", function() + it('not blocked by event bursts', function() + meths.set_keymap('', '<f2>', "<cmd>lua vim.rpcnotify(1, 'stop') winning = true <cr>", {noremap=true}) + + exec_lua [[ + winning = false + burst = vim.schedule_wrap(function(tell) + if tell then + vim.rpcnotify(1, 'start') + end + -- Are we winning, son? + if not winning then + burst(false) + end + end) + burst(true) + ]] + + eq({'notification', 'start', {}}, next_msg()) + feed '<f2>' + eq({'notification', 'stop', {}}, next_msg()) + end) +end) |