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
|