Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes for completions #57

Merged
merged 3 commits into from
Jan 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions internal/adapter/yamlls/trimTemplate.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ func prettyPrintNode(node *sitter.Node, previous []byte, result []byte) {

switch node.Type() {
case gotemplate.NodeTypeIfAction:
trim_if_action(node, previous, result)
trimIfAction(node, previous, result)
case gotemplate.NodeTypeBlockAction, gotemplate.NodeTypeWithAction, gotemplate.NodeTypeRangeAction:
trim_action(childCount, node, previous, result)
trimAction(childCount, node, previous, result)
case gotemplate.NodeTypeDefineAction:
earaseTemplate(node, previous, result)
case gotemplate.NodeTypeFunctionCall:
Expand All @@ -32,7 +32,7 @@ func prettyPrintNode(node *sitter.Node, previous []byte, result []byte) {
}
}

func trim_action(childCount uint32, node *sitter.Node, previous []byte, result []byte) {
func trimAction(childCount uint32, node *sitter.Node, previous []byte, result []byte) {
for i := 0; i < int(childCount); i++ {
child := node.Child(i)
switch child.Type() {
Expand Down Expand Up @@ -60,7 +60,7 @@ func trim_action(childCount uint32, node *sitter.Node, previous []byte, result [
}
}

func trim_if_action(node *sitter.Node, previous []byte, result []byte) {
func trimIfAction(node *sitter.Node, previous []byte, result []byte) {
curser := sitter.NewTreeCursor(node)
curser.GoToFirstChild()
for curser.GoToNextSibling() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package go_docs
package godocs

type GoTemplateSnippet struct {
Name string
Expand Down
14 changes: 7 additions & 7 deletions internal/handler/completion.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
lsp "go.lsp.dev/protocol"
yaml "gopkg.in/yaml.v2"

"github.com/mrjosh/helm-ls/internal/documentation/go_docs"
"github.com/mrjosh/helm-ls/internal/documentation/godocs"
)

var (
Expand All @@ -30,7 +30,7 @@
functionsCompletionItems = append(functionsCompletionItems, getFunctionCompletionItems(helmFuncs)...)
functionsCompletionItems = append(functionsCompletionItems, getFunctionCompletionItems(builtinFuncs)...)
functionsCompletionItems = append(functionsCompletionItems, getFunctionCompletionItems(sprigFuncs)...)
textCompletionsItems = append(textCompletionsItems, getTextCompletionItems(go_docs.TextSnippets)...)
textCompletionsItems = append(textCompletionsItems, getTextCompletionItems(godocs.TextSnippets)...)
}

func (h *langHandler) handleTextDocumentCompletion(ctx context.Context, reply jsonrpc2.Replier, req jsonrpc2.Request) (err error) {
Expand Down Expand Up @@ -73,7 +73,7 @@
variableSplitted = append(variableSplitted, s)
}

logger.Println(fmt.Sprintf("Word < %s >", word))
logger.Println(fmt.Sprintf("Word found for completions is < %s >", word))

if len(variableSplitted) == 0 {
return reply(ctx, basicItems, err)
Expand All @@ -86,9 +86,9 @@
}

switch variableSplitted[0] {
case "Chart":

Check failure on line 89 in internal/handler/completion.go

View workflow job for this annotation

GitHub Actions / lint (1.19.1, ubuntu-latest)

string `Chart` has 3 occurrences, make it a constant (goconst)
items = getVariableCompletionItems(chartVals)
case "Values":

Check failure on line 91 in internal/handler/completion.go

View workflow job for this annotation

GitHub Actions / lint (1.19.1, ubuntu-latest)

string `Values` has 3 occurrences, make it a constant (goconst)
items = h.getValue(h.values, variableSplitted[1:])
case "Release":
items = getVariableCompletionItems(releaseVals)
Expand Down Expand Up @@ -122,13 +122,13 @@
)

logger.Debug("currentNode", currentNode)
logger.Debug("relevantChildNode", relevantChildNode.Type())
logger.Debug("relevantChildNode", relevantChildNode)

switch relevantChildNode.Type() {
case gotemplate.NodeTypeIdentifier:
word = relevantChildNode.Content([]byte(doc.Content))
case gotemplate.NodeTypeDot:
logger.Debug("TraverseIdentifierPathUp")
logger.Debug("TraverseIdentifierPathUp for dot node")
word = lsplocal.TraverseIdentifierPathUp(relevantChildNode, doc)
case gotemplate.NodeTypeDotSymbol:
logger.Debug("GetFieldIdentifierPath")
Expand Down Expand Up @@ -258,14 +258,14 @@
}
}

func getTextCompletionItems(gotemplateSnippet []go_docs.GoTemplateSnippet) (result []lsp.CompletionItem) {
func getTextCompletionItems(gotemplateSnippet []godocs.GoTemplateSnippet) (result []lsp.CompletionItem) {
for _, item := range gotemplateSnippet {
result = append(result, textCompletionItem(item))
}
return result
}

func textCompletionItem(gotemplateSnippet go_docs.GoTemplateSnippet) lsp.CompletionItem {
func textCompletionItem(gotemplateSnippet godocs.GoTemplateSnippet) lsp.CompletionItem {
return lsp.CompletionItem{
Label: gotemplateSnippet.Name,
TextEdit: &lsp.TextEdit{
Expand Down
8 changes: 6 additions & 2 deletions internal/lsp/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package lsp

import (
"context"
"fmt"

"github.com/mrjosh/helm-ls/internal/tree-sitter/gotemplate"
sitter "github.com/smacker/go-tree-sitter"
Expand Down Expand Up @@ -49,12 +50,12 @@ func isPointLargerOrEq(a sitter.Point, b sitter.Point) bool {

func GetFieldIdentifierPath(node *sitter.Node, doc *Document) (path string) {
path = buildFieldIdentifierPath(node, doc)
logger.Debug("buildFieldIdentifierPath:", path)
logger.Debug(fmt.Sprintf("buildFieldIdentifierPath: %s for node %s with parent %s", path, node, node.Parent()))

return path
}

func buildFieldIdentifierPath(node *sitter.Node, doc *Document) string {

prepend := node.PrevNamedSibling()

currentPath := node.Content([]byte(doc.Content))
Expand All @@ -64,6 +65,9 @@ func buildFieldIdentifierPath(node *sitter.Node, doc *Document) string {
nodeContent = ""
}
currentPath = prepend.Content([]byte(doc.Content)) + "." + nodeContent
logger.Println("Adding currentpath", currentPath)
} else if node.Parent() != nil && node.Parent().Type() == gotemplate.NodeTypeError {
return buildFieldIdentifierPath(node.Parent(), doc)
}

if currentPath[0:1] == "$" {
Expand Down
127 changes: 127 additions & 0 deletions internal/lsp/ast_field_identifier_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
package lsp

import (
"testing"

sitter "github.com/smacker/go-tree-sitter"
"github.com/stretchr/testify/assert"
lsp "go.lsp.dev/protocol"
)

func TestGetFieldIdentifierPathSimple(t *testing.T) {
template := `{{ .Values.test }}`

var ast = ParseAst(template)
// (template [0, 0] - [1, 0]
// (selector_expression [0, 3] - [0, 15]
// operand: (field [0, 3] - [0, 10]
// name: (identifier [0, 4] - [0, 10]))
// field: (field_identifier [0, 11] - [0, 15]))

test_start := sitter.Point{Row: 0, Column: 12}
testNode := ast.RootNode().NamedDescendantForPointRange(test_start, test_start)

if testNode.Content([]byte(template)) != "test" {
t.Errorf("Nodes were not correctly selected")
}

doc := Document{
Content: template,
Ast: ast,
}

result := GetFieldIdentifierPath(testNode, &doc)
assert.Equal(t, ".Values.test", result)
}

func TestGetFieldIdentifierPathWith(t *testing.T) {
template := `{{ with .Values }}{{ .test }} {{ end }}`

var ast = ParseAst(template)
// (template [0, 0] - [1, 0]
// (with_action [0, 0] - [0, 39]
// condition: (field [0, 8] - [0, 15]
// name: (identifier [0, 9] - [0, 15]))
// consequence: (field [0, 21] - [0, 26]
// name: (identifier [0, 22] - [0, 26]))))

test_start := sitter.Point{Row: 0, Column: 22}
testNode := ast.RootNode().NamedDescendantForPointRange(test_start, test_start)

if testNode.Content([]byte(template)) != "test" {
t.Errorf("Nodes were not correctly selected")
}

doc := Document{
Content: template,
Ast: ast,
}

result := GetFieldIdentifierPath(testNode, &doc)
assert.Equal(t, ".Values.test", result)
}

func TestGetFieldIdentifierPathFunction(t *testing.T) {
template := `{{ and .Values.test1 .Values.test2 }}`

var ast = ParseAst(template)
// (template [0, 0] - [1, 0]
// (function_call [0, 3] - [0, 35]
// function: (identifier [0, 3] - [0, 6])
// arguments: (argument_list [0, 7] - [0, 35]
// (selector_expression [0, 7] - [0, 20]
// operand: (field [0, 7] - [0, 14]
// name: (identifier [0, 8] - [0, 14]))
// field: (field_identifier [0, 15] - [0, 20]))
// (selector_expression [0, 21] - [0, 34]
// operand: (field [0, 21] - [0, 28]
// name: (identifier [0, 22] - [0, 28]))
// field: (field_identifier [0, 29] - [0, 34])))))
//
test1_start := sitter.Point{Row: 0, Column: 16}
test2_start := sitter.Point{Row: 0, Column: 33}
test1Node := ast.RootNode().NamedDescendantForPointRange(test1_start, test1_start)
test2Node := ast.RootNode().NamedDescendantForPointRange(test2_start, test2_start)

test1NodeContent := test1Node.Content([]byte(template))
test2NodeContent := test2Node.Content([]byte(template))

assert.Equal(t, "test1", test1NodeContent, "Nodes were not correctly selected")
assert.Equal(t, "test2", test2NodeContent, "Nodes were not correctly selected")

doc := Document{
Content: template,
Ast: ast,
}

assert.Equal(t, ".Values.test1", GetFieldIdentifierPath(test1Node, &doc))
assert.Equal(t, ".Values.test2", GetFieldIdentifierPath(test2Node, &doc))
}

func TestGetFieldIdentifierPathFunctionForCompletion(t *testing.T) {
template := `{{ and .Values.image .Values. }}`
// | -> complete at dot

var ast = ParseAst(template)

var (
position = lsp.Position{Line: 0, Character: 29}
currentNode = NodeAtPosition(ast, position)
pointToLoopUp = sitter.Point{
Row: position.Line,
Column: position.Character,
}
relevantChildNode = FindRelevantChildNode(currentNode, pointToLoopUp)
)

childNodeContent := relevantChildNode.Content([]byte(template))

assert.Equal(t, ".", childNodeContent, "Nodes were not correctly selected ")

doc := Document{
Content: template,
Ast: ast,
}

assert.Equal(t, ".Values.", GetFieldIdentifierPath(relevantChildNode, &doc))
}
51 changes: 26 additions & 25 deletions internal/tree-sitter/gotemplate/node-types.go
Original file line number Diff line number Diff line change
@@ -1,38 +1,39 @@
package gotemplate

const (
NodeTypeIdentifier = "identifier"
NodeTypeVariable = "variable"
NodeTypeDot = "dot"
NodeTypeBlock = "block"
NodeTypeBlockAction = "block_action"
NodeTypeChainedPipeline = "chained_pipeline"
NodeTypeCloseBraces = "}}"
NodeTypeCloseBracesDash = "-}}"
NodeTypeComment = "comment"
NodeTypeDefine = "define"
NodeTypeDefineAction = "define_action"
NodeTypeDollar = "$"
NodeTypeDot = "dot"
NodeTypeDotSymbol = "."
NodeTypeVariableDefinition = "variable_definition"
NodeTypeRangeVariableDefinition = "range_variable_definition"
NodeTypeElse = "else"
NodeTypeElseIf = "else if"
NodeTypeEnd = "end"
NodeTypeError = "ERROR"
NodeTypeFieldIdentifier = "field_identifier"
NodeTypeText = "text"
NodeTypeTemplate = "template"
NodeTypeIfAction = "if_action"
NodeTypeFunctionCall = "function_call"
NodeTypeIdentifier = "identifier"
NodeTypeIf = "if"
NodeTypeBlockAction = "block_action"
NodeTypeWithAction = "with_action"
NodeTypeIfAction = "if_action"
NodeTypeInterpretedStringLiteral = "interpreted_string_literal"
NodeTypeOpenBraces = "{{"
NodeTypeOpenBracesDash = "{{-"
NodeTypeRange = "range"
NodeTypeRangeAction = "range_action"
NodeTypeDefineAction = "define_action"
NodeTypeFunctionCall = "function_call"
NodeTypeComment = "comment"
NodeTypeRangeVariableDefinition = "range_variable_definition"
NodeTypeSelectorExpression = "selector_expression"
NodeTypeElse = "else"
NodeTypeElseIf = "else if"
NodeTypeRange = "range"
NodeTypeTemplate = "template"
NodeTypeText = "text"
NodeTypeVariable = "variable"
NodeTypeVariableDefinition = "variable_definition"
NodeTypeWith = "with"
NodeTypeDefine = "define"
NodeTypeOpenBraces = "{{"
NodeTypeOpenBracesDash = "{{-"
NodeTypeCloseBraces = "}}"
NodeTypeCloseBracesDash = "-}}"
NodeTypeEnd = "end"
NodeTypeInterpretedStringLiteral = "interpreted_string_literal"
NodeTypeBlock = "block"
NodeTypeChainedPipeline = "chained_pipeline"
NodeTypeWithAction = "with_action"

FieldNameAlternative = "alternative"
FieldNameCondition = "condition"
Expand Down
Loading