aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/doc/lsp.txt4
-rw-r--r--runtime/lua/vim/lsp.lua34
-rw-r--r--runtime/lua/vim/lsp/util.lua159
-rw-r--r--runtime/lua/vim/shared.lua14
-rw-r--r--src/nvim/edit.c2
-rw-r--r--src/nvim/eval.c24
-rw-r--r--src/nvim/eval/funcs.c3
-rw-r--r--src/nvim/eval/typval.h5
-rw-r--r--src/nvim/ex_getln.c2
-rw-r--r--src/nvim/lua/vim.lua11
-rw-r--r--src/nvim/memline.c4
-rw-r--r--src/nvim/normal.c2
-rw-r--r--src/nvim/os/input.c20
-rw-r--r--src/nvim/screen.c2
-rw-r--r--src/nvim/state.c28
-rw-r--r--src/nvim/terminal.c2
-rw-r--r--src/nvim/testdir/test_cursor_func.vim5
-rw-r--r--test/functional/fixtures/fake-lsp-server.lua8
-rw-r--r--test/functional/lua/vim_spec.lua5
-rw-r--r--test/functional/plugin/lsp_spec.lua16
-rw-r--r--test/functional/ui/input_spec.lua38
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)