diff options
-rw-r--r-- | runtime/doc/lsp.txt | 58 | ||||
-rw-r--r-- | runtime/lua/vim/lsp.lua | 17 | ||||
-rw-r--r-- | runtime/lua/vim/lsp/buf.lua | 19 | ||||
-rw-r--r-- | runtime/lua/vim/lsp/diagnostic.lua | 63 | ||||
-rw-r--r-- | runtime/lua/vim/lsp/handlers.lua | 59 | ||||
-rw-r--r-- | runtime/lua/vim/lsp/util.lua | 5 | ||||
-rw-r--r-- | runtime/lua/vim/shared.lua | 10 | ||||
-rwxr-xr-x | scripts/pvscheck.sh | 2 | ||||
-rw-r--r-- | src/nvim/lua/executor.c | 61 | ||||
-rw-r--r-- | src/nvim/main.c | 5 | ||||
-rw-r--r-- | src/nvim/search.c | 2 | ||||
-rw-r--r-- | src/nvim/tui/tui.c | 3 | ||||
-rw-r--r-- | test/functional/lua/vim_spec.lua | 25 | ||||
-rw-r--r-- | test/functional/plugin/lsp/diagnostic_spec.lua | 32 |
14 files changed, 257 insertions, 104 deletions
diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt index 111c3ee7f7..62f529b463 100644 --- a/runtime/doc/lsp.txt +++ b/runtime/doc/lsp.txt @@ -1199,6 +1199,26 @@ clear({bufnr}, {client_id}, {diagnostic_ns}, {sign_ns}) namespace {sign_ns} number|nil Associated sign namespace +disable({bufnr}, {client_id}) *vim.lsp.diagnostic.disable()* + Disable diagnostics for the given buffer and client + + Parameters: ~ + {bufnr} (optional, number): Buffer handle, defaults + to current + {client_id} (optional, number): Disable diagnostics for + the given client. The default is to disable + diagnostics for all attached clients. + +enable({bufnr}, {client_id}) *vim.lsp.diagnostic.enable()* + Enable diagnostics for the given buffer and client + + Parameters: ~ + {bufnr} (optional, number): Buffer handle, defaults + to current + {client_id} (optional, number): Enable diagnostics for + the given client. The default is to enable + diagnostics for all attached clients. + get({bufnr}, {client_id}) *vim.lsp.diagnostic.get()* Return associated diagnostics for bufnr @@ -1630,23 +1650,29 @@ save({lenses}, {bufnr}, {client_id}) *vim.lsp.codelens.save()* ============================================================================== Lua module: vim.lsp.handlers *lsp-handlers* - *vim.lsp.handlers.progress_handler()* -progress_handler({_}, {_}, {params}, {client_id}) - See also: ~ - https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_executeCommand + *vim.lsp.handlers.hover()* +hover({_}, {method}, {result}, {_}, {_}, {config}) + |lsp-handler| for the method "textDocument/hover" > + + vim.lsp.handlers["textDocument/hover"] = vim.lsp.with( + vim.lsp.handlers.hover, { + -- Use a sharp border with `FloatBorder` highlights + border = "single" + } + ) +< - *vim.lsp.handlers.signature_help()* -signature_help({_}, {method}, {result}, {client_id}, {bufnr}, {config}) Parameters: ~ {config} table Configuration table. • border: (default=nil) • Add borders to the floating window • See |vim.api.nvim_open_win()| - See also: ~ - https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_declaration@seehttps://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_definition@seehttps://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_typeDefinition@seehttps://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_implementation|lsp-handler| for the method "textDocument/signatureHelp" - The active parameter is highlighted with - |hl-LspSignatureActiveParameter|> + *vim.lsp.handlers.signature_help()* +signature_help({_}, {method}, {result}, {client_id}, {bufnr}, {config}) + |lsp-handler| for the method "textDocument/signatureHelp". The + active parameter is highlighted with + |hl-LspSignatureActiveParameter|. > vim.lsp.handlers["textDocument/signatureHelp"] = vim.lsp.with( vim.lsp.handlers.signature_help, { @@ -1656,6 +1682,12 @@ signature_help({_}, {method}, {result}, {client_id}, {bufnr}, {config}) ) < + Parameters: ~ + {config} table Configuration table. + • border: (default=nil) + • Add borders to the floating window + • See |vim.api.nvim_open_win()| + ============================================================================== Lua module: vim.lsp.util *lsp-util* @@ -1915,14 +1947,14 @@ make_floating_popup_options({width}, {height}, {opts}) *vim.lsp.util.make_formatting_params()* make_formatting_params({options}) - Creates a `FormattingOptions` object for the current buffer - and cursor position. + Creates a `DocumentFormattingParams` object for the current + buffer and cursor position. Parameters: ~ {options} Table with valid `FormattingOptions` entries Return: ~ - `FormattingOptions object + `DocumentFormattingParams` object See also: ~ https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_formatting diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua index 75faf9bcc7..f5aefc8260 100644 --- a/runtime/lua/vim/lsp.lua +++ b/runtime/lua/vim/lsp.lua @@ -590,6 +590,10 @@ end --- as `initializationOptions`. See `initialize` in the LSP spec. --- --@param name (string, default=client-id) Name in log messages. +-- +--@param workspace_folders (table) List of workspace folders passed to the +--- language server. Defaults to root_dir if not set. See `workspaceFolders` in +--- the LSP spec --- --@param get_language_id function(bufnr, filetype) -> language ID as string. --- Defaults to the filetype. @@ -775,6 +779,14 @@ function lsp.start_client(config) off = 'off'; messages = 'messages'; verbose = 'verbose'; } local version = vim.version() + + if not config.workspace_folders then + config.workspace_folders = {{ + uri = vim.uri_from_fname(config.root_dir); + name = string.format("%s", config.root_dir); + }}; + end + local initialize_params = { -- The process Id of the parent process that started the server. Is null if -- the process has not been started by another process. If the parent @@ -815,10 +827,7 @@ function lsp.start_client(config) -- -- workspace folder in the user interface. -- name -- } - workspaceFolders = {{ - uri = vim.uri_from_fname(config.root_dir); - name = string.format("%s", config.root_dir); - }}; + workspaceFolders = config.workspace_folders, } if config.before_init then -- TODO(ashkan) handle errors here. diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua index ced1747ee0..29f8d6c3bc 100644 --- a/runtime/lua/vim/lsp/buf.lua +++ b/runtime/lua/vim/lsp/buf.lua @@ -422,6 +422,21 @@ function M.clear_references() util.buf_clear_references() end +--- Requests code actions from all clients and calls the handler exactly once +--- with all aggregated results +--@private +local function code_action_request(params) + local bufnr = vim.api.nvim_get_current_buf() + local method = 'textDocument/codeAction' + vim.lsp.buf_request_all(bufnr, method, params, function(results) + local actions = {} + for _, r in pairs(results) do + vim.list_extend(actions, r.result or {}) + end + vim.lsp.handlers[method](nil, method, actions, nil, bufnr) + end) +end + --- Selects a code action from the input list that is available at the current --- cursor position. -- @@ -432,7 +447,7 @@ function M.code_action(context) context = context or { diagnostics = vim.lsp.diagnostic.get_line_diagnostics() } local params = util.make_range_params() params.context = context - request('textDocument/codeAction', params) + code_action_request(params) end --- Performs |vim.lsp.buf.code_action()| for a given range. @@ -447,7 +462,7 @@ function M.range_code_action(context, start_pos, end_pos) context = context or { diagnostics = vim.lsp.diagnostic.get_line_diagnostics() } local params = util.make_given_range_params(start_pos, end_pos) params.context = context - request('textDocument/codeAction', params) + code_action_request(params) end --- Executes an LSP server command. diff --git a/runtime/lua/vim/lsp/diagnostic.lua b/runtime/lua/vim/lsp/diagnostic.lua index 1342df529f..9a97e5db2f 100644 --- a/runtime/lua/vim/lsp/diagnostic.lua +++ b/runtime/lua/vim/lsp/diagnostic.lua @@ -208,6 +208,9 @@ local diagnostic_cache_lines = setmetatable({}, bufnr_and_client_cacher_mt) local diagnostic_cache_counts = setmetatable({}, bufnr_and_client_cacher_mt) local diagnostic_attached_buffers = {} +-- Disabled buffers and clients +local diagnostic_disabled = setmetatable({}, bufnr_and_client_cacher_mt) + local _bufs_waiting_to_update = setmetatable({}, bufnr_and_client_cacher_mt) --- Store Diagnostic[] by line @@ -816,10 +819,7 @@ end ---@param diagnostic_ns number|nil Associated diagnostic namespace ---@param sign_ns number|nil Associated sign namespace function M.clear(bufnr, client_id, diagnostic_ns, sign_ns) - validate { bufnr = { bufnr, 'n' } } - - bufnr = (bufnr == 0 and api.nvim_get_current_buf()) or bufnr - + bufnr = get_bufnr(bufnr) if client_id == nil then return vim.lsp.for_each_buffer_client(bufnr, function(_, iter_client_id, _) return M.clear(bufnr, iter_client_id) @@ -1092,6 +1092,10 @@ end --@private --- Display diagnostics for the buffer, given a configuration. function M.display(diagnostics, bufnr, client_id, config) + if diagnostic_disabled[bufnr][client_id] then + return + end + config = vim.lsp._with_extend('vim.lsp.diagnostic.on_publish_diagnostics', { signs = true, underline = true, @@ -1282,6 +1286,57 @@ function M.set_loclist(opts) vim.cmd [[lopen]] end end + +--- Disable diagnostics for the given buffer and client +--- @param bufnr (optional, number): Buffer handle, defaults to current +--- @param client_id (optional, number): Disable diagnostics for the given +--- client. The default is to disable diagnostics for all attached +--- clients. +-- Note that when diagnostics are disabled for a buffer, the server will still +-- send diagnostic information and the client will still process it. The +-- diagnostics are simply not displayed to the user. +function M.disable(bufnr, client_id) + if not client_id then + return vim.lsp.for_each_buffer_client(bufnr, function(client) + M.disable(bufnr, client.id) + end) + end + + diagnostic_disabled[bufnr][client_id] = true + M.clear(bufnr, client_id) +end + +--- Enable diagnostics for the given buffer and client +--- @param bufnr (optional, number): Buffer handle, defaults to current +--- @param client_id (optional, number): Enable diagnostics for the given +--- client. The default is to enable diagnostics for all attached +--- clients. +function M.enable(bufnr, client_id) + if not client_id then + return vim.lsp.for_each_buffer_client(bufnr, function(client) + M.enable(bufnr, client.id) + end) + end + + if not diagnostic_disabled[bufnr][client_id] then + return + end + + diagnostic_disabled[bufnr][client_id] = nil + + -- We need to invoke the publishDiagnostics handler directly instead of just + -- calling M.display so that we can preserve any custom configuration options + -- the user may have set with vim.lsp.with. + vim.lsp.handlers["textDocument/publishDiagnostics"]( + nil, + "textDocument/publishDiagnostics", + { + diagnostics = M.get(bufnr, client_id), + uri = vim.uri_from_bufnr(bufnr), + }, + client_id + ) +end -- }}} return M diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua index 797ff762cb..acd20a3e0b 100644 --- a/runtime/lua/vim/lsp/handlers.lua +++ b/runtime/lua/vim/lsp/handlers.lua @@ -17,13 +17,12 @@ local function err_message(...) api.nvim_command("redraw") end ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_executeCommand +--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_executeCommand M['workspace/executeCommand'] = function() -- Error handling is done implicitly by wrapping all handlers; see end of this file end --- @msg of type ProgressParams --- Basically a token of type number/string +--@private local function progress_handler(_, _, params, client_id) local client = vim.lsp.get_client_by_id(client_id) local client_name = client and client.name or string.format("id=%d", client_id) @@ -59,10 +58,10 @@ local function progress_handler(_, _, params, client_id) vim.api.nvim_command("doautocmd <nomodeline> User LspProgressUpdate") end ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#progress +--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#progress M['$/progress'] = progress_handler ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#window_workDoneProgress_create +--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#window_workDoneProgress_create M['window/workDoneProgress/create'] = function(_, _, params, client_id) local client = vim.lsp.get_client_by_id(client_id) local token = params.token -- string or number @@ -74,7 +73,7 @@ M['window/workDoneProgress/create'] = function(_, _, params, client_id) return vim.NIL end ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#window_showMessageRequest +--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#window_showMessageRequest M['window/showMessageRequest'] = function(_, _, params) local actions = params.actions @@ -95,7 +94,7 @@ M['window/showMessageRequest'] = function(_, _, params) end end ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#client_registerCapability +--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#client_registerCapability M['client/registerCapability'] = function(_, _, _, client_id) local warning_tpl = "The language server %s triggers a registerCapability ".. "handler despite dynamicRegistration set to false. ".. @@ -107,7 +106,7 @@ M['client/registerCapability'] = function(_, _, _, client_id) return vim.NIL end ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_codeAction +--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_codeAction M['textDocument/codeAction'] = function(_, _, actions) if actions == nil or vim.tbl_isempty(actions) then print("No code actions available") @@ -141,7 +140,7 @@ M['textDocument/codeAction'] = function(_, _, actions) end end ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_applyEdit +--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_applyEdit M['workspace/applyEdit'] = function(_, _, workspace_edit) if not workspace_edit then return end -- TODO(ashkan) Do something more with label? @@ -155,7 +154,7 @@ M['workspace/applyEdit'] = function(_, _, workspace_edit) } end ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_configuration +--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_configuration M['workspace/configuration'] = function(_, _, params, client_id) local client = vim.lsp.get_client_by_id(client_id) if not client then @@ -207,34 +206,34 @@ local function response_to_qflist(map_result, entity) end ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_references +--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_references M['textDocument/references'] = response_to_qflist(util.locations_to_items, 'references') ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_documentSymbol +--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_documentSymbol M['textDocument/documentSymbol'] = response_to_qflist(util.symbols_to_items, 'document symbols') ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_symbol +--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_symbol M['workspace/symbol'] = response_to_qflist(util.symbols_to_items, 'symbols') ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_rename +--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_rename M['textDocument/rename'] = function(_, _, result) if not result then return end util.apply_workspace_edit(result) end ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_rangeFormatting +--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_rangeFormatting M['textDocument/rangeFormatting'] = function(_, _, result, _, bufnr) if not result then return end util.apply_text_edits(result, bufnr) end ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_formatting +--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_formatting M['textDocument/formatting'] = function(_, _, result, _, bufnr) if not result then return end util.apply_text_edits(result, bufnr) end ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion +--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion M['textDocument/completion'] = function(_, _, result) if vim.tbl_isempty(result or {}) then return end local row, col = unpack(api.nvim_win_get_cursor(0)) @@ -276,7 +275,7 @@ function M.hover(_, method, result, _, _, config) return util.open_floating_preview(markdown_lines, "markdown", config) end ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_hover +--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_hover M['textDocument/hover'] = M.hover --@private @@ -306,17 +305,17 @@ local function location_handler(_, method, result) end end ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_declaration +--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_declaration M['textDocument/declaration'] = location_handler ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_definition +--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_definition M['textDocument/definition'] = location_handler ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_typeDefinition +--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_typeDefinition M['textDocument/typeDefinition'] = location_handler ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_implementation +--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_implementation M['textDocument/implementation'] = location_handler ---- |lsp-handler| for the method "textDocument/signatureHelp" ---- The active parameter is highlighted with |hl-LspSignatureActiveParameter| +--- |lsp-handler| for the method "textDocument/signatureHelp". +--- The active parameter is highlighted with |hl-LspSignatureActiveParameter|. --- <pre> --- vim.lsp.handlers["textDocument/signatureHelp"] = vim.lsp.with( --- vim.lsp.handlers.signature_help, { @@ -358,10 +357,10 @@ function M.signature_help(_, method, result, client_id, bufnr, config) return fbuf, fwin end ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_signatureHelp +--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_signatureHelp M['textDocument/signatureHelp'] = M.signature_help ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_documentHighlight +--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_documentHighlight M['textDocument/documentHighlight'] = function(_, _, result, _, bufnr, _) if not result then return end util.buf_highlight_references(bufnr, result) @@ -394,13 +393,13 @@ local make_call_hierarchy_handler = function(direction) end end ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#callHierarchy/incomingCalls +--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#callHierarchy_incomingCalls M['callHierarchy/incomingCalls'] = make_call_hierarchy_handler('from') ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#callHierarchy/outgoingCalls +--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#callHierarchy_outgoingCalls M['callHierarchy/outgoingCalls'] = make_call_hierarchy_handler('to') ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#window/logMessage +--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#window_logMessage M['window/logMessage'] = function(_, _, result, client_id) local message_type = result.type local message = result.message @@ -421,7 +420,7 @@ M['window/logMessage'] = function(_, _, result, client_id) return result end ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#window/showMessage +--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#window_showMessage M['window/showMessage'] = function(_, _, result, client_id) local message_type = result.type local message = result.message diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index f047a12dff..dc15d67e1c 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -990,6 +990,7 @@ function M.make_floating_popup_options(width, height, opts) style = 'minimal', width = width, border = opts.border or default_border, + zindex = opts.zindex or 50, } end @@ -1868,10 +1869,10 @@ function M.get_effective_tabstop(bufnr) return (sts > 0 and sts) or (sts < 0 and bo.shiftwidth) or bo.tabstop end ---- Creates a `FormattingOptions` object for the current buffer and cursor position. +--- Creates a `DocumentFormattingParams` object for the current buffer and cursor position. --- --@param options Table with valid `FormattingOptions` entries ---@returns `FormattingOptions object +--@returns `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} } diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua index 0a663628a5..33c2b2c46c 100644 --- a/runtime/lua/vim/shared.lua +++ b/runtime/lua/vim/shared.lua @@ -200,6 +200,12 @@ function vim.tbl_isempty(t) return next(t) == nil end +--- we only merge empty tables or tables that are not a list +--@private +local function can_merge(v) + return type(v) == "table" and (vim.tbl_isempty(v) or not vim.tbl_islist(v)) +end + local function tbl_extend(behavior, deep_extend, ...) if (behavior ~= 'error' and behavior ~= 'keep' and behavior ~= 'force') then error('invalid "behavior": '..tostring(behavior)) @@ -219,8 +225,8 @@ local function tbl_extend(behavior, deep_extend, ...) vim.validate{["after the second argument"] = {tbl,'t'}} if tbl then for k, v in pairs(tbl) do - if type(v) == 'table' and deep_extend and not vim.tbl_islist(v) then - ret[k] = tbl_extend(behavior, true, ret[k] or vim.empty_dict(), v) + if deep_extend and can_merge(v) and can_merge(ret[k]) then + ret[k] = tbl_extend(behavior, true, ret[k], v) elseif behavior ~= 'force' and ret[k] ~= nil then if behavior == 'error' then error('key found in more than one map: '..k) diff --git a/scripts/pvscheck.sh b/scripts/pvscheck.sh index f3371b485e..aa27c94f29 100755 --- a/scripts/pvscheck.sh +++ b/scripts/pvscheck.sh @@ -379,7 +379,7 @@ run_analysis() {( --sourcetree-root . || true rm -rf PVS-studio.{xml,err,tsk,html.d} - local plog_args="PVS-studio.log --srcRoot . --excludedCodes V011" + local plog_args="PVS-studio.log --srcRoot . --excludedCodes V011,V1042" plog-converter $plog_args --renderTypes xml --output PVS-studio.xml plog-converter $plog_args --renderTypes errorfile --output PVS-studio.err plog-converter $plog_args --renderTypes tasklist --output PVS-studio.tsk diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index b6d1b5fda4..5799c3ee98 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -45,6 +45,9 @@ static int in_fast_callback = 0; +// Initialized in nlua_init(). +static lua_State *global_lstate = NULL; + typedef struct { Error err; String lua_err_str; @@ -250,7 +253,7 @@ static int nlua_luv_cfpcall(lua_State *lstate, int nargs, int nresult, static void nlua_schedule_event(void **argv) { LuaRef cb = (LuaRef)(ptrdiff_t)argv[0]; - lua_State *const lstate = nlua_enter(); + lua_State *const lstate = global_lstate; nlua_pushref(lstate, cb); nlua_unref(lstate, cb); if (lua_pcall(lstate, 0, 0, 0)) { @@ -553,14 +556,10 @@ static int nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL return 0; } -/// Initialize lua interpreter +/// Initialize global lua interpreter /// -/// Crashes Nvim if initialization fails. Should be called once per lua -/// interpreter instance. -/// -/// @return New lua interpreter instance. -static lua_State *nlua_init(void) - FUNC_ATTR_NONNULL_RET FUNC_ATTR_WARN_UNUSED_RESULT +/// Crashes Nvim if initialization fails. +void nlua_init(void) { #ifdef NLUA_TRACK_REFS const char *env = os_getenv("NVIM_LUA_NOTRACK"); @@ -577,28 +576,9 @@ static lua_State *nlua_init(void) luaL_openlibs(lstate); nlua_state_init(lstate); - return lstate; + global_lstate = lstate; } -// only to be used by nlua_enter and nlua_free_all_mem! -static lua_State *global_lstate = NULL; - -/// Enter lua interpreter -/// -/// Calls nlua_init() if needed. Is responsible for pre-lua call initialization -/// like updating `package.[c]path` with directories derived from &runtimepath. -/// -/// @return Interpreter instance to use. Will either be initialized now or -/// taken from previous initialization. -static lua_State *nlua_enter(void) - FUNC_ATTR_NONNULL_RET FUNC_ATTR_WARN_UNUSED_RESULT -{ - if (global_lstate == NULL) { - global_lstate = nlua_init(); - } - lua_State *const lstate = global_lstate; - return lstate; -} void nlua_free_all_mem(void) { @@ -1043,8 +1023,7 @@ void nlua_unref(lua_State *lstate, LuaRef ref) void api_free_luaref(LuaRef ref) { - lua_State *const lstate = nlua_enter(); - nlua_unref(lstate, ref); + nlua_unref(global_lstate, ref); } /// push a value referenced in the registry @@ -1064,7 +1043,7 @@ LuaRef api_new_luaref(LuaRef original_ref) return LUA_NOREF; } - lua_State *const lstate = nlua_enter(); + lua_State *const lstate = global_lstate; nlua_pushref(lstate, original_ref); LuaRef new_ref = nlua_ref(lstate, -1); lua_pop(lstate, 1); @@ -1143,7 +1122,7 @@ static void nlua_typval_exec(const char *lcmd, size_t lcmd_len, return; } - lua_State *const lstate = nlua_enter(); + lua_State *const lstate = global_lstate; if (luaL_loadbuffer(lstate, lcmd, lcmd_len, name)) { nlua_error(lstate, _("E5107: Error loading lua %.*s")); return; @@ -1233,7 +1212,7 @@ int typval_exec_lua_callable( /// @return Return value of the execution. Object nlua_exec(const String str, const Array args, Error *err) { - lua_State *const lstate = nlua_enter(); + lua_State *const lstate = global_lstate; if (luaL_loadbuffer(lstate, str.data, str.size, "<nvim>")) { size_t len; @@ -1270,7 +1249,7 @@ Object nlua_exec(const String str, const Array args, Error *err) Object nlua_call_ref(LuaRef ref, const char *name, Array args, bool retval, Error *err) { - lua_State *const lstate = nlua_enter(); + lua_State *const lstate = global_lstate; nlua_pushref(lstate, ref); int nargs = (int)args.size; if (name != NULL) { @@ -1346,7 +1325,7 @@ void ex_luado(exarg_T *const eap) const char *const cmd = (const char *)eap->arg; const size_t cmd_len = strlen(cmd); - lua_State *const lstate = nlua_enter(); + lua_State *const lstate = global_lstate; #define DOSTART "return function(line, linenr) " #define DOEND " end" @@ -1431,7 +1410,7 @@ void ex_luafile(exarg_T *const eap) bool nlua_exec_file(const char *path) FUNC_ATTR_NONNULL_ALL { - lua_State *const lstate = nlua_enter(); + lua_State *const lstate = global_lstate; if (luaL_loadfile(lstate, path)) { nlua_error(lstate, _("E5112: Error while creating lua chunk: %.*s")); @@ -1480,7 +1459,7 @@ int nlua_expand_pat(expand_T *xp, int *num_results, char_u ***results) { - lua_State *const lstate = nlua_enter(); + lua_State *const lstate = global_lstate; int ret = OK; // [ vim ] @@ -1690,7 +1669,7 @@ int nlua_CFunction_func_call( typval_T *rettv, void *state) { - lua_State *const lstate = nlua_enter(); + lua_State *const lstate = global_lstate; LuaCFunctionState *funcstate = (LuaCFunctionState *)state; return typval_exec_lua_callable(lstate, funcstate->lua_callable, @@ -1699,7 +1678,7 @@ int nlua_CFunction_func_call( void nlua_CFunction_func_free(void *state) { - lua_State *const lstate = nlua_enter(); + lua_State *const lstate = global_lstate; LuaCFunctionState *funcstate = (LuaCFunctionState *)state; nlua_unref(lstate, funcstate->lua_callable.func_ref); @@ -1730,7 +1709,7 @@ char_u *nlua_register_table_as_callable(typval_T *const arg) return NULL; } - lua_State *const lstate = nlua_enter(); + lua_State *const lstate = global_lstate; #ifndef NDEBUG int top = lua_gettop(lstate); @@ -1769,7 +1748,7 @@ void nlua_execute_log_keystroke(int c) char_u buf[NUMBUFLEN]; size_t buf_len = special_to_buf(c, mod_mask, false, buf); - lua_State *const lstate = nlua_enter(); + lua_State *const lstate = global_lstate; #ifndef NDEBUG int top = lua_gettop(lstate); diff --git a/src/nvim/main.c b/src/nvim/main.c index 621b93f9cc..cf9cb9cfbd 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -7,8 +7,6 @@ #include <string.h> #include <stdbool.h> -#include <lua.h> -#include <lauxlib.h> #include <msgpack.h> #include "nvim/ascii.h" @@ -258,6 +256,8 @@ int main(int argc, char **argv) // Check if we have an interactive window. check_and_set_isatty(¶ms); + nlua_init(); + // Process the command line arguments. File names are put in the global // argument list "global_alist". command_line_scan(¶ms); @@ -341,7 +341,6 @@ int main(int argc, char **argv) TIME_MSG("initialized screen early for UI"); } - // open terminals when opening files that start with term:// #define PROTO "term://" do_cmdline_cmd("augroup nvim_terminal"); diff --git a/src/nvim/search.c b/src/nvim/search.c index a946a5e24b..809eec7ffc 100644 --- a/src/nvim/search.c +++ b/src/nvim/search.c @@ -1501,7 +1501,7 @@ int searchc(cmdarg_T *cap, int t_cmd) FUNC_ATTR_NONNULL_ALL { int c = cap->nchar; // char to search for - Direction dir = cap->arg; // TRUE for searching forward + int dir = cap->arg; // true for searching forward long count = cap->count1; // repeat count int col; char_u *p; diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index 431237bac5..70d39339c3 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -1125,7 +1125,8 @@ static void tui_mode_change(UI *ui, String mode, Integer mode_idx) static void tui_grid_scroll(UI *ui, Integer g, Integer startrow, Integer endrow, Integer startcol, Integer endcol, - Integer rows, Integer cols FUNC_ATTR_UNUSED) + Integer rows, + Integer cols FUNC_ATTR_UNUSED) // -V751 { TUIData *data = ui->data; UGrid *grid = &data->grid; diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 976e63b44d..4e2bed4deb 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -603,6 +603,31 @@ describe('lua stdlib', function() return vim.tbl_islist(c) and count == 0 ]])) + eq(exec_lua([[ + local a = { a = { b = 1 } } + local b = { a = {} } + return vim.tbl_deep_extend("force", a, b) + ]]), {a = {b = 1}}) + + eq(exec_lua([[ + local a = { a = 123 } + local b = { a = { b = 1} } + return vim.tbl_deep_extend("force", a, b) + ]]), {a = {b = 1}}) + + ok(exec_lua([[ + local a = { a = {[2] = 3} } + local b = { a = {[3] = 3} } + local c = vim.tbl_deep_extend("force", a, b) + return vim.deep_equal(c, {a = {[3] = 3}}) + ]])) + + eq(exec_lua([[ + local a = { a = { b = 1} } + local b = { a = 123 } + return vim.tbl_deep_extend("force", a, b) + ]]), {a = 123 }) + eq('Error executing lua: vim/shared.lua:0: invalid "behavior": nil', pcall_err(exec_lua, [[ return vim.tbl_deep_extend() diff --git a/test/functional/plugin/lsp/diagnostic_spec.lua b/test/functional/plugin/lsp/diagnostic_spec.lua index c1c76c3916..7359ee4bce 100644 --- a/test/functional/plugin/lsp/diagnostic_spec.lua +++ b/test/functional/plugin/lsp/diagnostic_spec.lua @@ -241,6 +241,38 @@ describe('vim.lsp.diagnostic', function() ]])) end) + it('should not display diagnostics when disabled', function() + eq({0, 2}, exec_lua [[ + local server_1_diags = { + make_error("Error 1", 1, 1, 1, 5), + make_warning("Warning on Server 1", 2, 1, 2, 5), + } + local server_2_diags = { + make_warning("Warning 1", 2, 1, 2, 5), + } + + vim.lsp.diagnostic.on_publish_diagnostics(nil, nil, { uri = fake_uri, diagnostics = server_1_diags }, 1) + vim.lsp.diagnostic.on_publish_diagnostics(nil, nil, { uri = fake_uri, diagnostics = server_2_diags }, 2) + + vim.lsp.diagnostic.disable(diagnostic_bufnr, 1) + + return { + count_of_extmarks_for_client(diagnostic_bufnr, 1), + count_of_extmarks_for_client(diagnostic_bufnr, 2), + } + ]]) + + eq({4, 0}, exec_lua [[ + vim.lsp.diagnostic.enable(diagnostic_bufnr, 1) + vim.lsp.diagnostic.disable(diagnostic_bufnr, 2) + + return { + count_of_extmarks_for_client(diagnostic_bufnr, 1), + count_of_extmarks_for_client(diagnostic_bufnr, 2), + } + ]]) + end) + describe('reset', function() it('diagnostic count is 0 and displayed diagnostics are 0 after call', function() -- 1 Error (1) |