Add support for textDocument/references.

Add set_qflist and set_loclist.
- Also add locations_to_items, which calculates byte offsets for
character positions in files and avoids unnecessary operations.
This commit is contained in:
Ashkan Kiani
2019-11-24 03:01:18 -08:00
parent b78fdd7ce5
commit b35f6aa9dd
3 changed files with 79 additions and 22 deletions

View File

@@ -1,3 +1,4 @@
local vim = vim
local validate = vim.validate
local api = vim.api
local vfn = vim.fn
@@ -330,5 +331,19 @@ function M.rename(new_name)
end)
end
function M.references(context)
validate { context = { context, 't', true } }
local params = util.make_position_params()
params.context = context or {
includeDeclaration = true;
}
params[vim.type_idx] = vim.types.dictionary
request('textDocument/references', params, function(_, _, result)
if not result then return end
util.set_qflist(result)
vim.api.nvim_command("copen")
end)
end
return M
-- vim:sw=2 ts=2 et

View File

@@ -31,7 +31,7 @@ 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_loclist(bufnr, result.diagnostics)
-- util.set_loclist(result.diagnostics)
end
local function log_message(_, _, result, client_id)

View File

@@ -1,4 +1,5 @@
local protocol = require 'vim.lsp.protocol'
local vim = vim
local validate = vim.validate
local api = vim.api
@@ -573,30 +574,71 @@ do
end
end
function M.buf_loclist(bufnr, locations)
local targetwin
for _, winnr in ipairs(api.nvim_list_wins()) do
local winbuf = api.nvim_win_get_buf(winnr)
if winbuf == bufnr then
targetwin = winnr
break
end
end
if not targetwin then return end
local position_sort = sort_by_key(function(v)
return {v.line, v.character}
end)
-- Returns the items with the byte position calculated correctly and in sorted
-- order.
function M.locations_to_items(locations)
local items = {}
local path = api.nvim_buf_get_name(bufnr)
local grouped = setmetatable({}, {
__index = function(t, k)
local v = {}
rawset(t, k, v)
return v
end;
})
for _, d in ipairs(locations) do
-- TODO: URL parsing here?
local start = d.range.start
local fname = assert(vim.uri_to_fname(d.uri))
table.insert(grouped[fname], start)
end
local keys = vim.tbl_keys(grouped)
table.sort(keys)
-- TODO(ashkan) I wish we could do this lazily.
for _, fname in ipairs(keys) do
local rows = grouped[fname]
table.sort(rows, position_sort)
local i = 0
for line in io.lines(fname) do
for _, pos in ipairs(rows) do
local row = pos.line
if i == row then
local col
if pos.character > #line then
col = #line
else
col = vim.str_byteindex(line, pos.character)
end
table.insert(items, {
filename = path,
lnum = start.line + 1,
col = start.character + 1,
text = d.message,
filename = fname,
lnum = row + 1,
col = col + 1;
})
end
vim.fn.setloclist(targetwin, items, ' ', 'Language Server')
end
i = i + 1
end
end
return items
end
-- locations is Location[]
-- Only sets for the current window.
function M.set_loclist(locations)
vim.fn.setloclist(0, {}, ' ', {
title = 'Language Server';
items = M.locations_to_items(locations);
})
end
-- locations is Location[]
function M.set_qflist(locations)
vim.fn.setqflist({}, ' ', {
title = 'Language Server';
items = M.locations_to_items(locations);
})
end
-- Remove empty lines from the beginning and end.