Skip to content

Commit eda74fd

Browse files
committed
暂存-转到实现
1 parent 6347eea commit eda74fd

File tree

6 files changed

+311
-51
lines changed

6 files changed

+311
-51
lines changed

script/core/implementation.lua

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
local workspace = require 'workspace'
2+
local files = require 'files'
3+
local vm = require 'vm'
4+
local findSource = require 'core.find-source'
5+
local guide = require 'parser.guide'
6+
local rpath = require 'workspace.require-path'
7+
local jumpSource = require 'core.jump-source'
8+
9+
local function sortResults(results)
10+
-- 先按照顺序排序
11+
table.sort(results, function (a, b)
12+
local u1 = guide.getUri(a.target)
13+
local u2 = guide.getUri(b.target)
14+
if u1 == u2 then
15+
return a.target.start < b.target.start
16+
else
17+
return u1 < u2
18+
end
19+
end)
20+
-- 如果2个结果处于嵌套状态,则取范围小的那个
21+
local lf, lu
22+
for i = #results, 1, -1 do
23+
local res = results[i].target
24+
local f = res.finish
25+
local uri = guide.getUri(res)
26+
if lf and f > lf and uri == lu then
27+
table.remove(results, i)
28+
else
29+
lu = uri
30+
lf = f
31+
end
32+
end
33+
end
34+
35+
local accept = {
36+
['local'] = true,
37+
['setlocal'] = true,
38+
['getlocal'] = true,
39+
['label'] = true,
40+
['goto'] = true,
41+
['field'] = true,
42+
['method'] = true,
43+
['setglobal'] = true,
44+
['getglobal'] = true,
45+
['string'] = true,
46+
['boolean'] = true,
47+
['number'] = true,
48+
['integer'] = true,
49+
['...'] = true,
50+
51+
['doc.type.name'] = true,
52+
['doc.class.name'] = true,
53+
['doc.extends.name'] = true,
54+
['doc.alias.name'] = true,
55+
['doc.cast.name'] = true,
56+
['doc.enum.name'] = true,
57+
['doc.field.name'] = true,
58+
}
59+
60+
local function convertIndex(source)
61+
if not source then
62+
return
63+
end
64+
if source.type == 'string'
65+
or source.type == 'boolean'
66+
or source.type == 'number'
67+
or source.type == 'integer' then
68+
local parent = source.parent
69+
if not parent then
70+
return
71+
end
72+
if parent.type == 'setindex'
73+
or parent.type == 'getindex'
74+
or parent.type == 'tableindex' then
75+
return parent
76+
end
77+
end
78+
return source
79+
end
80+
81+
return function (uri, offset)
82+
local ast = files.getState(uri)
83+
if not ast then
84+
return nil
85+
end
86+
87+
local source = convertIndex(findSource(ast, offset, accept))
88+
if not source then
89+
return nil
90+
end
91+
92+
local results = {}
93+
94+
local defs = vm.getDefs(source)
95+
96+
for _, src in ipairs(defs) do
97+
if src.type == 'global' then
98+
goto CONTINUE
99+
end
100+
local root = guide.getRoot(src)
101+
if not root then
102+
goto CONTINUE
103+
end
104+
if src.type == 'self' then
105+
goto CONTINUE
106+
end
107+
src = src.field or src.method or src
108+
if src.type == 'getindex'
109+
or src.type == 'setindex'
110+
or src.type == 'tableindex' then
111+
src = src.index
112+
if not src then
113+
goto CONTINUE
114+
end
115+
if not guide.isLiteral(src) then
116+
goto CONTINUE
117+
end
118+
end
119+
if src.type == 'doc.type.function'
120+
or src.type == 'doc.type.table'
121+
or src.type == 'doc.type.boolean'
122+
or src.type == 'doc.type.integer'
123+
or src.type == 'doc.type.string' then
124+
goto CONTINUE
125+
end
126+
if src.type == 'doc.class' then
127+
goto CONTINUE
128+
end
129+
if src.type == 'doc.alias' then
130+
goto CONTINUE
131+
end
132+
if src.type == 'doc.enum' then
133+
goto CONTINUE
134+
end
135+
if src.type == 'doc.type.field' then
136+
goto CONTINUE
137+
end
138+
if src.type == 'doc.class.name'
139+
or src.type == 'doc.alias.name'
140+
or src.type == 'doc.enum.name'
141+
or src.type == 'doc.field.name' then
142+
goto CONTINUE
143+
end
144+
if src.type == 'doc.generic.name' then
145+
goto CONTINUE
146+
end
147+
if src.type == 'doc.param' then
148+
goto CONTINUE
149+
end
150+
151+
results[#results+1] = {
152+
target = src,
153+
uri = root.uri,
154+
source = source,
155+
}
156+
::CONTINUE::
157+
end
158+
159+
if #results == 0 then
160+
return nil
161+
end
162+
163+
sortResults(results)
164+
jumpSource(results)
165+
166+
return results
167+
end

script/core/type-definition.lua

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,9 @@ local accept = {
5252
['doc.class.name'] = true,
5353
['doc.extends.name'] = true,
5454
['doc.alias.name'] = true,
55+
['doc.cast.name'] = true,
5556
['doc.enum.name'] = true,
56-
['doc.see.name'] = true,
57+
['doc.field.name'] = true,
5758
}
5859

5960
local function checkRequire(source, offset)

script/provider/provider.lua

Lines changed: 59 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,39 @@ m.register 'textDocument/hover' {
368368
end
369369
}
370370

371+
local function convertDefinitionResult(state, result)
372+
local response = {}
373+
for i, info in ipairs(result) do
374+
---@type uri
375+
local targetUri = info.uri
376+
if targetUri then
377+
local targetState = files.getState(targetUri)
378+
if targetState then
379+
if client.getAbility 'textDocument.definition.linkSupport' then
380+
response[i] = converter.locationLink(targetUri
381+
, converter.packRange(targetState, info.target.start, info.target.finish)
382+
, converter.packRange(targetState, info.target.start, info.target.finish)
383+
, converter.packRange(state, info.source.start, info.source.finish)
384+
)
385+
else
386+
response[i] = converter.location(targetUri
387+
, converter.packRange(targetState, info.target.start, info.target.finish)
388+
)
389+
end
390+
else
391+
response[i] = converter.location(
392+
targetUri,
393+
converter.range(
394+
converter.position(guide.rowColOf(info.target.start)),
395+
converter.position(guide.rowColOf(info.target.finish))
396+
)
397+
)
398+
end
399+
end
400+
end
401+
return response
402+
end
403+
371404
m.register 'textDocument/definition' {
372405
capability = {
373406
definitionProvider = true,
@@ -388,35 +421,7 @@ m.register 'textDocument/definition' {
388421
if not result then
389422
return nil
390423
end
391-
local response = {}
392-
for i, info in ipairs(result) do
393-
---@type uri
394-
local targetUri = info.uri
395-
if targetUri then
396-
local targetState = files.getState(targetUri)
397-
if targetState then
398-
if client.getAbility 'textDocument.definition.linkSupport' then
399-
response[i] = converter.locationLink(targetUri
400-
, converter.packRange(targetState, info.target.start, info.target.finish)
401-
, converter.packRange(targetState, info.target.start, info.target.finish)
402-
, converter.packRange(state, info.source.start, info.source.finish)
403-
)
404-
else
405-
response[i] = converter.location(targetUri
406-
, converter.packRange(targetState, info.target.start, info.target.finish)
407-
)
408-
end
409-
else
410-
response[i] = converter.location(
411-
targetUri,
412-
converter.range(
413-
converter.position(guide.rowColOf(info.target.start)),
414-
converter.position(guide.rowColOf(info.target.finish))
415-
)
416-
)
417-
end
418-
end
419-
end
424+
local response = convertDefinitionResult(state, result)
420425
return response
421426
end
422427
}
@@ -441,27 +446,32 @@ m.register 'textDocument/typeDefinition' {
441446
if not result then
442447
return nil
443448
end
444-
local response = {}
445-
for i, info in ipairs(result) do
446-
---@type uri
447-
local targetUri = info.uri
448-
if targetUri then
449-
local targetState = files.getState(targetUri)
450-
if targetState then
451-
if client.getAbility 'textDocument.typeDefinition.linkSupport' then
452-
response[i] = converter.locationLink(targetUri
453-
, converter.packRange(targetState, info.target.start, info.target.finish)
454-
, converter.packRange(targetState, info.target.start, info.target.finish)
455-
, converter.packRange(state, info.source.start, info.source.finish)
456-
)
457-
else
458-
response[i] = converter.location(targetUri
459-
, converter.packRange(targetState, info.target.start, info.target.finish)
460-
)
461-
end
462-
end
463-
end
449+
local response = convertDefinitionResult(state, result)
450+
return response
451+
end
452+
}
453+
454+
m.register 'textDocument/implementation' {
455+
capability = {
456+
implementationProvider = true,
457+
},
458+
abortByFileUpdate = true,
459+
---@async
460+
function (params)
461+
local uri = files.getRealUri(params.textDocument.uri)
462+
workspace.awaitReady(uri)
463+
local _ <close> = progress.create(uri, lang.script.WINDOW_PROCESSING_TYPE_DEFINITION, 0.5)
464+
local state = files.getState(uri)
465+
if not state then
466+
return
467+
end
468+
local core = require 'core.implementation'
469+
local pos = converter.unpackPosition(state, params.position)
470+
local result = core(uri, pos)
471+
if not result then
472+
return nil
464473
end
474+
local response = convertDefinitionResult(state, result)
465475
return response
466476
end
467477
}

script/vm/function.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,7 @@ function vm.getMatchedFunctions(func, args, mark)
337337
local funcs = {}
338338
local node = vm.compileNode(func)
339339
for n in node:eachObject() do
340-
if (n.type == 'function' and not vm.isVarargFunctionWithOverloads(n))
340+
if n.type == 'function'
341341
or n.type == 'doc.type.function' then
342342
funcs[#funcs+1] = n
343343
end

test.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ local function testAll()
5555
test 'basic'
5656
test 'definition'
5757
test 'type_inference'
58+
test 'implementation'
5859
test 'references'
5960
test 'hover'
6061
test 'completion'

0 commit comments

Comments
 (0)