aboutsummaryrefslogtreecommitdiff
path: root/runtime/lua/vim
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/lua/vim')
-rw-r--r--runtime/lua/vim/diagnostic.lua24
-rw-r--r--runtime/lua/vim/lsp.lua50
-rw-r--r--runtime/lua/vim/lsp/health.lua2
-rw-r--r--runtime/lua/vim/lsp/rpc.lua43
-rw-r--r--runtime/lua/vim/lsp/util.lua1
-rw-r--r--runtime/lua/vim/shared.lua46
-rw-r--r--runtime/lua/vim/treesitter/health.lua2
7 files changed, 112 insertions, 56 deletions
diff --git a/runtime/lua/vim/diagnostic.lua b/runtime/lua/vim/diagnostic.lua
index c7c8c1878e..e8aba6b7a3 100644
--- a/runtime/lua/vim/diagnostic.lua
+++ b/runtime/lua/vim/diagnostic.lua
@@ -27,7 +27,10 @@ local global_diagnostic_options = {
---@private
local function to_severity(severity)
- return type(severity) == 'string' and M.severity[string.upper(severity)] or severity
+ if type(severity) == 'string' then
+ return assert(M.severity[string.upper(severity)], string.format("Invalid severity: %s", severity))
+ end
+ return severity
end
---@private
@@ -125,9 +128,7 @@ local function get_namespace(ns)
end
end
- if not name then
- return vim.notify("namespace does not exist or is anonymous", vim.log.levels.ERROR)
- end
+ assert(name, "namespace does not exist or is anonymous")
all_namespaces[ns] = {
name = name,
@@ -398,6 +399,17 @@ local function show_diagnostics(opts, diagnostics)
diagnostics = prefix_source(opts.source, diagnostics)
end
+ -- Use global setting for severity_sort since 'show_diagnostics' is namespace
+ -- independent
+ local severity_sort = global_diagnostic_options.severity_sort
+ if severity_sort then
+ if type(severity_sort) == "table" and severity_sort.reverse then
+ table.sort(diagnostics, function(a, b) return a.severity > b.severity end)
+ else
+ table.sort(diagnostics, function(a, b) return a.severity < b.severity end)
+ end
+ end
+
for i, diagnostic in ipairs(diagnostics) do
local prefix = string.format("%d. ", i)
local hiname = floating_highlight_map[diagnostic.severity]
@@ -510,6 +522,9 @@ local function diagnostic_move_pos(opts, pos)
return
end
+ -- Save position in the window's jumplist
+ vim.api.nvim_win_call(win_id, function() vim.cmd("normal! m'") end)
+
vim.api.nvim_win_set_cursor(win_id, {pos[1] + 1, pos[2]})
if enable_popup then
@@ -1140,7 +1155,6 @@ function M.show_position_diagnostics(opts, bufnr, position)
local diagnostics = M.get(bufnr, opts)
clamp_line_numbers(bufnr, diagnostics)
local position_diagnostics = vim.tbl_filter(match_position_predicate, diagnostics)
- table.sort(position_diagnostics, function(a, b) return a.severity < b.severity end)
return show_diagnostics(opts, position_diagnostics)
end
diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua
index c7a88a0993..a9e27cf6ac 100644
--- a/runtime/lua/vim/lsp.lua
+++ b/runtime/lua/vim/lsp.lua
@@ -41,6 +41,7 @@ lsp._request_name_to_capability = {
['textDocument/documentSymbol'] = 'document_symbol';
['textDocument/prepareCallHierarchy'] = 'call_hierarchy';
['textDocument/rename'] = 'rename';
+ ['textDocument/prepareRename'] = 'rename';
['textDocument/codeAction'] = 'code_action';
['textDocument/codeLens'] = 'code_lens';
['codeLens/resolve'] = 'code_lens_resolve';
@@ -1383,6 +1384,29 @@ function lsp.buf_notify(bufnr, method, params)
return resp
end
+
+---@private
+local function adjust_start_col(lnum, line, items, encoding)
+ local min_start_char = nil
+ for _, item in pairs(items) do
+ if item.textEdit and item.textEdit.range.start.line == lnum - 1 then
+ if min_start_char and min_start_char ~= item.textEdit.range.start.character then
+ return nil
+ end
+ min_start_char = item.textEdit.range.start.character
+ end
+ end
+ if min_start_char then
+ if encoding == 'utf-8' then
+ return min_start_char
+ else
+ return vim.str_byteindex(line, min_start_char, encoding == 'utf-16')
+ end
+ else
+ return nil
+ end
+end
+
--- Implements 'omnifunc' compatible LSP completion.
---
---@see |complete-functions|
@@ -1418,17 +1442,37 @@ function lsp.omnifunc(findstart, base)
-- Get the start position of the current keyword
local textMatch = vim.fn.match(line_to_cursor, '\\k*$')
- local prefix = line_to_cursor:sub(textMatch+1)
local params = util.make_position_params()
local items = {}
- lsp.buf_request(bufnr, 'textDocument/completion', params, function(err, result)
+ lsp.buf_request(bufnr, 'textDocument/completion', params, function(err, result, ctx)
if err or not result or vim.fn.mode() ~= "i" then return end
+
+ -- Completion response items may be relative to a position different than `textMatch`.
+ -- Concrete example, with sumneko/lua-language-server:
+ --
+ -- require('plenary.asy|
+ -- ▲ ▲ ▲
+ -- │ │ └── cursor_pos: 20
+ -- │ └────── textMatch: 17
+ -- └────────────── textEdit.range.start.character: 9
+ -- .newText = 'plenary.async'
+ -- ^^^
+ -- prefix (We'd remove everything not starting with `asy`,
+ -- so we'd eliminate the `plenary.async` result
+ --
+ -- `adjust_start_col` is used to prefer the language server boundary.
+ --
+ local client = lsp.get_client_by_id(ctx.client_id)
+ local encoding = client and client.offset_encoding or 'utf-16'
+ local candidates = util.extract_completion_items(result)
+ local startbyte = adjust_start_col(pos[1], line, candidates, encoding) or textMatch
+ local prefix = line:sub(startbyte + 1, pos[2])
local matches = util.text_document_completion_list_to_complete_items(result, prefix)
-- TODO(ashkan): is this the best way to do this?
vim.list_extend(items, matches)
- vim.fn.complete(textMatch+1, items)
+ vim.fn.complete(startbyte + 1, items)
end)
-- Return -2 to signal that we should continue completion so that we can
diff --git a/runtime/lua/vim/lsp/health.lua b/runtime/lua/vim/lsp/health.lua
index 855679a2df..ed3eea59df 100644
--- a/runtime/lua/vim/lsp/health.lua
+++ b/runtime/lua/vim/lsp/health.lua
@@ -1,7 +1,7 @@
local M = {}
--- Performs a healthcheck for LSP
-function M.check_health()
+function M.check()
local report_info = vim.fn['health#report_info']
local report_warn = vim.fn['health#report_warn']
diff --git a/runtime/lua/vim/lsp/rpc.lua b/runtime/lua/vim/lsp/rpc.lua
index 255eb65dfe..d9a684a738 100644
--- a/runtime/lua/vim/lsp/rpc.lua
+++ b/runtime/lua/vim/lsp/rpc.lua
@@ -13,36 +13,6 @@ local function is_dir(filename)
return stat and stat.type == 'directory' or false
end
-local NIL = vim.NIL
-
----@private
-local recursive_convert_NIL
-recursive_convert_NIL = function(v, tbl_processed)
- if v == NIL then
- return nil
- elseif not tbl_processed[v] and type(v) == 'table' then
- tbl_processed[v] = true
- local inside_list = vim.tbl_islist(v)
- return vim.tbl_map(function(x)
- if not inside_list or (inside_list and type(x) == "table") then
- return recursive_convert_NIL(x, tbl_processed)
- else
- return x
- end
- end, v)
- end
-
- return v
-end
-
----@private
---- Returns its argument, but converts `vim.NIL` to Lua `nil`.
----@param v (any) Argument
----@returns (any)
-local function convert_NIL(v)
- return recursive_convert_NIL(v, {})
-end
-
---@private
--- Merges current process env with the given env and returns the result as
--- a list of "k=v" strings.
@@ -457,7 +427,7 @@ local function start(cmd, cmd_args, dispatchers, extra_spawn_params)
---@private
local function handle_body(body)
- local ok, decoded = pcall(vim.json.decode, body)
+ local ok, decoded = pcall(vim.json.decode, body, { luanil = { object = true } })
if not ok then
on_error(client_errors.INVALID_SERVER_JSON, decoded)
return
@@ -466,8 +436,6 @@ local function start(cmd, cmd_args, dispatchers, extra_spawn_params)
if type(decoded.method) == 'string' and decoded.id then
local err
- -- Server Request
- decoded.params = convert_NIL(decoded.params)
-- Schedule here so that the users functions don't trigger an error and
-- we can still use the result.
schedule(function()
@@ -494,22 +462,16 @@ local function start(cmd, cmd_args, dispatchers, extra_spawn_params)
end)
-- This works because we are expecting vim.NIL here
elseif decoded.id and (decoded.result ~= vim.NIL or decoded.error ~= vim.NIL) then
- -- Server Result
- decoded.error = convert_NIL(decoded.error)
- decoded.result = convert_NIL(decoded.result)
-- We sent a number, so we expect a number.
local result_id = tonumber(decoded.id)
- -- Do not surface RequestCancelled or ContentModified to users, it is RPC-internal.
+ -- Do not surface RequestCancelled to users, it is RPC-internal.
if decoded.error then
local mute_error = false
if decoded.error.code == protocol.ErrorCodes.RequestCancelled then
local _ = log.debug() and log.debug("Received cancellation ack", decoded)
mute_error = true
- elseif decoded.error.code == protocol.ErrorCodes.ContentModified then
- local _ = log.debug() and log.debug("Received content modified ack", decoded)
- mute_error = true
end
if mute_error then
@@ -544,7 +506,6 @@ local function start(cmd, cmd_args, dispatchers, extra_spawn_params)
end
elseif type(decoded.method) == 'string' then
-- Notification
- decoded.params = convert_NIL(decoded.params)
try_call(client_errors.NOTIFICATION_HANDLER_ERROR,
dispatchers.notification, decoded.method, decoded.params)
else
diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua
index fca956fb57..3751f94caf 100644
--- a/runtime/lua/vim/lsp/util.lua
+++ b/runtime/lua/vim/lsp/util.lua
@@ -193,6 +193,7 @@ function M.get_progress_messages()
title = ctx.title or "empty title",
message = ctx.message,
percentage = ctx.percentage,
+ done = ctx.done,
progress = true,
}
table.insert(new_messages, new_report)
diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua
index 18c1e21049..b57b7ad4ad 100644
--- a/runtime/lua/vim/shared.lua
+++ b/runtime/lua/vim/shared.lua
@@ -98,17 +98,53 @@ end
--- <pre>
--- split(":aa::b:", ":") --> {'','aa','','b',''}
--- split("axaby", "ab?") --> {'','x','y'}
---- split(x*yz*o, "*", true) --> {'x','yz','o'}
+--- split("x*yz*o", "*", {plain=true}) --> {'x','yz','o'}
+--- split("|x|y|z|", "|", {trimempty=true}) --> {'x', 'y', 'z'}
--- </pre>
---
+---
---@see |vim.gsplit()|
---
---@param s String to split
---@param sep Separator string or pattern
----@param plain If `true` use `sep` literally (passed to String.find)
+---@param kwargs Keyword arguments:
+--- - plain: (boolean) If `true` use `sep` literally (passed to string.find)
+--- - trimempty: (boolean) If `true` remove empty items from the front
+--- and back of the list
---@returns List-like table of the split components.
-function vim.split(s,sep,plain)
- local t={} for c in vim.gsplit(s, sep, plain) do table.insert(t,c) end
+function vim.split(s, sep, kwargs)
+ local plain
+ local trimempty = false
+ if type(kwargs) == 'boolean' then
+ -- Support old signature for backward compatibility
+ plain = kwargs
+ else
+ vim.validate { kwargs = {kwargs, 't', true} }
+ kwargs = kwargs or {}
+ plain = kwargs.plain
+ trimempty = kwargs.trimempty
+ end
+
+ local t = {}
+ local skip = trimempty
+ for c in vim.gsplit(s, sep, plain) do
+ if c ~= "" then
+ skip = false
+ end
+
+ if not skip then
+ table.insert(t, c)
+ end
+ end
+
+ if trimempty then
+ for i = #t, 1, -1 do
+ if t[i] ~= "" then
+ break
+ end
+ table.remove(t, i)
+ end
+ end
+
return t
end
diff --git a/runtime/lua/vim/treesitter/health.lua b/runtime/lua/vim/treesitter/health.lua
index e031ba1bd6..53ccc6e88d 100644
--- a/runtime/lua/vim/treesitter/health.lua
+++ b/runtime/lua/vim/treesitter/health.lua
@@ -9,7 +9,7 @@ function M.list_parsers()
end
--- Performs a healthcheck for treesitter integration
-function M.check_health()
+function M.check()
local report_info = vim.fn['health#report_info']
local report_ok = vim.fn['health#report_ok']
local report_error = vim.fn['health#report_error']