97 lines
2.6 KiB
Lua
97 lines
2.6 KiB
Lua
local files = require("files")
|
|
local guide = require("parser.guide")
|
|
local converter = require("proto.converter")
|
|
local subString = require 'core.substring'
|
|
|
|
|
|
|
|
---@class psi.view.node
|
|
---@field name string
|
|
---@field attr? psi.view.attr
|
|
---@field children? psi.view.node[]
|
|
|
|
---@class psi.view.attr
|
|
---@field range psi.view.range
|
|
|
|
---@class psi.view.range
|
|
---@field start integer
|
|
---@field end integer
|
|
|
|
---@param astNode parser.object
|
|
---@param state parser.state
|
|
---@return psi.view.node | nil
|
|
local function toPsiNode(astNode, state)
|
|
if not astNode or not astNode.start then
|
|
return
|
|
end
|
|
|
|
local startOffset = guide.positionToOffset(state, astNode.start)
|
|
local finishOffset = guide.positionToOffset(state, astNode.finish)
|
|
local startPosition = converter.packPosition(state, astNode.start)
|
|
local finishPosition = converter.packPosition(state, astNode.finish)
|
|
return {
|
|
name = string.format("%s@[%d:%d .. %d:%d]",
|
|
astNode.type,
|
|
startPosition.line + 1, startPosition.character + 1,
|
|
finishPosition.line + 1, finishPosition.character + 1),
|
|
attr = {
|
|
range = {
|
|
start = startOffset,
|
|
["end"] = finishOffset
|
|
}
|
|
}
|
|
}
|
|
end
|
|
|
|
---@param astNode parser.object
|
|
---@return psi.view.node | nil
|
|
local function collectPsi(astNode, state)
|
|
local psiNode = toPsiNode(astNode, state)
|
|
|
|
if not psiNode then
|
|
return
|
|
end
|
|
|
|
guide.eachChild(astNode, function(child)
|
|
if psiNode.children == nil then
|
|
psiNode.children = {}
|
|
end
|
|
|
|
local psi = collectPsi(child, state)
|
|
if psi then
|
|
psiNode.children[#psiNode.children+1] = psi
|
|
end
|
|
end)
|
|
|
|
if psiNode.children and #psiNode.children > 0 and psiNode.attr then
|
|
local range = psiNode.attr.range
|
|
if range.start > psiNode.children[1].attr.range.start then
|
|
range.start = psiNode.children[1].attr.range.start
|
|
end
|
|
if range["end"] < psiNode.children[#psiNode.children].attr.range["end"] then
|
|
range["end"] = psiNode.children[#psiNode.children].attr.range["end"]
|
|
end
|
|
end
|
|
|
|
if not psiNode.children then
|
|
local subber = subString(state)
|
|
local showText = subber(astNode.start + 1, astNode.finish)
|
|
if string.len(showText) > 30 then
|
|
showText = showText:sub(0, 30).. " ... "
|
|
end
|
|
|
|
psiNode.name = psiNode.name .. " " .. showText
|
|
end
|
|
|
|
return psiNode
|
|
end
|
|
|
|
return function(uri)
|
|
local state = files.getState(uri)
|
|
if not state then
|
|
return
|
|
end
|
|
|
|
return { data = collectPsi(state.ast, state) }
|
|
end
|