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
|
local files = require 'files'
local searcher = require 'core.searcher'
local vm = require 'vm'
local hoverLabel = require 'core.hover.label'
local hoverDesc = require 'core.hover.description'
local guide = require 'parser.guide'
local function findNearCall(uri, ast, pos)
local text = files.getText(uri)
local nearCall
guide.eachSourceContain(ast.ast, pos, function (src)
if src.type == 'call'
or src.type == 'table'
or src.type == 'function' then
-- call(),$
if src.finish <= pos
and text:sub(src.finish, src.finish) == ')' then
return
end
-- {},$
if src.finish <= pos
and text:sub(src.finish, src.finish) == '}' then
return
end
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
local argStart, argLabel = label:match '()(%b())'
local converted = argLabel
: sub(2, -2)
: gsub('%b<>', function (str)
return ('_'):rep(#str)
end)
: gsub('[%[%]%(%)]', '_')
for start, finish in converted:gmatch '%s*()[^,]+()' do
i = i + 1
params[i] = {
label = {start + argStart, finish - 1 + argStart},
}
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
if call.args then
local args = {}
for _, arg in ipairs(call.args) do
if not arg.dummy then
args[#args+1] = arg
end
end
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 = {}
local defs = vm.getDefs(node)
local mark = {}
for _, src in ipairs(defs) do
src = searcher.getObjectValue(src) or src
if src.type == 'function'
or src.type == 'doc.type.function' then
if not mark[src] then
mark[src] = true
signs[#signs+1] = makeOneSignature(src, oop, index)
end
end
end
return signs
end
local function isSpace(char)
if char == ' '
or char == '\n'
or char == '\r'
or char == '\t' then
return true
end
return false
end
local function skipSpace(text, offset)
for i = offset, 1, -1 do
local char = text:sub(i, i)
if not isSpace(char) then
return i
end
end
return 0
end
return function (uri, pos)
local ast = files.getAst(uri)
if not ast then
return nil
end
local text = files.getText(uri)
pos = skipSpace(text, pos)
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
|