diff options
-rw-r--r-- | cmake/RunTests.cmake | 2 | ||||
-rw-r--r-- | runtime/doc/lsp.txt | 84 | ||||
-rw-r--r-- | runtime/lua/vim/lsp/buf.lua | 6 | ||||
-rw-r--r-- | runtime/lua/vim/lsp/codelens.lua | 4 | ||||
-rw-r--r-- | runtime/lua/vim/lsp/log.lua | 2 | ||||
-rw-r--r-- | runtime/lua/vim/lsp/protocol.lua | 11 | ||||
-rw-r--r-- | runtime/lua/vim/lsp/rpc.lua | 2 | ||||
-rw-r--r-- | runtime/lua/vim/lsp/util.lua | 134 | ||||
-rw-r--r-- | src/nvim/api/command.c | 2 | ||||
-rw-r--r-- | src/nvim/eval/funcs.c | 4 | ||||
-rw-r--r-- | src/nvim/ex_docmd.c | 76 | ||||
-rw-r--r-- | src/nvim/ex_getln.c | 9 | ||||
-rw-r--r-- | src/nvim/mark.c | 29 | ||||
-rw-r--r-- | src/nvim/path.c | 2 | ||||
-rw-r--r-- | src/nvim/syntax.c | 2 | ||||
-rw-r--r-- | src/nvim/version.c | 44 | ||||
-rw-r--r-- | test/functional/api/vim_spec.lua | 7 | ||||
-rw-r--r-- | test/functional/core/main_spec.lua | 17 | ||||
-rw-r--r-- | test/functional/editor/mark_spec.lua | 2 |
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() |