1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
|
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.uri, astNode.start)
local finishPosition = converter.packPosition(state.uri, 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
|