aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/doc/lsp.txt88
-rw-r--r--runtime/lua/vim/lsp.lua17
-rw-r--r--runtime/lua/vim/lsp/buf.lua22
-rw-r--r--runtime/lua/vim/lsp/callbacks.lua8
-rw-r--r--runtime/lua/vim/lsp/util.lua58
5 files changed, 166 insertions, 27 deletions
diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt
index 9de2aaf592..d5ed857f32 100644
--- a/runtime/doc/lsp.txt
+++ b/runtime/doc/lsp.txt
@@ -77,21 +77,6 @@ FAQ *lsp-faq*
"after/ftplugin/python.vim".
================================================================================
-LSP HIGHLIGHT *lsp-highlight*
-
-When LSP is activated these highlight groups are defined:
-
- LspDiagnosticsError
- LspDiagnosticsHint
- LspDiagnosticsInformation
- LspDiagnosticsUnderline
- LspDiagnosticsUnderlineError
- LspDiagnosticsUnderlineHint
- LspDiagnosticsUnderlineInformation
- LspDiagnosticsUnderlineWarning
- LspDiagnosticsWarning
-
-================================================================================
LSP API *lsp-api*
The `vim.lsp` Lua module is a framework for building LSP plugins.
@@ -174,6 +159,25 @@ name: >
vim.lsp.protocol.TextDocumentSyncKind[1] == "Full"
================================================================================
+LSP HIGHLIGHT *lsp-highlight*
+
+ *hl-LspDiagnosticsError*
+LspDiagnosticsError used for "Error" diagnostic virtual text
+ *hl-LspDiagnosticsWarning*
+LspDiagnosticsWarning used for "Warning" diagnostic virtual text
+ *hl-LspDiagnosticsInformation*
+LspDiagnosticInformation used for "Information" diagnostic virtual text
+ *hl-LspDiagnosticsHint*
+LspDiagnosticHint used for "Hint" diagnostic virtual text
+ *hl-LspReferenceText*
+LspReferenceText used for highlighting "text" references
+ *hl-LspReferenceRead*
+LspReferenceRead used for highlighting "read" references
+ *hl-LspReferenceWrite*
+LspReferenceWrite used for highlighting "write" references
+
+
+================================================================================
LSP EXAMPLE *lsp-extension-example*
This example is for plugin authors or users who want a lot of control. If you
@@ -290,6 +294,12 @@ The example will:
<
+==============================================================================
+AUTOCOMMANDS *lsp-autocommands*
+
+ *LspDiagnosticsChanged*
+LspDiagnosticsChanged After receiving publishDiagnostics server response
+
==============================================================================
Lua module: vim.lsp *lsp-core*
@@ -333,7 +343,7 @@ buf_notify({bufnr}, {method}, {params}) *vim.lsp.buf_notify()*
{params} (string) Parameters to send to the server
Return: ~
- nil
+ true if any client returns true; false otherwise
*vim.lsp.buf_request()*
buf_request({bufnr}, {method}, {params}, {callback})
@@ -720,6 +730,9 @@ declaration() *vim.lsp.buf.declaration()*
definition() *vim.lsp.buf.definition()*
TODO: Documentation
+document_highlight() *vim.lsp.buf.document_highlight()*
+ TODO: Documentation
+
formatting({options}) *vim.lsp.buf.formatting()*
TODO: Documentation
@@ -751,6 +764,10 @@ rename({new_name}) *vim.lsp.buf.rename()*
request({method}, {params}, {callback}) *vim.lsp.buf.request()*
TODO: Documentation
+server_ready() *vim.lsp.buf.server_ready()*
+ Sends a notification through all clients associated with current
+ buffer and returns `true` if server responds.
+
signature_help() *vim.lsp.buf.signature_help()*
TODO: Documentation
@@ -896,6 +913,33 @@ apply_workspace_edit({workspace_edit})
buf_clear_diagnostics({bufnr}) *vim.lsp.util.buf_clear_diagnostics()*
TODO: Documentation
+
+ *vim.lsp.util.buf_diagnostics_count()*
+buf_diagnostics_count({kind})
+ Returns the number of diagnostics of given kind for current buffer.
+ Useful for showing diagnostics counts in statusline. eg:
+
+>
+ function! LspStatus() abort
+ let sl = ''
+ if luaeval('vim.lsp.buf.server_ready()')
+ let sl.='%#MyStatuslineLSP#E:'
+ let sl.='%#MyStatuslineLSPErrors#%{luaeval("vim.lsp.util.buf_diagnostics_count(\"Error\")")}'
+ let sl.='%#MyStatuslineLSP# W:'
+ let sl.='%#MyStatuslineLSPWarnings#%{luaeval("vim.lsp.util.buf_diagnostics_count(\"Warning\")")}'
+ else
+ let sl.='%#MyStatuslineLSPErrors#off'
+ endif
+ return sl
+ endfunction
+ let &l:statusline = '%#MyStatuslineLSP#LSP '.LspStatus()
+<
+
+ Parameters: ~
+ {kind} Diagnostic severity kind: Error, Warning, Information or Hint.
+
+buf_clear_references({bufnr}) *vim.lsp.util.buf_clear_references()*
+ TODO: Documentation
*vim.lsp.util.buf_diagnostics_save_positions()*
buf_diagnostics_save_positions({bufnr}, {diagnostics})
@@ -909,6 +953,18 @@ buf_diagnostics_underline({bufnr}, {diagnostics})
buf_diagnostics_virtual_text({bufnr}, {diagnostics})
TODO: Documentation
+ *vim.lsp.util.buf_diagnostics_signs()*
+buf_diagnostics_signs({bufnr}, {diagnostics})
+ Place signs for each diagnostic in the sign column.
+ Sign characters can be customized with the following options:
+>
+let g:LspDiagnosticsErrorSign = 'E'
+let g:LspDiagnosticsWarningSign = 'W'
+let g:LspDiagnosticsInformationSign = 'I'
+let g:LspDiagnosticsHintSign = 'H'
+<
+
+
character_offset({buf}, {row}, {col}) *vim.lsp.util.character_offset()*
TODO: Documentation
diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua
index bc0da25ae5..71ec3cb6c4 100644
--- a/runtime/lua/vim/lsp.lua
+++ b/runtime/lua/vim/lsp.lua
@@ -893,21 +893,22 @@ function lsp.buf_request_sync(bufnr, method, params, timeout_ms)
return request_results
end
---- Sends a notification to all servers attached to the buffer.
----
---@param bufnr (optional, number) Buffer handle, or 0 for current
---@param method (string) LSP method name
---@param params (string) Parameters to send to the server
----
---@returns nil
+--- Send a notification to a server
+-- @param bufnr [number] (optional): The number of the buffer
+-- @param method [string]: Name of the request method
+-- @param params [string]: Arguments to send to the server
+--
+-- @returns true if any client returns true; false otherwise
function lsp.buf_notify(bufnr, method, params)
validate {
bufnr = { bufnr, 'n', true };
method = { method, 's' };
}
+ local resp = false
for_each_buffer_client(bufnr, function(client, _client_id)
- client.rpc.notify(method, params)
+ if client.rpc.notify(method, params) then resp = true end
end)
+ return resp
end
--- Implements 'omnifunc' compatible LSP completion.
diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua
index 19deb5df45..82aeccd4db 100644
--- a/runtime/lua/vim/lsp/buf.lua
+++ b/runtime/lua/vim/lsp/buf.lua
@@ -23,6 +23,10 @@ local function request(method, params, callback)
return vim.lsp.buf_request(0, method, params, callback)
end
+function M.server_ready()
+ return not not vim.lsp.buf_notify(0, "window/progress", {})
+end
+
function M.hover()
local params = util.make_position_params()
request('textDocument/hover', params)
@@ -134,5 +138,23 @@ function M.references(context)
request('textDocument/references', params)
end
+--- Send request to server to resolve document highlights for the
+--- current text document position. This request can be associated
+--- to key mapping or to events such as `CursorHold`, eg:
+---
+--- <pre>
+--- vim.api.nvim_command [[autocmd CursorHold <buffer> lua vim.lsp.buf.document_highlight()]]
+--- vim.api.nvim_command [[autocmd CursorHoldI <buffer> lua vim.lsp.buf.document_highlight()]]
+--- vim.api.nvim_command [[autocmd CursorMoved <buffer> lua vim.lsp.buf.clear_references()]]
+--- </pre>
+function M.document_highlight()
+ local params = util.make_position_params()
+ request('textDocument/documentHighlight', params)
+end
+
+function M.clear_references()
+ util.buf_clear_references()
+end
+
return M
-- vim:sw=2 ts=2 et
diff --git a/runtime/lua/vim/lsp/callbacks.lua b/runtime/lua/vim/lsp/callbacks.lua
index e76e07ca96..c9d63625fd 100644
--- a/runtime/lua/vim/lsp/callbacks.lua
+++ b/runtime/lua/vim/lsp/callbacks.lua
@@ -32,7 +32,9 @@ M['textDocument/publishDiagnostics'] = function(_, _, result)
util.buf_diagnostics_save_positions(bufnr, result.diagnostics)
util.buf_diagnostics_underline(bufnr, result.diagnostics)
util.buf_diagnostics_virtual_text(bufnr, result.diagnostics)
+ util.buf_diagnostics_signs(bufnr, result.diagnostics)
-- util.set_loclist(result.diagnostics)
+ vim.api.nvim_command("doautocmd User LspDiagnosticsChanged")
end
M['textDocument/references'] = function(_, _, result)
@@ -196,6 +198,12 @@ M['textDocument/peekDefinition'] = function(_, _, result, _)
api.nvim_buf_add_highlight(headbuf, -1, 'Keyword', 0, -1)
end
+M['textDocument/documentHighlight'] = function(_, _, result, _)
+ if not result then return end
+ local bufnr = api.nvim_get_current_buf()
+ util.buf_highlight_references(bufnr, result)
+end
+
local function log_message(_, _, 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 b7c7b7f75d..21e0dbfd1f 100644
--- a/runtime/lua/vim/lsp/util.lua
+++ b/runtime/lua/vim/lsp/util.lua
@@ -269,7 +269,7 @@ function M.convert_input_to_markdown_lines(input, contents)
end
end
end
- if contents[1] == '' or contents[1] == nil then
+ if (contents[1] == '' or contents[1] == nil) and #contents == 1 then
return {}
end
return contents
@@ -569,7 +569,8 @@ do
local all_buffer_diagnostics = {}
local diagnostic_ns = api.nvim_create_namespace("vim_lsp_diagnostics")
-
+ local reference_ns = api.nvim_create_namespace("vim_lsp_references")
+ local sign_ns = 'vim_lsp_signs'
local underline_highlight_name = "LspDiagnosticsUnderline"
vim.cmd(string.format("highlight default %s gui=underline cterm=underline", underline_highlight_name))
for kind, _ in pairs(protocol.DiagnosticSeverity) do
@@ -603,6 +604,11 @@ do
function M.buf_clear_diagnostics(bufnr)
validate { bufnr = {bufnr, 'n', true} }
bufnr = bufnr == 0 and api.nvim_get_current_buf() or bufnr
+
+ -- clear sign group
+ vim.fn.sign_unplace(sign_ns, {buffer=bufnr})
+
+ -- clear virtual text namespace
api.nvim_buf_clear_namespace(bufnr, diagnostic_ns, 0, -1)
end
@@ -683,7 +689,6 @@ do
end
end
-
function M.buf_diagnostics_underline(bufnr, diagnostics)
for _, diagnostic in ipairs(diagnostics) do
local start = diagnostic.range["start"]
@@ -705,6 +710,25 @@ do
end
end
+ function M.buf_clear_references(bufnr)
+ validate { bufnr = {bufnr, 'n', true} }
+ api.nvim_buf_clear_namespace(bufnr, reference_ns, 0, -1)
+ end
+
+ function M.buf_highlight_references(bufnr, references)
+ validate { bufnr = {bufnr, 'n', true} }
+ for _, reference in ipairs(references) do
+ local start_pos = {reference["range"]["start"]["line"], reference["range"]["start"]["character"]}
+ local end_pos = {reference["range"]["end"]["line"], reference["range"]["end"]["character"]}
+ local document_highlight_kind = {
+ [protocol.DocumentHighlightKind.Text] = "LspReferenceText";
+ [protocol.DocumentHighlightKind.Read] = "LspReferenceRead";
+ [protocol.DocumentHighlightKind.Write] = "LspReferenceWrite";
+ }
+ highlight_range(bufnr, reference_ns, document_highlight_kind[reference["kind"]], start_pos, end_pos)
+ end
+ end
+
function M.buf_diagnostics_virtual_text(bufnr, diagnostics)
local buffer_line_diagnostics = all_buffer_diagnostics[bufnr]
if not buffer_line_diagnostics then
@@ -725,6 +749,34 @@ do
api.nvim_buf_set_virtual_text(bufnr, diagnostic_ns, line, virt_texts, {})
end
end
+ function M.buf_diagnostics_count(kind)
+ local bufnr = vim.api.nvim_get_current_buf()
+ local buffer_line_diagnostics = all_buffer_diagnostics[bufnr]
+ if not buffer_line_diagnostics then return end
+ local count = 0
+ for _, line_diags in pairs(buffer_line_diagnostics) do
+ for _, diag in ipairs(line_diags) do
+ if protocol.DiagnosticSeverity[kind] == diag.severity then count = count + 1 end
+ end
+ end
+ return count
+ end
+ function M.buf_diagnostics_signs(bufnr, diagnostics)
+ vim.fn.sign_define('LspDiagnosticsErrorSign', {text=vim.g['LspDiagnosticsErrorSign'] or 'E', texthl='LspDiagnosticsError', linehl='', numhl=''})
+ vim.fn.sign_define('LspDiagnosticsWarningSign', {text=vim.g['LspDiagnosticsWarningSign'] or 'W', texthl='LspDiagnosticsWarning', linehl='', numhl=''})
+ vim.fn.sign_define('LspDiagnosticsInformationSign', {text=vim.g['LspDiagnosticsInformationSign'] or 'I', texthl='LspDiagnosticsInformation', linehl='', numhl=''})
+ vim.fn.sign_define('LspDiagnosticsHintSign', {text=vim.g['LspDiagnosticsHintSign'] or 'H', texthl='LspDiagnosticsHint', linehl='', numhl=''})
+
+ for _, diagnostic in ipairs(diagnostics) do
+ local diagnostic_severity_map = {
+ [protocol.DiagnosticSeverity.Error] = "LspDiagnosticsErrorSign";
+ [protocol.DiagnosticSeverity.Warning] = "LspDiagnosticsWarningSign";
+ [protocol.DiagnosticSeverity.Information] = "LspDiagnosticsInformationSign";
+ [protocol.DiagnosticSeverity.Hint] = "LspDiagnosticsHintSign";
+ }
+ vim.fn.sign_place(0, sign_ns, diagnostic_severity_map[diagnostic.severity], bufnr, {lnum=(diagnostic.range.start.line+1)})
+ end
+ end
end
local position_sort = sort_by_key(function(v)