summaryrefslogtreecommitdiff
path: root/script/core
diff options
context:
space:
mode:
Diffstat (limited to 'script/core')
-rw-r--r--script/core/view/psi-select.lua13
-rw-r--r--script/core/view/psi-view.lua84
2 files changed, 97 insertions, 0 deletions
diff --git a/script/core/view/psi-select.lua b/script/core/view/psi-select.lua
new file mode 100644
index 00000000..b6733aa5
--- /dev/null
+++ b/script/core/view/psi-select.lua
@@ -0,0 +1,13 @@
+local files = require("files")
+local guide = require("parser.guide")
+local converter = require("proto.converter")
+
+return function(uri, position)
+ local state = files.getState(uri)
+ if not state then
+ return
+ end
+
+ local pos = converter.unpackPosition(uri, position)
+ return { data = guide.positionToOffset(state, pos) }
+end
diff --git a/script/core/view/psi-view.lua b/script/core/view/psi-view.lua
new file mode 100644
index 00000000..b6cdae8c
--- /dev/null
+++ b/script/core/view/psi-view.lua
@@ -0,0 +1,84 @@
+local files = require("files")
+local guide = require("parser.guide")
+
+
+---@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
+---@return psi.view.node | nil
+local function toPsiNode(astNode, state)
+ if not astNode then
+ return
+ end
+ if astNode.type == "doc" then
+ return
+ end
+
+ local startOffset = guide.positionToOffset(state, astNode.start)
+ local finishOffset = guide.positionToOffset(state, astNode.finish)
+ return {
+ name = string.format("%s@%d..%d", astNode.type, startOffset, finishOffset),
+ 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.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
+ -- psiNode.name = psiNode.name
+ -- 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