summaryrefslogtreecommitdiff
path: root/server/src/core/signature.lua
blob: ca20f05424c2601879a034aca35da7ab721e021c (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
local getFunctionHover = require 'core.hover.function'
local getFunctionHoverAsLib = require 'core.hover.lib_function'
local findLib = require 'core.find_lib'
local buildValueName = require 'core.hover.name'
local findSource = require 'core.find_source'

local function findCall(vm, pos)
    local results = {}
    for _, src in ipairs(vm.sources) do
        if      src.type == 'call' 
            and src.start <= pos
            and src.finish >= pos
        then
            results[#results+1] = src
        end
    end
    if #results == 0 then
        return nil
    end
    -- 可能处于 'func1(func2(' 的嵌套中,将最近的call放到最前面
    table.sort(results, function (a, b)
        return a.start > b.start
    end)
    return results
end

local function getSelect(args, pos)
    if not args then
        return 1
    end
    for i, arg in ipairs(args) do
        if arg.start <= pos and arg.finish >= pos - 1 then
            return i
        end
    end
    return #args + 1
end

local function getFunctionSource(call)
    local simple = call:get 'simple'
    for i, source in ipairs(simple) do
        if source == call then
            return simple[i-1]
        end
    end
    return nil
end

local function getHover(call, pos)
    local func, args = call:bindCall()
    if not func then
        return
    end
    local select = getSelect(args, pos)
    local source = getFunctionSource(call)
    local object = source:get 'object'
    local lib, fullkey = findLib(source)
    local name = fullkey or buildValueName(source)
    local hover
    if lib then
        hover = getFunctionHoverAsLib(name, lib, object, select)
    else
        hover = getFunctionHover(name, func:getFunction(), object, select)
    end
    if hover and hover.argLabel then
        return hover
    end
end

local function isInFunctionOrTable(call, pos)
    local func, args = call:bindCall()
    if not func then
        return false
    end
    local select = getSelect(args, pos)
    local arg = args[select]
    if not arg then
        return false
    end
    if arg.type == 'function' or arg.type == 'table' then
        return true
    end
    return false
end

return function (vm, pos)
    local source = findSource(vm, pos) or findSource(vm, pos-1)
    if not source or source.type == 'string' then
        return
    end
    local calls = findCall(vm, pos)
    if not calls or #calls == 0 then
        return nil
    end

    local nearCall = calls[1]
    if isInFunctionOrTable(nearCall, pos) then
        return nil
    end

    local hovers = {}
    for _, call in ipairs(calls) do
        hovers[#hovers+1] = getHover(call, pos)
    end

    if #hovers == 0 then
        return nil
    end

    return hovers
end