aboutsummaryrefslogtreecommitdiff
path: root/runtime
diff options
context:
space:
mode:
Diffstat (limited to 'runtime')
-rw-r--r--runtime/autoload/man.vim18
-rw-r--r--runtime/doc/eval.txt17
-rw-r--r--runtime/doc/fold.txt3
-rw-r--r--runtime/doc/lsp.txt92
-rw-r--r--runtime/doc/lua.txt29
-rw-r--r--runtime/doc/options.txt11
-rw-r--r--runtime/doc/sign.txt10
-rw-r--r--runtime/doc/starting.txt13
-rw-r--r--runtime/doc/usr_41.txt1
-rw-r--r--runtime/doc/vim_diff.txt1
-rw-r--r--runtime/lua/vim/lsp.lua34
-rw-r--r--runtime/lua/vim/lsp/buf.lua27
-rw-r--r--runtime/lua/vim/lsp/callbacks.lua44
-rw-r--r--runtime/lua/vim/lsp/log.lua1
-rw-r--r--runtime/lua/vim/lsp/protocol.lua26
-rw-r--r--runtime/lua/vim/lsp/util.lua119
-rw-r--r--runtime/lua/vim/shared.lua18
-rw-r--r--runtime/lua/vim/treesitter.lua46
-rw-r--r--runtime/lua/vim/tshighlighter.lua2
-rw-r--r--runtime/scripts.vim4
20 files changed, 420 insertions, 96 deletions
diff --git a/runtime/autoload/man.vim b/runtime/autoload/man.vim
index 5feab0ce70..122ae357bc 100644
--- a/runtime/autoload/man.vim
+++ b/runtime/autoload/man.vim
@@ -328,18 +328,24 @@ function! man#complete(arg_lead, cmd_line, cursor_pos) abort
return s:complete(sect, sect, name)
endfunction
-function! s:get_paths(sect, name) abort
+function! s:get_paths(sect, name, do_fallback) abort
+ " callers must try-catch this, as some `man` implementations don't support `s:find_arg`
try
let mandirs = join(split(s:system(['man', s:find_arg]), ':\|\n'), ',')
+ return globpath(mandirs,'man?/'.a:name.'*.'.a:sect.'*', 0, 1)
catch
- call s:error(v:exception)
- return
+ if !a:do_fallback
+ throw v:exception
+ endif
+
+ " fallback to a single path, with the page we're trying to find
+ let [l:sect, l:name, l:path] = s:verify_exists(a:sect, a:name)
+ return [l:path]
endtry
- return globpath(mandirs,'man?/'.a:name.'*.'.a:sect.'*', 0, 1)
endfunction
function! s:complete(sect, psect, name) abort
- let pages = s:get_paths(a:sect, a:name)
+ let pages = s:get_paths(a:sect, a:name, v:false)
" We remove duplicates in case the same manpage in different languages was found.
return uniq(sort(map(pages, 's:format_candidate(v:val, a:psect)'), 'i'))
endfunction
@@ -387,7 +393,7 @@ endfunction
function! man#goto_tag(pattern, flags, info) abort
let [l:sect, l:name] = man#extract_sect_and_name_ref(a:pattern)
- let l:paths = s:get_paths(l:sect, l:name)
+ let l:paths = s:get_paths(l:sect, l:name, v:true)
let l:structured = []
for l:path in l:paths
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index 113a92d5e4..29c5c37bcd 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -2110,6 +2110,7 @@ extend({expr1}, {expr2} [, {expr3}])
exp({expr}) Float exponential of {expr}
expand({expr} [, {nosuf} [, {list}]])
any expand special keywords in {expr}
+expandcmd({expr}) String expand {expr} like with `:edit`
feedkeys({string} [, {mode}]) Number add key sequence to typeahead buffer
filereadable({file}) Number |TRUE| if {file} is a readable file
filewritable({file}) Number |TRUE| if {file} is a writable file
@@ -3733,6 +3734,14 @@ expand({expr} [, {nosuf} [, {list}]]) *expand()*
See |glob()| for finding existing files. See |system()| for
getting the raw output of an external command.
+expandcmd({expr}) *expandcmd()*
+ Expand special items in {expr} like what is done for an Ex
+ command such as `:edit`. This expands special keywords, like
+ with |expand()|, and environment variables, anywhere in
+ {expr}. Returns the expanded string.
+ Example: >
+ :echo expandcmd('make %<.o')
+<
extend({expr1}, {expr2} [, {expr3}]) *extend()*
{expr1} and {expr2} must be both |Lists| or both
|Dictionaries|.
@@ -7809,7 +7818,7 @@ sign_getplaced([{expr} [, {dict}]]) *sign_getplaced()*
priority sign priority
The returned signs in a buffer are ordered by their line
- number.
+ number and priority.
Returns an empty list on failure or if there are no placed
signs.
@@ -10370,8 +10379,8 @@ text...
The parsing works slightly different from |:echo|,
more like |:execute|. All the expressions are first
evaluated and concatenated before echoing anything.
- The expressions must evaluate to a Number or String, a
- Dictionary or List causes an error.
+ If expressions does not evaluate to a Number or
+ String, string() is used to turn it into a string.
Uses the highlighting set by the |:echohl| command.
Example: >
:echomsg "It's a Zizzer Zazzer Zuzz, as you can plainly see."
@@ -10382,7 +10391,7 @@ text...
message in the |message-history|. When used in a
script or function the line number will be added.
Spaces are placed between the arguments as with the
- :echo command. When used inside a try conditional,
+ |:echomsg| command. When used inside a try conditional,
the message is raised as an error exception instead
(see |try-echoerr|).
Example: >
diff --git a/runtime/doc/fold.txt b/runtime/doc/fold.txt
index f2f6c70b0c..8e2cb2f728 100644
--- a/runtime/doc/fold.txt
+++ b/runtime/doc/fold.txt
@@ -527,8 +527,7 @@ FOLDCOLUMN *fold-foldcolumn*
'foldcolumn' is a number, which sets the width for a column on the side of the
window to indicate folds. When it is zero, there is no foldcolumn. A normal
-value is 4 or 5. The minimal useful value is 2, although 1 still provides
-some information. The maximum is 12.
+value is auto:9. The maximum is 9.
An open fold is indicated with a column that has a '-' at the top and '|'
characters below it. This column stops where the open fold stops. When folds
diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt
index 9de2aaf592..2f5427f6fc 100644
--- a/runtime/doc/lsp.txt
+++ b/runtime/doc/lsp.txt
@@ -48,6 +48,7 @@ go-to-definition, hover, etc. Example config: >
nnoremap <silent> <c-k> <cmd>lua vim.lsp.buf.signature_help()<CR>
nnoremap <silent> 1gD <cmd>lua vim.lsp.buf.type_definition()<CR>
nnoremap <silent> gr <cmd>lua vim.lsp.buf.references()<CR>
+ nnoremap <silent> g0 <cmd>lua vim.lsp.buf.document_symbol()<CR>
Nvim provides the |vim.lsp.omnifunc| 'omnifunc' handler which allows
|i_CTRL-X_CTRL-O| to consume LSP completion. Example config (note the use of
@@ -77,21 +78,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 +160,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 +295,12 @@ The example will:
<
+==============================================================================
+AUTOCOMMANDS *lsp-autocommands*
+
+ *LspDiagnosticsChanged*
+LspDiagnosticsChanged After receiving publishDiagnostics server response
+
==============================================================================
Lua module: vim.lsp *lsp-core*
@@ -333,7 +344,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 +731,12 @@ declaration() *vim.lsp.buf.declaration()*
definition() *vim.lsp.buf.definition()*
TODO: Documentation
+document_highlight() *vim.lsp.buf.document_highlight()*
+ TODO: Documentation
+
+document_symbol() *vim.lsp.buf.document_symbol()*
+ TODO: Documentation
+
formatting({options}) *vim.lsp.buf.formatting()*
TODO: Documentation
@@ -751,6 +768,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 +917,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 +957,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/doc/lua.txt b/runtime/doc/lua.txt
index c113a70027..800f24b5c9 100644
--- a/runtime/doc/lua.txt
+++ b/runtime/doc/lua.txt
@@ -693,6 +693,35 @@ identical identifiers, highlighting both as |hl-WarningMsg|: >
(eq? @WarningMsg.left @WarningMsg.right))
------------------------------------------------------------------------------
+VIM.REGEX *lua-regex*
+
+Vim regexes can be used directly from lua. Currently they only allow
+matching within a single line.
+
+vim.regex({re}) *vim.regex()*
+
+ Parse the regex {re} and return a regex object. 'magic' and
+ 'ignorecase' options are ignored, lua regexes always defaults to magic
+ and ignoring case. The behavior can be changed with flags in
+ the beginning of the string |/magic|.
+
+Regex objects support the following methods:
+
+regex:match_str({str}) *regex:match_str()*
+ Match the string against the regex. If the string should match the
+ regex precisely, surround the regex with `^` and `$`.
+ If the was a match, the byte indices for the beginning and end of
+ the match is returned. When there is no match, `nil` is returned.
+ As any integer is truth-y, `regex:match()` can be directly used
+ as a condition in an if-statement.
+
+regex:match_line({bufnr}, {line_idx}[, {start}, {end}]) *regex:match_line()*
+ Match line {line_idx} (zero-based) in buffer {bufnr}. If {start} and
+ {end} are supplied, match only this byte index range. Otherwise see
+ |regex:match_str()|. If {start} is used, then the returned byte
+ indices will be relative {start}.
+
+------------------------------------------------------------------------------
VIM *lua-builtin*
vim.api.{func}({...}) *vim.api*
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
index 7107a0135d..283b2c3f12 100644
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -2421,11 +2421,14 @@ A jump table for the options with a short description can be found at |Q_op|.
automatically close when moving out of them.
*'foldcolumn'* *'fdc'*
-'foldcolumn' 'fdc' number (default 0)
+'foldcolumn' 'fdc' string (default "0")
local to window
- When non-zero, a column with the specified width is shown at the side
- of the window which indicates open and closed folds. The maximum
- value is 12.
+ When and how to draw the foldcolumn. Valid values are:
+ "auto": resize to the maximum amount of folds to display.
+ "auto:[1-9]": resize to accommodate multiple folds up to the
+ selected level
+ 0: to disable foldcolumn
+ "[1-9]": to display a fixed number of columns
See |folding|.
*'foldenable'* *'fen'* *'nofoldenable'* *'nofen'*
diff --git a/runtime/doc/sign.txt b/runtime/doc/sign.txt
index 4e0d91dae0..e3ba4ba181 100644
--- a/runtime/doc/sign.txt
+++ b/runtime/doc/sign.txt
@@ -176,9 +176,9 @@ See |sign_place()| for the equivalent Vim script function.
By default, the sign is assigned a default priority of 10. To
assign a different priority value, use "priority={prio}" to
- specify a value. The priority is used to determine the
- highlight group used when multiple signs are placed on the
- same line.
+ specify a value. The priority is used to determine the sign
+ that is displayed when multiple signs are placed on the same
+ line.
Examples: >
:sign place 5 line=3 name=sign1 file=a.py
@@ -198,7 +198,9 @@ See |sign_place()| for the equivalent Vim script function.
it (e.g., when the debugger has stopped at a breakpoint).
The optional "group={group}" attribute can be used before
- "file=" to select a sign in a particular group.
+ "file=" to select a sign in a particular group. The optional
+ "priority={prio}" attribute can be used to change the priority
+ of an existing sign.
:sign place {id} name={name} [buffer={nr}]
Same, but use buffer {nr}. If the buffer argument is not
diff --git a/runtime/doc/starting.txt b/runtime/doc/starting.txt
index e3f0d593a7..af7d233619 100644
--- a/runtime/doc/starting.txt
+++ b/runtime/doc/starting.txt
@@ -184,12 +184,17 @@ argument.
the 'modifiable' and 'write' options can be set to enable
changes and writing.
- *-Z* *restricted-mode* *E145*
+ *-Z* *restricted-mode* *E145* *E981*
-Z Restricted mode. All commands that make use of an external
shell are disabled. This includes suspending with CTRL-Z,
- ":sh", filtering, the system() function, backtick expansion,
- delete(), rename(), mkdir(), writefile(), libcall(),
- jobstart(), etc.
+ ":sh", filtering, the system() function, backtick expansion
+ and libcall().
+ Also disallowed are delete(), rename(), mkdir(), jobstart(),
+ etc.
+ Interfaces, such as Python, Ruby and Lua, are also disabled,
+ since they could be used to execute shell commands.
+ Note that the user may still find a loophole to execute a
+ shell command, it has only been made difficult.
-e *-e* *-E*
-E Start Nvim in Ex mode |gQ|.
diff --git a/runtime/doc/usr_41.txt b/runtime/doc/usr_41.txt
index 5f9253cbd0..234f7801ab 100644
--- a/runtime/doc/usr_41.txt
+++ b/runtime/doc/usr_41.txt
@@ -609,6 +609,7 @@ String manipulation: *string-functions*
strcharpart() get part of a string using char index
strgetchar() get character from a string using char index
expand() expand special keywords
+ expandcmd() expand a command like done for `:edit`
iconv() convert text from one encoding to another
byteidx() byte index of a character in a string
byteidxcomp() like byteidx() but count composing characters
diff --git a/runtime/doc/vim_diff.txt b/runtime/doc/vim_diff.txt
index 5835c7f314..376375e4ef 100644
--- a/runtime/doc/vim_diff.txt
+++ b/runtime/doc/vim_diff.txt
@@ -201,6 +201,7 @@ Options:
'guicursor' works in the terminal
'fillchars' flags: "msgsep" (see 'display'), "eob" for |hl-EndOfBuffer|
marker, "foldopen", "foldsep", "foldclose"
+ 'foldcolumn' supports up to 9 dynamic/fixed columns
'inccommand' shows interactive results for |:substitute|-like commands
'listchars' local to window
'pumblend' pseudo-transparent popupmenu
diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua
index 8190542955..afff4d9900 100644
--- a/runtime/lua/vim/lsp.lua
+++ b/runtime/lua/vim/lsp.lua
@@ -101,7 +101,7 @@ local function for_each_buffer_client(bufnr, callback)
for client_id in pairs(client_ids) do
local client = active_clients[client_id]
if client then
- callback(client, client_id)
+ callback(client, client_id, bufnr)
end
end
end
@@ -520,23 +520,24 @@ function lsp.start_client(config)
end
--- Checks capabilities before rpc.request-ing.
- function client.request(method, params, callback)
+ function client.request(method, params, callback, bufnr)
if not callback then
callback = resolve_callback(method)
or error("not found: request callback for client "..client.name)
end
- local _ = log.debug() and log.debug(log_prefix, "client.request", client_id, method, params, callback)
+ local _ = log.debug() and log.debug(log_prefix, "client.request", client_id, method, params, callback, bufnr)
-- TODO keep these checks or just let it go anyway?
if (not client.resolved_capabilities.hover and method == 'textDocument/hover')
or (not client.resolved_capabilities.signature_help and method == 'textDocument/signatureHelp')
or (not client.resolved_capabilities.goto_definition and method == 'textDocument/definition')
or (not client.resolved_capabilities.implementation and method == 'textDocument/implementation')
+ or (not client.resolved_capabilities.document_symbol and method == 'textDocument/documentSymbol')
then
- callback(unsupported_method(method), method, nil, client_id)
+ callback(unsupported_method(method), method, nil, client_id, bufnr)
return
end
return rpc.request(method, params, function(err, result)
- callback(err, method, result, client_id)
+ callback(err, method, result, client_id, bufnr)
end)
end
@@ -838,8 +839,8 @@ function lsp.buf_request(bufnr, method, params, callback)
callback = { callback, 'f', true };
}
local client_request_ids = {}
- for_each_buffer_client(bufnr, function(client, client_id)
- local request_success, request_id = client.request(method, params, callback)
+ for_each_buffer_client(bufnr, function(client, client_id, resolved_bufnr)
+ local request_success, request_id = client.request(method, params, callback, resolved_bufnr)
-- This could only fail if the client shut down in the time since we looked
-- it up and we did the request, which should be rare.
@@ -895,21 +896,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' };
}
- for_each_buffer_client(bufnr, function(client, _client_id)
- client.rpc.notify(method, params)
+ local resp = false
+ for_each_buffer_client(bufnr, function(client, _client_id, _resolved_bufnr)
+ 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..fc9e10cb73 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,28 @@ function M.references(context)
request('textDocument/references', params)
end
+function M.document_symbol()
+ local params = { textDocument = util.make_text_document_params() }
+ request('textDocument/documentSymbol', 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..644c12f98c 100644
--- a/runtime/lua/vim/lsp/callbacks.lua
+++ b/runtime/lua/vim/lsp/callbacks.lua
@@ -32,12 +32,19 @@ 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.set_loclist(result.diagnostics)
+ util.buf_diagnostics_signs(bufnr, result.diagnostics)
+ vim.api.nvim_command("doautocmd User LspDiagnosticsChanged")
end
M['textDocument/references'] = function(_, _, result)
if not result then return end
- util.set_qflist(result)
+ util.set_qflist(util.locations_to_items(result))
+end
+
+M['textDocument/documentSymbol'] = function(_, _, result, _, bufnr)
+ if not result or vim.tbl_isempty(result) then return end
+
+ util.set_qflist(util.symbols_to_items(result, bufnr))
api.nvim_command("copen")
api.nvim_command("wincmd p")
end
@@ -96,7 +103,7 @@ local function location_callback(_, method, result)
end
util.jump_to_location(result[1])
if #result > 1 then
- util.set_qflist(result)
+ util.set_qflist(util.locations_to_items(result))
api.nvim_command("copen")
api.nvim_command("wincmd p")
end
@@ -196,7 +203,33 @@ M['textDocument/peekDefinition'] = function(_, _, result, _)
api.nvim_buf_add_highlight(headbuf, -1, 'Keyword', 0, -1)
end
-local function log_message(_, _, result, client_id)
+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
+
+M['window/logMessage'] = function(_, _, result, client_id)
+ local message_type = result.type
+ local message = result.message
+ local client = vim.lsp.get_client_by_id(client_id)
+ local client_name = client and client.name or string.format("id=%d", client_id)
+ if not client then
+ err_message("LSP[", client_name, "] client has shut down after sending the message")
+ end
+ if message_type == protocol.MessageType.Error then
+ log.error(message)
+ elseif message_type == protocol.MessageType.Warning then
+ log.warn(message)
+ elseif message_type == protocol.MessageType.Info then
+ log.info(message)
+ else
+ log.debug(message)
+ end
+ return result
+end
+
+M['window/showMessage'] = function(_, _, result, client_id)
local message_type = result.type
local message = result.message
local client = vim.lsp.get_client_by_id(client_id)
@@ -213,9 +246,6 @@ local function log_message(_, _, result, client_id)
return result
end
-M['window/showMessage'] = log_message
-M['window/logMessage'] = log_message
-
-- Add boilerplate error validation and logging for all of these.
for k, fn in pairs(M) do
M[k] = function(err, method, params, client_id)
diff --git a/runtime/lua/vim/lsp/log.lua b/runtime/lua/vim/lsp/log.lua
index 974eaae38c..c0db5e5485 100644
--- a/runtime/lua/vim/lsp/log.lua
+++ b/runtime/lua/vim/lsp/log.lua
@@ -13,7 +13,6 @@ log.levels = {
INFO = 2;
WARN = 3;
ERROR = 4;
- -- FATAL = 4;
}
-- Default log level is warn.
diff --git a/runtime/lua/vim/lsp/protocol.lua b/runtime/lua/vim/lsp/protocol.lua
index f64b0b50e7..41e8119c8c 100644
--- a/runtime/lua/vim/lsp/protocol.lua
+++ b/runtime/lua/vim/lsp/protocol.lua
@@ -663,19 +663,19 @@ function protocol.make_client_capabilities()
documentHighlight = {
dynamicRegistration = false
};
- -- documentSymbol = {
- -- dynamicRegistration = false;
- -- symbolKind = {
- -- valueSet = (function()
- -- local res = {}
- -- for k in pairs(protocol.SymbolKind) do
- -- if type(k) == 'string' then table.insert(res, k) end
- -- end
- -- return res
- -- end)();
- -- };
- -- hierarchicalDocumentSymbolSupport = false;
- -- };
+ documentSymbol = {
+ dynamicRegistration = false;
+ symbolKind = {
+ valueSet = (function()
+ local res = {}
+ for k in pairs(protocol.SymbolKind) do
+ if type(k) == 'number' then table.insert(res, k) end
+ end
+ return res
+ end)();
+ };
+ hierarchicalDocumentSymbolSupport = true;
+ };
};
workspace = nil;
experimental = nil;
diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua
index 3dfe4d7d02..5dd010f2a4 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)
@@ -745,7 +797,7 @@ function M.locations_to_items(locations)
for _, d in ipairs(locations) do
local start = d.range.start
local fname = assert(vim.uri_to_fname(d.uri))
- table.insert(grouped[fname], {start = start, msg= d.message })
+ table.insert(grouped[fname], {start = start})
end
@@ -772,7 +824,7 @@ function M.locations_to_items(locations)
filename = fname,
lnum = row + 1,
col = col + 1;
- text = temp.msg;
+ text = line;
})
end
end
@@ -782,23 +834,60 @@ function M.locations_to_items(locations)
return items
end
--- locations is Location[]
--- Only sets for the current window.
-function M.set_loclist(locations)
+function M.set_loclist(items)
vim.fn.setloclist(0, {}, ' ', {
title = 'Language Server';
- items = M.locations_to_items(locations);
+ items = items;
})
end
--- locations is Location[]
-function M.set_qflist(locations)
+function M.set_qflist(items)
vim.fn.setqflist({}, ' ', {
title = 'Language Server';
- items = M.locations_to_items(locations);
+ items = items;
})
end
+--- Convert symbols to quickfix list items
+---
+--@symbols DocumentSymbol[] or SymbolInformation[]
+function M.symbols_to_items(symbols, bufnr)
+ local function _symbols_to_items(_symbols, _items, _bufnr)
+ for _, symbol in ipairs(_symbols) do
+ if symbol.location then -- SymbolInformation type
+ local range = symbol.location.range
+ local kind = protocol.SymbolKind[symbol.kind]
+ table.insert(_items, {
+ filename = vim.uri_to_fname(symbol.location.uri),
+ lnum = range.start.line + 1,
+ col = range.start.character + 1,
+ kind = kind,
+ text = '['..kind..'] '..symbol.name,
+ })
+ elseif symbol.range then -- DocumentSymbole type
+ local kind = protocol.SymbolKind[symbol.kind]
+ table.insert(_items, {
+ -- bufnr = _bufnr,
+ filename = vim.api.nvim_buf_get_name(_bufnr),
+ lnum = symbol.range.start.line + 1,
+ col = symbol.range.start.character + 1,
+ kind = kind,
+ text = '['..kind..'] '..symbol.name
+ })
+ if symbol.children then
+ for _, child in ipairs(symbol) do
+ for _, v in ipairs(_symbols_to_items(child, _items, _bufnr)) do
+ vim.list_extend(_items, v)
+ end
+ end
+ end
+ end
+ end
+ return _items
+ end
+ return _symbols_to_items(symbols, {}, bufnr)
+end
+
-- Remove empty lines from the beginning and end.
function M.trim_empty_lines(lines)
local start = 1
@@ -851,11 +940,15 @@ function M.make_position_params()
local line = api.nvim_buf_get_lines(0, row, row+1, true)[1]
col = str_utfindex(line, col)
return {
- textDocument = { uri = vim.uri_from_bufnr(0) };
+ textDocument = M.make_text_document_params();
position = { line = row; character = col; }
}
end
+function M.make_text_document_params()
+ return { uri = vim.uri_from_bufnr(0) }
+end
+
-- @param buf buffer handle or 0 for current.
-- @param row 0-indexed line
-- @param col 0-indexed byte offset in line
diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua
index 498992aa2e..1bf1c63fd7 100644
--- a/runtime/lua/vim/shared.lua
+++ b/runtime/lua/vim/shared.lua
@@ -356,6 +356,24 @@ function vim.tbl_islist(t)
end
end
+--- Counts the number of non-nil values in table `t`.
+---
+--- <pre>
+--- vim.tbl_count({ a=1, b=2 }) => 2
+--- vim.tbl_count({ 1, 2 }) => 2
+--- </pre>
+---
+--@see https://github.com/Tieske/Penlight/blob/master/lua/pl/tablex.lua
+--@param Table
+--@returns Number that is the number of the value in table
+function vim.tbl_count(t)
+ vim.validate{t={t,'t'}}
+
+ local count = 0
+ for _ in pairs(t) do count = count + 1 end
+ return count
+end
+
--- Trim whitespace (Lua pattern "%s") from both sides of a string.
---
--@see https://www.lua.org/pil/20.2.html
diff --git a/runtime/lua/vim/treesitter.lua b/runtime/lua/vim/treesitter.lua
index 0d0e22adb3..8dacfa11cf 100644
--- a/runtime/lua/vim/treesitter.lua
+++ b/runtime/lua/vim/treesitter.lua
@@ -113,12 +113,33 @@ end
local Query = {}
Query.__index = Query
+local magic_prefixes = {['\\v']=true, ['\\m']=true, ['\\M']=true, ['\\V']=true}
+local function check_magic(str)
+ if string.len(str) < 2 or magic_prefixes[string.sub(str,1,2)] then
+ return str
+ end
+ return '\\v'..str
+end
+
function M.parse_query(lang, query)
M.require_language(lang)
local self = setmetatable({}, Query)
self.query = vim._ts_parse_query(lang, query)
self.info = self.query:inspect()
self.captures = self.info.captures
+ self.regexes = {}
+ for id,preds in pairs(self.info.patterns) do
+ local regexes = {}
+ for i, pred in ipairs(preds) do
+ if (pred[1] == "match?" and type(pred[2]) == "number"
+ and type(pred[3]) == "string") then
+ regexes[i] = vim.regex(check_magic(pred[3]))
+ end
+ end
+ if next(regexes) then
+ self.regexes[id] = regexes
+ end
+ end
return self
end
@@ -131,8 +152,13 @@ local function get_node_text(node, bufnr)
return string.sub(line, start_col+1, end_col)
end
-local function match_preds(match, preds, bufnr)
- for _, pred in pairs(preds) do
+function Query:match_preds(match, pattern, bufnr)
+ local preds = self.info.patterns[pattern]
+ if not preds then
+ return true
+ end
+ local regexes = self.regexes[pattern]
+ for i, pred in pairs(preds) do
if pred[1] == "eq?" then
local node = match[pred[2]]
local node_text = get_node_text(node, bufnr)
@@ -149,6 +175,16 @@ local function match_preds(match, preds, bufnr)
if node_text ~= str or str == nil then
return false
end
+ elseif pred[1] == "match?" then
+ if not regexes or not regexes[i] then
+ return false
+ end
+ local node = match[pred[2]]
+ local start_row, start_col, end_row, end_col = node:range()
+ if start_row ~= end_row then
+ return false
+ end
+ return regexes[i]:match_line(bufnr, start_row, start_col, end_col)
else
return false
end
@@ -164,8 +200,7 @@ function Query:iter_captures(node, bufnr, start, stop)
local function iter()
local capture, captured_node, match = raw_iter()
if match ~= nil then
- local preds = self.info.patterns[match.pattern]
- local active = match_preds(match, preds, bufnr)
+ local active = self:match_preds(match, match.pattern, bufnr)
match.active = active
if not active then
return iter() -- tail call: try next match
@@ -184,8 +219,7 @@ function Query:iter_matches(node, bufnr, start, stop)
local function iter()
local pattern, match = raw_iter()
if match ~= nil then
- local preds = self.info.patterns[pattern]
- local active = (not preds) or match_preds(match, preds, bufnr)
+ local active = self:match_preds(match, pattern, bufnr)
if not active then
return iter() -- tail call: try next match
end
diff --git a/runtime/lua/vim/tshighlighter.lua b/runtime/lua/vim/tshighlighter.lua
index 9d094f0f9a..1440acf0d0 100644
--- a/runtime/lua/vim/tshighlighter.lua
+++ b/runtime/lua/vim/tshighlighter.lua
@@ -69,6 +69,8 @@ function TSHighlighter:set_query(query)
end
self.id_map[i] = hl
end
+
+ a.nvim__buf_redraw_range(self.buf, 0, a.nvim_buf_line_count(self.buf))
end
function TSHighlighter:on_change(changes)
diff --git a/runtime/scripts.vim b/runtime/scripts.vim
index a690431014..c552f0202f 100644
--- a/runtime/scripts.vim
+++ b/runtime/scripts.vim
@@ -376,6 +376,10 @@ else
elseif s:line1 =~? '-\*-.*erlang.*-\*-'
set ft=erlang
+ " YAML
+ elseif s:line1 =~# '^%YAML'
+ set ft=yaml
+
" CVS diff
else
let s:lnum = 1