merge changes for treesitter symbole context

mine
ray-x 2 years ago
parent a7886fc055
commit edee3e39c6

@ -264,6 +264,7 @@ require'navigator'.setup({
-- please check mapping.lua for all keymaps
treesitter_analysis = true, -- treesitter variable context
treesitter_analysis_max_num = 100, -- how many items to run treesitter analysis
treesitter_analysis_condense = true, -- condense form for treesitter analysis
-- this value prevent slow in large projects, e.g. found 100000 reference in a project
transparency = 50, -- 0 ~ 100 blur the main window, 100: fully transparent, 0: opaque, set to nil or 100 to disable it

@ -32,11 +32,15 @@ _NgConfigValues = {
ts_fold = false,
treesitter_analysis = true, -- treesitter variable context
treesitter_analysis_max_num = 100, -- how many items to run treesitter analysis
treesitter_analysis_condense = true, -- short format of function
transparency = 50, -- 0 ~ 100 blur the main window, 100: fully transparent, 0: opaque, set to nil to disable it
lsp_signature_help = true, -- if you would like to hook ray-x/lsp_signature plugin in navigator
-- setup here. if it is nil, navigator will not init signature help
signature_help_cfg = { debug = false }, -- if you would like to init ray-x/lsp_signature plugin in navigator, pass in signature help
ctags = { cmd = 'ctags', tagfile = '.tags', options = '-R --exclude=.git --exclude=node_modules --exclude=test --exclude=vendor --excmd=number',
ctags = {
cmd = 'ctags',
tagfile = '.tags',
options = '-R --exclude=.git --exclude=node_modules --exclude=test --exclude=vendor --excmd=number',
},
lsp = {
enable = true, -- if disabled make sure add require('navigator.lspclient.mapping').setup() in you on_attach

@ -89,7 +89,7 @@ local function ctags_symbols()
local height = _NgConfigValues.height or 0.4
local width = _NgConfigValues.width or 0.7
height = math.floor(height * vfn.winheight('%'))
width = math.floor(width * vfn.winwidth('%'))
width = math.floor(vim.api.nvim_get_option('columns') * width)
local items = {}
local ctags_file = _NgConfigValues.ctags.tagfile
if not util.file_exists(ctags_file) then

@ -117,7 +117,8 @@ local function def_preview(timeout_ms)
end
end
local width = 40
local maxwidth = math.floor(vim.fn.winwidth(0) * 4 / 5)
local maxwidth = math.floor( vim.api.nvim_get_option('columns') * 0.8)
for _, value in pairs(definition) do
-- log(key, value, width)
width = math.max(width, #value + 4)

@ -19,7 +19,7 @@ cwd = gutil.add_pec(cwd)
local ts_nodes = require('navigator.lru').new(1000, 1024 * 1024)
local ts_nodes_time = require('navigator.lru').new(1000)
local TS_analysis_enabled = require('navigator').config_values().treesitter_analysis
local nts = require('navigator.treesitter')
-- extract symbol from range
function M.get_symbol(text, range)
if range == nil then
@ -169,7 +169,7 @@ local function ts_functions(uri, optional)
lerr('ts not enabled')
return nil
end
local ts_func = require('navigator.treesitter').buf_func
local ts_func = nts.buf_func
local bufnr = vim.uri_to_bufnr(uri)
local x = os.clock()
trace(ts_nodes)
@ -230,7 +230,7 @@ local function ts_definition(uri, range, optional)
if optional then
return
end
local ts_def = require('navigator.treesitter').find_definition
local ts_def = nts.find_definition
local bufnr = vim.uri_to_bufnr(uri)
local x = os.clock()
trace(ts_nodes)
@ -252,6 +252,7 @@ local function ts_definition(uri, range, optional)
end
local function find_ts_func_by_range(funcs, range)
log(funcs, range)
if funcs == nil or range == nil then
return nil
end
@ -352,7 +353,6 @@ function M.locations_to_items(locations, ctx)
local unload_bufnrs = {}
for i, loc in ipairs(locations) do
local funcs = nil
local item = lsp.util.locations_to_items({ loc }, enc)[1]
item.range = locations[i].range or locations[i].targetRange
item.uri = locations[i].uri or locations[i].targetUri
@ -363,13 +363,25 @@ function M.locations_to_items(locations, ctx)
log(cwd)
end
-- only load top 30 file.
local proj_file = item.uri:find(cwd) or is_win or i < 30
local proj_file = item.uri:find(cwd) or is_win or i < _NgConfigValues.treesitter_analysis_max_num
local unload, def
local context = ''
if TS_analysis_enabled and proj_file then
funcs, unload = ts_functions(item.uri, ts_optional(i, #unload_bufnrs))
local ts_context = nts.ref_context
local bufnr = vim.uri_to_bufnr(item.uri)
if not api.nvim_buf_is_loaded(bufnr) then
log('! load buf !', item.uri, bufnr)
vim.fn.bufload(bufnr)
unload = bufnr
end
context = ts_context({ bufnr = bufnr, pos = item.range }) or ''
log(context)
-- TODO: unload buffers
if unload then
table.insert(unload_bufnrs, unload)
unload = nil
end
if not uri_def[item.uri] then
-- find def in file
@ -410,7 +422,7 @@ function M.locations_to_items(locations, ctx)
item.filename = assert(vim.uri_to_fname(item.uri))
local filename = item.filename:gsub(cwd .. path_sep, path_cur, 1)
item.display_filename = filename or item.filename
item.call_by = find_ts_func_by_range(funcs, item.range)
item.call_by = context -- find_ts_func_by_range(funcs, item.range)
item.rpath = util.get_relative_path(cwd, item.filename)
width = math.max(width, #item.text)
item.symbol_name = M.get_symbol(item.text, item.range)

@ -69,7 +69,7 @@ function M.prepare_for_render(items, opts)
icon = devicons.get_icon(fn, ext) or icon
end
-- local call_by_presented = false
opts.width = opts.width or 100
opts.width = opts.width or math.floor( vim.api.nvim_get_option('columns') * 0.8)
local win_width = opts.width -- buf
for i = 1, #items do
@ -150,31 +150,8 @@ function M.prepare_for_render(items, opts)
trace(ts_report, header_len)
item.text = item.text:gsub('%s*[%[%(%{]*%s*$', '')
if item.call_by ~= nil and #item.call_by > 0 then
trace('call_by:', #item.call_by)
for _, value in pairs(item.call_by) do
if value.node_text then
local txt = value.node_text:gsub('%s*[%[%(%{]*%s*$', '')
local endwise = '{}'
if value.type == 'method' or value.type == 'function' then
endwise = '()'
local syb = items[i].symbol_name
if txt == items[i].symbol_name or (#txt > #syb and txt:sub(#txt - #syb + 1) == syb) then
if ts_report ~= _NgConfigValues.icons.value_definition .. ' ' then
ts_report = ts_report .. _NgConfigValues.icons.value_definition .. ' '
end
header_len = #ts_report + 1
else
ts_report = ts_report .. ''
end
end
if #ts_report > header_len then
ts_report = ts_report .. ''
end
ts_report = ts_report .. value.kind .. txt .. endwise
trace(item)
end
end
if item.call_by ~= nil and item.call_by ~= '' then
ts_report = ts_report .. '' .. item.call_by
end
if #ts_report > 1 then
space, trim = get_pads(win_width, item.text, ts_report)
@ -195,7 +172,9 @@ function M.prepare_for_render(items, opts)
if #space + #item.text + #ts_report >= win_width then
if #item.text + #ts_report > win_width then
trace('exceeding', #item.text, #ts_report, win_width)
space = ' '
space = ' '
local len = math.max(win_width - #item.text - 4, 16)
ts_report = ts_report:sub(1, len)
else
local remain = win_width - #item.text - #ts_report
trace('remain', remain)

@ -23,6 +23,7 @@ local cwd = vim.loop.cwd()
local log = require('navigator.util').log
local lerr = require('navigator.util').error
local trace = function(...) end
trace = log
if vim.fn.has('nvim-0.7') == 1 then
local trace = require('navigator.util').trace
end
@ -109,6 +110,95 @@ function M.find_definition(range, bufnr)
end
end
function M.get_tsnode_at_pos(pos, bufnr, ignore_injected_langs)
if not pos or not pos.start then
return
end
local cursor_range = { pos.start.line, pos.start.character }
local buf = bufnr
local root_lang_tree = parsers.get_parser(buf)
if not root_lang_tree then
return
end
local root
if ignore_injected_langs then
for _, tree in ipairs(root_lang_tree:trees()) do
local tree_root = tree:root()
if tree_root and ts_utils.is_in_node_range(tree_root, cursor_range[1], cursor_range[2]) then
root = tree_root
break
end
end
else
root = ts_utils.get_root_for_position(cursor_range[1], cursor_range[2], root_lang_tree)
end
if not root then
return
end
return root:named_descendant_for_range(cursor_range[1], cursor_range[2], cursor_range[1], cursor_range[2])
end
-- Trim spaces and opening brackets from end
local transform_line = function(line)
line = line:gsub("%s*[%[%(%{]*%s*$", "")
line = line:gsub("function", "")
line = line:gsub("func%w*%s+", "")
if _NgConfigValues.treesitter_analysis_condense then
line = line:gsub("%([%a,%s]+%)", "()")
end
return line
end
function M.ref_context(opts)
if not parsers.has_parser() then
return
end
local options = opts or {}
-- if type(opts) == "number" then
-- options = { indicator_size = opts }
-- end
local bufnr = options.bufnr or 0
local pos = options.pos
if not pos then
pos = {start = vim.lsp.util.make_position_params().position}
end
local indicator_size = options.indicator_size or 100
local type_patterns = options.type_patterns or { "class", "function", "method" }
local transform_fn = options.transform_fn or transform_line
local separator = options.separator or ""
local current_node = M.get_tsnode_at_pos(pos, bufnr)
if not current_node then
log('no node at pos', bufnr, pos)
return ""
end
local lines = {}
local expr = current_node
while expr do
local line = ts_utils._get_line_for_node(expr, type_patterns, transform_fn, bufnr)
log(line)
if line ~= "" and not vim.tbl_contains(lines, line) then
table.insert(lines, 1, line)
end
expr = expr:parent()
end
local text = table.concat(lines, separator)
local text_len = #text
if text_len > indicator_size then
return "..." .. text:sub(text_len - indicator_size, text_len)
end
return text
end
--- Get definitions of bufnr (unique and sorted by order of appearance).
--- This function copy from treesitter/refactor/navigation.lua
local function get_definitions(bufnr)
@ -121,23 +211,23 @@ local function get_definitions(bufnr)
ts_locals.recurse_local_nodes(loc.definition, function(_, node, _, match)
-- lua doesn't compare tables by value,
-- use the value from byte count instead.
local k, l, start = node:start()
local row, col, offset = node:start()
local erow, ecol, end_ = node:end_()
trace(node, match)
trace(k, l, start, node:parent(), node:parent():start(), node:parent():type())
trace(row, col, erow, offset, node:parent(), node:parent():start(), node:parent():type())
if node and node:parent() and string.find(node:parent():type(), 'parameter_declaration') then
log('parameter_declaration skip')
return
end
nodes_set[start] = { node = node, type = match or '' }
nodes_set[offset] = { node = node, type = match or '' }
end)
end
if loc.method then -- for go
ts_locals.recurse_local_nodes(loc.method, function(def, node, full_match, match)
local k, l, start = node:start()
trace(k, l, start, def, node, full_match, match, node:parent(), node:parent():start(), node:parent():type())
local row, col, start = node:start()
trace(row, col, start, def, node, full_match, match, node:parent(), node:parent():start(), node:parent():type())
if node:type() == 'field_identifier' and nodes_set[start] == nil then
nodes_set[start] = { node = node, type = 'method' }
end
@ -154,16 +244,32 @@ local function get_definitions(bufnr)
end
if loc.reference then -- for go
ts_locals.recurse_local_nodes(loc.reference, function(def, node, full_match, match)
local k, l, start = node:start()
local row, col, start = node:start()
local p1, p1t = '', ''
local p2, p2t = '', ''
local p3, p3t = '', ''
if node:parent() and node:parent():parent() then
p1 = node:parent()
p1t = node:parent():type()
p2 = node:parent():parent()
p2t = node:parent():parent():type()
end
trace(k, l, start, def, node, full_match, match, p1t, p1, node:parent():start(), node:parent():type(), p2, p2t)
if p2 and p2:parent() then
p3 = p2:parent()
p3t = p2:parent():type()
end
trace(row, col, start, def, node, full_match, match, p1t, p1, node:parent():start(), node:parent():type(), p2, p2t, p3, p3t)
if p1t == 'arrow_function' then
row, col, start = p1:start()
trace('arrow_function 1', row, col)
nodes_set[start] = { node = p1, type = p1t }
end
if p2t == 'arrow_function' then
row, col, start = p2:start()
trace('arrow_function 2', row, col)
nodes_set[start] = { node = p2, type = p2t }
end
if nodes_set[start] == nil then
if -- qualified_type : e.g. io.Reader inside interface
node:parent()
@ -210,7 +316,7 @@ local function get_scope(type, source)
local parent = current:parent()
trace(source:type(), source:range(), parent)
if type == 'method' or type == 'function' and parent ~= nil then
if type == 'method' or type:find('function') and parent ~= nil then
trace(parent:type(), parent:range())
-- a function name
if parent:type() == 'function_name' then
@ -345,7 +451,7 @@ local function get_all_nodes(bufnr, filter, summary)
trace(bufnr, filter, summary)
if not bufnr then
vim.notify('get_all_node invalide bufnr', vim.lsp.log_levels.WARN)
vim.notify('get_all_node invalid bufnr', vim.lsp.log_levels.WARN)
end
summary = summary or false
local ft = vim.api.nvim_buf_get_option(bufnr, 'filetype')
@ -362,17 +468,13 @@ local function get_all_nodes(bufnr, filter, summary)
local display_filename = fname:gsub(cwd .. path_sep, path_cur, 1)
local all_nodes = {}
-- Support completion-nvim customized label map
-- local customized_labels = vim.g.completion_customize_lsp_label or {}
-- Force some types to act like they are parents
-- instead of neighbors of the next nodes.
local containers = {
local containers = filter or {
['function'] = true,
['local_function'] = true,
['arrow_function'] = true,
['type'] = true,
['class'] = true,
['call_expression'] = true,
-- ['var'] = true,
['struct'] = true,
['method'] = true,
@ -440,7 +542,10 @@ local function get_all_nodes(bufnr, filter, summary)
trace('skipped', item.type, item.kind)
goto continue
end
item.node_text = vim.treesitter.get_node_text(tsdata, bufnr) or ''
local text = vim.treesitter.get_node_text(tsdata, bufnr) or ''
text = vim.split(text, '\n')[1] or ''
item.node_text = text
log(item.node_text)
local scope, is_func
if summary then
@ -448,6 +553,7 @@ local function get_all_nodes(bufnr, filter, summary)
else
scope, is_func = get_smallest_context(tsdata)
end
log(item, scope, is_func)
if is_func then
-- hack for lua and maybe other language aswell
local parent = tsdata:parent()
@ -581,6 +687,7 @@ function M.buf_func(bufnr)
local all_nodes, width = get_all_nodes(bufnr, {
['function'] = true,
['arrow_function'] = true,
['var'] = true,
['method'] = true,
['class'] = true,
@ -614,6 +721,7 @@ function M.buf_func(bufnr)
return false
end)
end
log(all_nodes)
return all_nodes, width
end

@ -37,7 +37,7 @@ function M.workspace_symbol_live()
local height = _NgConfigValues.height or 0.4
height = math.floor(height * vfn.winheight('%'))
local width = _NgConfigValues.width or 0.7
width = math.floor(width * vfn.winwidth('%'))
width = math.floor(vim.api.nvim_get_option('columns') * width)
local bufnr = vim.api.nvim_get_current_buf()
local ft = vim.o.ft
local data = { { text = 'input the symbol name to start fuzzy search' } }

Loading…
Cancel
Save