mirror of
https://github.com/stevearc/aerial.nvim
synced 2024-09-16 14:34:08 +02:00
feat: experimental support for navigating to symbol names (#279)
Using the treesitter backend, we can use the same "selectionRange" logic that LSP symbol sources use to provide more detailed information about where the name of the symbol is. We already use the LSP information to change how we navigate the cursor to symbols, so once we parse this information from treesitter it will automatically get used. I'm putting this behind an experimental config option for now so we can test it out for a while before making a sudden change to the behavior.
This commit is contained in:
parent
de460a4a29
commit
e54cae0df0
8 changed files with 56 additions and 15 deletions
|
@ -1,6 +1,8 @@
|
|||
local config = require("aerial.config")
|
||||
-- This file is used by the markdown backend as well.
|
||||
-- We pcall(require) so it doesn't error when nvim-treesitter isn't installed.
|
||||
local _, utils = pcall(require, "nvim-treesitter.utils")
|
||||
local helpers = require("aerial.backends.treesitter.helpers")
|
||||
local M = {}
|
||||
|
||||
local get_node_text
|
||||
|
@ -178,6 +180,10 @@ M.help = {
|
|||
node = node:prev_sibling()
|
||||
item.lnum = row + 1
|
||||
item.col = col
|
||||
if item.selection_range then
|
||||
item.selection_range.lnum = row + 1
|
||||
item.selection_range.col = col
|
||||
end
|
||||
end
|
||||
item.name = table.concat(pieces, " ")
|
||||
end
|
||||
|
@ -278,6 +284,9 @@ local function c_postprocess(bufnr, item, match)
|
|||
end
|
||||
end
|
||||
item.name = get_node_text(root, bufnr) or "<parse error>"
|
||||
if config.treesitter.experimental_selection_range and not item.selection_range then
|
||||
item.selection_range = helpers.range_from_nodes(root, root)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
17
lua/aerial/backends/treesitter/helpers.lua
Normal file
17
lua/aerial/backends/treesitter/helpers.lua
Normal file
|
@ -0,0 +1,17 @@
|
|||
local M = {}
|
||||
|
||||
---@param start_node TSNode
|
||||
---@param end_node TSNode
|
||||
---@return aerial.Range
|
||||
M.range_from_nodes = function(start_node, end_node)
|
||||
local row, col = start_node:start()
|
||||
local end_row, end_col = end_node:end_()
|
||||
return {
|
||||
lnum = row + 1,
|
||||
end_lnum = end_row + 1,
|
||||
col = col,
|
||||
end_col = end_col,
|
||||
}
|
||||
end
|
||||
|
||||
return M
|
|
@ -1,5 +1,6 @@
|
|||
local backends = require("aerial.backends")
|
||||
local config = require("aerial.config")
|
||||
local helpers = require("aerial.backends.treesitter.helpers")
|
||||
local util = require("aerial.backends.util")
|
||||
|
||||
---@type aerial.Backend
|
||||
|
@ -60,12 +61,14 @@ M.fetch_symbols_sync = function(bufnr)
|
|||
)
|
||||
return
|
||||
end
|
||||
local use_selection_range = config.treesitter.experimental_selection_range
|
||||
-- This will track a loose hierarchy of recent node+items.
|
||||
-- It is used to determine node parents for the tree structure.
|
||||
local stack = {}
|
||||
local ext = extensions[lang]
|
||||
for match in query.iter_group_results(bufnr, "aerial", syntax_tree:root(), lang) do
|
||||
local name_match = match.name or {}
|
||||
local selection_match = match.selection or {}
|
||||
local type_node = (match.type or {}).node
|
||||
-- The location capture groups are optional. We default to the
|
||||
-- location of the @type capture
|
||||
|
@ -89,11 +92,17 @@ M.fetch_symbols_sync = function(bufnr)
|
|||
)
|
||||
break
|
||||
end
|
||||
local row, col = start_node:start()
|
||||
local end_row, end_col = end_node:end_()
|
||||
local range = helpers.range_from_nodes(start_node, end_node)
|
||||
local selection_range
|
||||
if selection_match.node then
|
||||
selection_range = helpers.range_from_nodes(selection_match.node, selection_match.node)
|
||||
end
|
||||
local name
|
||||
if name_match.node then
|
||||
name = get_node_text(name_match.node, bufnr, name_match) or "<parse error>"
|
||||
if not selection_range then
|
||||
selection_range = helpers.range_from_nodes(name_match.node, name_match.node)
|
||||
end
|
||||
else
|
||||
name = "<Anonymous>"
|
||||
end
|
||||
|
@ -103,11 +112,13 @@ M.fetch_symbols_sync = function(bufnr)
|
|||
name = name,
|
||||
level = level,
|
||||
parent = parent_item,
|
||||
lnum = row + 1,
|
||||
end_lnum = end_row + 1,
|
||||
col = col,
|
||||
end_col = end_col,
|
||||
}
|
||||
if use_selection_range then
|
||||
item.selection_range = selection_range
|
||||
end
|
||||
for k, v in pairs(range) do
|
||||
item[k] = v
|
||||
end
|
||||
if ext.postprocess(bufnr, item, match) == false or not include_kind[item.kind] then
|
||||
goto continue
|
||||
end
|
||||
|
|
|
@ -335,6 +335,10 @@ local default_options = {
|
|||
treesitter = {
|
||||
-- How long to wait (in ms) after a buffer change before updating
|
||||
update_delay = 300,
|
||||
-- Experimental feature to navigate to symbol names instead of the declaration
|
||||
-- See https://github.com/stevearc/aerial.nvim/issues/279
|
||||
-- If no bugs are reported for a time this will become the default
|
||||
experimental_selection_range = false,
|
||||
},
|
||||
|
||||
markdown = {
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
(string)? @name
|
||||
(function_definition) @type)
|
||||
(#set! "kind" "Function")
|
||||
) @start
|
||||
) @start @selection
|
||||
|
||||
(function_call
|
||||
name: (dot_index_expression
|
||||
|
@ -43,4 +43,4 @@
|
|||
(string)? @name
|
||||
(function_definition) @type)
|
||||
(#set! "kind" "Function")
|
||||
) @start
|
||||
) @start @selection
|
||||
|
|
|
@ -40,4 +40,4 @@
|
|||
(call) @name
|
||||
])?
|
||||
(#set! "kind" "Method")
|
||||
) @type
|
||||
) @type @selection
|
||||
|
|
|
@ -48,7 +48,7 @@
|
|||
(string
|
||||
(string_fragment) @name @string))?
|
||||
(#set! "kind" "Function")
|
||||
) @type
|
||||
) @type @selection
|
||||
|
||||
; test.skip("this test")
|
||||
(call_expression
|
||||
|
@ -60,7 +60,7 @@
|
|||
(string
|
||||
(string_fragment) @name @string))?
|
||||
(#set! "kind" "Function")
|
||||
) @type
|
||||
) @type @selection
|
||||
|
||||
; describe.each([])("Test suite")
|
||||
(call_expression
|
||||
|
@ -74,4 +74,4 @@
|
|||
(string
|
||||
(string_fragment) @name @string))?
|
||||
(#set! "kind" "Function")
|
||||
) @type
|
||||
) @type @selection
|
||||
|
|
|
@ -48,7 +48,7 @@
|
|||
(string
|
||||
(string_fragment) @name @string))?
|
||||
(#set! "kind" "Function")
|
||||
) @type
|
||||
) @type @selection
|
||||
|
||||
; test.skip("this test")
|
||||
(call_expression
|
||||
|
@ -60,7 +60,7 @@
|
|||
(string
|
||||
(string_fragment) @name @string))?
|
||||
(#set! "kind" "Function")
|
||||
) @type
|
||||
) @type @selection
|
||||
|
||||
; describe.each([])("Test suite")
|
||||
(call_expression
|
||||
|
@ -74,4 +74,4 @@
|
|||
(string
|
||||
(string_fragment) @name @string))?
|
||||
(#set! "kind" "Function")
|
||||
) @type
|
||||
) @type @selection
|
||||
|
|
Loading…
Reference in a new issue