summaryrefslogtreecommitdiff
path: root/script-beta/core/hover/init.lua
blob: 77f9d6d91cfcc1959831a47bc7e825a4cbed2e87 (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
local files      = require 'files'
local guide      = require 'parser.guide'
local vm         = require 'vm'
local getLabel   = require 'core.hover.label'
local getDesc    = require 'core.hover.description'
local util       = require 'utility'
local findSource = require 'core.find-source'
local lang       = require 'language'

local function getHoverAsFunction(source)
    local values = vm.getInfers(source)
    local desc   = getDesc(source)
    local labels = {}
    local defs = 0
    local protos = 0
    local other = 0
    local oop = source.type == 'method'
             or source.type == 'getmethod'
             or source.type == 'setmethod'
    for _, value in ipairs(values) do
        if value.type == 'function' then
            local label = getLabel(value.source, oop)
            if label then
                defs = defs + 1
                labels[label] = (labels[label] or 0) + 1
                if labels[label] == 1 then
                    protos = protos + 1
                end
            end
        elseif value.type == 'table'
        or     value.type == 'boolean'
        or     value.type == 'string'
        or     value.type == 'number' then
            other = other + 1
        end
    end

    if defs == 1 and other == 0 then
        return {
            label       = next(labels),
            source      = source,
            description = desc,
        }
    end

    local lines = {}
    if defs > 1 then
        lines[#lines+1] = lang.script('HOVER_MULTI_DEF_PROTO', defs, protos)
    end
    if other > 0 then
        lines[#lines+1] = lang.script('HOVER_MULTI_PROTO_NOT_FUNC', other)
    end
    if defs > 1 then
        for label, count in util.sortPairs(labels) do
            lines[#lines+1] = ('(%d) %s'):format(count, label)
        end
    else
        lines[#lines+1] = next(labels)
    end
    local label = table.concat(lines, '\n')
    return {
        label       = label,
        source      = source,
        description = desc,
    }
end

local function getHoverAsValue(source)
    local oop = source.type == 'method'
             or source.type == 'getmethod'
             or source.type == 'setmethod'
    local label = getLabel(source, oop)
    local desc  = getDesc(source)
    return {
        label       = label,
        source      = source,
        description = desc,
    }
end

local function getHover(source)
    vm.setSearchLevel(5)
    local isFunction = vm.hasInferType(source, 'function')
    if isFunction then
        return getHoverAsFunction(source)
    else
        return getHoverAsValue(source)
    end
end

local accept = {
    ['local']     = true,
    ['setlocal']  = true,
    ['getlocal']  = true,
    ['setglobal'] = true,
    ['getglobal'] = true,
    ['field']     = true,
    ['method']    = true,
    ['string']    = true,
    ['number']    = true,
}

local function getHoverByUri(uri, offset)
    local ast = files.getAst(uri)
    if not ast then
        return nil
    end
    local source = findSource(ast, offset, accept)
    if not source then
        return nil
    end
    local hover = getHover(source)
    return hover
end

return {
    get   = getHover,
    byUri = getHoverByUri,
}