Skip to content

Commit fd733b2

Browse files
Completion: Fix completion through an import pointing to a local bind (#118)
* Completion: Fix completion through an import pointing to a local bind Closes #113 This also fixes the go-to-definition functionality for this case, since it's the same code * Change order. Var ref is probably more exact than a stack search * Make it work nested
1 parent 92fc191 commit fd733b2

File tree

6 files changed

+119
-33
lines changed

6 files changed

+119
-33
lines changed

pkg/ast/processing/top_level_objects.go

+29-7
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,37 @@ func FindTopLevelObjects(stack *nodestack.NodeStack, vm *jsonnet.VM) []*ast.Desu
3737
rootNode, _, _ := vm.ImportAST(string(curr.Loc().File.DiagnosticFileName), filename)
3838
stack.Push(rootNode)
3939
case *ast.Index:
40-
container := stack.Peek()
41-
if containerObj, containerIsObj := container.(*ast.DesugaredObject); containerIsObj {
42-
indexValue, indexIsString := curr.Index.(*ast.LiteralString)
43-
if !indexIsString {
40+
indexValue, indexIsString := curr.Index.(*ast.LiteralString)
41+
if !indexIsString {
42+
continue
43+
}
44+
45+
var container ast.Node
46+
// If our target is a var, the container for the index is the var ref
47+
if varTarget, targetIsVar := curr.Target.(*ast.Var); targetIsVar {
48+
ref, err := FindVarReference(varTarget, vm)
49+
if err != nil {
50+
log.WithError(err).Errorf("Error finding var reference, ignoring this node")
4451
continue
4552
}
46-
objs := findObjectFieldsInObject(containerObj, indexValue.Value, false)
47-
if len(objs) > 0 {
48-
stack.Push(objs[0].Body)
53+
container = ref
54+
}
55+
56+
// If we have not found a viable container, peek at the next object on the stack
57+
if container == nil {
58+
container = stack.Peek()
59+
}
60+
61+
var possibleObjects []*ast.DesugaredObject
62+
if containerObj, containerIsObj := container.(*ast.DesugaredObject); containerIsObj {
63+
possibleObjects = []*ast.DesugaredObject{containerObj}
64+
} else if containerImport, containerIsImport := container.(*ast.Import); containerIsImport {
65+
possibleObjects = FindTopLevelObjectsInFile(vm, containerImport.File.Value, string(containerImport.Loc().File.DiagnosticFileName))
66+
}
67+
68+
for _, obj := range possibleObjects {
69+
for _, field := range findObjectFieldsInObject(obj, indexValue.Value, false) {
70+
stack.Push(field.Body)
4971
}
5072
}
5173
case *ast.Var:

pkg/server/completion_test.go

+80-22
Original file line numberDiff line numberDiff line change
@@ -454,28 +454,6 @@ func TestCompletion(t *testing.T) {
454454
},
455455
},
456456
},
457-
// TODO: This one doesn't work yet
458-
// Issue: https://github.com/grafana/jsonnet-language-server/issues/113
459-
// {
460-
// name: "autocomplete local at root 2",
461-
// filename: "testdata/local-at-root-2.jsonnet",
462-
// replaceString: "hello.to",
463-
// replaceByString: "hello.",
464-
// expected: protocol.CompletionList{
465-
// IsIncomplete: false,
466-
// Items: []protocol.CompletionItem{
467-
// {
468-
// Label: "to",
469-
// Kind: protocol.FieldCompletion,
470-
// Detail: "hello.to",
471-
// InsertText: "to",
472-
// LabelDetails: protocol.CompletionItemLabelDetails{
473-
// Description: "object",
474-
// },
475-
// },
476-
// },
477-
// },
478-
// },
479457
{
480458
// This checks that we don't match on `hello.hello.*` if we autocomplete on `hello.hel.`
481459
name: "autocomplete local at root, no partial match if full match exists",
@@ -508,6 +486,86 @@ func TestCompletion(t *testing.T) {
508486
Items: nil,
509487
},
510488
},
489+
{
490+
name: "autocomplete local at root 2",
491+
filename: "testdata/local-at-root-2.jsonnet",
492+
replaceString: "hello.to",
493+
replaceByString: "hello.",
494+
expected: protocol.CompletionList{
495+
IsIncomplete: false,
496+
Items: []protocol.CompletionItem{
497+
{
498+
Label: "to",
499+
Kind: protocol.FieldCompletion,
500+
Detail: "hello.to",
501+
InsertText: "to",
502+
LabelDetails: protocol.CompletionItemLabelDetails{
503+
Description: "object",
504+
},
505+
},
506+
},
507+
},
508+
},
509+
{
510+
name: "autocomplete local at root 2, nested",
511+
filename: "testdata/local-at-root-2.jsonnet",
512+
replaceString: "hello.to",
513+
replaceByString: "hello.to.",
514+
expected: protocol.CompletionList{
515+
IsIncomplete: false,
516+
Items: []protocol.CompletionItem{
517+
{
518+
Label: "the",
519+
Kind: protocol.FieldCompletion,
520+
Detail: "hello.to.the",
521+
InsertText: "the",
522+
LabelDetails: protocol.CompletionItemLabelDetails{
523+
Description: "object",
524+
},
525+
},
526+
},
527+
},
528+
},
529+
{
530+
name: "autocomplete local at root 3, import chain",
531+
filename: "testdata/local-at-root-3.jsonnet",
532+
replaceString: "hello2.the",
533+
replaceByString: "hello2.",
534+
expected: protocol.CompletionList{
535+
IsIncomplete: false,
536+
Items: []protocol.CompletionItem{
537+
{
538+
Label: "the",
539+
Kind: protocol.FieldCompletion,
540+
Detail: "hello2.the",
541+
InsertText: "the",
542+
LabelDetails: protocol.CompletionItemLabelDetails{
543+
Description: "object",
544+
},
545+
},
546+
},
547+
},
548+
},
549+
{
550+
name: "autocomplete local at root 4, import chain",
551+
filename: "testdata/local-at-root-4.jsonnet",
552+
replaceString: "hello3.world",
553+
replaceByString: "hello3.",
554+
expected: protocol.CompletionList{
555+
IsIncomplete: false,
556+
Items: []protocol.CompletionItem{
557+
{
558+
Label: "world",
559+
Kind: protocol.FieldCompletion,
560+
Detail: "hello3.world",
561+
InsertText: "world",
562+
LabelDetails: protocol.CompletionItemLabelDetails{
563+
Description: "string",
564+
},
565+
},
566+
},
567+
},
568+
},
511569
}
512570
for _, tc := range testCases {
513571
t.Run(tc.name, func(t *testing.T) {
+1-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
11
local hello = import 'local-at-root.jsonnet';
22

3-
{
4-
a: hello.to,
5-
}
3+
hello.to
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
local hello2 = import 'local-at-root-2.jsonnet';
2+
3+
hello2.the
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
local hello3 = import 'local-at-root-3.jsonnet';
2+
3+
hello3.world

pkg/server/testdata/local-at-root.jsonnet

+3-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ local hello = {
55
},
66
hello: {
77
to: {
8-
the: 'world',
8+
the: {
9+
world: 'hello',
10+
},
911
},
1012
},
1113
};

0 commit comments

Comments
 (0)