aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/lua/vim/lsp.lua7
-rw-r--r--runtime/lua/vim/lsp/tagfunc.lua72
2 files changed, 79 insertions, 0 deletions
diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua
index 0fc0a7a7aa..6254bb542a 100644
--- a/runtime/lua/vim/lsp.lua
+++ b/runtime/lua/vim/lsp.lua
@@ -1587,6 +1587,13 @@ function lsp.formatexpr(opts)
return 0
end
+-- Provides an interface between the built-in client and `tagfunc`
+--
+-- Used via `set tagfunc=v:lua.vim.lsp.tagfunc`
+function lsp.tagfunc(...)
+ return require('vim.lsp.tagfunc')(...)
+end
+
---Checks whether a client is stopped.
---
---@param client_id (Number)
diff --git a/runtime/lua/vim/lsp/tagfunc.lua b/runtime/lua/vim/lsp/tagfunc.lua
new file mode 100644
index 0000000000..a18397623b
--- /dev/null
+++ b/runtime/lua/vim/lsp/tagfunc.lua
@@ -0,0 +1,72 @@
+local lsp = vim.lsp
+local util = vim.lsp.util
+
+local function mk_tag_item(name, range, uri, offset_encoding)
+ local bufnr = vim.uri_to_bufnr(uri)
+ -- This is get_line_byte_from_position is 0-indexed, call cursor expects a 1-indexed position
+ local byte = util._get_line_byte_from_position(bufnr, range.start, offset_encoding) + 1
+ return {
+ name = name,
+ filename = vim.uri_to_fname(uri),
+ cmd = string.format('call cursor(%d, %d)|', range.start.line + 1, byte),
+ }
+end
+
+local function query_definition(pattern)
+ local params = lsp.util.make_position_params()
+ local results_by_client, err = lsp.buf_request_sync(0, 'textDocument/definition', params, 1000)
+ if err then
+ return {}
+ end
+ local results = {}
+ local add = function(range, uri, offset_encoding)
+ table.insert(results, mk_tag_item(pattern, range, uri, offset_encoding))
+ end
+ for client_id, lsp_results in pairs(results_by_client) do
+ local client = lsp.get_client_by_id(client_id)
+ local result = lsp_results.result or {}
+ if result.range then -- Location
+ add(result.range, result.uri)
+ else -- Location[] or LocationLink[]
+ for _, item in pairs(result) do
+ if item.range then -- Location
+ add(item.range, item.uri, client.offset_encoding)
+ else -- LocationLink
+ add(item.targetSelectionRange, item.targetUri, client.offset_encoding)
+ end
+ end
+ end
+ end
+ return results
+end
+
+local function query_workspace_symbols(pattern)
+ local results_by_client, err = lsp.buf_request_sync(0, 'workspace/symbol', { query = pattern }, 1000)
+ if err then
+ return {}
+ end
+ local results = {}
+ for client_id, symbols in pairs(results_by_client) do
+ local client = lsp.get_client_by_id(client_id)
+ for _, symbol in pairs(symbols.result or {}) do
+ local loc = symbol.location
+ local item = mk_tag_item(symbol.name, loc.range, loc.uri, client.offset_encoding)
+ item.kind = lsp.protocol.SymbolKind[symbol.kind] or 'Unknown'
+ table.insert(results, item)
+ end
+ end
+ return results
+end
+
+local function tagfunc(pattern, flags)
+ local matches
+ if string.match(flags, 'c') then
+ matches = query_definition(pattern)
+ else
+ matches = query_workspace_symbols(pattern)
+ end
+ -- fall back to tags if no matches
+ return #matches > 0 and matches or vim.NIL
+end
+
+return tagfunc