summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--script/core/code-lens.lua129
-rw-r--r--script/core/reference.lua7
-rw-r--r--script/proto/converter.lua18
-rw-r--r--script/provider/provider.lua40
-rw-r--r--script/vm/tracer.lua2
5 files changed, 193 insertions, 3 deletions
diff --git a/script/core/code-lens.lua b/script/core/code-lens.lua
new file mode 100644
index 00000000..65ef560c
--- /dev/null
+++ b/script/core/code-lens.lua
@@ -0,0 +1,129 @@
+local files = require 'files'
+local guide = require 'parser.guide'
+local await = require 'await'
+local conv = require 'proto.converter'
+local getRef = require 'core.reference'
+
+---@type codeLens
+local latestCodeLens
+
+---@class codeLens.resolving
+---@field mode 'reference'
+---@field source parser.object
+
+---@class codeLens.result
+---@field position integer
+---@field id integer
+
+---@class codeLens
+local mt = {}
+mt.__index = mt
+mt.type = 'codeLens'
+mt.id = 0
+
+---@param uri uri
+---@return boolean
+function mt:init(uri)
+ self.state = files.getState(uri)
+ if not self.state then
+ return false
+ end
+ ---@type uri
+ self.uri = uri
+ ---@type codeLens.result[]
+ self.results = {}
+ ---@type table<integer, codeLens.resolving>
+ self.resolving = {}
+ return true
+end
+
+---@param pos integer
+---@param resolving codeLens.resolving
+function mt:addResult(pos, resolving)
+ self.id = self.id + 1
+ self.results[#self.results+1] = {
+ position = pos,
+ id = self.id,
+ }
+ self.resolving[self.id] = resolving
+end
+
+---@async
+---@param id integer
+---@return proto.command?
+function mt:resolve(id)
+ local resolving = self.resolving[id]
+ if not resolving then
+ return nil
+ end
+ if resolving.mode == 'reference' then
+ return self:resolveReference(resolving.source)
+ end
+end
+
+---@async
+function mt:collectReferences()
+ await.delay()
+ guide.eachSourceType(self.state.ast, 'function', function (src)
+ local assign = src.parent
+ if not guide.isSet(assign) then
+ return
+ end
+ self:addResult(src.start, {
+ mode = 'reference',
+ source = assign,
+ })
+ end)
+end
+
+---@async
+---@param source parser.object
+---@return proto.command?
+function mt:resolveReference(source)
+ local refs = getRef(self.uri, source.start, false)
+ local count = refs and #refs or 0
+ local command = conv.command(
+ ('%d个引用'):format(count),
+ 'editor.action.showReferences',
+ {
+ self.uri,
+ conv.packPosition(self.state, source.start),
+ }
+ )
+ return command
+end
+
+---@async
+---@param uri uri
+---@return codeLens.result[]?
+local function codeLens(uri)
+ latestCodeLens = setmetatable({}, mt)
+ local suc = latestCodeLens:init(uri)
+ if not suc then
+ return nil
+ end
+
+ latestCodeLens:collectReferences()
+
+ if #latestCodeLens.results == 0 then
+ return nil
+ end
+
+ return latestCodeLens.results
+end
+
+---@async
+---@param id integer
+---@return proto.command?
+local function resolve(id)
+ if not latestCodeLens then
+ return nil
+ end
+ local command = latestCodeLens:resolve(id)
+ return command
+end
+
+return {
+ codeLens = codeLens,
+ resolve = resolve,
+}
diff --git a/script/core/reference.lua b/script/core/reference.lua
index f360a2f4..c6130c40 100644
--- a/script/core/reference.lua
+++ b/script/core/reference.lua
@@ -85,8 +85,11 @@ return function (uri, position, includeDeclaration)
if src.type == 'self' then
goto CONTINUE
end
- if not includeDeclaration and guide.isSet(src) then
- goto CONTINUE
+ if not includeDeclaration then
+ if guide.isSet(src)
+ or guide.isLiteral(src) then
+ goto CONTINUE
+ end
end
src = src.field or src.method or src
if src.type == 'getindex'
diff --git a/script/proto/converter.lua b/script/proto/converter.lua
index d761042c..a723face 100644
--- a/script/proto/converter.lua
+++ b/script/proto/converter.lua
@@ -4,6 +4,7 @@ local encoder = require 'encoder'
local offsetEncoding = 'utf16'
+---@class converter
local m = {}
---@alias position {line: integer, character: integer}
@@ -206,4 +207,21 @@ function m.setOffsetEncoding(encoding)
offsetEncoding = encoding:lower():gsub('%-', '')
end
+---@class proto.command
+---@field title string
+---@field command string
+---@field arguments any[]
+
+---@param title string
+---@param command string
+---@param arguments any[]
+---@return proto.command
+function m.command(title, command, arguments)
+ return {
+ title = title,
+ command = command,
+ arguments = arguments,
+ }
+end
+
return m
diff --git a/script/provider/provider.lua b/script/provider/provider.lua
index d19e0040..265b8cc8 100644
--- a/script/provider/provider.lua
+++ b/script/provider/provider.lua
@@ -918,6 +918,46 @@ m.register 'textDocument/codeAction' {
end
}
+m.register 'textDocument/codeLens' {
+ capability = {
+ codeLensProvider = {
+ resolveProvider = true,
+ }
+ },
+ ---@async
+ function (params)
+ local uri = files.getRealUri(params.textDocument.uri)
+ workspace.awaitReady(uri)
+ local state = files.getState(uri)
+ if not state then
+ return nil
+ end
+ local core = require 'core.code-lens'
+ local results = core.codeLens(uri)
+ if not results then
+ return nil
+ end
+ local codeLens = {}
+ for _, result in ipairs(results) do
+ codeLens[#codeLens+1] = {
+ range = converter.packRange(state, result.position, result.position),
+ data = result.id,
+ }
+ end
+ return codeLens
+ end
+}
+
+m.register 'codeLens/resolve' {
+ ---@async
+ function (codeLen)
+ local core = require 'core.code-lens'
+ local command = core.resolve(codeLen.data)
+ codeLen.command = command
+ return codeLen
+ end
+}
+
m.register 'workspace/executeCommand' {
capability = {
executeCommandProvider = {
diff --git a/script/vm/tracer.lua b/script/vm/tracer.lua
index 21a2619f..f03ab001 100644
--- a/script/vm/tracer.lua
+++ b/script/vm/tracer.lua
@@ -202,7 +202,7 @@ function mt:lookIntoChild(action, topNode, outNode)
end
end
elseif action.type == 'function' then
- self:lookIntoBlock(action, action.args.finish, topNode:copy())
+ self:lookIntoBlock(action, action.bstart, topNode:copy())
elseif action.type == 'unary' then
if not action[1] then
goto RETURN