summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author最萌小汐 <sumneko@hotmail.com>2022-09-30 23:27:06 +0800
committerGitHub <noreply@github.com>2022-09-30 23:27:06 +0800
commita8007df95719639d8f7f03d3192d03b372a1d5c6 (patch)
tree9971529811a2f31791bad0981b19647fde4b3cff
parente8dd3c3c674790771438173606a027f06a90c9ed (diff)
parent18691bdfea49c829115437e7d029aa15bddd3d58 (diff)
downloadlua-language-server-a8007df95719639d8f7f03d3192d03b372a1d5c6.zip
Merge pull request #1597 from CppCXY/master
psi viewer
-rw-r--r--script/core/view/psi-select.lua13
-rw-r--r--script/core/view/psi-view.lua96
-rw-r--r--script/provider/provider.lua31
3 files changed, 140 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..86089dd4
--- /dev/null
+++ b/script/core/view/psi-view.lua
@@ -0,0 +1,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 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.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
diff --git a/script/provider/provider.lua b/script/provider/provider.lua
index 823abae5..3ab5bb19 100644
--- a/script/provider/provider.lua
+++ b/script/provider/provider.lua
@@ -1400,6 +1400,37 @@ m.register '$/api/report' {
end
}
+m.register '$/psi/view' {
+ ---@async
+ function (params)
+ local uri = files.getRealUri(params.uri)
+ workspace.awaitReady(uri)
+ local _ <close> = progress.create(uri, lang.script.WINDOW_PROCESSING_TYPE_FORMATTING, 0.5)
+ if not files.exists(uri) then
+ return nil
+ end
+ local core = require 'core.view.psi-view'
+ local result = core(uri)
+ return result
+ end
+}
+
+m.register '$/psi/select' {
+ ---@async
+ function(params)
+ local uri = files.getRealUri(params.uri)
+ workspace.awaitReady(uri)
+ local _<close> = progress.create(uri, lang.script.WINDOW_PROCESSING_TYPE_FORMATTING, 0.5)
+ if not files.exists(uri) then
+ return nil
+ end
+ local core = require 'core.view.psi-select'
+ local result = core(uri, params.position)
+ return result
+ end
+}
+
+
local function refreshStatusBar()
local valid = config.get(nil, 'Lua.window.statusBar')
for _, scp in ipairs(workspace.folders) do