navigator.lua/lua/navigator/definition.lua

211 lines
6.7 KiB
Lua
Raw Normal View History

2021-12-29 04:50:41 +00:00
local util = require('navigator.util')
local lsphelper = require('navigator.lspwrapper')
2021-04-19 02:56:32 +00:00
local locations_to_items = lsphelper.locations_to_items
2021-12-29 04:50:41 +00:00
local gui = require('navigator.gui')
2021-04-19 02:56:32 +00:00
local log = util.log
2022-07-07 04:02:14 +00:00
local trace = util.trace
2021-12-29 04:50:41 +00:00
local TextView = require('guihua.textview')
2021-04-19 02:56:32 +00:00
-- callback for lsp definition, implementation and declaration handler
local definition_hdlr = function(err, locations, ctx, _)
if err ~= nil then
2023-03-09 09:16:11 +00:00
if tostring(err):find('no type definition') or tostring(err):find('invalid range') then
vim.notify('Definition: ' .. tostring(err), vim.log.levels.DEBUG)
return vim.lsp.buf.hover() -- this is a primitive type
elseif tostring(err):find('no identifier') then
return vim.notify('Definition: ' .. tostring(err), vim.log.levels.DEBUG)
end
vim.notify('Defination: ' .. tostring(err) .. vim.inspect(ctx), vim.log.levels.WARN)
return
end
2024-02-02 04:29:27 +00:00
if locations == nil or vim.tbl_isempty(locations) or type(locations) == 'number' then
log(locations)
2021-12-29 04:50:41 +00:00
log('unable to handle request')
vim.notify('Definition not found')
2021-04-19 02:56:32 +00:00
return
end
2022-01-17 05:16:31 +00:00
local oe = require('navigator.util').encoding(ctx.client_id)
2022-07-07 04:02:14 +00:00
locations = util.dedup(locations)
log(locations)
2023-03-09 09:16:11 +00:00
log('found ' .. #locations .. ' locations')
2021-04-19 02:56:32 +00:00
if vim.tbl_islist(locations) then
if #locations > 1 then
local items = locations_to_items(locations)
2023-02-14 12:58:38 +00:00
gui.new_list_view({ items = items, api = 'Definition', title = 'Definition' })
2021-04-19 02:56:32 +00:00
else
2023-03-09 09:16:11 +00:00
local loc = vim.lsp.util.make_position_params()
-- let check if the location is same as current
if
loc.textDocument.uri == locations[1].uri
and loc.position.line == locations[1].range.start.line
and loc.position.character == locations[1].range.start.character
then
vim.lsp.buf.type_definition()
else
vim.lsp.util.jump_to_location(locations[1], oe)
end
2021-04-19 02:56:32 +00:00
end
else
2024-02-02 04:29:27 +00:00
return
2021-04-19 02:56:32 +00:00
end
2024-02-02 04:29:27 +00:00
return true
end
2021-04-19 02:56:32 +00:00
local function get_symbol()
local currentWord = vim.fn.expand('<cword>')
return currentWord
end
2023-03-09 09:16:11 +00:00
local function def_preview(timeout_ms, method)
assert(next(vim.lsp.get_active_clients({ buffer = 0 })), 'Must have a client running')
method = method or 'textDocument/definition'
2021-04-19 02:56:32 +00:00
local params = vim.lsp.util.make_position_params()
local result = vim.lsp.buf_request_sync(0, method, params, timeout_ms or 1000)
2021-04-19 02:56:32 +00:00
if result == nil or vim.tbl_isempty(result) then
vim.notify('No result found: ' .. method, vim.log.levels.WARN)
2024-02-02 04:29:27 +00:00
return
2021-04-19 02:56:32 +00:00
end
log(result)
2024-02-02 04:29:27 +00:00
if not vim.tbl_islist(result) then
return
end
2021-04-19 02:56:32 +00:00
local data = {}
-- result = {vim.tbl_deep_extend("force", {}, unpack(result))}
-- log("def-preview", result)
for _, value in pairs(result) do
if value ~= nil and value.result ~= nil and not vim.tbl_isempty(value.result) then
table.insert(data, value.result[1])
end
2021-04-19 02:56:32 +00:00
end
if vim.tbl_isempty(data) then
vim.notify('No result found: ' .. method, vim.log.levels.WARN)
2024-02-02 04:29:27 +00:00
return
end
local range = data[1].targetRange or data[1].range or data[1].targetSelectionRange
2021-04-19 02:56:32 +00:00
local row = range.start.line
-- in case there are comments
row = math.max(row - 3, 1)
local delta = range.start.line - row + 3
2021-04-19 02:56:32 +00:00
local uri = data[1].uri or data[1].targetUri
if not uri then
return
end
2021-04-19 02:56:32 +00:00
local bufnr = vim.uri_to_bufnr(uri)
if not vim.api.nvim_buf_is_loaded(bufnr) then
vim.fn.bufload(bufnr)
end
2021-12-29 04:50:41 +00:00
local ok, parsers = pcall(require, 'nvim-treesitter.parsers')
2024-02-02 04:29:27 +00:00
if not ok then
return
end
-- TODO: 32/64 should be an option
local lines_num = 64
if range['end'] ~= nil then
lines_num = math.max(lines_num, range['end'].line - range.start.line + 4)
end
if ok then
2021-12-29 04:50:41 +00:00
local ts = require('navigator.treesitter')
local root = parsers.get_parser(bufnr)
log(range)
2022-06-01 15:41:26 +00:00
if ts == nil then
return
end
2021-12-29 04:50:41 +00:00
local def_node = ts.get_node_at_pos({ range['start'].line, range['start'].character }, root)
local sr, _, er, _ = ts.get_node_scope(def_node)
log(sr, er)
lines_num = math.max(lines_num, er - sr + 5) -- comments etc
end
-- TODO: 32 should be an option
2021-12-29 04:50:41 +00:00
local definition = vim.api.nvim_buf_get_lines(bufnr, row, range['end'].line + lines_num, false)
2021-04-19 02:56:32 +00:00
local def_line = vim.api.nvim_buf_get_lines(bufnr, range.start.line, range.start.line + 1, false)
for _ = 1, math.min(3, #definition), 1 do
if #definition[1] < 2 then
table.remove(definition, 1)
delta = delta - 1
row = row + 1
2021-04-19 02:56:32 +00:00
else
break
end
end
local width = 40
2023-03-09 09:16:11 +00:00
local maxwidth = math.floor(vim.api.nvim_get_option('columns') * 0.8)
2022-06-01 15:41:26 +00:00
for _, value in pairs(definition) do
-- log(key, value, width)
width = math.max(width, #value + 4)
width = math.min(maxwidth, width)
end
2021-12-29 04:50:41 +00:00
definition = vim.list_extend({ '  [' .. get_symbol() .. '] Definition: ' }, definition)
local filetype = vim.api.nvim_buf_get_option(bufnr, 'filetype')
2021-04-19 02:56:32 +00:00
-- TODO multiple resuts?
local opts = {
2021-12-29 04:50:41 +00:00
relative = 'cursor',
style = 'minimal',
2021-04-19 02:56:32 +00:00
ft = filetype,
rect = { width = width, height = math.min(#definition + 3, 16), pos_y = 2 }, -- TODO: 16 hardcoded
2021-04-19 02:56:32 +00:00
data = definition,
2021-08-12 13:34:27 +00:00
enter = true,
2021-12-29 04:50:41 +00:00
border = _NgConfigValues.border or 'shadow',
2021-04-19 02:56:32 +00:00
}
2021-08-12 13:34:27 +00:00
local view = TextView:new(opts)
log(view.buf)
vim.keymap.set('n', 'K', function()
local par = vim.lsp.util.make_position_params()
log(row, par, data[1])
par.position.line = par.position.line + row - 1 -- header 1
par.textDocument.uri = data[1].uri
log(par)
local bufnr_org = vim.uri_to_bufnr(data[1].uri)
return vim.lsp.buf_request(bufnr_org, 'textDocument/hover', par)
end, { buffer = view.buf })
2021-04-19 02:56:32 +00:00
delta = delta + 1 -- header
2021-12-29 04:50:41 +00:00
local cmd = 'normal! ' .. tostring(delta) .. 'G'
2021-04-19 02:56:32 +00:00
vim.cmd(cmd)
vim.cmd('set cursorline')
if #def_line > 0 then
local niddle = require('guihua.util').add_escape(def_line[1])
2021-04-20 07:42:03 +00:00
-- log(def_line[1], niddle)
2021-12-29 04:50:41 +00:00
vim.fn.matchadd('Search', niddle)
2021-04-19 02:56:32 +00:00
end
2024-02-02 04:29:27 +00:00
return true -- disable key-remap fallback
2021-04-19 02:56:32 +00:00
-- TODO:
-- https://github.com/oblitum/goyo.vim/blob/master/autoload/goyo.vim#L108-L135
end
2023-03-09 09:16:11 +00:00
local function type_preview(timeout_ms)
return def_preview(timeout_ms, 'textDocument/typeDefinition')
end
local def = function()
local bufnr = vim.api.nvim_get_current_buf()
local ref_params = vim.lsp.util.make_position_params()
2022-06-01 15:41:26 +00:00
vim.lsp.for_each_buffer_client(bufnr, function(client, _, _bufnr)
-- if client.resolved_capabilities.goto_definition then
if client.server_capabilities.definitionProvider then
2021-12-29 04:50:41 +00:00
client.request('textDocument/definition', ref_params, definition_hdlr, _bufnr)
return
end
end)
end
2021-04-19 02:56:32 +00:00
return {
definition = def,
2021-04-19 02:56:32 +00:00
definition_handler = definition_hdlr,
definition_preview = def_preview,
2023-03-09 09:16:11 +00:00
type_definition_preview = type_preview,
2021-04-19 02:56:32 +00:00
declaration_handler = definition_hdlr,
2023-03-09 09:16:11 +00:00
type_definition_handler = definition_hdlr,
2021-04-19 02:56:32 +00:00
}