aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmake/RunTests.cmake2
-rw-r--r--runtime/doc/lsp.txt84
-rw-r--r--runtime/lua/vim/lsp/buf.lua6
-rw-r--r--runtime/lua/vim/lsp/codelens.lua4
-rw-r--r--runtime/lua/vim/lsp/log.lua2
-rw-r--r--runtime/lua/vim/lsp/protocol.lua11
-rw-r--r--runtime/lua/vim/lsp/rpc.lua2
-rw-r--r--runtime/lua/vim/lsp/util.lua134
-rw-r--r--src/nvim/api/command.c2
-rw-r--r--src/nvim/eval/funcs.c4
-rw-r--r--src/nvim/ex_docmd.c76
-rw-r--r--src/nvim/ex_getln.c9
-rw-r--r--src/nvim/mark.c29
-rw-r--r--src/nvim/path.c2
-rw-r--r--src/nvim/syntax.c2
-rw-r--r--src/nvim/version.c44
-rw-r--r--test/functional/api/vim_spec.lua7
-rw-r--r--test/functional/core/main_spec.lua17
-rw-r--r--test/functional/editor/mark_spec.lua2
19 files changed, 249 insertions, 190 deletions
diff --git a/cmake/RunTests.cmake b/cmake/RunTests.cmake
index e1a0c8d6c3..5e83b72235 100644
--- a/cmake/RunTests.cmake
+++ b/cmake/RunTests.cmake
@@ -66,6 +66,8 @@ set(ENV{SYSTEM_NAME} ${CMAKE_HOST_SYSTEM_NAME}) # used by test/helpers.lua.
set(ENV{DEPS_INSTALL_DIR} ${DEPS_INSTALL_DIR}) # used by test/busted_runner.lua
execute_process(
+ # Note: because of "-ll" (low-level interpreter mode), some modules like
+ # _editor.lua are not loaded.
COMMAND ${NVIM_PRG} -ll ${WORKING_DIR}/test/busted_runner.lua -v -o test.busted.outputHandlers.${BUSTED_OUTPUT_TYPE}
--lazy --helper=${TEST_DIR}/${TEST_TYPE}/preload.lua
--lpath=${BUILD_DIR}/?.lua
diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt
index 95cbd211bf..c6f395dd15 100644
--- a/runtime/doc/lsp.txt
+++ b/runtime/doc/lsp.txt
@@ -1078,9 +1078,12 @@ add_workspace_folder({workspace_folder})
Add the folder at path to the workspace folders. If {path} is not
provided, the user will be prompted for a path using |input()|.
-clear_references() *vim.lsp.buf.clear_references()*
+clear_references({bufnr}) *vim.lsp.buf.clear_references()*
Removes document highlights from current buffer.
+ Parameters: ~
+ • {bufnr} integer|nil
+
code_action({options}) *vim.lsp.buf.code_action()*
Selects a code action available at the current cursor position.
@@ -1587,12 +1590,12 @@ character_offset({buf}, {row}, {col}, {offset_encoding})
• {buf} (integer) buffer number (0 for current)
• {row} 0-indexed line
• {col} 0-indexed byte offset in line
- • {offset_encoding} (string) utf-8|utf-16|utf-32|nil defaults to
+ • {offset_encoding} (string) utf-8|utf-16|utf-32 defaults to
`offset_encoding` of first client of `buf`
Return: ~
- (integer, integer) `offset_encoding` index of the character in line
- {row} column {col} in buffer {buf}
+ (integer) `offset_encoding` index of the character in line {row}
+ column {col} in buffer {buf}
*vim.lsp.util.convert_input_to_markdown_lines()*
convert_input_to_markdown_lines({input}, {contents})
@@ -1607,7 +1610,7 @@ convert_input_to_markdown_lines({input}, {contents})
lines. Defaults to {}.
Return: ~
- {contents}, extended with lines of converted markdown.
+ (table) {contents} extended with lines of converted markdown.
See also: ~
• https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_hover
@@ -1617,14 +1620,15 @@ convert_signature_help_to_markdown_lines({signature_help}, {ft}, {triggers})
Converts `textDocument/SignatureHelp` response to markdown lines.
Parameters: ~
- • {signature_help} Response of `textDocument/SignatureHelp`
- • {ft} optional filetype that will be use as the `lang` for
- the label markdown code block
- • {triggers} optional list of trigger characters from the lsp
+ • {signature_help} (table) Response of `textDocument/SignatureHelp`
+ • {ft} (string|nil) filetype that will be use as the `lang`
+ for the label markdown code block
+ • {triggers} (table|nil) list of trigger characters from the lsp
server. used to better determine parameter offsets
Return: ~
- (list) of lines of converted markdown.
+ (table|nil) table list of lines of converted markdown.
+ (table|nil) table of active hl
See also: ~
• https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_signatureHelp
@@ -1660,7 +1664,7 @@ jump_to_location({location}, {offset_encoding}, {reuse_win})
Parameters: ~
• {location} (table) (`Location`|`LocationLink`)
- • {offset_encoding} "utf-8" | "utf-16" | "utf-32"
+ • {offset_encoding} (string|nil) utf-8|utf-16|utf-32
• {reuse_win} (boolean|nil) Jump to existing window if buffer is
already open.
@@ -1678,7 +1682,8 @@ locations_to_items({locations}, {offset_encoding})
Parameters: ~
• {locations} (table) list of `Location`s or `LocationLink`s
• {offset_encoding} (string) offset_encoding for locations
- utf-8|utf-16|utf-32
+ utf-8|utf-16|utf-32 default to first client of
+ buffer
Return: ~
(table) list of items
@@ -1687,11 +1692,11 @@ lookup_section({settings}, {section}) *vim.lsp.util.lookup_section()*
Helper function to return nested values in language server settings
Parameters: ~
- • {settings} a table of language server settings
- • {section} a string indicating the field of the settings table
+ • {settings} (table) language server settings
+ • {section} string indicating the field of the settings table
Return: ~
- (table or string) The value of settings accessed via section
+ table|string The value of settings accessed via section
*vim.lsp.util.make_floating_popup_options()*
make_floating_popup_options({width}, {height}, {opts})
@@ -1701,7 +1706,7 @@ make_floating_popup_options({width}, {height}, {opts})
Parameters: ~
• {width} (integer) window width (in character cells)
• {height} (integer) window height (in character cells)
- • {opts} (table, optional)
+ • {opts} (table) optional
• offset_x (integer) offset to add to `col`
• offset_y (integer) offset to add to `row`
• border (string or table) override `border`
@@ -1742,8 +1747,8 @@ make_given_range_params({start_pos}, {end_pos}, {bufnr}, {offset_encoding})
`offset_encoding` of first client of `bufnr`
Return: ~
- { textDocument = { uri = `current_file_uri` }, range = { start =
- `start_position`, end = `end_position` } }
+ (table) { textDocument = { uri = `current_file_uri` }, range = { start
+ = `start_position`, end = `end_position` } }
*vim.lsp.util.make_position_params()*
make_position_params({window}, {offset_encoding})
@@ -1758,7 +1763,7 @@ make_position_params({window}, {offset_encoding})
`window`
Return: ~
- `TextDocumentPositionParams` object
+ (table) `TextDocumentPositionParams` object
See also: ~
• https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentPositionParams
@@ -1778,8 +1783,8 @@ make_range_params({window}, {offset_encoding})
`window`
Return: ~
- { textDocument = { uri = `current_file_uri` }, range = { start =
- `current_position`, end = `current_position` } }
+ (table) { textDocument = { uri = `current_file_uri` }, range = { start
+ = `current_position`, end = `current_position` } }
*vim.lsp.util.make_text_document_params()*
make_text_document_params({bufnr})
@@ -1789,7 +1794,7 @@ make_text_document_params({bufnr})
• {bufnr} (integer|nil) Buffer handle, defaults to current
Return: ~
- `TextDocumentIdentifier`
+ (table) `TextDocumentIdentifier`
See also: ~
• https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentIdentifier
@@ -1799,8 +1804,8 @@ make_workspace_params({added}, {removed})
Create the workspace params
Parameters: ~
- • {added}
- • {removed}
+ • {added} (table)
+ • {removed} (table)
*vim.lsp.util.open_floating_preview()*
open_floating_preview({contents}, {syntax}, {opts})
@@ -1832,8 +1837,8 @@ open_floating_preview({contents}, {syntax}, {opts})
window with the same {focus_id}
Return: ~
- bufnr,winnr buffer and window number of the newly created floating
- preview window
+ (integer) bufnr of newly created float window
+ (integer) winid of newly created float window preview window
parse_snippet({input}) *vim.lsp.util.parse_snippet()*
Parses snippets in a completion entry.
@@ -1853,10 +1858,11 @@ preview_location({location}, {opts}) *vim.lsp.util.preview_location()*
definition)
Parameters: ~
- • {location} a single `Location` or `LocationLink`
+ • {location} (table) a single `Location` or `LocationLink`
Return: ~
- (bufnr,winnr) buffer and window number of floating window or nil
+ (integer|nil) buffer id of float window
+ (integer|nil) window id of float window
rename({old_fname}, {new_fname}, {opts}) *vim.lsp.util.rename()*
Rename old_fname to new_fname
@@ -1873,7 +1879,7 @@ set_lines({lines}, {A}, {B}, {new_lines}) *vim.lsp.util.set_lines()*
• {lines} (table) Original list of strings
• {A} (table) Start position; a 2-tuple of {line,col} numbers
• {B} (table) End position; a 2-tuple of {line,col} numbers
- • {new_lines} A list of strings to replace the original
+ • {new_lines} (table) list of strings to replace the original
Return: ~
(table) The modified {lines} object
@@ -1884,7 +1890,7 @@ show_document({location}, {offset_encoding}, {opts})
Parameters: ~
• {location} (table) (`Location`|`LocationLink`)
- • {offset_encoding} "utf-8" | "utf-16" | "utf-32"
+ • {offset_encoding} (string|nil) utf-8|utf-16|utf-32
• {opts} (table|nil) options
• reuse_win (boolean) Jump to existing window if
buffer is already open.
@@ -1908,7 +1914,7 @@ stylize_markdown({bufnr}, {contents}, {opts})
Parameters: ~
• {contents} (table) of lines to show in window
- • {opts} dictionary with optional fields
+ • {opts} (table) with optional fields
• height of floating window
• width of floating window
• wrap_at character to wrap at for computing height
@@ -1919,13 +1925,13 @@ stylize_markdown({bufnr}, {contents}, {opts})
• separator insert separator after code block
Return: ~
- width,height size of float
+ (table) stripped content
symbols_to_items({symbols}, {bufnr}) *vim.lsp.util.symbols_to_items()*
Converts symbols to quickfix list items.
Parameters: ~
- • {symbols} DocumentSymbol[] or SymbolInformation[]
+ • {symbols} (table) DocumentSymbol[] or SymbolInformation[]
*vim.lsp.util.text_document_completion_list_to_complete_items()*
text_document_completion_list_to_complete_items({result}, {prefix})
@@ -1933,16 +1939,16 @@ text_document_completion_list_to_complete_items({result}, {prefix})
vim-compatible |complete-items|.
Parameters: ~
- • {result} The result of a `textDocument/completion` call, e.g. from
- |vim.lsp.buf.completion()|, which may be one of
+ • {result} (table) The result of a `textDocument/completion` call, e.g.
+ from |vim.lsp.buf.completion()|, which may be one of
`CompletionItem[]`, `CompletionList` or `null`
• {prefix} (string) the prefix to filter the completion items
Return: ~
- { matches = complete-items table, incomplete = bool }
+ (table) { matches = complete-items table, incomplete = bool }
See also: ~
- • |complete-items|
+ • complete-items
trim_empty_lines({lines}) *vim.lsp.util.trim_empty_lines()*
Removes empty lines from the beginning and end.
@@ -1980,7 +1986,7 @@ get_level() *vim.lsp.log.get_level()*
Gets the current log level.
Return: ~
- (string) current log level
+ (integer) current log level
set_format_func({handle}) *vim.lsp.log.set_format_func()*
Sets formatting function used to format logs
@@ -2117,6 +2123,6 @@ resolve_capabilities({server_capabilities})
server
Return: ~
- (table) Normalized table of capabilities
+ (table|nil) Normalized table of capabilities
vim:tw=78:ts=8:sw=4:sts=4:et:ft=help:norl:
diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua
index 0369725216..c742505ec6 100644
--- a/runtime/lua/vim/lsp/buf.lua
+++ b/runtime/lua/vim/lsp/buf.lua
@@ -581,9 +581,9 @@ function M.document_highlight()
end
--- Removes document highlights from current buffer.
----
-function M.clear_references()
- util.buf_clear_references()
+--- @param bufnr integer|nil
+function M.clear_references(bufnr)
+ util.buf_clear_references(bufnr or 0)
end
---@private
diff --git a/runtime/lua/vim/lsp/codelens.lua b/runtime/lua/vim/lsp/codelens.lua
index 5acfe90d5e..67104cc40b 100644
--- a/runtime/lua/vim/lsp/codelens.lua
+++ b/runtime/lua/vim/lsp/codelens.lua
@@ -33,11 +33,9 @@ local function execute_lens(lens, bufnr, client_id)
local client = vim.lsp.get_client_by_id(client_id)
assert(client, 'Client is required to execute lens, client_id=' .. client_id)
-
client._exec_cmd(lens.command, { bufnr = bufnr }, function(...)
- local result = vim.lsp.handlers['workspace/executeCommand'](...)
+ vim.lsp.handlers['workspace/executeCommand'](...)
M.refresh()
- return result
end)
end
diff --git a/runtime/lua/vim/lsp/log.lua b/runtime/lua/vim/lsp/log.lua
index 07d0500797..c77e7c045b 100644
--- a/runtime/lua/vim/lsp/log.lua
+++ b/runtime/lua/vim/lsp/log.lua
@@ -154,7 +154,7 @@ function log.set_level(level)
end
--- Gets the current log level.
----@return string current log level
+---@return integer current log level
function log.get_level()
return current_log_level
end
diff --git a/runtime/lua/vim/lsp/protocol.lua b/runtime/lua/vim/lsp/protocol.lua
index ea38bfe237..27da891656 100644
--- a/runtime/lua/vim/lsp/protocol.lua
+++ b/runtime/lua/vim/lsp/protocol.lua
@@ -880,7 +880,7 @@ end
--- Creates a normalized object describing LSP server capabilities.
---@param server_capabilities table Table of capabilities supported by the server
----@return table Normalized table of capabilities
+---@return table|nil Normalized table of capabilities
function protocol.resolve_capabilities(server_capabilities)
local TextDocumentSyncKind = protocol.TextDocumentSyncKind
local textDocumentSync = server_capabilities.textDocumentSync
@@ -898,7 +898,8 @@ function protocol.resolve_capabilities(server_capabilities)
elseif type(textDocumentSync) == 'number' then
-- Backwards compatibility
if not TextDocumentSyncKind[textDocumentSync] then
- return nil, 'Invalid server TextDocumentSyncKind for textDocumentSync'
+ vim.notify('Invalid server TextDocumentSyncKind for textDocumentSync', vim.log.levels.ERROR)
+ return nil
end
server_capabilities.textDocumentSync = {
openClose = true,
@@ -910,7 +911,11 @@ function protocol.resolve_capabilities(server_capabilities)
},
}
elseif type(textDocumentSync) ~= 'table' then
- return nil, string.format('Invalid type for textDocumentSync: %q', type(textDocumentSync))
+ vim.notify(
+ string.format('Invalid type for textDocumentSync: %q', type(textDocumentSync)),
+ vim.log.levels.ERROR
+ )
+ return nil
end
return server_capabilities
end
diff --git a/runtime/lua/vim/lsp/rpc.lua b/runtime/lua/vim/lsp/rpc.lua
index 64bc732bdf..6552eaa800 100644
--- a/runtime/lua/vim/lsp/rpc.lua
+++ b/runtime/lua/vim/lsp/rpc.lua
@@ -36,7 +36,7 @@ end
local function parse_headers(header)
assert(type(header) == 'string', 'header must be a string')
local headers = {}
- for line in vim.gsplit(header, '\r\n', true) do
+ for line in vim.gsplit(header, '\r\n', { plain = true }) do
if line == '' then
break
end
diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua
index 4c319e7c41..6cb91417f2 100644
--- a/runtime/lua/vim/lsp/util.lua
+++ b/runtime/lua/vim/lsp/util.lua
@@ -25,9 +25,9 @@ local default_border = {
---@private
--- Check the border given by opts or the default border for the additional
--- size it adds to a float.
----@param opts (table, optional) options for the floating window
+---@param opts table optional options for the floating window
--- - border (string or table) the border
----@returns (table) size of border in the form of { height = height, width = width }
+---@return table size of border in the form of { height = height, width = width }
local function get_border_size(opts)
local border = opts and opts.border or default_border
local height = 0
@@ -106,7 +106,7 @@ end
---@private
local function split_lines(value)
value = string.gsub(value, '\r\n?', '\n')
- return split(value, '\n', true)
+ return split(value, '\n', { plain = true })
end
---@private
@@ -122,7 +122,7 @@ end
--- Convenience wrapper around vim.str_utfindex
---@param line string line to be indexed
---@param index integer|nil byte index (utf-8), or `nil` for length
----@param encoding string utf-8|utf-16|utf-32|nil defaults to utf-16
+---@param encoding string|nil utf-8|utf-16|utf-32|nil defaults to utf-16
---@return integer `encoding` index of `index` in `line`
function M._str_utfindex_enc(line, index, encoding)
if not encoding then
@@ -150,7 +150,7 @@ end
---Alternative to vim.str_byteindex that takes an encoding.
---@param line string line to be indexed
---@param index integer UTF index
----@param encoding string utf-8|utf-16|utf-32|nil defaults to utf-16
+---@param encoding string utf-8|utf-16|utf-32| defaults to utf-16
---@return integer byte (utf-8) index of `encoding` index `index` in `line`
function M._str_byteindex_enc(line, index, encoding)
if not encoding then
@@ -180,8 +180,8 @@ local _str_byteindex_enc = M._str_byteindex_enc
---@param lines (table) Original list of strings
---@param A (table) Start position; a 2-tuple of {line,col} numbers
---@param B (table) End position; a 2-tuple of {line,col} numbers
----@param new_lines A list of strings to replace the original
----@returns (table) The modified {lines} object
+---@param new_lines (table) list of strings to replace the original
+---@return table The modified {lines} object
function M.set_lines(lines, A, B, new_lines)
-- 0-indexing to 1-indexing
local i_0 = A[1] + 1
@@ -241,7 +241,7 @@ end
---
---@param bufnr integer bufnr to get the lines from
---@param rows integer[] zero-indexed line numbers
----@return table<integer, string> a table mapping rows to lines
+---@return table<integer, string>|string a table mapping rows to lines
local function get_lines(bufnr, rows)
rows = type(rows) == 'table' and rows or { rows }
@@ -331,8 +331,9 @@ end
---@private
--- 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
----@param offset_encoding string utf-8|utf-16|utf-32
+---@param offset_encoding string|nil utf-8|utf-16|utf-32
--- 1-indexed
+---@return integer
local function get_line_byte_from_position(bufnr, position, offset_encoding)
-- LSP's line and characters are 0-indexed
-- Vim's line and columns are 1-indexed
@@ -598,8 +599,8 @@ end
--- Can be used to extract the completion items from a
--- `textDocument/completion` request, which may return one of
--- `CompletionItem[]`, `CompletionList` or null.
----@param result (table) The result of a `textDocument/completion` request
----@returns (table) List of completion items
+---@param result table The result of a `textDocument/completion` request
+---@return table List of completion items
---@see https://microsoft.github.io/language-server-protocol/specification#textDocument_completion
function M.extract_completion_items(result)
if type(result) == 'table' and result.items then
@@ -658,7 +659,7 @@ end
--- Parses snippets in a completion entry.
---
---@param input string unparsed snippet
----@returns string parsed snippet
+---@return string parsed snippet
function M.parse_snippet(input)
local ok, parsed = pcall(function()
return tostring(snippet.parse(input))
@@ -718,7 +719,7 @@ end
--- specification.
---
---@param completion_item_kind (`vim.lsp.protocol.completionItemKind`)
----@returns (`vim.lsp.protocol.completionItemKind`)
+---@return (`vim.lsp.protocol.completionItemKind`)
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion
function M._get_completion_item_kind_name(completion_item_kind)
return protocol.CompletionItemKind[completion_item_kind] or 'Unknown'
@@ -727,12 +728,12 @@ end
--- Turns the result of a `textDocument/completion` request into vim-compatible
--- |complete-items|.
---
----@param result The result of a `textDocument/completion` call, e.g. from
+---@param result table The result of a `textDocument/completion` call, e.g. from
---|vim.lsp.buf.completion()|, which may be one of `CompletionItem[]`,
--- `CompletionList` or `null`
---@param prefix (string) the prefix to filter the completion items
----@returns { matches = complete-items table, incomplete = bool }
----@see |complete-items|
+---@return table { matches = complete-items table, incomplete = bool }
+---@see complete-items
function M.text_document_completion_list_to_complete_items(result, prefix)
local items = M.extract_completion_items(result)
if vim.tbl_isempty(items) then
@@ -937,7 +938,7 @@ end
---
---@param input (`MarkedString` | `MarkedString[]` | `MarkupContent`)
---@param contents (table|nil) List of strings to extend with converted lines. Defaults to {}.
----@returns {contents}, extended with lines of converted markdown.
+---@return table {contents} extended with lines of converted markdown.
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_hover
function M.convert_input_to_markdown_lines(input, contents)
contents = contents or {}
@@ -985,10 +986,11 @@ end
--- Converts `textDocument/SignatureHelp` response to markdown lines.
---
----@param signature_help Response of `textDocument/SignatureHelp`
----@param ft optional filetype that will be use as the `lang` for the label markdown code block
----@param triggers optional list of trigger characters from the lsp server. used to better determine parameter offsets
----@returns list of lines of converted markdown.
+---@param signature_help table Response of `textDocument/SignatureHelp`
+---@param ft string|nil filetype that will be use as the `lang` for the label markdown code block
+---@param triggers table|nil list of trigger characters from the lsp server. used to better determine parameter offsets
+---@return table|nil table list of lines of converted markdown.
+---@return table|nil table of active hl
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_signatureHelp
function M.convert_signature_help_to_markdown_lines(signature_help, ft, triggers)
if not signature_help.signatures then
@@ -1015,7 +1017,7 @@ function M.convert_signature_help_to_markdown_lines(signature_help, ft, triggers
-- wrap inside a code block so stylize_markdown can render it properly
label = ('```%s\n%s\n```'):format(ft, label)
end
- list_extend(contents, split(label, '\n', true))
+ list_extend(contents, split(label, '\n', { plain = true }))
if signature.documentation then
M.convert_input_to_markdown_lines(signature.documentation, contents)
end
@@ -1087,16 +1089,16 @@ end
--- Creates a table with sensible default options for a floating window. The
--- table can be passed to |nvim_open_win()|.
---
----@param width (integer) window width (in character cells)
----@param height (integer) window height (in character cells)
----@param opts (table, optional)
+---@param width integer window width (in character cells)
+---@param height integer window height (in character cells)
+---@param opts table optional
--- - offset_x (integer) offset to add to `col`
--- - offset_y (integer) offset to add to `row`
--- - border (string or table) override `border`
--- - focusable (string or table) override `focusable`
--- - zindex (string or table) override `zindex`, defaults to 50
--- - relative ("mouse"|"cursor") defaults to "cursor"
----@returns (table) Options
+---@return table Options
function M.make_floating_popup_options(width, height, opts)
validate({
opts = { opts, 't', true },
@@ -1160,7 +1162,7 @@ end
--- Shows document and optionally jumps to the location.
---
---@param location table (`Location`|`LocationLink`)
----@param offset_encoding "utf-8" | "utf-16" | "utf-32"
+---@param offset_encoding string|nil utf-8|utf-16|utf-32
---@param opts table|nil options
--- - reuse_win (boolean) Jump to existing window if buffer is already open.
--- - focus (boolean) Whether to focus/jump to location if possible. Defaults to true.
@@ -1217,7 +1219,7 @@ end
--- Jumps to a location.
---
---@param location table (`Location`|`LocationLink`)
----@param offset_encoding "utf-8" | "utf-16" | "utf-32"
+---@param offset_encoding string|nil utf-8|utf-16|utf-32
---@param reuse_win boolean|nil Jump to existing window if buffer is already open.
---@return boolean `true` if the jump succeeded
function M.jump_to_location(location, offset_encoding, reuse_win)
@@ -1237,8 +1239,9 @@ end
--- - for Location, range is shown (e.g., function definition)
--- - for LocationLink, targetRange is shown (e.g., body of function definition)
---
----@param location a single `Location` or `LocationLink`
----@returns (bufnr,winnr) buffer and window number of floating window or nil
+---@param location table a single `Location` or `LocationLink`
+---@return integer|nil buffer id of float window
+---@return integer|nil window id of float window
function M.preview_location(location, opts)
-- location may be LocationLink or Location (more useful for the former)
local uri = location.targetUri or location.uri
@@ -1275,10 +1278,10 @@ end
--- Trims empty lines from input and pad top and bottom with empty lines
---
---@param contents table of lines to trim and pad
----@param opts dictionary with optional fields
+---@param opts table with optional fields
--- - pad_top number of lines to pad contents at top (default 0)
--- - pad_bottom number of lines to pad contents at bottom (default 0)
----@return contents table of trimmed and padded lines
+---@return table table of trimmed and padded lines
function M._trim(contents, opts)
validate({
contents = { contents, 't' },
@@ -1301,7 +1304,7 @@ end
--- Generates a table mapping markdown code block lang to vim syntax,
--- based on g:markdown_fenced_languages
----@return a table of lang -> syntax mappings
+---@return table table of lang -> syntax mappings
---@private
local function get_markdown_fences()
local fences = {}
@@ -1324,7 +1327,7 @@ end
--- If you want to open a popup with fancy markdown, use `open_floating_preview` instead
---
---@param contents table of lines to show in window
----@param opts dictionary with optional fields
+---@param opts table with optional fields
--- - height of floating window
--- - width of floating window
--- - wrap_at character to wrap at for computing height
@@ -1333,7 +1336,7 @@ end
--- - pad_top number of lines to pad contents at top
--- - pad_bottom number of lines to pad contents at bottom
--- - separator insert separator after code block
----@returns width,height size of float
+---@return table stripped content
function M.stylize_markdown(bufnr, contents, opts)
validate({
contents = { contents, 't' },
@@ -1480,10 +1483,10 @@ function M.stylize_markdown(bufnr, contents, opts)
if not langs[lang] then
-- HACK: reset current_syntax, since some syntax files like markdown won't load if it is already set
pcall(api.nvim_buf_del_var, bufnr, 'current_syntax')
- -- TODO(ashkan): better validation before this.
- if not pcall(vim.cmd, string.format('syntax include %s syntax/%s.vim', lang, ft)) then
+ if #api.nvim_get_runtime_file(('syntax/%s.vim'):format(ft), true) == 0 then
return
end
+ vim.cmd(string.format('syntax include %s syntax/%s.vim', lang, ft))
langs[lang] = true
end
vim.cmd(
@@ -1542,7 +1545,7 @@ end
---@param events table list of events
---@param winnr integer window id of preview window
---@param bufnrs table list of buffers where the preview window will remain visible
----@see |autocmd-events|
+---@see autocmd-events
local function close_preview_autocmd(events, winnr, bufnrs)
local augroup = api.nvim_create_augroup('preview_window_' .. winnr, {
clear = true,
@@ -1572,13 +1575,14 @@ end
--- Computes 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
+---@param opts table with optional fields
--- - height of floating window
--- - width of floating window
--- - wrap_at character to wrap at for computing height
--- - max_width maximal width of floating window
--- - max_height maximal height of floating window
----@returns width,height size of float
+---@return integer width size of float
+---@return integer height size of float
function M._make_floating_popup_size(contents, opts)
validate({
contents = { contents, 't' },
@@ -1662,7 +1666,8 @@ end
--- - focus: (boolean, default true) If `true`, and if {focusable}
--- is also `true`, focus an existing floating window with the same
--- {focus_id}
----@returns bufnr,winnr buffer and window number of the newly created floating
+---@return integer bufnr of newly created float window
+---@return integer winid of newly created float window
---preview window
function M.open_floating_preview(contents, syntax, opts)
validate({
@@ -1766,7 +1771,7 @@ do --[[ References ]]
---
---@param bufnr integer Buffer id
function M.buf_clear_references(bufnr)
- validate({ bufnr = { bufnr, 'n', true } })
+ validate({ bufnr = { bufnr, { 'n', 'nil' }, true } })
api.nvim_buf_clear_namespace(bufnr or 0, reference_ns, 0, -1)
end
@@ -1828,13 +1833,15 @@ end)
---
---@param locations table list of `Location`s or `LocationLink`s
---@param offset_encoding string offset_encoding for locations utf-8|utf-16|utf-32
----@returns (table) list of items
+--- default to first client of buffer
+---@return table list of items
function M.locations_to_items(locations, offset_encoding)
if offset_encoding == nil then
vim.notify_once(
'locations_to_items must be called with valid offset encoding',
vim.log.levels.WARN
)
+ offset_encoding = vim.lsp.get_active_clients({ bufnr = 0 })[1].offset_encoding
end
local items = {}
@@ -1896,7 +1903,7 @@ end
--- Converts symbols to quickfix list items.
---
----@param symbols DocumentSymbol[] or SymbolInformation[]
+---@param symbols table DocumentSymbol[] or SymbolInformation[]
function M.symbols_to_items(symbols, bufnr)
---@private
local function _symbols_to_items(_symbols, _items, _bufnr)
@@ -1936,8 +1943,8 @@ function M.symbols_to_items(symbols, bufnr)
end
--- Removes empty lines from the beginning and end.
----@param lines (table) list of lines to trim
----@returns (table) trimmed list of lines
+---@param lines table list of lines to trim
+---@return table trimmed list of lines
function M.trim_empty_lines(lines)
local start = 1
for i = 1, #lines do
@@ -1961,8 +1968,8 @@ end
---
--- CAUTION: Modifies the input in-place!
---
----@param lines (table) list of lines
----@returns (string) filetype or "markdown" if it was unchanged.
+---@param lines table list of lines
+---@return string filetype or "markdown" if it was unchanged.
function M.try_trim_markdown_code_blocks(lines)
local language_id = lines[1]:match('^```(.*)')
if language_id then
@@ -2007,7 +2014,7 @@ end
---
---@param window integer|nil: window handle or 0 for current, defaults to current
---@param offset_encoding string|nil utf-8|utf-16|utf-32|nil defaults to `offset_encoding` of first client of buffer of `window`
----@returns `TextDocumentPositionParams` object
+---@return table `TextDocumentPositionParams` object
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentPositionParams
function M.make_position_params(window, offset_encoding)
window = window or 0
@@ -2021,7 +2028,7 @@ end
--- Utility function for getting the encoding of the first LSP client on the given buffer.
---@param bufnr (integer) buffer handle or 0 for current, defaults to current
----@returns (string) encoding first client if there is one, nil otherwise
+---@return string encoding first client if there is one, nil otherwise
function M._get_offset_encoding(bufnr)
validate({
bufnr = { bufnr, 'n', true },
@@ -2060,7 +2067,7 @@ end
---
---@param window integer|nil: window handle or 0 for current, defaults to current
---@param offset_encoding "utf-8"|"utf-16"|"utf-32"|nil defaults to `offset_encoding` of first client of buffer of `window`
----@returns { textDocument = { uri = `current_file_uri` }, range = { start =
+---@return table { textDocument = { uri = `current_file_uri` }, range = { start =
---`current_position`, end = `current_position` } }
function M.make_range_params(window, offset_encoding)
local buf = api.nvim_win_get_buf(window or 0)
@@ -2081,7 +2088,7 @@ end
--- Defaults to the end of the last visual selection.
---@param bufnr integer|nil buffer handle or 0 for current, defaults to current
---@param offset_encoding "utf-8"|"utf-16"|"utf-32"|nil defaults to `offset_encoding` of first client of `bufnr`
----@returns { textDocument = { uri = `current_file_uri` }, range = { start =
+---@return table { textDocument = { uri = `current_file_uri` }, range = { start =
---`start_position`, end = `end_position` } }
function M.make_given_range_params(start_pos, end_pos, bufnr, offset_encoding)
validate({
@@ -2121,15 +2128,15 @@ end
--- Creates a `TextDocumentIdentifier` object for the current buffer.
---
---@param bufnr integer|nil: Buffer handle, defaults to current
----@returns `TextDocumentIdentifier`
+---@return table `TextDocumentIdentifier`
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentIdentifier
function M.make_text_document_params(bufnr)
return { uri = vim.uri_from_bufnr(bufnr or 0) }
end
--- Create the workspace params
----@param added
----@param removed
+---@param added table
+---@param removed table
function M.make_workspace_params(added, removed)
return { event = { added = added, removed = removed } }
end
@@ -2137,7 +2144,7 @@ end
---
---@see 'shiftwidth'
---@param bufnr (integer|nil): Buffer handle, defaults to current
----@returns (integer) indentation size
+---@return (integer) indentation size
function M.get_effective_tabstop(bufnr)
validate({ bufnr = { bufnr, 'n', true } })
local bo = bufnr and vim.bo[bufnr] or vim.bo
@@ -2148,7 +2155,7 @@ end
--- Creates a `DocumentFormattingParams` object for the current buffer and cursor position.
---
---@param options table|nil with valid `FormattingOptions` entries
----@returns `DocumentFormattingParams` object
+---@return `DocumentFormattingParams` object
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_formatting
function M.make_formatting_params(options)
validate({ options = { options, 't', true } })
@@ -2167,8 +2174,8 @@ end
---@param buf integer buffer number (0 for current)
---@param row 0-indexed line
---@param col 0-indexed byte offset in line
----@param offset_encoding string utf-8|utf-16|utf-32|nil defaults to `offset_encoding` of first client of `buf`
----@returns (integer, integer) `offset_encoding` index of the character in line {row} column {col} in buffer {buf}
+---@param offset_encoding string utf-8|utf-16|utf-32 defaults to `offset_encoding` of first client of `buf`
+---@return integer `offset_encoding` index of the character in line {row} column {col} in buffer {buf}
function M.character_offset(buf, row, col, offset_encoding)
local line = get_line(buf, row)
if offset_encoding == nil then
@@ -2176,6 +2183,7 @@ function M.character_offset(buf, row, col, offset_encoding)
'character_offset must be called with valid offset encoding',
vim.log.levels.WARN
)
+ offset_encoding = vim.lsp.get_active_clients({ bufnr = buf })[1].offset_encoding
end
-- If the col is past the EOL, use the line length.
if col > #line then
@@ -2186,11 +2194,11 @@ end
--- Helper function to return nested values in language server settings
---
----@param settings a table of language server settings
----@param section a string indicating the field of the settings table
----@returns (table or string) The value of settings accessed via section
+---@param settings table language server settings
+---@param section string indicating the field of the settings table
+---@return table|string The value of settings accessed via section
function M.lookup_section(settings, section)
- for part in vim.gsplit(section, '.', true) do
+ for part in vim.gsplit(section, '.', { plain = true }) do
settings = settings[part]
if settings == nil then
return vim.NIL
diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c
index 3157132256..b254e326f9 100644
--- a/src/nvim/api/command.c
+++ b/src/nvim/api/command.c
@@ -109,7 +109,7 @@ Dictionary nvim_parse_cmd(String str, Dictionary opts, Error *err)
exarg_T ea;
CmdParseInfo cmdinfo;
char *cmdline = string_to_cstr(str);
- char *errormsg = NULL;
+ const char *errormsg = NULL;
if (!parse_cmdline(cmdline, &ea, &cmdinfo, &errormsg)) {
if (errormsg != NULL) {
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index 99fec3d773..f53c5fc0c5 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -1716,7 +1716,7 @@ static void f_expand(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
emsg_off++;
}
size_t len;
- char *errormsg = NULL;
+ const char *errormsg = NULL;
char *result = eval_vars((char *)s, s, &len, NULL, &errormsg, NULL, false);
if (p_verbose == 0) {
emsg_off--;
@@ -1781,7 +1781,7 @@ static void f_menu_get(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
/// Expand all the special characters in a command string.
static void f_expandcmd(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
- char *errormsg = NULL;
+ const char *errormsg = NULL;
bool emsgoff = true;
if (argvars[1].v_type == VAR_DICT
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index b854bdb6fe..a70b3b1893 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -1342,7 +1342,7 @@ void set_cmd_count(exarg_T *eap, linenr_T count, bool validate)
}
}
-static int parse_count(exarg_T *eap, char **errormsg, bool validate)
+static int parse_count(exarg_T *eap, const char **errormsg, bool validate)
{
// Check for a count. When accepting a EX_BUFNAME, don't use "123foo" as a
// count, it's a buffer name.
@@ -1396,7 +1396,7 @@ bool is_cmd_ni(cmdidx_T cmdidx)
/// @param[out] errormsg Error message, if any
///
/// @return Success or failure
-bool parse_cmdline(char *cmdline, exarg_T *eap, CmdParseInfo *cmdinfo, char **errormsg)
+bool parse_cmdline(char *cmdline, exarg_T *eap, CmdParseInfo *cmdinfo, const char **errormsg)
{
char *after_modifier = NULL;
bool retval = false;
@@ -1564,7 +1564,7 @@ static void shift_cmd_args(exarg_T *eap)
xfree(oldarglens);
}
-static int execute_cmd0(int *retv, exarg_T *eap, char **errormsg, bool preview)
+static int execute_cmd0(int *retv, exarg_T *eap, const char **errormsg, bool preview)
{
// If filename expansion is enabled, expand filenames
if (eap->argt & EX_XFILE) {
@@ -1649,7 +1649,7 @@ static int execute_cmd0(int *retv, exarg_T *eap, char **errormsg, bool preview)
/// @param preview Execute command preview callback instead of actual command
int execute_cmd(exarg_T *eap, CmdParseInfo *cmdinfo, bool preview)
{
- char *errormsg = NULL;
+ const char *errormsg = NULL;
int retv = 0;
#undef ERROR
@@ -1881,7 +1881,7 @@ static bool skip_cmd(const exarg_T *eap)
static char *do_one_cmd(char **cmdlinep, int flags, cstack_T *cstack, LineGetter fgetline,
void *cookie)
{
- char *errormsg = NULL; // error message
+ const char *errormsg = NULL; // error message
const int save_reg_executing = reg_executing;
const bool save_pending_end_reg_executing = pending_end_reg_executing;
@@ -2376,7 +2376,7 @@ char *ex_errmsg(const char *const msg, const char *const arg)
/// - set 'eventignore' to "all" for ":noautocmd"
///
/// @return FAIL when the command is not to be executed.
-int parse_command_modifiers(exarg_T *eap, char **errormsg, cmdmod_T *cmod, bool skip_only)
+int parse_command_modifiers(exarg_T *eap, const char **errormsg, cmdmod_T *cmod, bool skip_only)
{
CLEAR_POINTER(cmod);
@@ -2557,7 +2557,10 @@ int parse_command_modifiers(exarg_T *eap, char **errormsg, cmdmod_T *cmod, bool
if (checkforcmd(&p, "tab", 3)) {
if (!skip_only) {
int tabnr = (int)get_address(eap, &eap->cmd, ADDR_TABS, eap->skip, skip_only,
- false, 1);
+ false, 1, errormsg);
+ if (eap->cmd == NULL) {
+ return false;
+ }
if (tabnr == MAXLNUM) {
cmod->cmod_tab = tabpage_index(curtab) + 1;
@@ -2701,7 +2704,7 @@ void undo_cmdmod(cmdmod_T *cmod)
/// May set the last search pattern, unless "silent" is true.
///
/// @return FAIL and set "errormsg" or return OK.
-int parse_cmd_address(exarg_T *eap, char **errormsg, bool silent)
+int parse_cmd_address(exarg_T *eap, const char **errormsg, bool silent)
FUNC_ATTR_NONNULL_ALL
{
int address_count = 1;
@@ -2715,7 +2718,7 @@ int parse_cmd_address(exarg_T *eap, char **errormsg, bool silent)
eap->line2 = get_cmd_default_range(eap);
eap->cmd = skipwhite(eap->cmd);
lnum = get_address(eap, &eap->cmd, eap->addr_type, eap->skip, silent,
- eap->addr_count == 0, address_count++);
+ eap->addr_count == 0, address_count++, errormsg);
if (eap->cmd == NULL) { // error detected
goto theend;
}
@@ -2794,13 +2797,13 @@ int parse_cmd_address(exarg_T *eap, char **errormsg, bool silent)
eap->cmd++;
if (!eap->skip) {
fmark_T *fm = mark_get_visual(curbuf, '<');
- if (!mark_check(fm)) {
+ if (!mark_check(fm, errormsg)) {
goto theend;
}
assert(fm != NULL);
eap->line1 = fm->mark.lnum;
fm = mark_get_visual(curbuf, '>');
- if (!mark_check(fm)) {
+ if (!mark_check(fm, errormsg)) {
goto theend;
}
assert(fm != NULL);
@@ -3229,29 +3232,30 @@ char *skip_range(const char *cmd, int *ctx)
return (char *)cmd;
}
-static void addr_error(cmd_addr_T addr_type)
+static const char *addr_error(cmd_addr_T addr_type)
{
if (addr_type == ADDR_NONE) {
- emsg(_(e_norange));
+ return _(e_norange);
} else {
- emsg(_(e_invrange));
+ return _(e_invrange);
}
}
-/// Get a single EX address
+/// Gets a single EX address.
///
-/// Set ptr to the next character after the part that was interpreted.
-/// Set ptr to NULL when an error is encountered.
-/// This may set the last used search pattern.
+/// Sets ptr to the next character after the part that was interpreted.
+/// Sets ptr to NULL when an error is encountered (stored in `errormsg`).
+/// May set the last used search pattern.
///
/// @param skip only skip the address, don't use it
/// @param silent no errors or side effects
/// @param to_other_file flag: may jump to other file
/// @param address_count 1 for first, >1 after comma
+/// @param errormsg Error message, if any
///
/// @return MAXLNUM when no Ex address was found.
static linenr_T get_address(exarg_T *eap, char **ptr, cmd_addr_T addr_type, int skip, bool silent,
- int to_other_file, int address_count)
+ int to_other_file, int address_count, const char **errormsg)
FUNC_ATTR_NONNULL_ALL
{
int c;
@@ -3287,7 +3291,7 @@ static linenr_T get_address(exarg_T *eap, char **ptr, cmd_addr_T addr_type, int
case ADDR_NONE:
case ADDR_TABS_RELATIVE:
case ADDR_UNSIGNED:
- addr_error(addr_type);
+ *errormsg = addr_error(addr_type);
cmd = NULL;
goto error;
break;
@@ -3332,7 +3336,7 @@ static linenr_T get_address(exarg_T *eap, char **ptr, cmd_addr_T addr_type, int
case ADDR_NONE:
case ADDR_TABS_RELATIVE:
case ADDR_UNSIGNED:
- addr_error(addr_type);
+ *errormsg = addr_error(addr_type);
cmd = NULL;
goto error;
break;
@@ -3357,7 +3361,7 @@ static linenr_T get_address(exarg_T *eap, char **ptr, cmd_addr_T addr_type, int
goto error;
}
if (addr_type != ADDR_LINES) {
- addr_error(addr_type);
+ *errormsg = addr_error(addr_type);
cmd = NULL;
goto error;
}
@@ -3373,7 +3377,7 @@ static linenr_T get_address(exarg_T *eap, char **ptr, cmd_addr_T addr_type, int
// Jumped to another file.
lnum = curwin->w_cursor.lnum;
} else {
- if (!mark_check(fm)) {
+ if (!mark_check(fm, errormsg)) {
cmd = NULL;
goto error;
}
@@ -3387,7 +3391,7 @@ static linenr_T get_address(exarg_T *eap, char **ptr, cmd_addr_T addr_type, int
case '?': // '/' or '?' - search
c = (uint8_t)(*cmd++);
if (addr_type != ADDR_LINES) {
- addr_error(addr_type);
+ *errormsg = addr_error(addr_type);
cmd = NULL;
goto error;
}
@@ -3436,7 +3440,7 @@ static linenr_T get_address(exarg_T *eap, char **ptr, cmd_addr_T addr_type, int
case '\\': // "\?", "\/" or "\&", repeat search
cmd++;
if (addr_type != ADDR_LINES) {
- addr_error(addr_type);
+ *errormsg = addr_error(addr_type);
cmd = NULL;
goto error;
}
@@ -3445,7 +3449,7 @@ static linenr_T get_address(exarg_T *eap, char **ptr, cmd_addr_T addr_type, int
} else if (*cmd == '?' || *cmd == '/') {
i = RE_SEARCH;
} else {
- emsg(_(e_backslash));
+ *errormsg = _(e_backslash);
cmd = NULL;
goto error;
}
@@ -3527,13 +3531,13 @@ static linenr_T get_address(exarg_T *eap, char **ptr, cmd_addr_T addr_type, int
// "number", "+number" or "-number"
n = getdigits_int32(&cmd, false, MAXLNUM);
if (n == MAXLNUM) {
- emsg(_(e_line_number_out_of_range));
+ *errormsg = _(e_line_number_out_of_range);
goto error;
}
}
if (addr_type == ADDR_TABS_RELATIVE) {
- emsg(_(e_invrange));
+ *errormsg = _(e_invrange);
cmd = NULL;
goto error;
} else if (addr_type == ADDR_LOADED_BUFFERS || addr_type == ADDR_BUFFERS) {
@@ -3549,7 +3553,7 @@ static linenr_T get_address(exarg_T *eap, char **ptr, cmd_addr_T addr_type, int
lnum -= n;
} else {
if (n >= INT32_MAX - lnum) {
- emsg(_(e_line_number_out_of_range));
+ *errormsg = _(e_line_number_out_of_range);
goto error;
}
lnum += n;
@@ -3762,7 +3766,7 @@ char *replace_makeprg(exarg_T *eap, char *arg, char **cmdlinep)
/// When an error is detected, "errormsgp" is set to a non-NULL pointer.
///
/// @return FAIL for failure, OK otherwise.
-int expand_filename(exarg_T *eap, char **cmdlinep, char **errormsgp)
+int expand_filename(exarg_T *eap, char **cmdlinep, const char **errormsgp)
{
// Skip a regexp pattern for ":vimgrep[add] pat file..."
char *p = skip_grep_pat(eap);
@@ -5855,8 +5859,12 @@ static void ex_put(exarg_T *eap)
/// Handle ":copy" and ":move".
static void ex_copymove(exarg_T *eap)
{
- long n = get_address(eap, &eap->arg, eap->addr_type, false, false, false, 1);
+ const char *errormsg = NULL;
+ long n = get_address(eap, &eap->arg, eap->addr_type, false, false, false, 1, &errormsg);
if (eap->arg == NULL) { // error detected
+ if (errormsg != NULL) {
+ emsg(errormsg);
+ }
eap->nextcmd = NULL;
return;
}
@@ -6770,8 +6778,8 @@ ssize_t find_cmdline_var(const char *src, size_t *usedlen)
/// @return an allocated string if a valid match was found.
/// Returns NULL if no match was found. "usedlen" then still contains the
/// number of characters to skip.
-char *eval_vars(char *src, const char *srcstart, size_t *usedlen, linenr_T *lnump, char **errormsg,
- int *escaped, bool empty_is_error)
+char *eval_vars(char *src, const char *srcstart, size_t *usedlen, linenr_T *lnump,
+ const char **errormsg, int *escaped, bool empty_is_error)
{
char *result;
char *resultbuf = NULL;
@@ -7044,7 +7052,7 @@ char *expand_sfile(char *arg)
} else {
// replace "<sfile>" with the sourced file name, and do ":" stuff
size_t srclen;
- char *errormsg;
+ const char *errormsg;
char *repl = eval_vars(p, result, &srclen, NULL, &errormsg, NULL, true);
if (errormsg != NULL) {
if (*errormsg) {
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index 969023b70d..f77822cec6 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -236,7 +236,7 @@ static bool do_incsearch_highlighting(int firstc, int *search_delim, incsearch_s
bool delim_optional = false;
int delim;
char *end;
- char *dummy;
+ const char *dummy;
pos_T save_cursor;
bool use_last_pat;
bool retval = false;
@@ -261,7 +261,6 @@ static bool do_incsearch_highlighting(int firstc, int *search_delim, incsearch_s
return false;
}
- emsg_off++;
exarg_T ea = {
.line1 = 1,
.line2 = 1,
@@ -369,7 +368,6 @@ static bool do_incsearch_highlighting(int firstc, int *search_delim, incsearch_s
curwin->w_cursor = save_cursor;
retval = true;
theend:
- emsg_off--;
return retval;
}
@@ -2428,13 +2426,10 @@ static bool cmdpreview_may_show(CommandLineState *s)
// Copy the command line so we can modify it.
int cmdpreview_type = 0;
char *cmdline = xstrdup(ccline.cmdbuff);
- char *errormsg = NULL;
- emsg_off++; // Block errors when parsing the command line, and don't update v:errmsg
+ const char *errormsg = NULL;
if (!parse_cmdline(cmdline, &ea, &cmdinfo, &errormsg)) {
- emsg_off--;
goto end;
}
- emsg_off--;
// Check if command is previewable, if not, don't attempt to show preview
if (!(ea.argt & EX_PREVIEW)) {
diff --git a/src/nvim/mark.c b/src/nvim/mark.c
index b3f94a42fc..c67dbb0b52 100644
--- a/src/nvim/mark.c
+++ b/src/nvim/mark.c
@@ -541,7 +541,11 @@ MarkMoveRes mark_move_to(fmark_T *fm, MarkMove flags)
{
static fmark_T fm_copy = INIT_FMARK;
MarkMoveRes res = kMarkMoveSuccess;
- if (!mark_check(fm)) {
+ const char *errormsg = NULL;
+ if (!mark_check(fm, &errormsg)) {
+ if (errormsg != NULL) {
+ emsg(errormsg);
+ }
res = kMarkMoveFailed;
goto end;
}
@@ -557,7 +561,10 @@ MarkMoveRes mark_move_to(fmark_T *fm, MarkMove flags)
goto end;
}
// Check line count now that the **destination buffer is loaded**.
- if (!mark_check_line_bounds(curbuf, fm)) {
+ if (!mark_check_line_bounds(curbuf, fm, &errormsg)) {
+ if (errormsg != NULL) {
+ emsg(errormsg);
+ }
res |= kMarkMoveFailed;
goto end;
}
@@ -710,43 +717,45 @@ static void fmarks_check_one(xfmark_T *fm, char *name, buf_T *buf)
/// Check the position in @a fm is valid.
///
-/// Emit error message and return accordingly.
-///
/// Checks for:
/// - NULL raising unknown mark error.
/// - Line number <= 0 raising mark not set.
/// - Line number > buffer line count, raising invalid mark.
+///
/// @param fm[in] File mark to check.
+/// @param errormsg[out] Error message, if any.
///
/// @return true if the mark passes all the above checks, else false.
-bool mark_check(fmark_T *fm)
+bool mark_check(fmark_T *fm, const char **errormsg)
{
if (fm == NULL) {
- emsg(_(e_umark));
+ *errormsg = _(e_umark);
return false;
} else if (fm->mark.lnum <= 0) {
// In both cases it's an error but only raise when equals to 0
if (fm->mark.lnum == 0) {
- emsg(_(e_marknotset));
+ *errormsg = _(e_marknotset);
}
return false;
}
// Only check for valid line number if the buffer is loaded.
- if (fm->fnum == curbuf->handle && !mark_check_line_bounds(curbuf, fm)) {
+ if (fm->fnum == curbuf->handle && !mark_check_line_bounds(curbuf, fm, errormsg)) {
return false;
}
return true;
}
/// Check if a mark line number is greater than the buffer line count, and set e_markinval.
+///
/// @note Should be done after the buffer is loaded into memory.
/// @param buf Buffer where the mark is set.
/// @param fm Mark to check.
+/// @param errormsg[out] Error message, if any.
/// @return true if below line count else false.
-bool mark_check_line_bounds(buf_T *buf, fmark_T *fm)
+bool mark_check_line_bounds(buf_T *buf, fmark_T *fm, const char **errormsg)
{
if (buf != NULL && fm->mark.lnum > buf->b_ml.ml_line_count) {
- emsg(_(e_markinval));
+ *errormsg = _(e_markinval);
return false;
}
return true;
diff --git a/src/nvim/path.c b/src/nvim/path.c
index 0927a3a102..b9ae756027 100644
--- a/src/nvim/path.c
+++ b/src/nvim/path.c
@@ -2129,7 +2129,7 @@ int expand_wildcards_eval(char **pat, int *num_file, char ***file, int flags)
int ret = FAIL;
char *eval_pat = NULL;
char *exp_pat = *pat;
- char *ignored_msg;
+ const char *ignored_msg;
size_t usedlen;
const bool is_cur_alt_file = *exp_pat == '%' || *exp_pat == '#';
bool star_follows = false;
diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c
index d237972e40..ea7f3a085f 100644
--- a/src/nvim/syntax.c
+++ b/src/nvim/syntax.c
@@ -3979,7 +3979,7 @@ static void syn_cmd_include(exarg_T *eap, int syncing)
int sgl_id = 1;
char *group_name_end;
char *rest;
- char *errormsg = NULL;
+ const char *errormsg = NULL;
int prev_toplvl_grp;
int prev_syn_inc_tag;
bool source = false;
diff --git a/src/nvim/version.c b/src/nvim/version.c
index b9fa7799a6..95e275bceb 100644
--- a/src/nvim/version.c
+++ b/src/nvim/version.c
@@ -2700,33 +2700,39 @@ void list_version(void)
msg(longVersion);
msg(version_buildtype);
list_lua_version();
+
+ if (p_verbose > 0) {
#ifndef NDEBUG
- msg(version_cflags);
+ msg(version_cflags);
#endif
-
- version_msg("\n\n");
+ version_msg("\n\n");
#ifdef SYS_VIMRC_FILE
- version_msg(_(" system vimrc file: \""));
- version_msg(SYS_VIMRC_FILE);
- version_msg("\"\n");
-#endif // ifdef SYS_VIMRC_FILE
-#ifdef HAVE_PATHDEF
-
- if (*default_vim_dir != NUL) {
- version_msg(_(" fall-back for $VIM: \""));
- version_msg(default_vim_dir);
+ version_msg(_(" system vimrc file: \""));
+ version_msg(SYS_VIMRC_FILE);
version_msg("\"\n");
- }
+#endif
- if (*default_vimruntime_dir != NUL) {
- version_msg(_(" f-b for $VIMRUNTIME: \""));
- version_msg(default_vimruntime_dir);
- version_msg("\"\n");
+#ifdef HAVE_PATHDEF
+ if (*default_vim_dir != NUL) {
+ version_msg(_(" fall-back for $VIM: \""));
+ version_msg(default_vim_dir);
+ version_msg("\"\n");
+ }
+
+ if (*default_vimruntime_dir != NUL) {
+ version_msg(_(" f-b for $VIMRUNTIME: \""));
+ version_msg(default_vimruntime_dir);
+ version_msg("\"\n");
+ }
+#endif
}
-#endif // ifdef HAVE_PATHDEF
- version_msg("\nRun :checkhealth for more info");
+ version_msg(p_verbose > 0
+ ? "\nRun :checkhealth for more info"
+ : (starting
+ ? "\nRun \"nvim -V1 -v\" for more info"
+ : "\nRun \":verbose version\" for more info"));
}
/// Show the intro message when not editing a file.
diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua
index 1ac732b128..c4f89318e0 100644
--- a/test/functional/api/vim_spec.lua
+++ b/test/functional/api/vim_spec.lua
@@ -3467,6 +3467,7 @@ describe('API', function()
end)
end)
end)
+
describe('nvim_parse_cmd', function()
it('works', function()
eq({
@@ -4048,7 +4049,13 @@ describe('API', function()
meths.cmd(meths.parse_cmd("set cursorline", {}), {})
eq(true, meths.get_option_value("cursorline", {}))
end)
+ it('no side-effects (error messages) in pcall() #20339', function()
+ eq({ false, 'Error while parsing command line: E16: Invalid range' },
+ exec_lua([=[return {pcall(vim.api.nvim_parse_cmd, "'<,'>n", {})}]=]))
+ eq('', eval('v:errmsg'))
+ end)
end)
+
describe('nvim_cmd', function()
it('works', function ()
meths.cmd({ cmd = "set", args = { "cursorline" } }, {})
diff --git a/test/functional/core/main_spec.lua b/test/functional/core/main_spec.lua
index efab40dd11..19c7a93730 100644
--- a/test/functional/core/main_spec.lua
+++ b/test/functional/core/main_spec.lua
@@ -3,6 +3,7 @@ local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
local eq = helpers.eq
+local matches = helpers.matches
local feed = helpers.feed
local eval = helpers.eval
local clear = helpers.clear
@@ -12,21 +13,24 @@ local write_file = helpers.write_file
local is_os = helpers.is_os
local skip = helpers.skip
-describe('Command-line option', function()
+describe('command-line option', function()
describe('-s', function()
local fname = 'Xtest-functional-core-main-s'
local fname_2 = fname .. '.2'
local nonexistent_fname = fname .. '.nonexistent'
local dollar_fname = '$' .. fname
+
before_each(function()
clear()
os.remove(fname)
os.remove(dollar_fname)
end)
+
after_each(function()
os.remove(fname)
os.remove(dollar_fname)
end)
+
it('treats - as stdin', function()
eq(nil, luv.fs_stat(fname))
funcs.system(
@@ -38,6 +42,7 @@ describe('Command-line option', function()
local attrs = luv.fs_stat(fname)
eq(#('42\n'), attrs.size)
end)
+
it('does not expand $VAR', function()
eq(nil, luv.fs_stat(fname))
eq(true, not not dollar_fname:find('%$%w+'))
@@ -50,6 +55,7 @@ describe('Command-line option', function()
local attrs = luv.fs_stat(fname)
eq(#('100500\n'), attrs.size)
end)
+
it('does not crash after reading from stdin in non-headless mode', function()
skip(is_os('win'))
local screen = Screen.new(40, 8)
@@ -100,6 +106,7 @@ describe('Command-line option', function()
]])
]=]
end)
+
it('errors out when trying to use nonexistent file with -s', function()
eq(
'Cannot open for reading: "'..nonexistent_fname..'": no such file or directory\n',
@@ -110,6 +117,7 @@ describe('Command-line option', function()
'-s', nonexistent_fname}))
eq(2, eval('v:shell_error'))
end)
+
it('errors out when trying to use -s twice', function()
write_file(fname, ':call setline(1, "1")\n:wqall!\n')
write_file(dollar_fname, ':call setline(1, "2")\n:wqall!\n')
@@ -124,4 +132,11 @@ describe('Command-line option', function()
eq(nil, luv.fs_stat(fname_2))
end)
end)
+
+ it('nvim -v, :version', function()
+ matches('Run ":verbose version"', funcs.execute(':version'))
+ matches('Compilation: .*Run :checkhealth', funcs.execute(':verbose version'))
+ matches('Run "nvim %-V1 %-v"', funcs.system({nvim_prog_abs(), '-v'}))
+ matches('Compilation: .*Run :checkhealth', funcs.system({nvim_prog_abs(), '-V1', '-v'}))
+ end)
end)
diff --git a/test/functional/editor/mark_spec.lua b/test/functional/editor/mark_spec.lua
index a6e4b0c5eb..36485ded7a 100644
--- a/test/functional/editor/mark_spec.lua
+++ b/test/functional/editor/mark_spec.lua
@@ -161,7 +161,7 @@ describe('named marks', function()
feed('ifoo<Esc>mA')
command('enew')
feed('ibar<Esc>')
- eq('Vim(print):E20: Mark not set', pcall_err(command, [['Aprint]]))
+ eq("Vim(print):E20: Mark not set: 'Aprint", pcall_err(command, [['Aprint]]))
end)
it("leave a context mark when moving with '", function()