Skip to content

Commit 130d948

Browse files
authored
Merge pull request #1 from stsewd/definitions-toc
Navigation: improve list_definitions and implement list_definitions_toc
2 parents b9ebd81 + f53141b commit 130d948

File tree

4 files changed

+102
-13
lines changed

4 files changed

+102
-13
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ require'nvim-treesitter.configs'.setup {
7979
keymaps = {
8080
goto_definition = "gnd",
8181
list_definitions = "gnD",
82+
list_definitions_toc = "gO",
8283
goto_next_usage = "<a-*>",
8384
goto_previous_usage = "<a-#>",
8485
},

doc/nvim-treesitter-refactor.txt

+6
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,9 @@ Supported options:
105105
No default mapping
106106
- list_definitions: list all definitions from the current file.
107107
Defaults to `gnD`.
108+
- list_definitions_toc: list all definitions from the current file like a
109+
table of contents (similar to the one you see when pressing |gO| in help files).
110+
Defaults to `gO`.
108111
- goto_next_usage: go to next usage of identifier under the cursor.
109112
Defaults to `<a-*>`.
110113
- goto_previous_usage: go to previous usage of identifier.
@@ -119,6 +122,7 @@ Supported options:
119122
keymaps = {
120123
goto_definition = "gnd",
121124
list_definitions = "gnD",
125+
list_definitions_toc = "gO",
122126
goto_next_usage = "<a-*>",
123127
goto_previous_usage = "<a-#>",
124128
},
@@ -148,3 +152,5 @@ the cursor.
148152
`TSCurrentScope`
149153
*hl-TSCurrentScope*
150154
Used by refactor.highlight_current_scope to highlight the current scope.
155+
156+
vim:tw=78:ts=8:expandtab:noet:ft=help:norl:

lua/nvim-treesitter-refactor.lua

+1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ function M.init()
3434
keymaps = {
3535
goto_definition = "gnd",
3636
list_definitions = "gnD",
37+
list_definitions_toc = "gO",
3738
goto_next_usage = "<a-*>",
3839
goto_previous_usage = "<a-#>",
3940
}

lua/nvim-treesitter-refactor/navigation.lua

+94-13
Original file line numberDiff line numberDiff line change
@@ -25,32 +25,113 @@ end
2525

2626
function M.goto_definition_lsp_fallback(bufnr) M.goto_definition(bufnr, vim.lsp.buf.definition) end
2727

28+
--- Get definitions of bufnr (unique and sorted by order of appearance).
29+
local function get_definitions(bufnr)
30+
local local_nodes = locals.get_locals(bufnr)
31+
32+
-- Make sure the nodes are unique.
33+
local nodes_set = {}
34+
for _, loc in ipairs(local_nodes) do
35+
if loc.definition then
36+
locals.recurse_local_nodes(loc.definition, function(_, node, _, match)
37+
-- lua doesn't compare tables by value,
38+
-- use the value from byte count instead.
39+
local _, _, start = node:start()
40+
nodes_set[start] = {node = node, type = match or ""}
41+
end)
42+
end
43+
end
44+
45+
-- Sort by order of appearance.
46+
local definition_nodes = vim.tbl_values(nodes_set)
47+
table.sort(definition_nodes, function (a, b)
48+
local _, _, start_a = a.node:start()
49+
local _, _, start_b = b.node:start()
50+
return start_a < start_b
51+
end)
52+
53+
return definition_nodes
54+
end
55+
2856
function M.list_definitions(bufnr)
2957
local bufnr = bufnr or api.nvim_get_current_buf()
30-
local definitions = locals.get_definitions(bufnr)
58+
local definitions = get_definitions(bufnr)
3159

3260
if #definitions < 1 then return end
3361

3462
local qf_list = {}
3563

36-
for _, def in ipairs(definitions) do
37-
locals.recurse_local_nodes(def, function(_, node, _, match)
38-
local lnum, col, _ = node:start()
39-
40-
table.insert(qf_list, {
41-
bufnr = bufnr,
42-
lnum = lnum + 1,
43-
col = col + 1,
44-
text = ts_utils.get_node_text(node)[1] or "",
45-
kind = match and match:sub(1, 1) or ""
46-
})
47-
end)
64+
for _, node in ipairs(definitions) do
65+
local lnum, col, _ = node.node:start()
66+
local type = string.upper(node.type:sub(1, 1))
67+
local text = ts_utils.get_node_text(node.node)[1] or ""
68+
table.insert(qf_list, {
69+
bufnr = bufnr,
70+
lnum = lnum + 1,
71+
col = col + 1,
72+
text = text,
73+
type = type,
74+
})
4875
end
4976

5077
vim.fn.setqflist(qf_list, 'r')
5178
api.nvim_command('copen')
5279
end
5380

81+
function M.list_definitions_toc()
82+
local winnr = api.nvim_get_current_win()
83+
local bufnr = api.nvim_win_get_buf(winnr)
84+
local definitions = get_definitions(bufnr)
85+
86+
if #definitions < 1 then return end
87+
88+
local loc_list = {}
89+
90+
-- Force some types to act like they are parents
91+
-- instead of neighbors of the next nodes.
92+
local containers = {
93+
['function'] = true,
94+
['type'] = true,
95+
['method'] = true,
96+
}
97+
98+
local parents = {}
99+
100+
for _, def in ipairs(definitions) do
101+
-- Get indentation level by putting all parents in a stack.
102+
-- The length of the stack minus one is the current level of indentation.
103+
local n = #parents
104+
for i=1, n do
105+
local index = n + 1 - i
106+
local parent_def = parents[index]
107+
if ts_utils.is_parent(parent_def.node, def.node)
108+
or (containers[parent_def.type] and ts_utils.is_parent(parent_def.node:parent(), def.node)) then
109+
break
110+
else
111+
parents[index] = nil
112+
end
113+
end
114+
parents[#parents + 1] = def
115+
116+
local lnum, col, _ = def.node:start()
117+
local type = string.upper(def.type:sub(1, 1))
118+
local text = ts_utils.get_node_text(def.node)[1] or ""
119+
table.insert(loc_list, {
120+
bufnr = bufnr,
121+
lnum = lnum + 1,
122+
col = col + 1,
123+
text = string.rep(' ', #parents - 1) .. text,
124+
type = type,
125+
})
126+
end
127+
128+
vim.fn.setloclist(winnr, loc_list, 'r')
129+
-- The title needs to end with `TOC`,
130+
-- so Neovim displays it like a TOC instead of an error list.
131+
vim.fn.setloclist(winnr, {}, 'a', {title = 'Definitions TOC'})
132+
api.nvim_command('lopen')
133+
end
134+
54135
function M.goto_adjacent_usage(bufnr, delta)
55136
local bufnr = bufnr or api.nvim_get_current_buf()
56137
local node_at_point = ts_utils.get_node_at_cursor()

0 commit comments

Comments
 (0)