summaryrefslogtreecommitdiff
path: root/server/src/core/document_symbol.lua
blob: 199aab7bee65cb86629715aebf9a6c1f3e592d23 (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
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 buildFunction(vm, var, source)
    local func = var.value
    if func.source.start == 0 then
        return nil
    end
    local name = hoverName(var, source)
    local hvr = hoverFunction(name, func, source.object)
    if not hvr then
        return nil
    end
    local selectionRange = { source.start, source.finish }
    local range = { math.min(source.start, func.source.start), func.source.finish }
    local kind = SymbolKind.Function
    if source.isSuffix then
        kind = SymbolKind.Field
    end

    return {
        name = name,
        -- 前端不支持多行
        detail = hvr.label:gsub('[\r\n]', ''),
        kind = kind,
        range = range,
        selectionRange = selectionRange,
    }
end

local function isLocalTable(var, source)
    if not var.value or var.value:getType() ~= 'table' then
        return false
    end
    if var.value.source.start == 0 then
        return false
    end
    if source ~= var.value:getDeclarat() then
        return false
    end
    if var.value.source.finish < source.finish then
        return false
    end
    return true
end

local function buildVar(vm, var, source)
    if source.start == 0 then
        return nil
    end
    if var.value:getType() == 'function' then
        return buildFunction(vm, var, source)
    end
    if not source.isLocal and not source.isIndex then
        return nil
    end
    if var.hide then
        return nil
    end
    local key = var.key
    if key == '_' then
        return nil
    end
    if type(key) ~= 'string' then
        key = ('[%s]'):format(key)
    end
    local range
    if isLocalTable(var, source) then
        range = { source.start, var.value.source.finish }
    else
        range = { source.start, source.finish }
    end
    local hvr = hover(var, source)
    if not hvr then
        return nil
    end
    local kind
    if source.isIndex then
        kind = SymbolKind.Class
    else
        kind = SymbolKind.Variable
    end
    return {
        name = key,
        -- 前端不支持多行
        detail = hvr.label:gsub('[\r\n]', ''),
        kind = kind,
        range = range,
        selectionRange = { source.start, source.finish },
    }
end

local function packChild(symbols, finish, kind)
    local t
    while true do
        local symbol = symbols[#symbols]
        if not symbol then
            break
        end
        if symbol.range[1] > finish then
            break
        end
        symbols[#symbols] = nil
        symbol.children = packChild(symbols, symbol.range[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.range[1] > b.range[1]
    end)
    -- 处理嵌套
    return packChild(symbols, math.maxinteger, SymbolKind.Function)
end

return function (vm)
    local symbols = {}

    for _, source in ipairs(vm.results.sources) do
        if source.bind then
            symbols[#symbols+1] = buildVar(vm, source.bind, source)
        end
    end

    local packedSymbols = packSymbols(symbols)

    return packedSymbols
end