Skip to content

Commit 1233a00

Browse files
Go-to-definition: Return a list of Locations all the way to the top (#28)
The `processing.FindRangesFromIndexList` function already returned a list of object ranges (never more than one in it for now, though) However, this list didn't make it up to the server's `Definition` method. This refactors the server code and the tests to allow us to return and test for a list of locations. All that will remain (so easy, right) is to modify the `processing` package code Progress towards #6
1 parent 6e04307 commit 1233a00

File tree

3 files changed

+463
-437
lines changed

3 files changed

+463
-437
lines changed

pkg/server/definition.go

+41-37
Original file line numberDiff line numberDiff line change
@@ -17,20 +17,25 @@ import (
1717
)
1818

1919
func (s *server) Definition(ctx context.Context, params *protocol.DefinitionParams) (protocol.Definition, error) {
20-
definitionLink, err := s.DefinitionLink(ctx, params)
20+
responseDefLinks, err := s.definitionLink(ctx, params, true)
2121
if err != nil {
22-
return nil, nil
22+
return nil, err
2323
}
24-
definition := protocol.Definition{
25-
{
26-
URI: definitionLink.TargetURI,
27-
Range: definitionLink.TargetRange,
28-
},
24+
25+
// TODO: Support LocationLink instead of Location (this needs to be changed in the upstream protocol lib)
26+
// When that's done, we can get rid of the intermediary `definitionLink` function which is used for testing
27+
var response protocol.Definition
28+
for _, item := range responseDefLinks {
29+
response = append(response, protocol.Location{
30+
URI: item.TargetURI,
31+
Range: item.TargetRange,
32+
})
2933
}
30-
return definition, nil
34+
35+
return response, nil
3136
}
3237

33-
func (s *server) DefinitionLink(ctx context.Context, params *protocol.DefinitionParams) (*protocol.DefinitionLink, error) {
38+
func (s *server) definitionLink(ctx context.Context, params *protocol.DefinitionParams, warnIfNotFound bool) ([]protocol.DefinitionLink, error) {
3439
doc, err := s.cache.get(params.TextDocument.URI)
3540
if err != nil {
3641
return nil, utils.LogErrorf("Definition: %s: %w", errorRetrievingDocument, err)
@@ -44,28 +49,24 @@ func (s *server) DefinitionLink(ctx context.Context, params *protocol.Definition
4449
if err != nil {
4550
return nil, utils.LogErrorf("error creating the VM: %w", err)
4651
}
47-
definition, err := Definition(doc.ast, params, vm)
52+
responseDefLinks, err := findDefinition(doc.ast, params, vm)
4853
if err != nil {
49-
log.Warn(err.Error())
54+
if warnIfNotFound {
55+
log.Warn(err.Error())
56+
return nil, nil
57+
}
5058
return nil, err
5159
}
5260

53-
return definition, nil
61+
return responseDefLinks, nil
5462
}
5563

56-
func Definition(node ast.Node, params *protocol.DefinitionParams, vm *jsonnet.VM) (*protocol.DefinitionLink, error) {
57-
responseDefLink, err := findDefinition(node, params, vm)
58-
if err != nil {
59-
return nil, err
60-
}
61-
return responseDefLink, nil
62-
}
64+
func findDefinition(root ast.Node, params *protocol.DefinitionParams, vm *jsonnet.VM) ([]protocol.DefinitionLink, error) {
65+
var response []protocol.DefinitionLink
6366

64-
func findDefinition(root ast.Node, params *protocol.DefinitionParams, vm *jsonnet.VM) (*protocol.DefinitionLink, error) {
6567
searchStack, _ := processing.FindNodeByPosition(root, position.PositionProtocolToAST(params.Position))
6668
var deepestNode ast.Node
6769
searchStack, deepestNode = searchStack.Pop()
68-
var responseDefLink protocol.DefinitionLink
6970
switch deepestNode := deepestNode.(type) {
7071
case *ast.Var:
7172
log.Debugf("Found Var node %s", deepestNode.Id)
@@ -96,11 +97,11 @@ func findDefinition(root ast.Node, params *protocol.DefinitionParams, vm *jsonne
9697
return nil, fmt.Errorf("no matching bind found for %s", deepestNode.Id)
9798
}
9899

99-
responseDefLink = protocol.DefinitionLink{
100+
response = append(response, protocol.DefinitionLink{
100101
TargetURI: protocol.DocumentURI(filename),
101102
TargetRange: resultRange,
102103
TargetSelectionRange: resultSelectionRange,
103-
}
104+
})
104105
case *ast.SuperIndex, *ast.Index:
105106
indexSearchStack := nodestack.NewNodeStack(deepestNode)
106107
indexList := indexSearchStack.BuildIndexList()
@@ -109,32 +110,35 @@ func findDefinition(root ast.Node, params *protocol.DefinitionParams, vm *jsonne
109110
if err != nil {
110111
return nil, err
111112
}
112-
objectRange := objectRanges[0] // TODO: Handle multiple positions
113-
responseDefLink = protocol.DefinitionLink{
114-
TargetURI: protocol.DocumentURI(objectRange.Filename),
115-
TargetRange: position.RangeASTToProtocol(objectRange.FullRange),
116-
TargetSelectionRange: position.RangeASTToProtocol(objectRange.SelectionRange),
113+
for _, o := range objectRanges {
114+
response = append(response, protocol.DefinitionLink{
115+
TargetURI: protocol.DocumentURI(o.Filename),
116+
TargetRange: position.RangeASTToProtocol(o.FullRange),
117+
TargetSelectionRange: position.RangeASTToProtocol(o.SelectionRange),
118+
})
117119
}
118120
case *ast.Import:
119121
filename := deepestNode.File.Value
120122
importedFile, _ := vm.ResolveImport(string(params.TextDocument.URI), filename)
121-
responseDefLink = protocol.DefinitionLink{
123+
response = append(response, protocol.DefinitionLink{
122124
TargetURI: protocol.DocumentURI(importedFile),
123-
}
125+
})
124126
default:
125127
log.Debugf("cannot find definition for node type %T", deepestNode)
126128
return nil, fmt.Errorf("cannot find definition")
127129

128130
}
129131

130-
link := string(responseDefLink.TargetURI)
131-
if !strings.HasPrefix(link, "file://") {
132-
targetFile, err := filepath.Abs(link)
133-
if err != nil {
134-
return nil, err
132+
for i, item := range response {
133+
link := string(item.TargetURI)
134+
if !strings.HasPrefix(link, "file://") {
135+
targetFile, err := filepath.Abs(link)
136+
if err != nil {
137+
return nil, err
138+
}
139+
response[i].TargetURI = protocol.URIFromPath(targetFile)
135140
}
136-
responseDefLink.TargetURI = protocol.URIFromPath(targetFile)
137141
}
138142

139-
return &responseDefLink, nil
143+
return response, nil
140144
}

0 commit comments

Comments
 (0)