summaryrefslogtreecommitdiff
path: root/script/core/code-lens.lua
blob: bc39ec8651e7779770492438342e071658686f70 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
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'

---@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<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()
    ---@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
    local command = conv.command(
        lang.script('COMMAND_REFERENCE_COUNT', count),
        '',
        {}
    )
    return command
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,
}