127 lines
4.3 KiB
Lua
127 lines
4.3 KiB
Lua
local cfg = require('outline.config')
|
|
local folding = require('outline.folding')
|
|
local lsp_utils = require('outline.utils.lsp_utils')
|
|
local symbols = require('outline.symbols')
|
|
local t_utils = require('outline.utils.table')
|
|
|
|
local M = {}
|
|
|
|
---Parses result from LSP into a reorganized tree of symbols (not flattened,
|
|
-- simply reoganized by merging each property table from the arguments into a
|
|
-- table for each symbol)
|
|
---@param result table The result from a language server.
|
|
---@param depth number? The current depth of the symbol in the hierarchy.
|
|
---@param hierarchy table? A table of booleans which tells if a symbols parent was the last in its group.
|
|
---@param parent table? A reference to the current symbol's parent in the function's recursion
|
|
---@param bufnr integer The buffer number which the result was from
|
|
---@return outline.SymbolNode[]
|
|
local function parse_result(result, depth, hierarchy, parent, bufnr)
|
|
local ret = {}
|
|
|
|
for index, value in pairs(result) do
|
|
-- FIXME: If a parent was excluded, all children will not be considered
|
|
if cfg.should_include_symbol(symbols.kinds[value.kind], bufnr) then
|
|
-- the hierarchy is basically a table of booleans which
|
|
-- tells whether the parent was the last in its group or
|
|
-- not
|
|
local hir = hierarchy or {}
|
|
-- how many parents this node has, 1 is the lowest value because its
|
|
-- easier to work it
|
|
local level = depth or 1
|
|
-- whether this node is the last (~born~) in its siblings
|
|
local isLast = index == #result
|
|
|
|
local selectionRange = lsp_utils.get_selection_range(value)
|
|
local range = lsp_utils.get_range(value)
|
|
|
|
local node = {
|
|
deprecated = value.deprecated,
|
|
kind = value.kind,
|
|
icon = symbols.icon_from_kind(value.kind),
|
|
name = value.name or value.text,
|
|
detail = value.detail,
|
|
line = selectionRange.start.line,
|
|
character = selectionRange.start.character,
|
|
range_start = range.start.line,
|
|
range_end = range['end'].line,
|
|
depth = level,
|
|
isLast = isLast,
|
|
hierarchy = hir,
|
|
parent = parent,
|
|
traversal_child = 1,
|
|
}
|
|
|
|
table.insert(ret, node)
|
|
|
|
local children = nil
|
|
if value.children ~= nil then
|
|
-- copy by value because we dont want it messing with the hir table
|
|
local child_hir = t_utils.array_copy(hir)
|
|
table.insert(child_hir, isLast)
|
|
children = parse_result(value.children, level + 1, child_hir, node, bufnr)
|
|
else
|
|
value.children = {}
|
|
end
|
|
|
|
node.children = children
|
|
end
|
|
end
|
|
return ret
|
|
end
|
|
|
|
---Sorts and reorganizes the response from lsp request
|
|
--'textDocument/documentSymbol', buf_request_all.
|
|
---Used when refreshing and setting up new symbols
|
|
---@param response table The result from buf_request_all
|
|
---@param bufnr integer
|
|
---@return outline.SymbolNode[]
|
|
function M.parse(response, bufnr)
|
|
local sorted = lsp_utils.sort_symbols(response)
|
|
|
|
return parse_result(sorted, nil, nil, { is_root = true, child_count = #sorted }, bufnr)
|
|
end
|
|
|
|
---Iterator that traverses the tree parent first before children, returning each node.
|
|
-- Essentailly 'flatten' items, but returns an iterator.
|
|
---@param items outline.SymbolNode[] Tree of symbols parsed by parse_result
|
|
---@param children_check function? Takes a node and return whether the children should be explored.
|
|
---Note that the root node (param items) is always explored regardless of children_check.
|
|
function M.preorder_iter(items, children_check)
|
|
local node = { children = items, traversal_child = 1, depth = 1, is_root = true }
|
|
local prev
|
|
local visited = {}
|
|
|
|
if children_check == nil then
|
|
children_check = function(n)
|
|
return not folding.is_folded(n)
|
|
end
|
|
end
|
|
|
|
return function()
|
|
while node do
|
|
if node.name and not visited[node] then
|
|
visited[node] = true
|
|
return node
|
|
end
|
|
|
|
if
|
|
node.children
|
|
and node.traversal_child <= #node.children
|
|
and (node.is_root or children_check(node))
|
|
then
|
|
prev = node
|
|
if node.children[node.traversal_child] then
|
|
node.children[node.traversal_child].parent_node = node
|
|
node = node.children[node.traversal_child]
|
|
end
|
|
prev.traversal_child = prev.traversal_child + 1
|
|
else
|
|
node.traversal_child = 1
|
|
node = node.parent_node
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
return M
|