diff options
-rw-r--r-- | script/core/code-lens.lua | 129 | ||||
-rw-r--r-- | script/core/reference.lua | 7 | ||||
-rw-r--r-- | script/proto/converter.lua | 18 | ||||
-rw-r--r-- | script/provider/provider.lua | 40 | ||||
-rw-r--r-- | script/vm/tracer.lua | 2 |
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 |