|
25 | 25 |
|
26 | 26 | function M.goto_definition_lsp_fallback(bufnr) M.goto_definition(bufnr, vim.lsp.buf.definition) end
|
27 | 27 |
|
| 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 | + |
28 | 56 | function M.list_definitions(bufnr)
|
29 | 57 | local bufnr = bufnr or api.nvim_get_current_buf()
|
30 |
| - local definitions = locals.get_definitions(bufnr) |
| 58 | + local definitions = get_definitions(bufnr) |
31 | 59 |
|
32 | 60 | if #definitions < 1 then return end
|
33 | 61 |
|
34 | 62 | local qf_list = {}
|
35 | 63 |
|
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 | + }) |
48 | 75 | end
|
49 | 76 |
|
50 | 77 | vim.fn.setqflist(qf_list, 'r')
|
51 | 78 | api.nvim_command('copen')
|
52 | 79 | end
|
53 | 80 |
|
| 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 | + |
54 | 135 | function M.goto_adjacent_usage(bufnr, delta)
|
55 | 136 | local bufnr = bufnr or api.nvim_get_current_buf()
|
56 | 137 | local node_at_point = ts_utils.get_node_at_cursor()
|
|
0 commit comments