summaryrefslogtreecommitdiff
path: root/server/src/core/document_symbol.lua
blob: 47389ec29504d46ad9f09064926bea198f3e867f (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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
local hoverFunction = require 'core.hover.function'
local hoverName = require 'core.hover.name'
local hover = require 'core.hover'

local SymbolKind = {
    File = 1,
    Module = 2,
    Namespace = 3,
    Package = 4,
    Class = 5,
    Method = 6,
    Property = 7,
    Field = 8,
    Constructor = 9,
    Enum = 10,
    Interface = 11,
    Function = 12,
    Variable = 13,
    Constant = 14,
    String = 15,
    Number = 16,
    Boolean = 17,
    Array = 18,
    Object = 19,
    Key = 20,
    Null = 21,
    EnumMember = 22,
    Struct = 23,
    Event = 24,
    Operator = 25,
    TypeParameter = 26,
}

local function buildLocal(source, callback)
    local loc = source:bindLocal()
    local value = loc:getInitValue()
    local hvr = hover(source)
    if not hvr then
        return
    end
    local kind
    if value:getType() == 'function' then
        kind = SymbolKind.Function
    elseif source:get 'table index' then
        kind = SymbolKind.Class
    else
        kind = SymbolKind.Variable
    end
    local valueSource = value.source
    if valueSource.start == 0 then
        valueSource = source
    end
    -- 由于范围不允许交叉,为了支持 local x, y, z = 1, 2, 3 的形式
    -- 范围只能限定在变量上
    -- 而 local function xx() 的形式范围会包含整个 function
    if source.start > valueSource.start then
        callback {
            name = hvr.name,
            detail = hvr.label:gsub('[\r\n]', ''),
            kind = kind,
            range = { valueSource.start, valueSource.finish },
            selectionRange = { source.start, source.finish },
            valueRange = { valueSource.start, valueSource.finish },
        }
    else
        callback {
            name = hvr.name,
            detail = hvr.label:gsub('[\r\n]', ''),
            kind = kind,
            range = { source.start, source.finish },
            selectionRange = { source.start, source.finish },
            valueRange = { valueSource.start, valueSource.finish },
        }
    end
end

local function buildSet(source, callback)
    if source:bindLocal() then
        return
    end
    local value = source:bindValue()
    local hvr = hover(source)
    if not hvr then
        return
    end
    local kind
    if value:getFunction() then
        local func = value:getFunction()
        if func:getObject() then
            kind = SymbolKind.Field
        else
            kind = SymbolKind.Function
        end
    elseif source:get 'table index' then
        kind = SymbolKind.Class
    else
        kind = SymbolKind.Object
    end
    local valueSource = value.source
    -- 由于范围不允许交叉,为了支持 x, y, z = 1, 2, 3 的形式
    -- 范围只能限定在变量上
    -- 而 function xx() 的形式范围会包含整个 function
    if source.start > valueSource.start then
        callback {
            name = hvr.name,
            -- 前端不支持多行
            detail = hvr.label:gsub('[\r\n]', ''),
            kind = kind,
            range = { valueSource.start, valueSource.finish },
            selectionRange = { source.start, source.finish },
            valueRange = { valueSource.start, valueSource.finish },
        }
    else
        callback {
            name = hvr.name,
            -- 前端不支持多行
            detail = hvr.label:gsub('[\r\n]', ''),
            kind = kind,
            range = { source.start, source.finish },
            selectionRange = { source.start, source.finish },
            valueRange = { valueSource.start, valueSource.finish },
        }
    end
end

local function buildReturn(source, callback)
    local value = source:bindFunction()
    if not value then
        return
    end
    local hvr = hoverFunction('', value:getFunction())
    if not hvr then
        return
    end
    local kind = SymbolKind.Function
    callback {
        name = '',
        -- 前端不支持多行
        detail = hvr.label:gsub('[\r\n]', ''),
        kind = kind,
        range = { source.start, source.finish },
        selectionRange = { source.start, source.start },
        valueRange = { source.start, source.finish },
    }
end

local function buildSource(source, callback)
    if source:action() == 'local' then
        buildLocal(source, callback)
        return
    end
    if source:action() == 'set' then
        buildSet(source, callback)
        return
    end
    if source.type == 'return' then
        for _, src in ipairs(source) do
            buildReturn(src, callback)
        end
        return
    end
end

local function packChild(symbols, finish, kind)
    local t
    while true do
        local symbol = symbols[#symbols]
        if not symbol then
            break
        end
        if symbol.valueRange[1] > finish then
            break
        end
        symbols[#symbols] = nil
        symbol.children = packChild(symbols, symbol.valueRange[2], symbol.kind)
        if symbol.kind == SymbolKind.Class and kind == SymbolKind.Function then
        else
            if not t then
                t = {}
            end
            t[#t+1] = symbol
        end
    end
    return t
end

local function packSymbols(symbols)
    -- 按照start位置反向排序
    table.sort(symbols, function (a, b)
        return a.valueRange[1] > b.valueRange[1]
    end)
    -- 处理嵌套
    return packChild(symbols, math.maxinteger, SymbolKind.Function)
end

return function (vm)
    local symbols = {}

    for _, source in ipairs(vm.sources) do
        buildSource(source, function (data)
            symbols[#symbols+1] = data
        end)
    end

    local packedSymbols = packSymbols(symbols)

    return packedSymbols
end