diff --git a/internal/handler/completion_main_test.go b/internal/handler/completion_main_test.go index d3b3fd5e..14c02320 100644 --- a/internal/handler/completion_main_test.go +++ b/internal/handler/completion_main_test.go @@ -161,6 +161,10 @@ func TestCompletionMain(t *testing.T) { assert.Equal(t, tt.expectedError, err) assert.NotNil(t, result) + if result == nil { + return + } + insertTexts := []string{} for _, item := range result.Items { insertTexts = append(insertTexts, item.InsertText) diff --git a/internal/lsp/symbol_table_test.go b/internal/lsp/symbol_table_test.go index 62ab6fe4..530bf7e1 100644 --- a/internal/lsp/symbol_table_test.go +++ b/internal/lsp/symbol_table_test.go @@ -62,6 +62,10 @@ func TestSymbolTableForValues(t *testing.T) { {{ .Test }} {{ . }} + +{{ if (and .Values. ) }} + +{{ end }} ` ast := ParseAst(nil, content) @@ -210,3 +214,41 @@ func TestSymbolTableForValuesTestFile(t *testing.T) { assert.Contains(t, points, v.startPoint) } } + +func TestSymbolTableForValuesSingleTests(t *testing.T) { + type testCase struct { + template string + path []string + startPoint sitter.Point + } + + testCases := []testCase{ + { + template: `{{ if (and .Values. ) }} {{ end }} `, + path: []string{"Values"}, + startPoint: sitter.Point{ + Row: 0, + Column: 12, + }, + }, + { + template: `{{ if (and .Values. ) }} {{ end }} `, + path: []string{"Values", ""}, + startPoint: sitter.Point{ + Row: 0, + Column: 18, + }, + }, + } + + for _, v := range testCases { + ast := ParseAst(nil, v.template) + symbolTable := NewSymbolTable(ast, []byte(v.template)) + values := symbolTable.GetTemplateContextRanges(v.path) + points := []sitter.Point{} + for _, v := range values { + points = append(points, v.StartPoint) + } + assert.Contains(t, points, v.startPoint) + } +} diff --git a/internal/lsp/symbol_table_values.go b/internal/lsp/symbol_table_values.go index 4b81e7dd..b082a0b5 100644 --- a/internal/lsp/symbol_table_values.go +++ b/internal/lsp/symbol_table_values.go @@ -48,7 +48,8 @@ func (v *TemplateContextVisitor) RestoreStashedContext() { } func (v *TemplateContextVisitor) Enter(node *sitter.Node) { - switch node.Type() { + nodeType := node.Type() + switch nodeType { case gotemplate.NodeTypeDot: v.symbolTable.AddTemplateContext(v.currentContext, GetRangeForNode(node)) case gotemplate.NodeTypeFieldIdentifier: @@ -57,6 +58,12 @@ func (v *TemplateContextVisitor) Enter(node *sitter.Node) { case gotemplate.NodeTypeField: content := node.ChildByFieldName("name").Content(v.content) v.symbolTable.AddTemplateContext(append(v.currentContext, content), GetRangeForNode(node.ChildByFieldName("name"))) + case gotemplate.NodeTypeUnfinishedSelectorExpression: + operandNode := node.ChildByFieldName("operand") + if operandNode.Type() == gotemplate.NodeTypeVariable && operandNode.Content(v.content) == "$" { + v.StashContext() + } + v.symbolTable.AddTemplateContext(append(getContextForSelectorExpression(operandNode, v.content), ""), GetRangeForNode(node.Child(int(node.ChildCount())-1))) case gotemplate.NodeTypeSelectorExpression: operandNode := node.ChildByFieldName("operand") if operandNode.Type() == gotemplate.NodeTypeVariable && operandNode.Content(v.content) == "$" { @@ -67,7 +74,7 @@ func (v *TemplateContextVisitor) Enter(node *sitter.Node) { func (v *TemplateContextVisitor) Exit(node *sitter.Node) { switch node.Type() { - case gotemplate.NodeTypeSelectorExpression: + case gotemplate.NodeTypeSelectorExpression, gotemplate.NodeTypeUnfinishedSelectorExpression: operandNode := node.ChildByFieldName("operand") if operandNode.Type() == gotemplate.NodeTypeVariable && operandNode.Content(v.content) == "$" { v.RestoreStashedContext() @@ -83,7 +90,7 @@ func (v *TemplateContextVisitor) EnterContextShift(node *sitter.Node, suffix str case gotemplate.NodeTypeField: content := node.ChildByFieldName("name").Content(v.content) + suffix v.PushContext(content) - case gotemplate.NodeTypeSelectorExpression: + case gotemplate.NodeTypeSelectorExpression, gotemplate.NodeTypeUnfinishedSelectorExpression: s := getContextForSelectorExpression(node, v.content) if len(s) > 0 { s[len(s)-1] = s[len(s)-1] + suffix @@ -100,7 +107,7 @@ func (v *TemplateContextVisitor) ExitContextShift(node *sitter.Node) { switch node.Type() { case gotemplate.NodeTypeField, gotemplate.NodeTypeFieldIdentifier: v.PopContext() - case gotemplate.NodeTypeSelectorExpression: + case gotemplate.NodeTypeSelectorExpression, gotemplate.NodeTypeUnfinishedSelectorExpression: s := getContextForSelectorExpression(node, v.content) if len(s) > 0 && s[0] == "$" { v.RestoreStashedContext() diff --git a/internal/lsp/visitor.go b/internal/lsp/visitor.go index 4d652498..7c96e639 100644 --- a/internal/lsp/visitor.go +++ b/internal/lsp/visitor.go @@ -56,7 +56,7 @@ func (v *Visitors) visitNodesRecursiveWithScopeShift(node *sitter.Node) { for _, visitor := range v.visitors { visitor.ExitContextShift(rangeNode) } - case gotemplate.NodeTypeSelectorExpression: + case gotemplate.NodeTypeSelectorExpression, gotemplate.NodeTypeUnfinishedSelectorExpression: operand := node.ChildByFieldName("operand") v.visitNodesRecursiveWithScopeShift(operand) for _, visitor := range v.visitors { diff --git a/internal/tree-sitter/gotemplate/node-types.go b/internal/tree-sitter/gotemplate/node-types.go index 085a8413..1b877e9b 100644 --- a/internal/tree-sitter/gotemplate/node-types.go +++ b/internal/tree-sitter/gotemplate/node-types.go @@ -1,42 +1,43 @@ package gotemplate const ( - NodeTypeAssignment = "assignment" - NodeTypeArgumentList = "argument_list" - NodeTypeBlock = "block" - NodeTypeBlockAction = "block_action" - NodeTypeChainedPipeline = "chained_pipeline" - NodeTypeCloseBraces = "}}" - NodeTypeCloseBracesDash = "-}}" - NodeTypeComment = "comment" - NodeTypeDefine = "define" - NodeTypeDefineAction = "define_action" - NodeTypeDollar = "$" - NodeTypeDot = "dot" - NodeTypeDotSymbol = "." - NodeTypeElse = "else" - NodeTypeElseIf = "else if" - NodeTypeEnd = "end" - NodeTypeError = "ERROR" - NodeTypeField = "field" - NodeTypeFieldIdentifier = "field_identifier" - NodeTypeFunctionCall = "function_call" - NodeTypeIdentifier = "identifier" - NodeTypeIf = "if" - NodeTypeIfAction = "if_action" - NodeTypeInterpretedStringLiteral = "interpreted_string_literal" - NodeTypeOpenBraces = "{{" - NodeTypeOpenBracesDash = "{{-" - NodeTypeRange = "range" - NodeTypeRangeAction = "range_action" - NodeTypeRangeVariableDefinition = "range_variable_definition" - NodeTypeSelectorExpression = "selector_expression" - NodeTypeTemplate = "template" - NodeTypeText = "text" - NodeTypeVariable = "variable" - NodeTypeVariableDefinition = "variable_definition" - NodeTypeWith = "with" - NodeTypeWithAction = "with_action" + NodeTypeAssignment = "assignment" + NodeTypeArgumentList = "argument_list" + NodeTypeBlock = "block" + NodeTypeBlockAction = "block_action" + NodeTypeChainedPipeline = "chained_pipeline" + NodeTypeCloseBraces = "}}" + NodeTypeCloseBracesDash = "-}}" + NodeTypeComment = "comment" + NodeTypeDefine = "define" + NodeTypeDefineAction = "define_action" + NodeTypeDollar = "$" + NodeTypeDot = "dot" + NodeTypeDotSymbol = "." + NodeTypeElse = "else" + NodeTypeElseIf = "else if" + NodeTypeEnd = "end" + NodeTypeError = "ERROR" + NodeTypeField = "field" + NodeTypeFieldIdentifier = "field_identifier" + NodeTypeFunctionCall = "function_call" + NodeTypeIdentifier = "identifier" + NodeTypeIf = "if" + NodeTypeIfAction = "if_action" + NodeTypeInterpretedStringLiteral = "interpreted_string_literal" + NodeTypeOpenBraces = "{{" + NodeTypeOpenBracesDash = "{{-" + NodeTypeRange = "range" + NodeTypeRangeAction = "range_action" + NodeTypeRangeVariableDefinition = "range_variable_definition" + NodeTypeSelectorExpression = "selector_expression" + NodeTypeUnfinishedSelectorExpression = "unfished_selector_expression" // TODO: fix this typo in the grammar + NodeTypeTemplate = "template" + NodeTypeText = "text" + NodeTypeVariable = "variable" + NodeTypeVariableDefinition = "variable_definition" + NodeTypeWith = "with" + NodeTypeWithAction = "with_action" FieldNameAlternative = "alternative" FieldNameCondition = "condition" diff --git a/testdata/example/templates/completion-test.yaml b/testdata/example/templates/completion-test.yaml index cea82b73..09367806 100644 --- a/testdata/example/templates/completion-test.yaml +++ b/testdata/example/templates/completion-test.yaml @@ -6,7 +6,6 @@ {{ .Chart.N }} {{ . }} -{{ toYaml .Release. }} -{{ toYaml (.Release. ) }} -{{ .Release. }} +{{ if (and .Values. ) }} +{{ end }}