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
|
local files = require 'files'
local guide = require 'parser.guide'
local vm = require 'vm'
local hoverLabel = require 'core.hover.label'
local hoverDesc = require 'core.hover.description'
local function findNearCall(uri, ast, pos)
local text = files.getText(uri)
-- 检查 `f()$` 的情况,注意要区别于 `f($`
if text:sub(pos, pos) == ')' then
return nil
end
local nearCall
guide.eachSourceContain(ast.ast, pos, function (src)
if src.type == 'call'
or src.type == 'table'
or src.type == 'function' then
if not nearCall or nearCall.start < src.start then
nearCall = src
end
end
end)
if not nearCall then
return nil
end
if nearCall.type ~= 'call' then
return nil
end
return nearCall
end
local function makeOneSignature(source, oop, index)
local label = hoverLabel(source, oop)
-- 去掉返回值
label = label:gsub('%s*->.+', '')
local params = {}
local i = 0
for start, finish in label:gmatch '[%(%)%,]%s*().-()%s*%f[%(%)%,%[%]]' do
i = i + 1
params[i] = {
label = {start, finish-1},
}
end
-- 不定参数
if index > i and i > 0 then
local lastLabel = params[i].label
local text = label:sub(lastLabel[1], lastLabel[2])
if text == '...' then
index = i
end
end
return {
label = label,
params = params,
index = index,
description = hoverDesc(source),
}
end
local function makeSignatures(call, pos)
local node = call.node
local oop = node.type == 'method'
or node.type == 'getmethod'
or node.type == 'setmethod'
local index
local args = call.args
if args then
for i, arg in ipairs(args) do
if arg.start <= pos and arg.finish >= pos then
index = i
break
end
end
if not index then
index = #args + 1
end
else
index = 1
end
local signs = {}
vm.eachDef(node, function (src)
if src.type == 'function' then
signs[#signs+1] = makeOneSignature(src, oop, index)
end
end)
return signs
end
return function (uri, pos)
local ast = files.getAst(uri)
if not ast then
return nil
end
local call = findNearCall(uri, ast, pos)
if not call then
return nil
end
local signs = makeSignatures(call, pos)
if not signs or #signs == 0 then
return nil
end
return signs
end
|