summaryrefslogtreecommitdiff
path: root/script/core/hover/init.lua
blob: 949156aa0bdfae366fe29c5010b956eb06f2d124 (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
local files      = require 'files'
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 markdown   = require 'provider.markdown'
local guide      = require 'parser.guide'

---@async
local function getHover(source)
    local md        = markdown()
    local defMark   = {}
    local labelMark = {}
    local descMark  = {}

    ---@async
    local function addHover(def, checkLable, oop)
        if defMark[def] then
            return
        end
        defMark[def] = true

        if checkLable then
            local label = getLabel(def, oop)
            if not labelMark[tostring(label)] then
                labelMark[tostring(label)] = true
                md:add('lua', label)
                md:splitLine()
            end
        end

        local desc  = getDesc(def)
        if not descMark[tostring(desc)] then
            descMark[tostring(desc)] = true
            md:add('md', desc)
            md:splitLine()
        end
    end

    local oop
    if vm.getInfer(source):view(guide.getUri(source)) == 'function' then
        local defs = vm.getDefs(source)
        -- make sure `function` is before `doc.type.function`
        local orders = {}
        for i, def in ipairs(defs) do
            if def.type == 'function' then
                orders[def] = i - 20000
            elseif def.type == 'doc.type.function' then
                orders[def] = i - 10000
            else
                orders[def] = i
            end
        end
        table.sort(defs, function (a, b)
            return orders[a] < orders[b]
        end)
        local hasFunc
        for _, def in ipairs(defs) do
            if guide.isOOP(def) then
                oop = true
            end
            if def.type == 'function'
            or def.type == 'doc.type.function' then
                hasFunc = true
                addHover(def, true, oop)
            end
        end
        if not hasFunc then
            addHover(source, true, oop)
        end
    else
        addHover(source, true, oop)
        for _, def in ipairs(vm.getDefs(source)) do
            if def.type == 'global' then
                goto CONTINUE
            end
            if guide.isOOP(def) then
                oop = true
            end
            local isFunction
            if def.type == 'function'
            or def.type == 'doc.type.function' then
                isFunction = true
            end
            addHover(def, isFunction, oop)
            ::CONTINUE::
        end
    end

    return md
end

local accept = {
    ['local']         = true,
    ['setlocal']      = true,
    ['getlocal']      = true,
    ['setglobal']     = true,
    ['getglobal']     = true,
    ['field']         = true,
    ['method']        = true,
    ['string']        = true,
    ['number']        = true,
    ['integer']       = true,
    ['doc.type.name'] = true,
    ['function']      = true,
    ['doc.module']    = true,
}

---@async
local function getHoverByUri(uri, position)
    local ast = files.getState(uri)
    if not ast then
        return nil
    end
    local source = findSource(ast, position, accept)
    if not source then
        return nil
    end
    local hover = getHover(source)
    if SHOWSOURCE then
        hover:splitLine()
        hover:add('lua', util.dump(source, {
            deep = 1,
        }))
    end
    return hover, source
end

return {
    get   = getHover,
    byUri = getHoverByUri,
}