aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.builds/openbsd.yml10
-rw-r--r--config/CMakeLists.txt2
-rw-r--r--runtime/autoload/remote/define.vim2
-rw-r--r--runtime/doc/autocmd.txt1
-rw-r--r--runtime/doc/eval.txt3
-rw-r--r--runtime/doc/lua.txt4
-rw-r--r--runtime/filetype.vim7
-rw-r--r--runtime/lua/vim/lsp.lua2
-rw-r--r--runtime/lua/vim/lsp/callbacks.lua11
-rw-r--r--runtime/lua/vim/lsp/protocol.lua22
-rw-r--r--runtime/lua/vim/lsp/util.lua188
-rw-r--r--runtime/lua/vim/shared.lua2
-rw-r--r--src/nvim/buffer.c11
-rw-r--r--src/nvim/eval.c3
-rw-r--r--src/nvim/eval/userfunc.c3
-rw-r--r--src/nvim/ex_getln.c6
-rw-r--r--src/nvim/globals.h4
-rw-r--r--src/nvim/main.c7
-rw-r--r--src/nvim/message.c5
-rw-r--r--src/nvim/normal.c15
-rw-r--r--src/nvim/ops.c4
-rw-r--r--src/nvim/os/signal.c1
-rw-r--r--src/nvim/regexp_nfa.c6
-rw-r--r--src/nvim/syntax.c4
-rw-r--r--src/nvim/testdir/test_autocmd.vim10
-rw-r--r--src/nvim/testdir/test_cmdline.vim16
-rw-r--r--src/nvim/testdir/test_filetype.vim2
-rw-r--r--src/nvim/testdir/test_ga.vim1
-rw-r--r--src/nvim/testdir/test_maparg.vim8
-rw-r--r--test/functional/api/keymap_spec.lua4
-rw-r--r--test/functional/autocmd/textyankpost_spec.lua48
-rw-r--r--test/functional/eval/map_functions_spec.lua2
-rw-r--r--test/functional/legacy/075_maparg_spec.lua6
-rw-r--r--test/functional/lua/vim_spec.lua10
-rw-r--r--test/functional/plugin/lsp_spec.lua74
-rw-r--r--test/functional/provider/define_spec.lua15
36 files changed, 392 insertions, 127 deletions
diff --git a/.builds/openbsd.yml b/.builds/openbsd.yml
index ed2962998c..5fa6556066 100644
--- a/.builds/openbsd.yml
+++ b/.builds/openbsd.yml
@@ -1,17 +1,17 @@
# sourcehut CI: https://builds.sr.ht/~jmk/neovim
-image: openbsd/6.5
+image: openbsd/6.7
packages:
- autoconf-2.69p2
- automake-1.15.1
- cmake
-- gettext-0.19.8.1p3
-- gettext-tools-0.19.8.1
+- gettext-runtime-0.20.1p1
+- gettext-tools-0.20.1p3
- gmake
- libtool
-- ninja-1.8.2p0
-- unzip-6.0p11
+- ninja-1.10.0
+- unzip-6.0p13
sources:
- https://github.com/neovim/neovim
diff --git a/config/CMakeLists.txt b/config/CMakeLists.txt
index 0ca41d5dfd..6c9e06d59d 100644
--- a/config/CMakeLists.txt
+++ b/config/CMakeLists.txt
@@ -12,7 +12,7 @@ check_type_size("size_t" SIZEOF_SIZE_T)
check_type_size("long long" SIZEOF_LONG_LONG)
check_type_size("void *" SIZEOF_VOID_PTR)
-if (CMAKE_HOST_SYSTEM_VERSION MATCHES ".*-Microsoft")
+if (CMAKE_HOST_SYSTEM_VERSION MATCHES ".*-(Microsoft|microsoft-standard)")
# Windows Subsystem for Linux
set(HAVE_WSL 1)
endif()
diff --git a/runtime/autoload/remote/define.vim b/runtime/autoload/remote/define.vim
index 2688a62a82..2aec96e365 100644
--- a/runtime/autoload/remote/define.vim
+++ b/runtime/autoload/remote/define.vim
@@ -24,7 +24,7 @@ function! remote#define#CommandOnHost(host, method, sync, name, opts)
endif
if has_key(a:opts, 'nargs')
- call add(forward_args, ' <args>')
+ call add(forward_args, ' " . <q-args> . "')
endif
exe s:GetCommandPrefix(a:name, a:opts)
diff --git a/runtime/doc/autocmd.txt b/runtime/doc/autocmd.txt
index 64ca7b6a45..f1753b75cc 100644
--- a/runtime/doc/autocmd.txt
+++ b/runtime/doc/autocmd.txt
@@ -844,6 +844,7 @@ TextYankPost Just after a |yank| or |deleting| command, but not
regcontents
regname
regtype
+ visual
The `inclusive` flag combined with the |'[|
and |']| marks can be used to calculate the
precise region of the operation.
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index 214d815006..99bc526659 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -1591,6 +1591,8 @@ v:event Dictionary of event data for the current |autocommand|. Valid
operation.
regtype Type of register as returned by
|getregtype()|.
+ visual Selection is visual (as opposed to,
+ e.g., via motion).
completed_item Current selected complete item on
|CompleteChanged|, Is `{}` when no complete
item selected.
@@ -5833,6 +5835,7 @@ maparg({name} [, {mode} [, {abbr} [, {dict}]]]) *maparg()*
"rhs" The {rhs} of the mapping as typed.
"silent" 1 for a |:map-silent| mapping, else 0.
"noremap" 1 if the {rhs} of the mapping is not remappable.
+ "script" 1 if mapping was defined with <script>.
"expr" 1 for an expression mapping (|:map-<expr>|).
"buffer" 1 for a buffer local mapping (|:map-local|).
"mode" Modes for which the mapping is defined. In
diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt
index 7c1b0ee73b..5a49d36503 100644
--- a/runtime/doc/lua.txt
+++ b/runtime/doc/lua.txt
@@ -705,6 +705,10 @@ the highlight via
>
au TextYankPost * silent! lua require'vim.highlight'.on_yank("IncSearch", 500)
<
+If you want to exclude visual selections from highlighting on yank, use
+>
+au TextYankPost * silent! lua return (not vim.v.event.visual) and require'vim.highlight'.on_yank()
+<
vim.highlight.on_yank([{higroup}, {timeout}, {event}])
*vim.highlight.on_yank()*
diff --git a/runtime/filetype.vim b/runtime/filetype.vim
index b29168984c..383a45b9d3 100644
--- a/runtime/filetype.vim
+++ b/runtime/filetype.vim
@@ -883,11 +883,12 @@ au BufNewFile,BufRead *.ll setf lifelines
" Lilo: Linux loader
au BufNewFile,BufRead lilo.conf setf lilo
-" Lisp (*.el = ELisp, *.cl = Common Lisp, *.jl = librep Lisp)
+" Lisp (*.el = ELisp, *.cl = Common Lisp)
+" *.jl was removed, it's also used for Julia, better skip than guess wrong.
if has("fname_case")
- au BufNewFile,BufRead *.lsp,*.lisp,*.el,*.cl,*.jl,*.L,.emacs,.sawfishrc setf lisp
+ au BufNewFile,BufRead *.lsp,*.lisp,*.el,*.cl,*.L,.emacs,.sawfishrc setf lisp
else
- au BufNewFile,BufRead *.lsp,*.lisp,*.el,*.cl,*.jl,.emacs,.sawfishrc setf lisp
+ au BufNewFile,BufRead *.lsp,*.lisp,*.el,*.cl,.emacs,.sawfishrc setf lisp
endif
" SBCL implementation of Common Lisp
diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua
index 84812b8c64..2fbc51481f 100644
--- a/runtime/lua/vim/lsp.lua
+++ b/runtime/lua/vim/lsp.lua
@@ -507,6 +507,8 @@ function lsp.start_client(config)
or (not client.resolved_capabilities.signature_help and method == 'textDocument/signatureHelp')
or (not client.resolved_capabilities.goto_definition and method == 'textDocument/definition')
or (not client.resolved_capabilities.implementation and method == 'textDocument/implementation')
+ or (not client.resolved_capabilities.declaration and method == 'textDocument/declaration')
+ or (not client.resolved_capabilities.type_definition and method == 'textDocument/typeDefinition')
or (not client.resolved_capabilities.document_symbol and method == 'textDocument/documentSymbol')
or (not client.resolved_capabilities.workspace_symbol and method == 'textDocument/workspaceSymbol')
then
diff --git a/runtime/lua/vim/lsp/callbacks.lua b/runtime/lua/vim/lsp/callbacks.lua
index 7c51fc2cc2..4b14f0132d 100644
--- a/runtime/lua/vim/lsp/callbacks.lua
+++ b/runtime/lua/vim/lsp/callbacks.lua
@@ -72,6 +72,17 @@ M['textDocument/publishDiagnostics'] = function(_, _, result)
err_message("LSP.publishDiagnostics: Couldn't find buffer for ", uri)
return
end
+
+ -- Unloaded buffers should not handle diagnostics.
+ -- When the buffer is loaded, we'll call on_attach, which sends textDocument/didOpen.
+ -- This should trigger another publish of the diagnostics.
+ --
+ -- In particular, this stops a ton of spam when first starting a server for current
+ -- unloaded buffers.
+ if not api.nvim_buf_is_loaded(bufnr) then
+ return
+ end
+
util.buf_clear_diagnostics(bufnr)
-- https://microsoft.github.io/language-server-protocol/specifications/specification-current/#diagnostic
diff --git a/runtime/lua/vim/lsp/protocol.lua b/runtime/lua/vim/lsp/protocol.lua
index 7d5f8f5ef1..64911fe7bb 100644
--- a/runtime/lua/vim/lsp/protocol.lua
+++ b/runtime/lua/vim/lsp/protocol.lua
@@ -923,6 +923,28 @@ function protocol.resolve_capabilities(server_capabilities)
error("The server sent invalid codeActionProvider")
end
+ if server_capabilities.declarationProvider == nil then
+ general_properties.declaration = false
+ elseif type(server_capabilities.declarationProvider) == 'boolean' then
+ general_properties.declaration = server_capabilities.declarationProvider
+ elseif type(server_capabilities.declarationProvider) == 'table' then
+ -- TODO: support more detailed declarationProvider options.
+ general_properties.declaration = false
+ else
+ error("The server sent invalid declarationProvider")
+ end
+
+ if server_capabilities.typeDefinitionProvider == nil then
+ general_properties.type_definition = false
+ elseif type(server_capabilities.typeDefinitionProvider) == 'boolean' then
+ general_properties.type_definition = server_capabilities.typeDefinitionProvider
+ elseif type(server_capabilities.typeDefinitionProvider) == 'table' then
+ -- TODO: support more detailed typeDefinitionProvider options.
+ general_properties.type_definition = false
+ else
+ error("The server sent invalid typeDefinitionProvider")
+ end
+
if server_capabilities.implementationProvider == nil then
general_properties.implementation = false
elseif type(server_capabilities.implementationProvider) == 'boolean' then
diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua
index 79d428d12d..49e2557c16 100644
--- a/runtime/lua/vim/lsp/util.lua
+++ b/runtime/lua/vim/lsp/util.lua
@@ -95,17 +95,23 @@ local edit_sort_key = sort_by_key(function(e)
return {e.A[1], e.A[2], e.i}
end)
-local function get_line_byte_from_line_character(bufnr, lnum, cnum)
- -- Skip check when the byte and character position is the same
- if cnum > 0 then
- local lines = api.nvim_buf_get_lines(bufnr, lnum, lnum+1, false)
-
+--- Position is a https://microsoft.github.io/language-server-protocol/specifications/specification-current/#position
+-- Returns a zero-indexed column, since set_lines() does the conversion to
+-- 1-indexed
+local function get_line_byte_from_position(bufnr, position)
+ -- LSP's line and characters are 0-indexed
+ -- Vim's line and columns are 1-indexed
+ local col = position.character
+ -- When on the first character, we can ignore the difference between byte and
+ -- character
+ if col > 0 then
+ local line = position.line
+ local lines = api.nvim_buf_get_lines(bufnr, line, line + 1, false)
if #lines > 0 then
- return vim.str_byteindex(lines[1], cnum)
+ return vim.str_byteindex(lines[1], col)
end
end
-
- return cnum
+ return col
end
function M.apply_text_edits(text_edits, bufnr)
@@ -118,15 +124,9 @@ function M.apply_text_edits(text_edits, bufnr)
for i, e in ipairs(text_edits) do
-- adjust start and end column for UTF-16 encoding of non-ASCII characters
local start_row = e.range.start.line
- local start_col = get_line_byte_from_line_character(
- bufnr,
- start_row,
- e.range.start.character)
+ local start_col = get_line_byte_from_position(bufnr, e.range.start)
local end_row = e.range["end"].line
- local end_col = get_line_byte_from_line_character(
- bufnr,
- end_row,
- e.range["end"].character)
+ local end_col = get_line_byte_from_position(bufnr, e.range['end'])
start_line = math.min(e.range.start.line, start_line)
finish_line = math.max(e.range["end"].line, finish_line)
-- TODO(ashkan) sanity check ranges for overlap.
@@ -289,7 +289,7 @@ local function get_completion_word(item)
return item.label
end
--- Some lanuguage servers return complementary candidates whose prefixes do not match are also returned.
+-- Some language servers return complementary candidates whose prefixes do not match are also returned.
-- So we exclude completion candidates whose prefix does not match.
local function remove_unmatch_completion_items(items, prefix)
return vim.tbl_filter(function(item)
@@ -543,9 +543,7 @@ function M.jump_to_location(location)
api.nvim_buf_set_option(0, 'buflisted', true)
local range = location.range or location.targetSelectionRange
local row = range.start.line
- local col = range.start.character
- local line = api.nvim_buf_get_lines(0, row, row+1, true)[1]
- col = vim.str_byteindex(line, col)
+ local col = get_line_byte_from_position(0, range.start)
api.nvim_win_set_cursor(0, {row + 1, col})
return true
end
@@ -616,13 +614,53 @@ function M.focusable_preview(unique_name, fn)
end)
end
--- Convert markdown into syntax highlighted regions by stripping the code
--- blocks and converting them into highlighted code.
--- This will by default insert a blank line separator after those code block
--- regions to improve readability.
+--- Trim empty lines from input and pad left and right with spaces
+---
+--@param contents table of lines to trim and pad
+--@param opts dictionary with optional fields
+-- - pad_left amount of columns to pad contents at left (default 1)
+-- - pad_right amount of columns to pad contents at right (default 1)
+--@return contents table of trimmed and padded lines
+function M._trim_and_pad(contents, opts)
+ validate {
+ contents = { contents, 't' };
+ opts = { opts, 't', true };
+ }
+ opts = opts or {}
+ local left_padding = (" "):rep(opts.pad_left or 1)
+ local right_padding = (" "):rep(opts.pad_right or 1)
+ contents = M.trim_empty_lines(contents)
+ for i, line in ipairs(contents) do
+ contents[i] = string.format('%s%s%s', left_padding, line:gsub("\r", ""), right_padding)
+ end
+ return contents
+end
+
+
+
+--- Convert markdown into syntax highlighted regions by stripping the code
+--- blocks and converting them into highlighted code.
+--- This will by default insert a blank line separator after those code block
+--- regions to improve readability.
+--- The result is shown in a floating preview
+--- TODO: refactor to separate stripping/converting and make use of open_floating_preview
+---
+--@param contents table of lines to show in window
+--@param opts dictionary with optional fields
+-- - height of floating window
+-- - width of floating window
+-- - wrap_at character to wrap at for computing height
+-- - pad_left amount of columns to pad contents at left
+-- - pad_right amount of columns to pad contents at right
+-- - separator insert separator after code block
+--@return width,height size of float
function M.fancy_floating_markdown(contents, opts)
- local pad_left = opts and opts.pad_left
- local pad_right = opts and opts.pad_right
+ validate {
+ contents = { contents, 't' };
+ opts = { opts, 't', true };
+ }
+ opts = opts or {}
+
local stripped = {}
local highlights = {}
do
@@ -656,31 +694,27 @@ function M.fancy_floating_markdown(contents, opts)
end
end
end
- local width = 0
- for i, v in ipairs(stripped) do
- v = v:gsub("\r", "")
- if pad_left then v = (" "):rep(pad_left)..v end
- if pad_right then v = v..(" "):rep(pad_right) end
- stripped[i] = v
- width = math.max(width, #v)
- end
- if opts and opts.max_width then
- width = math.min(opts.max_width, width)
- end
- -- TODO(ashkan): decide how to make this customizable.
- local insert_separator = true
+ -- Clean up and add padding
+ stripped = M._trim_and_pad(stripped, opts)
+
+ -- Compute size of float needed to show (wrapped) lines
+ opts.wrap_at = opts.wrap_at or (vim.wo["wrap"] and api.nvim_win_get_width(0))
+ local width, height = M._make_floating_popup_size(stripped, opts)
+
+ -- Insert blank line separator after code block
+ local insert_separator = opts.separator or true
if insert_separator then
for i, h in ipairs(highlights) do
h.start = h.start + i - 1
h.finish = h.finish + i - 1
if h.finish + 1 <= #stripped then
table.insert(stripped, h.finish + 1, string.rep("─", width))
+ height = height + 1
end
end
end
-- Make the floating window.
- local height = #stripped
local bufnr = api.nvim_create_buf(false, true)
local winnr = api.nvim_open_win(bufnr, false, M.make_floating_popup_options(width, height, opts))
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, stripped)
@@ -721,33 +755,81 @@ function M.close_preview_autocmd(events, winnr)
api.nvim_command("autocmd "..table.concat(events, ',').." <buffer> ++once lua pcall(vim.api.nvim_win_close, "..winnr..", true)")
end
-function M.open_floating_preview(contents, filetype, opts)
+--- Compute size of float needed to show contents (with optional wrapping)
+---
+--@param contents table of lines to show in window
+--@param opts dictionary with optional fields
+-- - height of floating window
+-- - width of floating window
+-- - wrap_at character to wrap at for computing height
+--@return width,height size of float
+function M._make_floating_popup_size(contents, opts)
validate {
contents = { contents, 't' };
- filetype = { filetype, 's', true };
opts = { opts, 't', true };
}
opts = opts or {}
- -- Trim empty lines from the end.
- contents = M.trim_empty_lines(contents)
-
local width = opts.width
- local height = opts.height or #contents
+ local height = opts.height
+ local line_widths = {}
+
if not width then
width = 0
for i, line in ipairs(contents) do
- -- Clean up the input and add left pad.
- line = " "..line:gsub("\r", "")
-- TODO(ashkan) use nvim_strdisplaywidth if/when that is introduced.
- local line_width = vim.fn.strdisplaywidth(line)
- width = math.max(line_width, width)
- contents[i] = line
+ line_widths[i] = vim.fn.strdisplaywidth(line)
+ width = math.max(line_widths[i], width)
+ end
+ end
+
+ if not height then
+ height = #contents
+ local wrap_at = opts.wrap_at
+ if wrap_at and width > wrap_at then
+ height = 0
+ if vim.tbl_isempty(line_widths) then
+ for _, line in ipairs(contents) do
+ local line_width = vim.fn.strdisplaywidth(line)
+ height = height + math.ceil(line_width/wrap_at)
+ end
+ else
+ for i = 1, #contents do
+ height = height + math.ceil(line_widths[i]/wrap_at)
+ end
+ end
end
- -- Add right padding of 1 each.
- width = width + 1
end
+ return width, height
+end
+
+--- Show contents in a floating window
+---
+--@param contents table of lines to show in window
+--@param filetype string of filetype to set for opened buffer
+--@param opts dictionary with optional fields
+-- - height of floating window
+-- - width of floating window
+-- - wrap_at character to wrap at for computing height
+-- - pad_left amount of columns to pad contents at left
+-- - pad_right amount of columns to pad contents at right
+--@return bufnr,winnr buffer and window number of floating window or nil
+function M.open_floating_preview(contents, filetype, opts)
+ validate {
+ contents = { contents, 't' };
+ filetype = { filetype, 's', true };
+ opts = { opts, 't', true };
+ }
+ opts = opts or {}
+
+ -- Clean up input: trim empty lines from the end, pad
+ contents = M._trim_and_pad(contents, opts)
+
+ -- Compute size of float needed to show (wrapped) lines
+ opts.wrap_at = opts.wrap_at or (vim.wo["wrap"] and api.nvim_win_get_width(0))
+ local width, height = M._make_floating_popup_size(contents, opts)
+
local floating_bufnr = api.nvim_create_buf(false, true)
if filetype then
api.nvim_buf_set_option(floating_bufnr, 'filetype', filetype)
diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua
index 2135bfc837..384d22cb89 100644
--- a/runtime/lua/vim/shared.lua
+++ b/runtime/lua/vim/shared.lua
@@ -79,7 +79,7 @@ function vim.gsplit(s, sep, plain)
end
return function()
- if done then
+ if done or (s == '' and sep == '') then
return
end
if sep == '' then
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
index 7c8f93163a..3ce39feda5 100644
--- a/src/nvim/buffer.c
+++ b/src/nvim/buffer.c
@@ -186,14 +186,17 @@ int open_buffer(
}
}
- /*
- * if there is no memfile at all, exit
- * This is OK, since there are no changes to lose.
- */
+ // If there is no memfile at all, exit.
+ // This is OK, since there are no changes to lose.
if (curbuf == NULL) {
EMSG(_("E82: Cannot allocate any buffer, exiting..."));
+
+ // Don't try to do any saving, with "curbuf" NULL almost nothing
+ // will work.
+ v_dying = 2;
getout(2);
}
+
EMSG(_("E83: Cannot allocate buffer, using other one..."));
enter_buffer(curbuf);
if (old_tw != curbuf->b_p_tw) {
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 017d46e802..5f8f3f96f7 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -6120,7 +6120,7 @@ void common_function(typval_T *argvars, typval_T *rettv,
if (tv_list_len(list) == 0) {
arg_idx = 0;
} else if (tv_list_len(list) > MAX_FUNC_ARGS) {
- emsg_funcname((char *)e_toomanyarg, name);
+ emsg_funcname((char *)e_toomanyarg, s);
xfree(name);
goto theend;
}
@@ -6754,6 +6754,7 @@ void mapblock_fill_dict(dict_T *const dict,
}
tv_dict_add_allocated_str(dict, S_LEN("lhs"), lhs);
tv_dict_add_nr(dict, S_LEN("noremap"), noremap_value);
+ tv_dict_add_nr(dict, S_LEN("script"), mp->m_noremap == REMAP_SCRIPT ? 1 : 0);
tv_dict_add_nr(dict, S_LEN("expr"), mp->m_expr ? 1 : 0);
tv_dict_add_nr(dict, S_LEN("silent"), mp->m_silent ? 1 : 0);
tv_dict_add_nr(dict, S_LEN("sid"), (varnumber_T)mp->m_script_ctx.sc_sid);
diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c
index c054433255..4d658498c1 100644
--- a/src/nvim/eval/userfunc.c
+++ b/src/nvim/eval/userfunc.c
@@ -170,6 +170,7 @@ int get_lambda_tv(char_u **arg, typval_T *rettv, bool evaluate)
garray_T newargs = GA_EMPTY_INIT_VALUE;
garray_T *pnewargs;
ufunc_T *fp = NULL;
+ partial_T *pt = NULL;
int varargs;
int ret;
char_u *start = skipwhite(*arg + 1);
@@ -219,7 +220,6 @@ int get_lambda_tv(char_u **arg, typval_T *rettv, bool evaluate)
int len, flags = 0;
char_u *p;
char_u name[20];
- partial_T *pt;
garray_T newlines;
lambda_no++;
@@ -274,6 +274,7 @@ int get_lambda_tv(char_u **arg, typval_T *rettv, bool evaluate)
errret:
ga_clear_strings(&newargs);
xfree(fp);
+ xfree(pt);
eval_lavars_used = old_eval_lavars;
return FAIL;
}
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index b799e86ff7..56a8f56753 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -5361,12 +5361,12 @@ void globpath(char_u *path, char_u *file, garray_T *ga, int expand_options)
// Concatenate new results to previous ones.
ga_grow(ga, num_p);
+ // take over the pointers and put them in "ga"
for (int i = 0; i < num_p; i++) {
- ((char_u **)ga->ga_data)[ga->ga_len] = vim_strsave(p[i]);
+ ((char_u **)ga->ga_data)[ga->ga_len] = p[i];
ga->ga_len++;
}
-
- FreeWild(num_p, p);
+ xfree(p);
}
}
}
diff --git a/src/nvim/globals.h b/src/nvim/globals.h
index f102c3ddd8..d6d00d6e83 100644
--- a/src/nvim/globals.h
+++ b/src/nvim/globals.h
@@ -203,7 +203,7 @@ EXTERN int msg_nowait INIT(= false); // don't wait for this msg
EXTERN int emsg_off INIT(= 0); // don't display errors for now,
// unless 'debug' is set.
EXTERN int info_message INIT(= false); // printing informative message
-EXTERN int msg_hist_off INIT(= false); // don't add messages to history
+EXTERN bool msg_hist_off INIT(= false); // don't add messages to history
EXTERN int need_clr_eos INIT(= false); // need to clear text before
// displaying a message.
EXTERN int emsg_skip INIT(= 0); // don't display errors for
@@ -478,6 +478,8 @@ EXTERN int sc_col; // column for shown command
EXTERN int starting INIT(= NO_SCREEN);
// true when planning to exit. Might keep running if there is a changed buffer.
EXTERN bool exiting INIT(= false);
+// internal value of v:dying
+EXTERN int v_dying INIT(= 0);
// is stdin a terminal?
EXTERN int stdin_isatty INIT(= true);
// is stdout a terminal?
diff --git a/src/nvim/main.c b/src/nvim/main.c
index 6ac9cdfbae..b3a903cbe3 100644
--- a/src/nvim/main.c
+++ b/src/nvim/main.c
@@ -621,7 +621,7 @@ void getout(int exitval)
/* Optionally print hashtable efficiency. */
hash_debug_results();
- if (get_vim_var_nr(VV_DYING) <= 1) {
+ if (v_dying <= 1) {
const tabpage_T *next_tp;
// Trigger BufWinLeave for all windows, but only once per buffer.
@@ -670,8 +670,9 @@ void getout(int exitval)
shada_write_file(NULL, false);
}
- if (get_vim_var_nr(VV_DYING) <= 1)
- apply_autocmds(EVENT_VIMLEAVE, NULL, NULL, FALSE, curbuf);
+ if (v_dying <= 1) {
+ apply_autocmds(EVENT_VIMLEAVE, NULL, NULL, false, curbuf);
+ }
profile_dump();
diff --git a/src/nvim/message.c b/src/nvim/message.c
index 9aa588e035..8999365d32 100644
--- a/src/nvim/message.c
+++ b/src/nvim/message.c
@@ -306,11 +306,6 @@ bool msg_attr_keep(char_u *s, int attr, bool keep, bool multiline)
add_msg_hist((const char *)s, -1, attr, multiline);
}
- /* When displaying keep_msg, don't let msg_start() free it, caller must do
- * that. */
- if (s == keep_msg)
- keep_msg = NULL;
-
/* Truncate the message if needed. */
msg_start();
buf = msg_strtrunc(s, FALSE);
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index 87d687198d..968cfde388 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -621,6 +621,8 @@ static void normal_redraw_mode_message(NormalState *s)
update_screen(0);
// now reset it, otherwise it's put in the history again
keep_msg = kmsg;
+
+ kmsg = vim_strsave(keep_msg);
msg_attr((const char *)kmsg, keep_msg_attr);
xfree(kmsg);
}
@@ -1265,10 +1267,15 @@ static void normal_redraw(NormalState *s)
// Display message after redraw. If an external message is still visible,
// it contains the kept message already.
if (keep_msg != NULL && !msg_ext_is_visible()) {
- // msg_attr_keep() will set keep_msg to NULL, must free the string here.
- // Don't reset keep_msg, msg_attr_keep() uses it to check for duplicates.
- char *p = (char *)keep_msg;
- msg_attr(p, keep_msg_attr);
+ char_u *const p = vim_strsave(keep_msg);
+
+ // msg_start() will set keep_msg to NULL, make a copy
+ // first. Don't reset keep_msg, msg_attr_keep() uses it to
+ // check for duplicates. Never put this message in
+ // history.
+ msg_hist_off = true;
+ msg_attr((const char *)p, keep_msg_attr);
+ msg_hist_off = false;
xfree(p);
}
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index a70224f98b..755c1519fd 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -2748,6 +2748,10 @@ static void do_autocmd_textyankpost(oparg_T *oap, yankreg_T *reg)
buf[1] = NUL;
tv_dict_add_str(dict, S_LEN("operator"), buf);
+ // Selection type: visual or not.
+ tv_dict_add_special(dict, S_LEN("visual"),
+ oap->is_VIsual ? kSpecialVarTrue : kSpecialVarFalse);
+
tv_dict_set_keys_readonly(dict);
textlock++;
apply_autocmds(EVENT_TEXTYANKPOST, NULL, NULL, false, curbuf);
diff --git a/src/nvim/os/signal.c b/src/nvim/os/signal.c
index 112de9fed8..bfe230b521 100644
--- a/src/nvim/os/signal.c
+++ b/src/nvim/os/signal.c
@@ -157,6 +157,7 @@ static void deadly_signal(int signum)
{
// Set the v:dying variable.
set_vim_var_nr(VV_DYING, 1);
+ v_dying = 1;
WLOG("got signal %d (%s)", signum, signal_name(signum));
diff --git a/src/nvim/regexp_nfa.c b/src/nvim/regexp_nfa.c
index f33c61d39f..2ca5f42e51 100644
--- a/src/nvim/regexp_nfa.c
+++ b/src/nvim/regexp_nfa.c
@@ -249,6 +249,7 @@ static char_u e_nul_found[] = N_(
static char_u e_misplaced[] = N_("E866: (NFA regexp) Misplaced %c");
static char_u e_ill_char_class[] = N_(
"E877: (NFA regexp) Invalid character class: %" PRId64);
+static char_u e_value_too_large[] = N_("E951: \\% value too large");
/* Since the out pointers in the list are always
* uninitialized, we use the pointers themselves
@@ -1499,7 +1500,8 @@ static int nfa_regatom(void)
c = getchr();
while (ascii_isdigit(c)) {
if (n > (INT32_MAX - (c - '0')) / 10) {
- EMSG(_("E951: \\% value too large"));
+ // overflow.
+ EMSG(_(e_value_too_large));
return FAIL;
}
n = n * 10 + (c - '0');
@@ -1526,7 +1528,7 @@ static int nfa_regatom(void)
limit = INT32_MAX / MB_MAXBYTES;
}
if (n >= limit) {
- EMSG(_("E951: \\% value too large"));
+ EMSG(_(e_value_too_large));
return FAIL;
}
EMIT((int)n);
diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c
index ef4dfb3caa..f3b05c3961 100644
--- a/src/nvim/syntax.c
+++ b/src/nvim/syntax.c
@@ -7444,6 +7444,8 @@ static int syn_add_group(char_u *name)
return 0;
}
+ char_u *const name_up = vim_strsave_up(name);
+
// Append another syntax_highlight entry.
struct hl_group* hlgp = GA_APPEND_VIA_PTR(struct hl_group, &highlight_ga);
memset(hlgp, 0, sizeof(*hlgp));
@@ -7452,7 +7454,7 @@ static int syn_add_group(char_u *name)
hlgp->sg_rgb_fg = -1;
hlgp->sg_rgb_sp = -1;
hlgp->sg_blend = -1;
- hlgp->sg_name_u = vim_strsave_up(name);
+ hlgp->sg_name_u = name_up;
return highlight_ga.ga_len; /* ID is index plus one */
}
diff --git a/src/nvim/testdir/test_autocmd.vim b/src/nvim/testdir/test_autocmd.vim
index 954e5d875f..5217aa7339 100644
--- a/src/nvim/testdir/test_autocmd.vim
+++ b/src/nvim/testdir/test_autocmd.vim
@@ -1246,23 +1246,23 @@ func Test_TextYankPost()
norm "ayiw
call assert_equal(
- \{'regcontents': ['foo'], 'inclusive': v:true, 'regname': 'a', 'operator': 'y', 'regtype': 'v'},
+ \{'regcontents': ['foo'], 'inclusive': v:true, 'regname': 'a', 'operator': 'y', 'visual': v:false, 'regtype': 'v'},
\g:event)
norm y_
call assert_equal(
- \{'regcontents': ['foo'], 'inclusive': v:false, 'regname': '', 'operator': 'y', 'regtype': 'V'},
+ \{'regcontents': ['foo'], 'inclusive': v:false, 'regname': '', 'operator': 'y', 'visual': v:false, 'regtype': 'V'},
\g:event)
call feedkeys("\<C-V>y", 'x')
call assert_equal(
- \{'regcontents': ['f'], 'inclusive': v:true, 'regname': '', 'operator': 'y', 'regtype': "\x161"},
+ \{'regcontents': ['f'], 'inclusive': v:true, 'regname': '', 'operator': 'y', 'visual': v:true, 'regtype': "\x161"},
\g:event)
norm "xciwbar
call assert_equal(
- \{'regcontents': ['foo'], 'inclusive': v:true, 'regname': 'x', 'operator': 'c', 'regtype': 'v'},
+ \{'regcontents': ['foo'], 'inclusive': v:true, 'regname': 'x', 'operator': 'c', 'visual': v:false, 'regtype': 'v'},
\g:event)
norm "bdiw
call assert_equal(
- \{'regcontents': ['bar'], 'inclusive': v:true, 'regname': 'b', 'operator': 'd', 'regtype': 'v'},
+ \{'regcontents': ['bar'], 'inclusive': v:true, 'regname': 'b', 'operator': 'd', 'visual': v:false, 'regtype': 'v'},
\g:event)
call assert_equal({}, v:event)
diff --git a/src/nvim/testdir/test_cmdline.vim b/src/nvim/testdir/test_cmdline.vim
index 2c7d64f078..f8d84f1a49 100644
--- a/src/nvim/testdir/test_cmdline.vim
+++ b/src/nvim/testdir/test_cmdline.vim
@@ -692,6 +692,22 @@ func Test_getcmdwin_autocmd()
augroup END
endfunc
+" Test error: "E135: *Filter* Autocommands must not change current buffer"
+func Test_cmd_bang_E135()
+ new
+ call setline(1, ['a', 'b', 'c', 'd'])
+ augroup test_cmd_filter_E135
+ au!
+ autocmd FilterReadPost * help
+ augroup END
+ call assert_fails('2,3!echo "x"', 'E135:')
+
+ augroup test_cmd_filter_E135
+ au!
+ augroup END
+ %bwipe!
+endfunc
+
func Test_verbosefile()
set verbosefile=Xlog
echomsg 'foo'
diff --git a/src/nvim/testdir/test_filetype.vim b/src/nvim/testdir/test_filetype.vim
index 832f1726fb..ffd2cee80f 100644
--- a/src/nvim/testdir/test_filetype.vim
+++ b/src/nvim/testdir/test_filetype.vim
@@ -252,7 +252,7 @@ let s:filename_checks = {
\ 'lilo': ['lilo.conf'],
\ 'limits': ['/etc/limits', '/etc/anylimits.conf', '/etc/anylimits.d/file.conf'],
\ 'liquid': ['file.liquid'],
- \ 'lisp': ['sbclrc', '.sbclrc'],
+ \ 'lisp': ['file.lsp', 'file.lisp', 'file.el', 'file.cl', '.emacs', '.sawfishrc', 'sbclrc', '.sbclrc'],
\ 'lite': ['file.lite', 'file.lt'],
\ 'litestep': ['/LiteStep/any/file.rc'],
\ 'loginaccess': ['/etc/login.access'],
diff --git a/src/nvim/testdir/test_ga.vim b/src/nvim/testdir/test_ga.vim
index ea3d211aeb..87f1382342 100644
--- a/src/nvim/testdir/test_ga.vim
+++ b/src/nvim/testdir/test_ga.vim
@@ -24,6 +24,7 @@ func Test_ga_command()
" Test a few multi-bytes characters.
call assert_equal("\n<é> 233, Hex 00e9, Oct 351, Digr e'", Do_ga('é'))
call assert_equal("\n<ẻ> 7867, Hex 1ebb, Oct 17273, Digr e2", Do_ga('ẻ'))
+ call assert_equal("\n<\U00012345> 74565, Hex 00012345, Octal 221505", Do_ga("\U00012345"))
" Test with combining characters.
call assert_equal("\n<e> 101, Hex 65, Octal 145 < ́> 769, Hex 0301, Octal 1401", Do_ga("e\u0301"))
diff --git a/src/nvim/testdir/test_maparg.vim b/src/nvim/testdir/test_maparg.vim
index 5f73bd80ad..238d2f900d 100644
--- a/src/nvim/testdir/test_maparg.vim
+++ b/src/nvim/testdir/test_maparg.vim
@@ -15,23 +15,23 @@ function Test_maparg()
map foo<C-V> is<F4>foo
vnoremap <script> <buffer> <expr> <silent> bar isbar
call assert_equal("is<F4>foo", maparg('foo<C-V>'))
- call assert_equal({'silent': 0, 'noremap': 0, 'lhs': 'foo<C-V>',
+ call assert_equal({'silent': 0, 'noremap': 0, 'script': 0, 'lhs': 'foo<C-V>',
\ 'mode': ' ', 'nowait': 0, 'expr': 0, 'sid': sid, 'lnum': lnum + 1,
\ 'rhs': 'is<F4>foo', 'buffer': 0},
\ maparg('foo<C-V>', '', 0, 1))
- call assert_equal({'silent': 1, 'noremap': 1, 'lhs': 'bar', 'mode': 'v',
+ call assert_equal({'silent': 1, 'noremap': 1, 'script': 1, 'lhs': 'bar', 'mode': 'v',
\ 'nowait': 0, 'expr': 1, 'sid': sid, 'lnum': lnum + 2,
\ 'rhs': 'isbar', 'buffer': 1},
\ maparg('bar', '', 0, 1))
let lnum = expand('<sflnum>')
map <buffer> <nowait> foo bar
- call assert_equal({'silent': 0, 'noremap': 0, 'lhs': 'foo', 'mode': ' ',
+ call assert_equal({'silent': 0, 'noremap': 0, 'script': 0, 'lhs': 'foo', 'mode': ' ',
\ 'nowait': 1, 'expr': 0, 'sid': sid, 'lnum': lnum + 1, 'rhs': 'bar',
\ 'buffer': 1},
\ maparg('foo', '', 0, 1))
let lnum = expand('<sflnum>')
tmap baz foo
- call assert_equal({'silent': 0, 'noremap': 0, 'lhs': 'baz', 'mode': 't',
+ call assert_equal({'silent': 0, 'noremap': 0, 'script': 0, 'lhs': 'baz', 'mode': 't',
\ 'nowait': 0, 'expr': 0, 'sid': sid, 'lnum': lnum + 1, 'rhs': 'foo',
\ 'buffer': 0},
\ maparg('baz', 't', 0, 1))
diff --git a/test/functional/api/keymap_spec.lua b/test/functional/api/keymap_spec.lua
index 210394c83f..5da2c6b531 100644
--- a/test/functional/api/keymap_spec.lua
+++ b/test/functional/api/keymap_spec.lua
@@ -21,6 +21,7 @@ describe('nvim_get_keymap', function()
local foo_bar_string = 'nnoremap foo bar'
local foo_bar_map_table = {
lhs='foo',
+ script=0,
silent=0,
rhs='bar',
expr=0,
@@ -245,6 +246,7 @@ describe('nvim_get_keymap', function()
it('works correctly despite various &cpo settings', function()
local cpo_table = {
+ script=0,
silent=0,
expr=0,
sid=0,
@@ -302,6 +304,7 @@ describe('nvim_get_keymap', function()
lhs='| |',
rhs='| |',
mode='n',
+ script=0,
silent=0,
expr=0,
sid=0,
@@ -343,6 +346,7 @@ describe('nvim_set_keymap, nvim_del_keymap', function()
to_return.noremap = not opts.noremap and 0 or 1
to_return.lhs = lhs
to_return.rhs = rhs
+ to_return.script = 0
to_return.silent = not opts.silent and 0 or 1
to_return.nowait = not opts.nowait and 0 or 1
to_return.expr = not opts.expr and 0 or 1
diff --git a/test/functional/autocmd/textyankpost_spec.lua b/test/functional/autocmd/textyankpost_spec.lua
index 8c23b72cff..3898d59e58 100644
--- a/test/functional/autocmd/textyankpost_spec.lua
+++ b/test/functional/autocmd/textyankpost_spec.lua
@@ -27,7 +27,8 @@ describe('TextYankPost', function()
operator = 'y',
regcontents = { 'foo\nbar' },
regname = '',
- regtype = 'V'
+ regtype = 'V',
+ visual = false
}, eval('g:event'))
eq(1, eval('g:count'))
@@ -40,7 +41,8 @@ describe('TextYankPost', function()
operator = 'y',
regcontents = { 'baz ' },
regname = '',
- regtype = 'v'
+ regtype = 'v',
+ visual = false
}, eval('g:event'))
eq(2, eval('g:count'))
@@ -50,7 +52,8 @@ describe('TextYankPost', function()
operator = 'y',
regcontents = { 'foo', 'baz' },
regname = '',
- regtype = "\0223" -- ^V + block width
+ regtype = "\0223", -- ^V + block width
+ visual = true
}, eval('g:event'))
eq(3, eval('g:count'))
end)
@@ -62,7 +65,8 @@ describe('TextYankPost', function()
operator = 'y',
regcontents = { 'foo\nbar' },
regname = '',
- regtype = 'V'
+ regtype = 'V',
+ visual = false
}, eval('g:event'))
command('set debug=msg')
@@ -92,7 +96,8 @@ describe('TextYankPost', function()
operator = 'y',
regcontents = { 'foo\nbar' },
regname = '',
- regtype = 'V'
+ regtype = 'V',
+ visual = false
}, eval('g:event'))
eq(1, eval('g:count'))
eq({ 'foo\nbar' }, funcs.getreg('+',1,1))
@@ -105,7 +110,8 @@ describe('TextYankPost', function()
operator = 'd',
regcontents = { 'foo' },
regname = '',
- regtype = 'v'
+ regtype = 'v',
+ visual = false
}, eval('g:event'))
eq(1, eval('g:count'))
@@ -115,7 +121,8 @@ describe('TextYankPost', function()
operator = 'd',
regcontents = { '\nbar' },
regname = '',
- regtype = 'V'
+ regtype = 'V',
+ visual = false
}, eval('g:event'))
eq(2, eval('g:count'))
@@ -125,7 +132,8 @@ describe('TextYankPost', function()
operator = 'c',
regcontents = { 'baz' },
regname = '',
- regtype = 'v'
+ regtype = 'v',
+ visual = false
}, eval('g:event'))
eq(3, eval('g:count'))
end)
@@ -153,7 +161,8 @@ describe('TextYankPost', function()
operator = 'y',
regcontents = { 'bar' },
regname = 'b',
- regtype = 'v'
+ regtype = 'v',
+ visual = false
}, eval('g:event'))
feed('"*yy')
@@ -162,7 +171,8 @@ describe('TextYankPost', function()
operator = 'y',
regcontents = { 'foo\nbar' },
regname = '*',
- regtype = 'V'
+ regtype = 'V',
+ visual = false
}, eval('g:event'))
command("set clipboard=unnamed")
@@ -174,7 +184,8 @@ describe('TextYankPost', function()
operator = 'y',
regcontents = { 'foo\nbar' },
regname = '',
- regtype = 'V'
+ regtype = 'V',
+ visual = false
}, eval('g:event'))
feed('"*yy')
@@ -183,7 +194,8 @@ describe('TextYankPost', function()
operator = 'y',
regcontents = { 'foo\nbar' },
regname = '*',
- regtype = 'V'
+ regtype = 'V',
+ visual = false
}, eval('g:event'))
end)
@@ -194,7 +206,8 @@ describe('TextYankPost', function()
operator = 'd',
regcontents = { 'foo\nbar' },
regname = '+',
- regtype = 'V'
+ regtype = 'V',
+ visual = false
}, eval('g:event'))
eq(1, eval('g:count'))
@@ -204,7 +217,8 @@ describe('TextYankPost', function()
operator = 'y',
regcontents = { 'baz text' },
regname = '',
- regtype = 'V'
+ regtype = 'V',
+ visual = false
}, eval('g:event'))
eq(2, eval('g:count'))
@@ -214,7 +228,8 @@ describe('TextYankPost', function()
operator = 'y',
regcontents = { 'baz ' },
regname = '',
- regtype = 'v'
+ regtype = 'v',
+ visual = false
}, eval('g:event'))
eq(3, eval('g:count'))
@@ -224,7 +239,8 @@ describe('TextYankPost', function()
operator = 'd',
regcontents = { 'baz text' },
regname = '',
- regtype = 'V'
+ regtype = 'V',
+ visual = false
}, eval('g:event'))
eq(4, eval('g:count'))
end)
diff --git a/test/functional/eval/map_functions_spec.lua b/test/functional/eval/map_functions_spec.lua
index 2747a94570..275c72d212 100644
--- a/test/functional/eval/map_functions_spec.lua
+++ b/test/functional/eval/map_functions_spec.lua
@@ -13,6 +13,7 @@ describe('maparg()', function()
local foo_bar_map_table = {
lhs='foo',
+ script=0,
silent=0,
rhs='bar',
expr=0,
@@ -147,6 +148,7 @@ describe('maparg()', function()
mode = 'n',
noremap = 1,
nowait = 0,
+ script=0,
sid = 0,
silent = 0,
lnum = 0,
diff --git a/test/functional/legacy/075_maparg_spec.lua b/test/functional/legacy/075_maparg_spec.lua
index 0164f5077a..ee2b041b51 100644
--- a/test/functional/legacy/075_maparg_spec.lua
+++ b/test/functional/legacy/075_maparg_spec.lua
@@ -49,9 +49,9 @@ describe('maparg()', function()
-- Assert buffer contents.
expect([[
is<F4>foo
- {'lnum': 0, 'silent': 0, 'noremap': 0, 'lhs': 'foo<C-V>', 'mode': ' ', 'nowait': 0, 'expr': 0, 'sid': 0, 'rhs': 'is<F4>foo', 'buffer': 0}
- {'lnum': 0, 'silent': 1, 'noremap': 1, 'lhs': 'bar', 'mode': 'v', 'nowait': 0, 'expr': 1, 'sid': 0, 'rhs': 'isbar', 'buffer': 1}
- {'lnum': 0, 'silent': 0, 'noremap': 0, 'lhs': 'foo', 'mode': ' ', 'nowait': 1, 'expr': 0, 'sid': 0, 'rhs': 'bar', 'buffer': 1}
+ {'lnum': 0, 'script': 0, 'silent': 0, 'noremap': 0, 'lhs': 'foo<C-V>', 'mode': ' ', 'nowait': 0, 'expr': 0, 'sid': 0, 'rhs': 'is<F4>foo', 'buffer': 0}
+ {'lnum': 0, 'script': 1, 'silent': 1, 'noremap': 1, 'lhs': 'bar', 'mode': 'v', 'nowait': 0, 'expr': 1, 'sid': 0, 'rhs': 'isbar', 'buffer': 1}
+ {'lnum': 0, 'script': 0, 'silent': 0, 'noremap': 0, 'lhs': 'foo', 'mode': ' ', 'nowait': 1, 'expr': 0, 'sid': 0, 'rhs': 'bar', 'buffer': 1}
xrx
yRy
abcd]])
diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua
index 596b960419..9b2697b3c2 100644
--- a/test/functional/lua/vim_spec.lua
+++ b/test/functional/lua/vim_spec.lua
@@ -243,6 +243,8 @@ describe('lua stdlib', function()
{ "here be dragons", " ", false, { "here", "be", "dragons"} },
{ "axaby", "ab?", false, { '', 'x', 'y' } },
{ "f v2v v3v w2w ", "([vw])2%1", false, { 'f ', ' v3v ', ' ' } },
+ { "", "", false, {} },
+ { "", "a", false, { '' } },
{ "x*yz*oo*l", "*", true, { 'x', 'yz', 'oo', 'l' } },
}
@@ -1165,14 +1167,6 @@ describe('lua stdlib', function()
]])
end)
- it('should call callbacks more times with small `interval`', function()
- eq(true, exec_lua [[
- vim.g.wait_count = 0
- vim.wait(50, function() vim.g.wait_count = vim.g.wait_count + 1 end, 5)
- return vim.g.wait_count > 5
- ]])
- end)
-
it('should play nice with `not` when fails', function()
eq(true, exec_lua [[
if not vim.wait(50, function() end) then
diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua
index f1478c782d..ae436360c3 100644
--- a/test/functional/plugin/lsp_spec.lua
+++ b/test/functional/plugin/lsp_spec.lua
@@ -800,13 +800,14 @@ describe('LSP', function()
make_edit(0, 0, 0, 0, {"123"});
make_edit(1, 0, 1, 1, {"2"});
make_edit(2, 0, 2, 2, {"3"});
+ make_edit(3, 2, 3, 4, {""});
}
exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1)
eq({
'123First line of text';
'2econd line of text';
'3ird line of text';
- 'Fourth line of text';
+ 'Foth line of text';
'å å ɧ 汉语 ↥ 🤦 🦄';
}, buf_lines(1))
end)
@@ -1317,4 +1318,75 @@ describe('LSP', function()
eq("Unknown", exec_lua("return vim.lsp.util._get_symbol_kind_name(1000)"))
end)
end)
+
+ describe('lsp.util.jump_to_location', function()
+ local target_bufnr
+
+ before_each(function()
+ target_bufnr = exec_lua [[
+ local bufnr = vim.uri_to_bufnr("file://fake/uri")
+ local lines = {"1st line of text", "å å ɧ 汉语 ↥ 🤦 🦄"}
+ vim.api.nvim_buf_set_lines(bufnr, 0, 1, false, lines)
+ return bufnr
+ ]]
+ end)
+
+ local location = function(start_line, start_char, end_line, end_char)
+ return {
+ uri = "file://fake/uri",
+ range = {
+ start = { line = start_line, character = start_char },
+ ["end"] = { line = end_line, character = end_char },
+ },
+ }
+ end
+
+ local jump = function(msg)
+ eq(true, exec_lua('return vim.lsp.util.jump_to_location(...)', msg))
+ eq(target_bufnr, exec_lua[[return vim.fn.bufnr('%')]])
+ return {
+ line = exec_lua[[return vim.fn.line('.')]],
+ col = exec_lua[[return vim.fn.col('.')]],
+ }
+ end
+
+ it('jumps to a Location', function()
+ local pos = jump(location(0, 9, 0, 9))
+ eq(1, pos.line)
+ eq(10, pos.col)
+ end)
+
+ it('jumps to a LocationLink', function()
+ local pos = jump({
+ targetUri = "file://fake/uri",
+ targetSelectionRange = {
+ start = { line = 0, character = 4 },
+ ["end"] = { line = 0, character = 4 },
+ },
+ targetRange = {
+ start = { line = 1, character = 5 },
+ ["end"] = { line = 1, character = 5 },
+ },
+ })
+ eq(1, pos.line)
+ eq(5, pos.col)
+ end)
+
+ it('jumps to the correct multibyte column', function()
+ local pos = jump(location(1, 2, 1, 2))
+ eq(2, pos.line)
+ eq(4, pos.col)
+ eq('å', exec_lua[[return vim.fn.expand('<cword>')]])
+ end)
+ end)
+
+ describe('lsp.util._make_floating_popup_size', function()
+ exec_lua [[ contents =
+ {"text tαxt txtα tex",
+ "text tααt tααt text",
+ "text tαxt tαxt"}
+ ]]
+ eq({19,3}, exec_lua[[ return {vim.lsp.util._make_floating_popup_size(contents)} ]])
+ eq({15,5}, exec_lua[[ return {vim.lsp.util._make_floating_popup_size(contents,{width = 15, wrap_at = 14})} ]])
+ end)
end)
diff --git a/test/functional/provider/define_spec.lua b/test/functional/provider/define_spec.lua
index 51a8831274..1d50ce0a56 100644
--- a/test/functional/provider/define_spec.lua
+++ b/test/functional/provider/define_spec.lua
@@ -89,6 +89,21 @@ local function command_specs_for(fn, sync, first_arg_factory, init)
runx(sync, handler, on_setup)
end)
+ it('with nargs/double-quote', function()
+ call(fn, args..', {"nargs": "*"}')
+ local function on_setup()
+ command('RpcCommand "arg1" "arg2" "arg3"')
+ end
+
+ local function handler(method, arguments)
+ eq('test-handler', method)
+ eq({'"arg1"', '"arg2"', '"arg3"'}, arguments[1])
+ return ''
+ end
+
+ runx(sync, handler, on_setup)
+ end)
+
it('with range', function()
call(fn,args..', {"range": ""}')
local function on_setup()