local files = require 'files' local guide = require 'parser.guide' local await = require 'await' local conv = require 'proto.converter' local getRef = require 'core.reference' local lang = require 'language' local client = require 'client' ---@class parser.state ---@field package _codeLens? codeLens ---@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 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() ---@async guide.eachSourceType(self.state.ast, 'function', function (src) local parent = src.parent if guide.isAssign(parent) then src = parent elseif parent.type == 'return' then else return end await.delay() self:addResult(src.start, { mode = 'reference', source = src, }) end) end ---@async ---@param source parser.object ---@return proto.command? function mt:resolveReference(source) local refs = getRef(self.uri, source.finish, false) local count = refs and #refs or 0 if client.getOption('codeLensViewReferences') then local locations = {} for _, ref in ipairs(refs or {}) do local state = files.getState(ref.uri) if state then locations[#locations+1] = conv.location( ref.uri, conv.packRange(state, ref.target.start, ref.target.finish) ) end end local command = conv.command( lang.script('COMMAND_REFERENCE_COUNT', count), 'lua.showReferences', { self.uri, conv.packPosition(self.state, source.start), locations, } ) return command else local command = conv.command( lang.script('COMMAND_REFERENCE_COUNT', count), '', {} ) return command end end ---@async ---@param uri uri ---@return codeLens.result[]? local function getCodeLens(uri) local state = files.getState(uri) if not state then return nil end local codeLens = setmetatable({}, mt) local suc = codeLens:init(uri) if not suc then return nil end state._codeLens = codeLens codeLens:collectReferences() if #codeLens.results == 0 then return nil end return codeLens.results end ---@async ---@param id integer ---@return proto.command? local function resolve(uri, id) local state = files.getState(uri) if not state then return nil end local codeLens = state._codeLens if not codeLens then return nil end local command = codeLens:resolve(id) return command end return { codeLens = getCodeLens, resolve = resolve, }