From 88706f04df6b23d2b03fc10d7171c4c1e3374c4c Mon Sep 17 00:00:00 2001 From: qvalentin Date: Sat, 4 May 2024 10:16:41 +0200 Subject: [PATCH] feat: completion for unfinished_selector_expression --- .../yamlls/completion_integration_test.go | 2 +- internal/adapter/yamlls/diagnostics.go | 7 + internal/adapter/yamlls/documentSync.go | 3 + internal/adapter/yamlls/hover.go | 22 +- .../adapter/yamlls/hover_integration_test.go | 2 +- internal/charts/chart.go | 5 +- .../documentation/helm/helm-documentation.go | 8 +- internal/handler/completion.go | 109 +---- internal/handler/completion_main_test.go | 158 ++++--- internal/handler/definition.go | 3 +- internal/handler/generic_document_usecase.go | 38 +- internal/handler/hover.go | 13 +- internal/handler/initialization.go | 7 +- internal/handler/references.go | 5 +- internal/handler/text_document.go | 15 + internal/language_features/function_call.go | 5 +- .../generic_document_usecase.go | 10 - internal/language_features/includes.go | 44 +- .../language_features/template_context.go | 61 +-- .../template_context_completion.go | 73 ++++ internal/language_features/text.go | 54 +++ internal/language_features/usecases.go | 3 + internal/lsp/ast.go | 9 + internal/lsp/document.go | 52 --- internal/lsp/document_store.go | 82 ++++ internal/lsp/symbol_table.go | 24 +- internal/lsp/symbol_table_includes.go | 6 +- ...es.go => symbol_table_template_context.go} | 24 +- internal/lsp/symbol_table_test.go | 42 ++ internal/lsp/visitor.go | 2 +- internal/protocol/completion.go | 55 ++- internal/{util/lsp.go => protocol/hover.go} | 6 +- internal/tree-sitter/gotemplate/README.md | 2 +- internal/tree-sitter/gotemplate/node-types.go | 73 ++-- internal/tree-sitter/gotemplate/parser.c | 396 +++++++++--------- internal/util/values.go | 10 +- internal/util/yaml_path.go | 59 --- .../example/templates/completion-test.yaml | 6 +- 38 files changed, 836 insertions(+), 659 deletions(-) create mode 100644 internal/language_features/template_context_completion.go create mode 100644 internal/language_features/text.go create mode 100644 internal/lsp/document_store.go rename internal/lsp/{symbol_table_values.go => symbol_table_template_context.go} (82%) rename internal/{util/lsp.go => protocol/hover.go} (88%) delete mode 100644 internal/util/yaml_path.go diff --git a/internal/adapter/yamlls/completion_integration_test.go b/internal/adapter/yamlls/completion_integration_test.go index 4b73c2f4..3e3687b4 100644 --- a/internal/adapter/yamlls/completion_integration_test.go +++ b/internal/adapter/yamlls/completion_integration_test.go @@ -24,7 +24,7 @@ func TestYamllsCompletionIntegration(t *testing.T) { expected []lsp.CompletionItem }{ { - desc: "test hover on deployment.yaml", + desc: "test completion on deployment.yaml", file: "../../../testdata/example/templates/deployment.yaml", position: lsp.Position{ Line: 42, diff --git a/internal/adapter/yamlls/diagnostics.go b/internal/adapter/yamlls/diagnostics.go index 7b92f6f6..b140103d 100644 --- a/internal/adapter/yamlls/diagnostics.go +++ b/internal/adapter/yamlls/diagnostics.go @@ -2,6 +2,8 @@ package yamlls import ( "context" + "runtime" + "strings" lsplocal "github.com/mrjosh/helm-ls/internal/lsp" sitter "github.com/smacker/go-tree-sitter" @@ -71,6 +73,11 @@ func diagnisticIsRelevant(diagnostic lsp.Diagnostic, node *sitter.Node) bool { // {{- end }} return false default: + // TODO: remove this once the tree-sitter grammar behavior for windows newlines is the same as for unix + if strings.HasPrefix(diagnostic.Message, "Incorrect type. Expected") && runtime.GOOS == "windows" { + return false + } + return true } } diff --git a/internal/adapter/yamlls/documentSync.go b/internal/adapter/yamlls/documentSync.go index 02c9bae7..1d566b58 100644 --- a/internal/adapter/yamlls/documentSync.go +++ b/internal/adapter/yamlls/documentSync.go @@ -14,6 +14,9 @@ func (yamllsConnector Connector) InitiallySyncOpenDocuments(docs []*lsplocal.Doc return } for _, doc := range docs { + if !doc.IsOpen { + continue + } yamllsConnector.DocumentDidOpen(doc.Ast, lsp.DidOpenTextDocumentParams{ TextDocument: lsp.TextDocumentItem{ URI: doc.URI, diff --git a/internal/adapter/yamlls/hover.go b/internal/adapter/yamlls/hover.go index 92b12453..b6f85df2 100644 --- a/internal/adapter/yamlls/hover.go +++ b/internal/adapter/yamlls/hover.go @@ -3,12 +3,15 @@ package yamlls import ( "context" - "github.com/mrjosh/helm-ls/internal/util" + "github.com/mrjosh/helm-ls/internal/protocol" lsp "go.lsp.dev/protocol" ) // Calls the Hover method of yamlls to get a fitting hover response // If hover returns nothing appropriate, calls yamlls for completions +// +// Yamlls can not handle hover if the schema validation returns error, +// thats why we fall back to calling completion func (yamllsConnector Connector) CallHover(ctx context.Context, params lsp.HoverParams, word string) (*lsp.Hover, error) { if yamllsConnector.server == nil { return &lsp.Hover{}, nil @@ -25,15 +28,17 @@ func (yamllsConnector Connector) CallHover(ctx context.Context, params lsp.Hover return (yamllsConnector).getHoverFromCompletion(ctx, params, word) } -func (yamllsConnector Connector) getHoverFromCompletion(ctx context.Context, params lsp.HoverParams, word string) (*lsp.Hover, error) { +func (yamllsConnector Connector) getHoverFromCompletion(ctx context.Context, params lsp.HoverParams, word string) (response *lsp.Hover, err error) { var ( - err error + resultRange lsp.Range documentation string completionParams = lsp.CompletionParams{ TextDocumentPositionParams: params.TextDocumentPositionParams, } ) + word = removeTrailingColon(word) + completionList, err := yamllsConnector.server.Completion(ctx, &completionParams) if err != nil { logger.Error("Error calling yamlls for Completion", err) @@ -43,10 +48,17 @@ func (yamllsConnector Connector) getHoverFromCompletion(ctx context.Context, par for _, completionItem := range completionList.Items { if completionItem.InsertText == word { documentation = completionItem.Documentation.(string) + resultRange = completionItem.TextEdit.Range break } } - response := util.BuildHoverResponse(documentation, lsp.Range{}) - return response, nil + return protocol.BuildHoverResponse(documentation, resultRange), nil +} + +func removeTrailingColon(word string) string { + if len(word) > 2 && string(word[len(word)-1]) == ":" { + word = word[0 : len(word)-1] + } + return word } diff --git a/internal/adapter/yamlls/hover_integration_test.go b/internal/adapter/yamlls/hover_integration_test.go index c4b97754..2cc474e5 100644 --- a/internal/adapter/yamlls/hover_integration_test.go +++ b/internal/adapter/yamlls/hover_integration_test.go @@ -73,7 +73,7 @@ func TestYamllsHoverIntegration(t *testing.T) { }, }, tt.word) return err == nil && strings.Contains(result.Contents.Value, tt.expected) - }, time.Second*10, time.Second/2) + }, time.Second*40, time.Second*2) }) } } diff --git a/internal/charts/chart.go b/internal/charts/chart.go index 4e4f16b4..2ca97c9f 100644 --- a/internal/charts/chart.go +++ b/internal/charts/chart.go @@ -60,8 +60,9 @@ func (c *Chart) ResolveValueFiles(query []string, chartStore *ChartStore) []*Que } func (c *Chart) GetValueLocation(templateContext []string) (lsp.Location, error) { - modifyedVar := make([]string, 0) - // for Charts, we make the first letter lowercase + modifyedVar := make([]string, len(templateContext)) + // make the first letter lowercase since in the template the first letter is + // capitalized, but it is not in the Chart.yaml file for _, value := range templateContext { restOfString := "" if (len(value)) > 1 { diff --git a/internal/documentation/helm/helm-documentation.go b/internal/documentation/helm/helm-documentation.go index d1e0773d..d770eec1 100644 --- a/internal/documentation/helm/helm-documentation.go +++ b/internal/documentation/helm/helm-documentation.go @@ -261,13 +261,7 @@ var ( ) func GetFunctionByName(name string) (HelmDocumentation, bool) { - completionItems := [][]HelmDocumentation{ - BuiltinFuncs, - SprigFuncs, - HelmFuncs, - } - toSearch := util.ConcatMultipleSlices(completionItems) - for _, completionItem := range toSearch { + for _, completionItem := range AllFuncs { if name == completionItem.Name { return completionItem, true } diff --git a/internal/handler/completion.go b/internal/handler/completion.go index fb6a0c9a..2a7104ce 100644 --- a/internal/handler/completion.go +++ b/internal/handler/completion.go @@ -2,48 +2,27 @@ package handler import ( "context" - "fmt" languagefeatures "github.com/mrjosh/helm-ls/internal/language_features" lsplocal "github.com/mrjosh/helm-ls/internal/lsp" - gotemplate "github.com/mrjosh/helm-ls/internal/tree-sitter/gotemplate" - sitter "github.com/smacker/go-tree-sitter" - "go.lsp.dev/protocol" + "github.com/mrjosh/helm-ls/internal/protocol" lsp "go.lsp.dev/protocol" - "github.com/mrjosh/helm-ls/internal/documentation/godocs" helmdocs "github.com/mrjosh/helm-ls/internal/documentation/helm" ) -var ( - emptyItems = make([]lsp.CompletionItem, 0) - textCompletionsItems = make([]lsp.CompletionItem, 0) -) - -func init() { - textCompletionsItems = append(textCompletionsItems, getTextCompletionItems(godocs.TextSnippets)...) -} - func (h *langHandler) Completion(ctx context.Context, params *lsp.CompletionParams) (result *lsp.CompletionList, err error) { logger.Debug("Running completion with params", params) - genericDocumentUseCase, err := h.NewGenericDocumentUseCase(params.TextDocumentPositionParams) + genericDocumentUseCase, err := h.NewGenericDocumentUseCase(params.TextDocumentPositionParams, lsplocal.NestedNodeAtPositionForCompletion) if err != nil { return nil, err } - var ( - currentNode = lsplocal.NodeAtPosition(genericDocumentUseCase.Document.Ast, params.Position) - pointToLoopUp = sitter.Point{ - Row: params.Position.Line, - Column: params.Position.Character, - } - relevantChildNode = lsplocal.FindRelevantChildNodeCompletion(currentNode, pointToLoopUp) - ) - genericDocumentUseCase = genericDocumentUseCase.WithNode(relevantChildNode) - usecases := []languagefeatures.CompletionUseCase{ languagefeatures.NewTemplateContextFeature(genericDocumentUseCase), languagefeatures.NewFunctionCallFeature(genericDocumentUseCase), + languagefeatures.NewTextFeature(ctx, genericDocumentUseCase, h.yamllsConnector, ¶ms.TextDocumentPositionParams), + languagefeatures.NewIncludesCallFeature(genericDocumentUseCase), } for _, usecase := range usecases { @@ -52,79 +31,15 @@ func (h *langHandler) Completion(ctx context.Context, params *lsp.CompletionPara } } - word, isTextNode := completionAstParsing(genericDocumentUseCase.Document, params.Position) - - if isTextNode { - result := make([]lsp.CompletionItem, 0) - result = append(result, textCompletionsItems...) - result = append(result, yamllsCompletions(ctx, h, params)...) - logger.Debug("Sending completions ", result) - return &protocol.CompletionList{IsIncomplete: false, Items: result}, err - } - - logger.Println(fmt.Sprintf("Word found for completions is < %s >", word)) - items := []lsp.CompletionItem{} + // If no usecase matched, we assume we are at {{ }} + // and provide the basic BuiltInObjects and functions + items := []helmdocs.HelmDocumentation{} for _, v := range helmdocs.BuiltInObjects { - items = append(items, lsp.CompletionItem{ - Label: v.Name, - InsertText: "." + v.Name, - Detail: v.Detail, - Documentation: v.Doc, - }) + v.Name = "." + v.Name + items = append(items, v) } - return &lsp.CompletionList{IsIncomplete: false, Items: items}, err -} -func yamllsCompletions(ctx context.Context, h *langHandler, params *lsp.CompletionParams) []lsp.CompletionItem { - response, err := h.yamllsConnector.CallCompletion(ctx, params) - if err != nil { - logger.Error("Error getting yamlls completions", err) - return []lsp.CompletionItem{} - } - logger.Debug("Got completions from yamlls", response) - return response.Items -} - -func completionAstParsing(doc *lsplocal.Document, position lsp.Position) (string, bool) { - var ( - currentNode = lsplocal.NodeAtPosition(doc.Ast, position) - pointToLoopUp = sitter.Point{ - Row: position.Line, - Column: position.Character, - } - relevantChildNode = lsplocal.FindRelevantChildNode(currentNode, pointToLoopUp) - word string - ) - - nodeType := relevantChildNode.Type() - switch nodeType { - case gotemplate.NodeTypeIdentifier: - word = relevantChildNode.Content([]byte(doc.Content)) - case gotemplate.NodeTypeText, gotemplate.NodeTypeTemplate: - return word, true - } - logger.Debug("word", word) - return word, false -} - -func getTextCompletionItems(gotemplateSnippet []godocs.GoTemplateSnippet) (result []lsp.CompletionItem) { - for _, item := range gotemplateSnippet { - result = append(result, textCompletionItem(item)) - } - return result -} - -func textCompletionItem(gotemplateSnippet godocs.GoTemplateSnippet) lsp.CompletionItem { - return lsp.CompletionItem{ - Label: gotemplateSnippet.Name, - // TextEdit: &lsp.TextEdit{ - // // Range: lsp.Range{}, // TODO: range must contain the requested range - // NewText: gotemplateSnippet.Snippet, - // }, - InsertText: gotemplateSnippet.Snippet, - Detail: gotemplateSnippet.Detail, - Documentation: gotemplateSnippet.Doc, - Kind: lsp.CompletionItemKindText, - InsertTextFormat: lsp.InsertTextFormatSnippet, - } + return protocol.CompletionResults{}. + WithDocs(items, lsp.CompletionItemKindConstant). + WithDocs(helmdocs.AllFuncs, lsp.CompletionItemKindFunction).ToList(), nil } diff --git a/internal/handler/completion_main_test.go b/internal/handler/completion_main_test.go index d3b3fd5e..7b6e66e9 100644 --- a/internal/handler/completion_main_test.go +++ b/internal/handler/completion_main_test.go @@ -2,7 +2,9 @@ package handler import ( "context" + "errors" "os" + "strings" "testing" "github.com/mrjosh/helm-ls/internal/adapter/yamlls" @@ -11,6 +13,7 @@ import ( lsplocal "github.com/mrjosh/helm-ls/internal/lsp" "github.com/mrjosh/helm-ls/internal/util" "github.com/stretchr/testify/assert" + "go.lsp.dev/protocol" lsp "go.lsp.dev/protocol" "go.lsp.dev/uri" ) @@ -23,6 +26,31 @@ func TestCompletionMain(t *testing.T) { notExpectedInsertTexts []string expectedError error }{ + { + desc: "Test completion on {{ not }}", + position: lsp.Position{ + Line: 11, + Character: 7, + }, + expectedInsertText: "toYaml", + notExpectedInsertTexts: []string{ + "replicaCount", + }, + expectedError: nil, + }, + { + desc: "Test completion on text", + position: lsp.Position{ + Line: 4, + Character: 0, + }, + expectedInsertText: "{{- if $1 }}\n $2 \n{{- else }}\n $0 \n{{- end }}", + notExpectedInsertTexts: []string{ + "replicaCount", + "toYaml", + }, + expectedError: nil, + }, { desc: "Test completion on {{ if (and .Values. ) }}", position: lsp.Position{ @@ -70,6 +98,7 @@ func TestCompletionMain(t *testing.T) { expectedInsertText: "Chart", notExpectedInsertTexts: []string{ helmdocs.HelmFuncs[0].Name, + "js", "replicaCount", "toYaml", }, @@ -99,36 +128,9 @@ func TestCompletionMain(t *testing.T) { }, expectedError: nil, }, - { - desc: "Test completion on text", - position: lsp.Position{ - Line: 4, - Character: 0, - }, - expectedInsertText: "{{- if $1 }}\n $2 \n{{- else }}\n $0 \n{{- end }}", - notExpectedInsertTexts: []string{ - "replicaCount", - "toYaml", - }, - expectedError: nil, - }, - // { - // desc: "Test completion on {{ }}", - // position: lsp.Position{ - // Line: 4, - // Character: 3, - // }, - // expectedInsertText: "toYaml", - // notExpectedInsertTexts: []string{ - // "replicaCount", - // }, - // expectedError: nil, - // }, } for _, tt := range testCases { t.Run(tt.desc, func(t *testing.T) { - documents := lsplocal.NewDocumentStore() - path := "../../testdata/example/templates/completion-test.yaml" fileURI := uri.File(path) @@ -136,31 +138,14 @@ func TestCompletionMain(t *testing.T) { if err != nil { t.Fatal("Could not read test file", err) } - d := lsp.DidOpenTextDocumentParams{ - TextDocument: lsp.TextDocumentItem{ - URI: fileURI, - LanguageID: "", - Version: 0, - Text: string(content), - }, - } - documents.DidOpen(&d, util.DefaultConfig) - h := &langHandler{ - chartStore: charts.NewChartStore(uri.File("."), charts.NewChart), - documents: documents, - yamllsConnector: &yamlls.Connector{}, - } - result, err := h.Completion(context.Background(), &lsp.CompletionParams{ - TextDocumentPositionParams: lsp.TextDocumentPositionParams{ - TextDocument: lsp.TextDocumentIdentifier{ - URI: fileURI, - }, - Position: tt.position, - }, - }) + result, err := completionTestCall(fileURI, string(content), tt.position) 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) @@ -173,3 +158,78 @@ func TestCompletionMain(t *testing.T) { }) } } + +func TestCompletionMainSingleLines(t *testing.T) { + testCases := []struct { + templateWithMark string + expectedInsertTexts []string + notExpectedInsertTexts []string + err error + }{ + {"Test completion on {{ .Bad.^ }}", []string{}, []string{}, errors.New("[Bad ] is no valid template context for helm")}, + {"Test completion on {{ n^ }}", []string{"not"}, []string{}, nil}, + {"Test completion on {{ .Values.^ }}", []string{"replicaCount"}, []string{}, nil}, + {"Test completion on {{ .Release.N^ }}", []string{"Name"}, []string{}, nil}, + {"Test completion on {{ .Capabilities.KubeVersion.^ }}", []string{"Minor"}, []string{}, nil}, + {"Test completion on {{ .Capabilities.KubeVersion.Mi^ }}", []string{"nor"}, []string{}, nil}, + {`Test completion on {{ define "test" }} T1 {{ end }} {{ include "te^"}}`, []string{"test"}, []string{}, nil}, + } + + for _, tt := range testCases { + t.Run(tt.templateWithMark, func(t *testing.T) { + // seen chars up to ^ + col := strings.Index(tt.templateWithMark, "^") + buf := strings.Replace(tt.templateWithMark, "^", "", 1) + pos := protocol.Position{Line: 0, Character: uint32(col)} + // to get the correct values file + fileURI := uri.File("../../testdata/example/templates/completion-test.yaml") + + result, err := completionTestCall(fileURI, buf, pos) + assert.NotNil(t, result) + assert.Equal(t, tt.err, err) + + if result == nil { + return + } + + insertTexts := []string{} + for _, item := range result.Items { + insertTexts = append(insertTexts, item.InsertText) + } + for _, expectedInsertText := range tt.expectedInsertTexts { + assert.Contains(t, insertTexts, expectedInsertText) + } + + for _, notExpectedInsertText := range tt.notExpectedInsertTexts { + assert.NotContains(t, insertTexts, notExpectedInsertText) + } + }) + } +} + +func completionTestCall(fileURI uri.URI, buf string, pos lsp.Position) (*lsp.CompletionList, error) { + documents := lsplocal.NewDocumentStore() + d := lsp.DidOpenTextDocumentParams{ + TextDocument: lsp.TextDocumentItem{ + URI: fileURI, + LanguageID: "", + Version: 0, + Text: buf, + }, + } + documents.DidOpen(&d, util.DefaultConfig) + h := &langHandler{ + chartStore: charts.NewChartStore(uri.File("."), charts.NewChart), + documents: documents, + yamllsConnector: &yamlls.Connector{}, + } + result, err := h.Completion(context.Background(), &lsp.CompletionParams{ + TextDocumentPositionParams: lsp.TextDocumentPositionParams{ + TextDocument: lsp.TextDocumentIdentifier{ + URI: fileURI, + }, + Position: pos, + }, + }) + return result, err +} diff --git a/internal/handler/definition.go b/internal/handler/definition.go index a3d5f5e6..c62560d9 100644 --- a/internal/handler/definition.go +++ b/internal/handler/definition.go @@ -4,11 +4,12 @@ import ( "context" languagefeatures "github.com/mrjosh/helm-ls/internal/language_features" + lsplocal "github.com/mrjosh/helm-ls/internal/lsp" lsp "go.lsp.dev/protocol" ) func (h *langHandler) Definition(_ context.Context, params *lsp.DefinitionParams) (result []lsp.Location, err error) { - genericDocumentUseCase, err := h.NewGenericDocumentUseCase(params.TextDocumentPositionParams) + genericDocumentUseCase, err := h.NewGenericDocumentUseCase(params.TextDocumentPositionParams, lsplocal.NodeAtPosition) if err != nil { return nil, err } diff --git a/internal/handler/generic_document_usecase.go b/internal/handler/generic_document_usecase.go index 841e521e..14e1ec61 100644 --- a/internal/handler/generic_document_usecase.go +++ b/internal/handler/generic_document_usecase.go @@ -4,12 +4,14 @@ import ( "errors" languagefeatures "github.com/mrjosh/helm-ls/internal/language_features" - lsplocal "github.com/mrjosh/helm-ls/internal/lsp" sitter "github.com/smacker/go-tree-sitter" lsp "go.lsp.dev/protocol" ) -func (h *langHandler) NewGenericDocumentUseCase(params lsp.TextDocumentPositionParams) (*languagefeatures.GenericDocumentUseCase, error) { +func (h *langHandler) NewGenericDocumentUseCase( + params lsp.TextDocumentPositionParams, + nodeSelection func(ast *sitter.Tree, position lsp.Position) (node *sitter.Node), +) (*languagefeatures.GenericDocumentUseCase, error) { doc, ok := h.documents.Get(params.TextDocument.URI) if !ok { return &languagefeatures.GenericDocumentUseCase{}, errors.New("Could not get document: " + params.TextDocument.URI.Filename()) @@ -18,19 +20,29 @@ func (h *langHandler) NewGenericDocumentUseCase(params lsp.TextDocumentPositionP if err != nil { logger.Error("Error getting chart info for file", params.TextDocument.URI, err) } - node := h.getNode(doc, params.Position) + + node := nodeSelection(doc.Ast, params.Position) if node == nil { return &languagefeatures.GenericDocumentUseCase{}, errors.New("Could not get node for: " + params.TextDocument.URI.Filename()) } - return languagefeatures.GenericDocumentUseCase{ - Document: doc, - DocumentStore: h.documents, - Chart: chart, - ChartStore: h.chartStore, - }.WithNode(node), nil -} -func (h *langHandler) getNode(doc *lsplocal.Document, position lsp.Position) *sitter.Node { - currentNode := lsplocal.NodeAtPosition(doc.Ast, position) - return currentNode + var ( + nodeType = node.Type() + parentNode = node.Parent() + parentNodeType string + ) + if parentNode != nil { + parentNodeType = parentNode.Type() + } + + return &languagefeatures.GenericDocumentUseCase{ + Document: doc, + DocumentStore: h.documents, + Chart: chart, + ChartStore: h.chartStore, + Node: node, + NodeType: nodeType, + ParentNode: parentNode, + ParentNodeType: parentNodeType, + }, nil } diff --git a/internal/handler/hover.go b/internal/handler/hover.go index 7df10878..7c60374a 100644 --- a/internal/handler/hover.go +++ b/internal/handler/hover.go @@ -4,20 +4,20 @@ import ( "context" languagefeatures "github.com/mrjosh/helm-ls/internal/language_features" - lspinternal "github.com/mrjosh/helm-ls/internal/lsp" + lsplocal "github.com/mrjosh/helm-ls/internal/lsp" + "github.com/mrjosh/helm-ls/internal/protocol" "github.com/mrjosh/helm-ls/internal/tree-sitter/gotemplate" - "github.com/mrjosh/helm-ls/internal/util" lsp "go.lsp.dev/protocol" ) func (h *langHandler) Hover(ctx context.Context, params *lsp.HoverParams) (result *lsp.Hover, err error) { - genericDocumentUseCase, err := h.NewGenericDocumentUseCase(params.TextDocumentPositionParams) + genericDocumentUseCase, err := h.NewGenericDocumentUseCase(params.TextDocumentPositionParams, lsplocal.NodeAtPosition) if err != nil { return nil, err } - wordRange := lspinternal.GetLspRangeForNode(genericDocumentUseCase.Node) + wordRange := lsplocal.GetLspRangeForNode(genericDocumentUseCase.Node) usecases := []languagefeatures.HoverUseCase{ languagefeatures.NewBuiltInObjectsFeature(genericDocumentUseCase), // has to be before template context @@ -29,15 +29,12 @@ func (h *langHandler) Hover(ctx context.Context, params *lsp.HoverParams) (resul for _, usecase := range usecases { if usecase.AppropriateForNode() { result, err := usecase.Hover() - return util.BuildHoverResponse(result, wordRange), err + return protocol.BuildHoverResponse(result, wordRange), err } } if genericDocumentUseCase.NodeType == gotemplate.NodeTypeText { word := genericDocumentUseCase.Document.WordAt(params.Position) - if len(word) > 2 && string(word[len(word)-1]) == ":" { - word = word[0 : len(word)-1] - } response, err := h.yamllsConnector.CallHover(ctx, *params, word) return response, err } diff --git a/internal/handler/initialization.go b/internal/handler/initialization.go index 15ed6b32..40f3923d 100644 --- a/internal/handler/initialization.go +++ b/internal/handler/initialization.go @@ -27,7 +27,7 @@ func (h *langHandler) Initialize(ctx context.Context, params *lsp.InitializePara } logger.Debug("Initializing chartStore") - h.chartStore = charts.NewChartStore(workspaceURI, h.NewChartWithWatchedFiles) + h.chartStore = charts.NewChartStore(workspaceURI, h.NewChartWithInitActions) logger.Debug("Initializing done") return &lsp.InitializeResult{ @@ -83,3 +83,8 @@ func configureLogLevel(helmlsConfig util.HelmlsConfiguration) { logger.SetLevel(logrus.DebugLevel) } } + +func (h *langHandler) NewChartWithInitActions(rootURI uri.URI, valuesFilesConfig util.ValuesFilesConfig) *charts.Chart { + go h.LoadDocsOnNewChart(rootURI) + return h.NewChartWithWatchedFiles(rootURI, valuesFilesConfig) +} diff --git a/internal/handler/references.go b/internal/handler/references.go index d7be4e9d..f41b3a14 100644 --- a/internal/handler/references.go +++ b/internal/handler/references.go @@ -4,11 +4,12 @@ import ( "context" languagefeatures "github.com/mrjosh/helm-ls/internal/language_features" + lsplocal "github.com/mrjosh/helm-ls/internal/lsp" lsp "go.lsp.dev/protocol" ) -func (h *langHandler) References(ctx context.Context, params *lsp.ReferenceParams) (result []lsp.Location, err error) { - genericDocumentUseCase, err := h.NewGenericDocumentUseCase(params.TextDocumentPositionParams) +func (h *langHandler) References(_ context.Context, params *lsp.ReferenceParams) (result []lsp.Location, err error) { + genericDocumentUseCase, err := h.NewGenericDocumentUseCase(params.TextDocumentPositionParams, lsplocal.NodeAtPosition) if err != nil { return nil, err } diff --git a/internal/handler/text_document.go b/internal/handler/text_document.go index 8f7724c7..d8c75a8e 100644 --- a/internal/handler/text_document.go +++ b/internal/handler/text_document.go @@ -3,9 +3,12 @@ package handler import ( "context" "errors" + "io/fs" + "path/filepath" lsplocal "github.com/mrjosh/helm-ls/internal/lsp" lsp "go.lsp.dev/protocol" + "go.lsp.dev/uri" ) func (h *langHandler) DidOpen(ctx context.Context, params *lsp.DidOpenTextDocumentParams) (err error) { @@ -94,3 +97,15 @@ func (h *langHandler) DidRenameFiles(ctx context.Context, params *lsp.RenameFile logger.Error("DidRenameFiles unimplemented") return nil } + +// TODO: maybe use the helm implementation of this once https://github.com/mrjosh/helm-ls/pull/77 is resolved +func (h *langHandler) LoadDocsOnNewChart(rootURI uri.URI) { + _ = filepath.WalkDir(filepath.Join(rootURI.Filename(), "templates"), + func(path string, d fs.DirEntry, err error) error { + if !d.IsDir() { + return h.documents.Store(uri.File(path), h.helmlsConfig) + } + return nil + }, + ) +} diff --git a/internal/language_features/function_call.go b/internal/language_features/function_call.go index a47cf650..80f651b4 100644 --- a/internal/language_features/function_call.go +++ b/internal/language_features/function_call.go @@ -20,7 +20,8 @@ func NewFunctionCallFeature(genericDocumentUseCase *GenericDocumentUseCase) *Fun } func (f *FunctionCallFeature) AppropriateForNode() bool { - return f.NodeType == gotemplate.NodeTypeIdentifier && f.ParentNodeType == gotemplate.NodeTypeFunctionCall + return f.NodeType == gotemplate.NodeTypeIdentifier && + f.ParentNodeType == gotemplate.NodeTypeFunctionCall } func (f *FunctionCallFeature) Hover() (string, error) { @@ -32,5 +33,5 @@ func (f *FunctionCallFeature) Hover() (string, error) { } func (f *FunctionCallFeature) Completion() (result *lsp.CompletionList, err error) { - return protocol.NewCompletionResults(helmdocs.AllFuncs).ToLSP(), nil + return protocol.CompletionResults{}.WithDocs(helmdocs.AllFuncs, lsp.CompletionItemKindFunction).ToList(), nil } diff --git a/internal/language_features/generic_document_usecase.go b/internal/language_features/generic_document_usecase.go index 90b369c2..23afbbf9 100644 --- a/internal/language_features/generic_document_usecase.go +++ b/internal/language_features/generic_document_usecase.go @@ -20,13 +20,3 @@ type GenericDocumentUseCase struct { func (u *GenericDocumentUseCase) NodeContent() string { return u.Node.Content([]byte(u.Document.Content)) } - -func (u GenericDocumentUseCase) WithNode(node *sitter.Node) *GenericDocumentUseCase { - u.Node = node - u.NodeType = node.Type() - u.ParentNode = node.Parent() - if u.ParentNode != nil { - u.ParentNodeType = u.ParentNode.Type() - } - return &u -} diff --git a/internal/language_features/includes.go b/internal/language_features/includes.go index 84b0fbd9..656a59ad 100644 --- a/internal/language_features/includes.go +++ b/internal/language_features/includes.go @@ -4,8 +4,10 @@ import ( lsp "go.lsp.dev/protocol" lsplocal "github.com/mrjosh/helm-ls/internal/lsp" + "github.com/mrjosh/helm-ls/internal/protocol" "github.com/mrjosh/helm-ls/internal/tree-sitter/gotemplate" "github.com/mrjosh/helm-ls/internal/util" + sitter "github.com/smacker/go-tree-sitter" ) type IncludesFeature struct { @@ -18,14 +20,29 @@ type IncludesCallFeature struct { // should be called on {{ include "name" . }} func (f *IncludesCallFeature) AppropriateForNode() bool { - if f.ParentNodeType != gotemplate.NodeTypeArgumentList { + functionCallNode := f.getFunctionCallNode() + + if functionCallNode == nil { return false } - functionCallNode := f.Node.Parent().Parent() _, err := lsplocal.ParseIncludeFunctionCall(functionCallNode, []byte(f.GenericDocumentUseCase.Document.Content)) return err == nil } +func (f *IncludesCallFeature) getFunctionCallNode() *sitter.Node { + var functionCallNode *sitter.Node + if f.ParentNodeType == gotemplate.NodeTypeArgumentList { + functionCallNode = f.Node.Parent().Parent() + } + if f.ParentNodeType == gotemplate.NodeTypeInterpretedStringLiteral { + parentParent := f.ParentNode.Parent() + if parentParent != nil && parentParent.Type() == gotemplate.NodeTypeArgumentList { + functionCallNode = parentParent.Parent() + } + } + return functionCallNode +} + type IncludesDefinitionFeature struct { *IncludesFeature } @@ -57,7 +74,7 @@ func (f *IncludesCallFeature) References() (result []lsp.Location, err error) { } func (f *IncludesCallFeature) getIncludeName() (string, error) { - functionCallNode := f.Node.Parent().Parent() + functionCallNode := f.getFunctionCallNode() return lsplocal.ParseIncludeFunctionCall(functionCallNode, []byte(f.GenericDocumentUseCase.Document.Content)) } @@ -90,14 +107,14 @@ func (f *IncludesFeature) getDefinitionLocations(includeName string) []lsp.Locat return locations } -func (f *IncludesFeature) getDefinitionsHover(includeName string) util.HoverResultsWithFiles { - result := util.HoverResultsWithFiles{} +func (f *IncludesFeature) getDefinitionsHover(includeName string) protocol.HoverResultsWithFiles { + result := protocol.HoverResultsWithFiles{} for _, doc := range f.GenericDocumentUseCase.DocumentStore.GetAllDocs() { referenceRanges := doc.SymbolTable.GetIncludeDefinitions(includeName) for _, referenceRange := range referenceRanges { node := doc.Ast.RootNode().NamedDescendantForPointRange(referenceRange.StartPoint, referenceRange.EndPoint) if node != nil { - result = append(result, util.HoverResultWithFile{ + result = append(result, protocol.HoverResultWithFile{ Value: node.Content([]byte(doc.Content)), URI: doc.URI, }) @@ -125,3 +142,18 @@ func (f *IncludesCallFeature) Definition() (result []lsp.Location, err error) { } return f.getDefinitionLocations(includeName), nil } + +func (f *IncludesCallFeature) Completion() (*lsp.CompletionList, error) { + items := []lsp.CompletionItem{} + for _, doc := range f.GenericDocumentUseCase.DocumentStore.GetAllDocs() { + inlcudeDefinitionNames := doc.SymbolTable.GetAllIncludeDefinitionsNames() + for _, includeDefinitionName := range inlcudeDefinitionNames { + items = append(items, lsp.CompletionItem{ + InsertText: includeDefinitionName, + Kind: lsp.CompletionItemKindFunction, + Label: includeDefinitionName, + }) + } + } + return &lsp.CompletionList{IsIncomplete: false, Items: items}, nil +} diff --git a/internal/language_features/template_context.go b/internal/language_features/template_context.go index 26cfb80c..8dcf15af 100644 --- a/internal/language_features/template_context.go +++ b/internal/language_features/template_context.go @@ -26,9 +26,6 @@ func NewTemplateContextFeature(genericDocumentUseCase *GenericDocumentUseCase) * } func (f *TemplateContextFeature) AppropriateForNode() bool { - nodeContent := f.NodeContent() - println(nodeContent) - if f.NodeType == gotemplate.NodeTypeDot || f.NodeType == gotemplate.NodeTypeDotSymbol { return true } @@ -104,13 +101,13 @@ func (f *TemplateContextFeature) Hover() (string, error) { func (f *TemplateContextFeature) valuesHover(templateContext lsplocal.TemplateContext) (string, error) { var ( valuesFiles = f.Chart.ResolveValueFiles(templateContext, f.ChartStore) - hoverResults = util.HoverResultsWithFiles{} + hoverResults = protocol.HoverResultsWithFiles{} ) for _, valuesFiles := range valuesFiles { for _, valuesFile := range valuesFiles.ValuesFiles.AllValuesFiles() { result, err := util.GetTableOrValueForSelector(valuesFile.Values, strings.Join(valuesFiles.Selector, ".")) if err == nil { - hoverResults = append(hoverResults, util.HoverResultWithFile{URI: valuesFile.URI, Value: result}) + hoverResults = append(hoverResults, protocol.HoverResultWithFile{URI: valuesFile.URI, Value: result}) } } } @@ -122,57 +119,3 @@ func (f *TemplateContextFeature) getMetadataField(v *chart.Metadata, fieldName s field := reflect.Indirect(r).FieldByName(fieldName) return util.FormatToYAML(field, fieldName) } - -func (f *TemplateContextFeature) Completion() (result *lsp.CompletionList, err error) { - templateContext, err := f.getTemplateContext() - if err != nil { - return nil, err - } - - if len(templateContext) == 0 { - result := helmdocs.BuiltInObjects - return protocol.NewCompletionResults(result).ToLSP(), nil - } - - if len(templateContext) == 1 { - result, ok := helmdocs.BuiltInOjectVals[templateContext[0]] - if !ok { - result := helmdocs.BuiltInObjects - return protocol.NewCompletionResults(result).ToLSP(), nil - } - return protocol.NewCompletionResults(result).ToLSP(), nil - } - - switch templateContext[0] { - case "Values": - return f.valuesCompletion(templateContext) - case "Chart", "Release", "Files", "Capabilities", "Template": - // TODO: make this more fine, by checking the length - result, ok := helmdocs.BuiltInOjectVals[templateContext[0]] - if !ok { - result := helmdocs.BuiltInObjects - return protocol.NewCompletionResults(result).ToLSP(), nil - } - return protocol.NewCompletionResults(result).ToLSP(), nil - - } - - return nil, nil -} - -func (f *TemplateContextFeature) valuesCompletion(templateContext lsplocal.TemplateContext) (*lsp.CompletionList, error) { - m := make(map[string]lsp.CompletionItem) - for _, queriedValuesFiles := range f.Chart.ResolveValueFiles(templateContext.Tail(), f.ChartStore) { - for _, valuesFile := range queriedValuesFiles.ValuesFiles.AllValuesFiles() { - for _, item := range util.GetValueCompletion(valuesFile.Values, queriedValuesFiles.Selector) { - m[item.InsertText] = item - } - } - } - completions := []lsp.CompletionItem{} - for _, item := range m { - completions = append(completions, item) - } - - return &lsp.CompletionList{Items: completions, IsIncomplete: false}, nil -} diff --git a/internal/language_features/template_context_completion.go b/internal/language_features/template_context_completion.go new file mode 100644 index 00000000..815539d1 --- /dev/null +++ b/internal/language_features/template_context_completion.go @@ -0,0 +1,73 @@ +package languagefeatures + +import ( + "fmt" + "strings" + + helmdocs "github.com/mrjosh/helm-ls/internal/documentation/helm" + lsplocal "github.com/mrjosh/helm-ls/internal/lsp" + "github.com/mrjosh/helm-ls/internal/protocol" + "github.com/mrjosh/helm-ls/internal/util" + lsp "go.lsp.dev/protocol" +) + +func (f *TemplateContextFeature) Completion() (*lsp.CompletionList, error) { + templateContext, err := f.getTemplateContext() + if err != nil { + return nil, err + } + + if len(templateContext) == 0 { + return protocol.CompletionResults{}.WithDocs(helmdocs.BuiltInObjects, lsp.CompletionItemKindConstant).ToList(), nil + } + + if len(templateContext) == 1 { + result, ok := helmdocs.BuiltInOjectVals[templateContext[0]] + if !ok { + return protocol.CompletionResults{}.WithDocs(helmdocs.BuiltInObjects, lsp.CompletionItemKindConstant).ToList(), nil + } + return protocol.CompletionResults{}.WithDocs(result, lsp.CompletionItemKindValue).ToList(), nil + } + if templateContext[0] == "Values" { + return f.valuesCompletion(templateContext) + } + nestedDocs, ok := helmdocs.BuiltInOjectVals[templateContext[0]] + if ok { + if len(templateContext) < 3 { + return protocol.CompletionResults{}.WithDocs(nestedDocs, lsp.CompletionItemKindValue).ToList(), nil + } + + adjustedDocs := trimPrefixForNestedDocs(nestedDocs, templateContext) + return protocol.CompletionResults{}.WithDocs(adjustedDocs, lsp.CompletionItemKindValue).ToList(), nil + } + return protocol.CompletionResults{}.ToList(), fmt.Errorf("%s is no valid template context for helm", templateContext) +} + +// handels the completion for .Capabilities.KubeVersion.^ where the result should not contain KubeVersion again +func trimPrefixForNestedDocs(nestedDocs []helmdocs.HelmDocumentation, templateContext lsplocal.TemplateContext) []helmdocs.HelmDocumentation { + adjustedDocs := []helmdocs.HelmDocumentation{} + for _, v := range nestedDocs { + if strings.HasPrefix(v.Name, templateContext.Tail().Format()) { + v.Name = strings.TrimPrefix(v.Name, templateContext.Tail().Format()) + adjustedDocs = append(adjustedDocs, v) + } + } + return adjustedDocs +} + +func (f *TemplateContextFeature) valuesCompletion(templateContext lsplocal.TemplateContext) (*lsp.CompletionList, error) { + m := make(map[string]lsp.CompletionItem) + for _, queriedValuesFiles := range f.Chart.ResolveValueFiles(templateContext.Tail(), f.ChartStore) { + for _, valuesFile := range queriedValuesFiles.ValuesFiles.AllValuesFiles() { + for _, item := range util.GetValueCompletion(valuesFile.Values, queriedValuesFiles.Selector) { + m[item.InsertText] = item + } + } + } + completions := []lsp.CompletionItem{} + for _, item := range m { + completions = append(completions, item) + } + + return &lsp.CompletionList{Items: completions, IsIncomplete: false}, nil +} diff --git a/internal/language_features/text.go b/internal/language_features/text.go new file mode 100644 index 00000000..8b603543 --- /dev/null +++ b/internal/language_features/text.go @@ -0,0 +1,54 @@ +package languagefeatures + +import ( + "context" + + "github.com/mrjosh/helm-ls/internal/adapter/yamlls" + "github.com/mrjosh/helm-ls/internal/documentation/godocs" + "github.com/mrjosh/helm-ls/internal/protocol" + "github.com/mrjosh/helm-ls/internal/tree-sitter/gotemplate" + lsp "go.lsp.dev/protocol" +) + +type TextFeature struct { + *GenericDocumentUseCase + textDocumentPosition *lsp.TextDocumentPositionParams + ctx context.Context + yamllsConnector *yamlls.Connector +} + +func NewTextFeature( + ctx context.Context, + genericDocumentUseCase *GenericDocumentUseCase, + yamllsConnector *yamlls.Connector, + textDocumentPosition *lsp.TextDocumentPositionParams, +) *TextFeature { + return &TextFeature{ + GenericDocumentUseCase: genericDocumentUseCase, + textDocumentPosition: textDocumentPosition, + ctx: ctx, + yamllsConnector: yamllsConnector, + } +} + +func (f *TextFeature) AppropriateForNode() bool { + return f.NodeType == gotemplate.NodeTypeText || f.NodeType == gotemplate.NodeTypeTemplate +} + +func (f *TextFeature) Completion() (result *lsp.CompletionList, err error) { + comletions := f.yamllsCompletions(&lsp.CompletionParams{ + TextDocumentPositionParams: *f.textDocumentPosition, + }) + + return protocol.CompletionResults{Items: comletions}.WithSnippets(godocs.TextSnippets).ToList(), nil +} + +func (f *TextFeature) yamllsCompletions(params *lsp.CompletionParams) []lsp.CompletionItem { + response, err := f.yamllsConnector.CallCompletion(f.ctx, params) + if err != nil { + logger.Error("Error getting yamlls completions", err) + return []lsp.CompletionItem{} + } + logger.Debug("Got completions from yamlls", response) + return response.Items +} diff --git a/internal/language_features/usecases.go b/internal/language_features/usecases.go index 0fa4fa16..f1449bfa 100644 --- a/internal/language_features/usecases.go +++ b/internal/language_features/usecases.go @@ -1,9 +1,12 @@ package languagefeatures import ( + "github.com/mrjosh/helm-ls/internal/log" lsp "go.lsp.dev/protocol" ) +var logger = log.GetLogger() + // interface for use cases type UseCase interface { AppropriateForNode() bool diff --git a/internal/lsp/ast.go b/internal/lsp/ast.go index 00a134b1..c90ccea7 100644 --- a/internal/lsp/ast.go +++ b/internal/lsp/ast.go @@ -20,6 +20,15 @@ func NodeAtPosition(tree *sitter.Tree, position lsp.Position) *sitter.Node { return tree.RootNode().NamedDescendantForPointRange(start, start) } +func NestedNodeAtPositionForCompletion(tree *sitter.Tree, position lsp.Position) *sitter.Node { + currentNode := NodeAtPosition(tree, position) + pointToLoopUp := sitter.Point{ + Row: position.Line, + Column: position.Character, + } + return FindRelevantChildNodeCompletion(currentNode, pointToLoopUp) +} + func FindDirectChildNodeByStart(currentNode *sitter.Node, pointToLookUp sitter.Point) *sitter.Node { for i := 0; i < int(currentNode.ChildCount()); i++ { child := currentNode.Child(i) diff --git a/internal/lsp/document.go b/internal/lsp/document.go index 5a5f2395..99b8172c 100644 --- a/internal/lsp/document.go +++ b/internal/lsp/document.go @@ -2,65 +2,13 @@ package lsp import ( "bytes" - "fmt" "strings" - "sync" "github.com/mrjosh/helm-ls/internal/util" sitter "github.com/smacker/go-tree-sitter" lsp "go.lsp.dev/protocol" - "go.lsp.dev/uri" ) -// documentStore holds opened documents. -type DocumentStore struct { - documents sync.Map -} - -func NewDocumentStore() *DocumentStore { - return &DocumentStore{ - documents: sync.Map{}, - } -} - -func (s *DocumentStore) GetAllDocs() []*Document { - var docs []*Document - s.documents.Range(func(_, v interface{}) bool { - docs = append(docs, v.(*Document)) - return true - }) - return docs -} - -func (s *DocumentStore) DidOpen(params *lsp.DidOpenTextDocumentParams, helmlsConfig util.HelmlsConfiguration) (*Document, error) { - logger.Debug(fmt.Sprintf("Opening document %s with langID %s", params.TextDocument.URI, params.TextDocument.LanguageID)) - - uri := params.TextDocument.URI - path := uri.Filename() - ast := ParseAst(nil, params.TextDocument.Text) - doc := &Document{ - URI: uri, - Path: path, - Content: params.TextDocument.Text, - Ast: ast, - DiagnosticsCache: NewDiagnosticsCache(helmlsConfig), - IsOpen: true, - SymbolTable: NewSymbolTable(ast, []byte(params.TextDocument.Text)), - } - logger.Debug("Storing doc ", path) - s.documents.Store(path, doc) - return doc, nil -} - -func (s *DocumentStore) Get(docuri uri.URI) (*Document, bool) { - path := docuri.Filename() - d, ok := s.documents.Load(path) - if !ok { - return nil, false - } - return d.(*Document), ok -} - // Document represents an opened file. type Document struct { URI lsp.DocumentURI diff --git a/internal/lsp/document_store.go b/internal/lsp/document_store.go new file mode 100644 index 00000000..d7c8428d --- /dev/null +++ b/internal/lsp/document_store.go @@ -0,0 +1,82 @@ +package lsp + +import ( + "fmt" + "os" + "sync" + + "github.com/mrjosh/helm-ls/internal/util" + lsp "go.lsp.dev/protocol" + "go.lsp.dev/uri" +) + +// documentStore holds opened documents. +type DocumentStore struct { + documents sync.Map +} + +func NewDocumentStore() *DocumentStore { + return &DocumentStore{ + documents: sync.Map{}, + } +} + +func (s *DocumentStore) GetAllDocs() []*Document { + var docs []*Document + s.documents.Range(func(_, v interface{}) bool { + docs = append(docs, v.(*Document)) + return true + }) + return docs +} + +func (s *DocumentStore) DidOpen(params *lsp.DidOpenTextDocumentParams, helmlsConfig util.HelmlsConfiguration) (*Document, error) { + logger.Debug(fmt.Sprintf("Opening document %s with langID %s", params.TextDocument.URI, params.TextDocument.LanguageID)) + + uri := params.TextDocument.URI + path := uri.Filename() + ast := ParseAst(nil, params.TextDocument.Text) + doc := &Document{ + URI: uri, + Path: path, + Content: params.TextDocument.Text, + Ast: ast, + DiagnosticsCache: NewDiagnosticsCache(helmlsConfig), + IsOpen: true, + SymbolTable: NewSymbolTable(ast, []byte(params.TextDocument.Text)), + } + logger.Debug("Storing doc ", path) + s.documents.Store(path, doc) + return doc, nil +} + +func (s *DocumentStore) Store(uri uri.URI, helmlsConfig util.HelmlsConfiguration) error { + content, err := os.ReadFile(uri.Filename()) + if err != nil { + logger.Error("Could not open file ", uri.Filename(), " ", err) + return err + } + + ast := ParseAst(nil, string(content)) + s.documents.Store(uri.Filename(), + &Document{ + URI: uri, + Path: uri.Filename(), + Content: string(content), + Ast: ast, + DiagnosticsCache: NewDiagnosticsCache(helmlsConfig), + IsOpen: false, + SymbolTable: NewSymbolTable(ast, content), + }, + ) + return nil +} + +func (s *DocumentStore) Get(docuri uri.URI) (*Document, bool) { + path := docuri.Filename() + d, ok := s.documents.Load(path) + if !ok { + return nil, false + } + return d.(*Document), ok +} diff --git a/internal/lsp/symbol_table.go b/internal/lsp/symbol_table.go index 2f3d6719..8588c57e 100644 --- a/internal/lsp/symbol_table.go +++ b/internal/lsp/symbol_table.go @@ -17,6 +17,15 @@ func (t TemplateContext) Tail() TemplateContext { return t[1:] } +func (t TemplateContext) IsVariable() bool { + return len(t) > 0 && t[0] == "$" +} + +func (t TemplateContext) AppendSuffix(suffix string) TemplateContext { + t[len(t)-1] = t[len(t)-1] + suffix + return t +} + type SymbolTable struct { contexts map[string][]sitter.Range contextsReversed map[sitter.Range]TemplateContext @@ -26,10 +35,10 @@ type SymbolTable struct { func NewSymbolTable(ast *sitter.Tree, content []byte) *SymbolTable { s := &SymbolTable{ - contexts: make(map[string][]sitter.Range), - contextsReversed: make(map[sitter.Range]TemplateContext), - includeDefinitions: make(map[string][]sitter.Range), - includeUseages: make(map[string][]sitter.Range), + contexts: map[string][]sitter.Range{}, + contextsReversed: map[sitter.Range]TemplateContext{}, + includeDefinitions: map[string][]sitter.Range{}, + includeUseages: map[string][]sitter.Range{}, } s.parseTree(ast, content) return s @@ -66,6 +75,13 @@ func (s *SymbolTable) GetIncludeDefinitions(symbol string) []sitter.Range { return s.includeDefinitions[symbol] } +func (s *SymbolTable) GetAllIncludeDefinitionsNames() (result []string) { + for k := range s.includeDefinitions { + result = append(result, k) + } + return result +} + func (s *SymbolTable) GetIncludeReference(symbol string) []sitter.Range { result := s.includeUseages[symbol] definitions := s.includeDefinitions[symbol] diff --git a/internal/lsp/symbol_table_includes.go b/internal/lsp/symbol_table_includes.go index 9e35c76e..b1d2d7de 100644 --- a/internal/lsp/symbol_table_includes.go +++ b/internal/lsp/symbol_table_includes.go @@ -59,6 +59,6 @@ func ParseIncludeFunctionCall(node *sitter.Node, content []byte) (string, error) return util.RemoveQuotes(firstArgument.Content(content)), nil } -func (v *IncludeDefinitionsVisitor) Exit(node *sitter.Node) {} -func (v *IncludeDefinitionsVisitor) EnterContextShift(node *sitter.Node, suffix string) {} -func (v *IncludeDefinitionsVisitor) ExitContextShift(node *sitter.Node) {} +func (v *IncludeDefinitionsVisitor) Exit(_ *sitter.Node) {} +func (v *IncludeDefinitionsVisitor) EnterContextShift(_ *sitter.Node, _ string) {} +func (v *IncludeDefinitionsVisitor) ExitContextShift(_ *sitter.Node) {} diff --git a/internal/lsp/symbol_table_values.go b/internal/lsp/symbol_table_template_context.go similarity index 82% rename from internal/lsp/symbol_table_values.go rename to internal/lsp/symbol_table_template_context.go index 4b81e7dd..b77cdcbf 100644 --- a/internal/lsp/symbol_table_values.go +++ b/internal/lsp/symbol_table_template_context.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,13 @@ 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 +75,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,13 +91,13 @@ 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 - if s[0] == "$" { + s = s.AppendSuffix(suffix) + if s.IsVariable() { v.StashContext() - s = s[1:] + s = s.Tail() } } v.PushContextMany(s) @@ -100,9 +108,9 @@ 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] == "$" { + if s.IsVariable() { v.RestoreStashedContext() } else { v.PopContextN(len(s)) 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/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/protocol/completion.go b/internal/protocol/completion.go index 3e1efe5f..5ff66033 100644 --- a/internal/protocol/completion.go +++ b/internal/protocol/completion.go @@ -1,42 +1,57 @@ package protocol import ( + "github.com/mrjosh/helm-ls/internal/documentation/godocs" helmdocs "github.com/mrjosh/helm-ls/internal/documentation/helm" lsp "go.lsp.dev/protocol" ) -type CompletionResults []CompletionResult +type CompletionResults struct { + Items []lsp.CompletionItem +} -func NewCompletionResults(docs []helmdocs.HelmDocumentation) *CompletionResults { - result := CompletionResults{} +func (c CompletionResults) ToList() (result *lsp.CompletionList) { + return &lsp.CompletionList{Items: c.Items, IsIncomplete: false} +} +func (c CompletionResults) WithDocs(docs []helmdocs.HelmDocumentation, kind lsp.CompletionItemKind) CompletionResults { + items := c.Items for _, doc := range docs { - result = append(result, CompletionResult{doc}) + items = append(items, + lsp.CompletionItem{ + Label: doc.Name, + Detail: doc.Detail, + InsertText: doc.Name, + InsertTextFormat: lsp.InsertTextFormatPlainText, + Kind: kind, + }, + ) } - - return &result + return CompletionResults{Items: items} } -type CompletionResult struct { - Documentation helmdocs.HelmDocumentation +func (c CompletionResults) WithSnippets(snippets []godocs.GoTemplateSnippet) CompletionResults { + items := c.Items + for _, snippet := range snippets { + items = append(items, textCompletionItem(snippet)) + } + return CompletionResults{Items: items} } -func (c *CompletionResult) ToLSP() (result lsp.CompletionItem) { +func textCompletionItem(gotemplateSnippet godocs.GoTemplateSnippet) lsp.CompletionItem { return lsp.CompletionItem{ - Label: c.Documentation.Name, - Detail: c.Documentation.Detail, - InsertText: c.Documentation.Name, + Label: gotemplateSnippet.Name, + InsertText: gotemplateSnippet.Snippet, + Detail: gotemplateSnippet.Detail, + Documentation: gotemplateSnippet.Doc, + Kind: lsp.CompletionItemKindText, InsertTextFormat: lsp.InsertTextFormatSnippet, - Kind: lsp.CompletionItemKindConstant, // TODO: make this more variable } } -func (c *CompletionResults) ToLSP() (result *lsp.CompletionList) { - items := []lsp.CompletionItem{} - - for _, completion := range *c { - items = append(items, completion.ToLSP()) +func GetTextCompletionItems(gotemplateSnippet []godocs.GoTemplateSnippet) (result []lsp.CompletionItem) { + for _, item := range gotemplateSnippet { + result = append(result, textCompletionItem(item)) } - - return &lsp.CompletionList{Items: items} + return result } diff --git a/internal/util/lsp.go b/internal/protocol/hover.go similarity index 88% rename from internal/util/lsp.go rename to internal/protocol/hover.go index c77636fa..a075fdab 100644 --- a/internal/util/lsp.go +++ b/internal/protocol/hover.go @@ -1,4 +1,4 @@ -package util +package protocol import ( "fmt" @@ -36,10 +36,6 @@ func (h HoverResultsWithFiles) Format(rootURI uri.URI) string { return formatted } -func (h *HoverResultsWithFiles) Add(hoverResult HoverResultWithFile) { - *h = append(*h, hoverResult) -} - func BuildHoverResponse(value string, wordRange lsp.Range) *lsp.Hover { content := lsp.MarkupContent{ Kind: lsp.Markdown, diff --git a/internal/tree-sitter/gotemplate/README.md b/internal/tree-sitter/gotemplate/README.md index 45f71268..b306f859 100644 --- a/internal/tree-sitter/gotemplate/README.md +++ b/internal/tree-sitter/gotemplate/README.md @@ -4,4 +4,4 @@ Taken from https://github.com/ngalaiko/tree-sitter-go-template, or currently thi ## Binding -Using this libary: https://github.com/smacker/go-tree-sitter +Using this library: https://github.com/smacker/go-tree-sitter diff --git a/internal/tree-sitter/gotemplate/node-types.go b/internal/tree-sitter/gotemplate/node-types.go index 085a8413..281f10e1 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 = "unfinished_selector_expression" + NodeTypeTemplate = "template" + NodeTypeText = "text" + NodeTypeVariable = "variable" + NodeTypeVariableDefinition = "variable_definition" + NodeTypeWith = "with" + NodeTypeWithAction = "with_action" FieldNameAlternative = "alternative" FieldNameCondition = "condition" diff --git a/internal/tree-sitter/gotemplate/parser.c b/internal/tree-sitter/gotemplate/parser.c index ed4c264d..dce287c1 100644 --- a/internal/tree-sitter/gotemplate/parser.c +++ b/internal/tree-sitter/gotemplate/parser.c @@ -1,7 +1,6 @@ -#include +#include "tree_sitter/parser.h" #if defined(__GNUC__) || defined(__clang__) -#pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wmissing-field-initializers" #endif @@ -16,7 +15,7 @@ #define MAX_ALIAS_SEQUENCE_LENGTH 12 #define PRODUCTION_ID_COUNT 35 -enum { +enum ts_symbol_identifiers { aux_sym_text_token1 = 1, aux_sym_text_token2 = 2, aux_sym_text_token3 = 3, @@ -37,7 +36,7 @@ enum { anon_sym_PIPE = 18, anon_sym_LPAREN = 19, anon_sym_RPAREN = 20, - anon_sym_ = 21, + anon_sym_SPACE = 21, sym_pipeline_stub = 22, anon_sym_DOT = 23, anon_sym_DOT2 = 24, @@ -85,7 +84,7 @@ enum { sym_argument_list = 66, sym__expression = 67, sym_selector_expression = 68, - sym_unfished_selector_expression = 69, + sym_unfinished_selector_expression = 69, sym__field_identifier = 70, sym_field = 71, sym_variable = 72, @@ -125,7 +124,7 @@ static const char * const ts_symbol_names[] = { [anon_sym_PIPE] = "|", [anon_sym_LPAREN] = "(", [anon_sym_RPAREN] = ")", - [anon_sym_] = " ", + [anon_sym_SPACE] = " ", [sym_pipeline_stub] = "pipeline_stub", [anon_sym_DOT] = ".", [anon_sym_DOT2] = ".", @@ -173,7 +172,7 @@ static const char * const ts_symbol_names[] = { [sym_argument_list] = "argument_list", [sym__expression] = "_expression", [sym_selector_expression] = "selector_expression", - [sym_unfished_selector_expression] = "unfished_selector_expression", + [sym_unfinished_selector_expression] = "unfinished_selector_expression", [sym__field_identifier] = "_field_identifier", [sym_field] = "field", [sym_variable] = "variable", @@ -213,7 +212,7 @@ static const TSSymbol ts_symbol_map[] = { [anon_sym_PIPE] = anon_sym_PIPE, [anon_sym_LPAREN] = anon_sym_LPAREN, [anon_sym_RPAREN] = anon_sym_RPAREN, - [anon_sym_] = anon_sym_, + [anon_sym_SPACE] = anon_sym_SPACE, [sym_pipeline_stub] = sym_pipeline_stub, [anon_sym_DOT] = anon_sym_DOT, [anon_sym_DOT2] = anon_sym_DOT, @@ -261,7 +260,7 @@ static const TSSymbol ts_symbol_map[] = { [sym_argument_list] = sym_argument_list, [sym__expression] = sym__expression, [sym_selector_expression] = sym_selector_expression, - [sym_unfished_selector_expression] = sym_unfished_selector_expression, + [sym_unfinished_selector_expression] = sym_unfinished_selector_expression, [sym__field_identifier] = sym__field_identifier, [sym_field] = sym_field, [sym_variable] = sym_variable, @@ -364,7 +363,7 @@ static const TSSymbolMetadata ts_symbol_metadata[] = { .visible = true, .named = false, }, - [anon_sym_] = { + [anon_sym_SPACE] = { .visible = true, .named = false, }, @@ -556,7 +555,7 @@ static const TSSymbolMetadata ts_symbol_metadata[] = { .visible = true, .named = true, }, - [sym_unfished_selector_expression] = { + [sym_unfinished_selector_expression] = { .visible = true, .named = true, }, @@ -622,7 +621,7 @@ static const TSSymbolMetadata ts_symbol_metadata[] = { }, }; -enum { +enum ts_field_identifiers { field_alternative = 1, field_argument = 2, field_arguments = 3, @@ -14613,9 +14612,7 @@ static bool ts_lex(TSLexer *lexer, TSStateId state) { if (lookahead == '{') ADVANCE(33); if (lookahead == '|') ADVANCE(107); if (lookahead == '}') ADVANCE(34); - if (lookahead == '\t' || - lookahead == '\n' || - lookahead == '\r' || + if (('\t' <= lookahead && lookahead <= '\r') || lookahead == ' ') SKIP(76) if (('1' <= lookahead && lookahead <= '9')) ADVANCE(167); END_STATE(); @@ -14623,8 +14620,7 @@ static bool ts_lex(TSLexer *lexer, TSStateId state) { if (lookahead == '\n') SKIP(12) if (lookahead == '"') ADVANCE(180); if (lookahead == '\\') ADVANCE(24); - if (lookahead == '\t' || - lookahead == '\r' || + if (('\t' <= lookahead && lookahead <= '\r') || lookahead == ' ') ADVANCE(181); if (lookahead != 0) ADVANCE(182); END_STATE(); @@ -14645,9 +14641,7 @@ static bool ts_lex(TSLexer *lexer, TSStateId state) { if (lookahead == 't') ADVANCE(154); if (lookahead == '|') ADVANCE(107); if (lookahead == '}') ADVANCE(34); - if (lookahead == '\t' || - lookahead == '\n' || - lookahead == '\r') SKIP(3) + if (('\t' <= lookahead && lookahead <= '\r')) SKIP(3) if (('1' <= lookahead && lookahead <= '9')) ADVANCE(167); END_STATE(); case 3: @@ -14667,9 +14661,7 @@ static bool ts_lex(TSLexer *lexer, TSStateId state) { if (lookahead == 't') ADVANCE(154); if (lookahead == '|') ADVANCE(107); if (lookahead == '}') ADVANCE(34); - if (lookahead == '\t' || - lookahead == '\n' || - lookahead == '\r') SKIP(3) + if (('\t' <= lookahead && lookahead <= '\r')) SKIP(3) if (('1' <= lookahead && lookahead <= '9')) ADVANCE(167); END_STATE(); case 4: @@ -14682,9 +14674,7 @@ static bool ts_lex(TSLexer *lexer, TSStateId state) { if (sym_identifier_character_set_3(lookahead)) ADVANCE(164); if (lookahead == '|') ADVANCE(107); if (lookahead == '}') ADVANCE(34); - if (lookahead == '\t' || - lookahead == '\n' || - lookahead == '\r') SKIP(5) + if (('\t' <= lookahead && lookahead <= '\r')) SKIP(5) END_STATE(); case 5: if (lookahead == ' ') ADVANCE(110); @@ -14695,9 +14685,7 @@ static bool ts_lex(TSLexer *lexer, TSStateId state) { if (sym_identifier_character_set_3(lookahead)) ADVANCE(164); if (lookahead == '|') ADVANCE(107); if (lookahead == '}') ADVANCE(34); - if (lookahead == '\t' || - lookahead == '\n' || - lookahead == '\r') SKIP(5) + if (('\t' <= lookahead && lookahead <= '\r')) SKIP(5) END_STATE(); case 6: if (lookahead == '"') ADVANCE(180); @@ -14715,9 +14703,7 @@ static bool ts_lex(TSLexer *lexer, TSStateId state) { if (lookahead == 't') ADVANCE(154); if (lookahead == '|') ADVANCE(107); if (lookahead == '}') ADVANCE(34); - if (lookahead == '\t' || - lookahead == '\n' || - lookahead == '\r' || + if (('\t' <= lookahead && lookahead <= '\r') || lookahead == ' ') SKIP(7) if (('1' <= lookahead && lookahead <= '9')) ADVANCE(167); END_STATE(); @@ -14737,9 +14723,7 @@ static bool ts_lex(TSLexer *lexer, TSStateId state) { if (lookahead == 't') ADVANCE(154); if (lookahead == '|') ADVANCE(107); if (lookahead == '}') ADVANCE(34); - if (lookahead == '\t' || - lookahead == '\n' || - lookahead == '\r' || + if (('\t' <= lookahead && lookahead <= '\r') || lookahead == ' ') SKIP(7) if (('1' <= lookahead && lookahead <= '9')) ADVANCE(167); END_STATE(); @@ -14762,9 +14746,7 @@ static bool ts_lex(TSLexer *lexer, TSStateId state) { if (lookahead == 'r') ADVANCE(161); if (lookahead == 't') ADVANCE(116); if (lookahead == 'w') ADVANCE(136); - if (lookahead == '\t' || - lookahead == '\n' || - lookahead == '\r' || + if (('\t' <= lookahead && lookahead <= '\r') || lookahead == ' ') SKIP(8) if (('1' <= lookahead && lookahead <= '9')) ADVANCE(167); END_STATE(); @@ -14787,9 +14769,7 @@ static bool ts_lex(TSLexer *lexer, TSStateId state) { if (lookahead == 'r') ADVANCE(161); if (lookahead == 't') ADVANCE(116); if (lookahead == 'w') ADVANCE(136); - if (lookahead == '\t' || - lookahead == '\n' || - lookahead == '\r' || + if (('\t' <= lookahead && lookahead <= '\r') || lookahead == ' ') SKIP(9) if (('1' <= lookahead && lookahead <= '9')) ADVANCE(167); END_STATE(); @@ -14812,9 +14792,7 @@ static bool ts_lex(TSLexer *lexer, TSStateId state) { if (lookahead == 'r') ADVANCE(161); if (lookahead == 't') ADVANCE(116); if (lookahead == 'w') ADVANCE(136); - if (lookahead == '\t' || - lookahead == '\n' || - lookahead == '\r' || + if (('\t' <= lookahead && lookahead <= '\r') || lookahead == ' ') SKIP(10) if (('1' <= lookahead && lookahead <= '9')) ADVANCE(167); END_STATE(); @@ -14836,24 +14814,21 @@ static bool ts_lex(TSLexer *lexer, TSStateId state) { if (lookahead == 'r') ADVANCE(161); if (lookahead == 't') ADVANCE(116); if (lookahead == 'w') ADVANCE(136); - if (lookahead == '\t' || - lookahead == '\n' || - lookahead == '\r' || + if (('\t' <= lookahead && lookahead <= '\r') || lookahead == ' ') SKIP(11) if (('1' <= lookahead && lookahead <= '9')) ADVANCE(167); END_STATE(); case 12: if (lookahead == '"') ADVANCE(180); - if (lookahead == '\t' || - lookahead == '\n' || - lookahead == '\r' || + if (('\t' <= lookahead && lookahead <= '\r') || lookahead == ' ') SKIP(12) END_STATE(); case 13: if (lookahead == '"') ADVANCE(80); if (lookahead == '{') ADVANCE(73); if (lookahead != 0 && - lookahead != '\n') ADVANCE(13); + lookahead != '\n' && + lookahead != '\r') ADVANCE(13); END_STATE(); case 14: if (lookahead == '\'') ADVANCE(175); @@ -14862,7 +14837,8 @@ static bool ts_lex(TSLexer *lexer, TSStateId state) { if (lookahead == '\'') ADVANCE(82); if (lookahead == '{') ADVANCE(74); if (lookahead != 0 && - lookahead != '\n') ADVANCE(15); + lookahead != '\n' && + lookahead != '\r') ADVANCE(15); END_STATE(); case 16: if (lookahead == ')') ADVANCE(109); @@ -14874,9 +14850,7 @@ static bool ts_lex(TSLexer *lexer, TSStateId state) { if (sym_identifier_character_set_3(lookahead)) ADVANCE(164); if (lookahead == '|') ADVANCE(107); if (lookahead == '}') ADVANCE(34); - if (lookahead == '\t' || - lookahead == '\n' || - lookahead == '\r' || + if (('\t' <= lookahead && lookahead <= '\r') || lookahead == ' ') SKIP(17) END_STATE(); case 17: @@ -14888,9 +14862,7 @@ static bool ts_lex(TSLexer *lexer, TSStateId state) { if (sym_identifier_character_set_3(lookahead)) ADVANCE(164); if (lookahead == '|') ADVANCE(107); if (lookahead == '}') ADVANCE(34); - if (lookahead == '\t' || - lookahead == '\n' || - lookahead == '\r' || + if (('\t' <= lookahead && lookahead <= '\r') || lookahead == ' ') SKIP(17) END_STATE(); case 18: @@ -14940,7 +14912,8 @@ static bool ts_lex(TSLexer *lexer, TSStateId state) { if (lookahead == ']') ADVANCE(78); if (lookahead == '{') ADVANCE(72); if (lookahead != 0 && - lookahead != '\n') ADVANCE(26); + lookahead != '\n' && + lookahead != '\r') ADVANCE(26); END_STATE(); case 27: if (lookahead == '_') ADVANCE(43); @@ -14964,7 +14937,8 @@ static bool ts_lex(TSLexer *lexer, TSStateId state) { case 32: if (lookahead == '{') ADVANCE(72); if (lookahead != 0 && - lookahead != '\n') ADVANCE(26); + lookahead != '\n' && + lookahead != '\r') ADVANCE(26); END_STATE(); case 33: if (lookahead == '{') ADVANCE(188); @@ -14983,6 +14957,7 @@ static bool ts_lex(TSLexer *lexer, TSStateId state) { lookahead == ' ') ADVANCE(26); if (lookahead != 0 && lookahead != '\n' && + lookahead != '\r' && lookahead != '{') ADVANCE(87); END_STATE(); case 38: @@ -14990,6 +14965,7 @@ static bool ts_lex(TSLexer *lexer, TSStateId state) { lookahead == ' ') ADVANCE(13); if (lookahead != 0 && lookahead != '\n' && + lookahead != '\r' && lookahead != '{') ADVANCE(85); END_STATE(); case 39: @@ -14997,6 +14973,7 @@ static bool ts_lex(TSLexer *lexer, TSStateId state) { lookahead == ' ') ADVANCE(15); if (lookahead != 0 && lookahead != '\n' && + lookahead != '\r' && lookahead != '{') ADVANCE(86); END_STATE(); case 40: @@ -15150,33 +15127,38 @@ static bool ts_lex(TSLexer *lexer, TSStateId state) { if (lookahead != 0 && lookahead != '\t' && lookahead != '\n' && + lookahead != '\r' && lookahead != ' ' && lookahead != '{') ADVANCE(89); END_STATE(); case 72: if (lookahead != 0 && lookahead != '\n' && + lookahead != '\r' && lookahead != '{') ADVANCE(26); END_STATE(); case 73: if (lookahead != 0 && lookahead != '\n' && + lookahead != '\r' && lookahead != '{') ADVANCE(13); END_STATE(); case 74: if (lookahead != 0 && lookahead != '\n' && + lookahead != '\r' && lookahead != '{') ADVANCE(15); END_STATE(); case 75: if (eof) ADVANCE(77); if (lookahead == '\n') SKIP(75) - if (lookahead == '\r') ADVANCE(84); if (lookahead == '"') ADVANCE(88); if (lookahead == '\'') ADVANCE(90); if (lookahead == '[') ADVANCE(91); if (lookahead == '{') ADVANCE(93); - if (lookahead == '\t' || + if (lookahead == 11 || + lookahead == '\f') ADVANCE(84); + if (('\t' <= lookahead && lookahead <= '\r') || lookahead == ' ') ADVANCE(92); if (lookahead != 0) ADVANCE(89); END_STATE(); @@ -15210,9 +15192,7 @@ static bool ts_lex(TSLexer *lexer, TSStateId state) { if (lookahead == '{') ADVANCE(33); if (lookahead == '|') ADVANCE(107); if (lookahead == '}') ADVANCE(34); - if (lookahead == '\t' || - lookahead == '\n' || - lookahead == '\r' || + if (('\t' <= lookahead && lookahead <= '\r') || lookahead == ' ') SKIP(76) if (('1' <= lookahead && lookahead <= '9')) ADVANCE(167); END_STATE(); @@ -15224,7 +15204,8 @@ static bool ts_lex(TSLexer *lexer, TSStateId state) { if (lookahead == ']') ADVANCE(78); if (lookahead == '{') ADVANCE(72); if (lookahead != 0 && - lookahead != '\n') ADVANCE(26); + lookahead != '\n' && + lookahead != '\r') ADVANCE(26); END_STATE(); case 79: ACCEPT_TOKEN(aux_sym_text_token1); @@ -15233,14 +15214,16 @@ static bool ts_lex(TSLexer *lexer, TSStateId state) { if (lookahead == '\t' || lookahead == ' ') ADVANCE(26); if (lookahead != 0 && - lookahead != '\n') ADVANCE(87); + lookahead != '\n' && + lookahead != '\r') ADVANCE(87); END_STATE(); case 80: ACCEPT_TOKEN(aux_sym_text_token2); if (lookahead == '"') ADVANCE(80); if (lookahead == '{') ADVANCE(73); if (lookahead != 0 && - lookahead != '\n') ADVANCE(13); + lookahead != '\n' && + lookahead != '\r') ADVANCE(13); END_STATE(); case 81: ACCEPT_TOKEN(aux_sym_text_token2); @@ -15249,14 +15232,16 @@ static bool ts_lex(TSLexer *lexer, TSStateId state) { if (lookahead == '\t' || lookahead == ' ') ADVANCE(13); if (lookahead != 0 && - lookahead != '\n') ADVANCE(85); + lookahead != '\n' && + lookahead != '\r') ADVANCE(85); END_STATE(); case 82: ACCEPT_TOKEN(aux_sym_text_token3); if (lookahead == '\'') ADVANCE(82); if (lookahead == '{') ADVANCE(74); if (lookahead != 0 && - lookahead != '\n') ADVANCE(15); + lookahead != '\n' && + lookahead != '\r') ADVANCE(15); END_STATE(); case 83: ACCEPT_TOKEN(aux_sym_text_token3); @@ -15265,16 +15250,19 @@ static bool ts_lex(TSLexer *lexer, TSStateId state) { if (lookahead == '\t' || lookahead == ' ') ADVANCE(15); if (lookahead != 0 && - lookahead != '\n') ADVANCE(86); + lookahead != '\n' && + lookahead != '\r') ADVANCE(86); END_STATE(); case 84: ACCEPT_TOKEN(aux_sym_text_token4); - if (lookahead == '\r') ADVANCE(84); if (lookahead == '"') ADVANCE(88); if (lookahead == '\'') ADVANCE(90); if (lookahead == '[') ADVANCE(91); if (lookahead == '{') ADVANCE(93); + if (lookahead == 11 || + lookahead == '\f') ADVANCE(84); if (lookahead == '\t' || + lookahead == '\r' || lookahead == ' ') ADVANCE(92); if (lookahead != 0 && lookahead != '\n') ADVANCE(89); @@ -15286,7 +15274,8 @@ static bool ts_lex(TSLexer *lexer, TSStateId state) { if (lookahead == '\t' || lookahead == ' ') ADVANCE(13); if (lookahead != 0 && - lookahead != '\n') ADVANCE(85); + lookahead != '\n' && + lookahead != '\r') ADVANCE(85); END_STATE(); case 86: ACCEPT_TOKEN(aux_sym_text_token4); @@ -15295,7 +15284,8 @@ static bool ts_lex(TSLexer *lexer, TSStateId state) { if (lookahead == '\t' || lookahead == ' ') ADVANCE(15); if (lookahead != 0 && - lookahead != '\n') ADVANCE(86); + lookahead != '\n' && + lookahead != '\r') ADVANCE(86); END_STATE(); case 87: ACCEPT_TOKEN(aux_sym_text_token4); @@ -15304,7 +15294,8 @@ static bool ts_lex(TSLexer *lexer, TSStateId state) { if (lookahead == '\t' || lookahead == ' ') ADVANCE(26); if (lookahead != 0 && - lookahead != '\n') ADVANCE(87); + lookahead != '\n' && + lookahead != '\r') ADVANCE(87); END_STATE(); case 88: ACCEPT_TOKEN(aux_sym_text_token4); @@ -15312,7 +15303,8 @@ static bool ts_lex(TSLexer *lexer, TSStateId state) { if (lookahead == '\t' || lookahead == ' ') ADVANCE(13); if (lookahead != 0 && - lookahead != '\n') ADVANCE(85); + lookahead != '\n' && + lookahead != '\r') ADVANCE(85); END_STATE(); case 89: ACCEPT_TOKEN(aux_sym_text_token4); @@ -15320,6 +15312,7 @@ static bool ts_lex(TSLexer *lexer, TSStateId state) { if (lookahead != 0 && lookahead != '\t' && lookahead != '\n' && + lookahead != '\r' && lookahead != ' ') ADVANCE(89); END_STATE(); case 90: @@ -15328,7 +15321,8 @@ static bool ts_lex(TSLexer *lexer, TSStateId state) { if (lookahead == '\t' || lookahead == ' ') ADVANCE(15); if (lookahead != 0 && - lookahead != '\n') ADVANCE(86); + lookahead != '\n' && + lookahead != '\r') ADVANCE(86); END_STATE(); case 91: ACCEPT_TOKEN(aux_sym_text_token4); @@ -15336,16 +15330,19 @@ static bool ts_lex(TSLexer *lexer, TSStateId state) { if (lookahead == '\t' || lookahead == ' ') ADVANCE(26); if (lookahead != 0 && - lookahead != '\n') ADVANCE(87); + lookahead != '\n' && + lookahead != '\r') ADVANCE(87); END_STATE(); case 92: ACCEPT_TOKEN(aux_sym_text_token5); - if (lookahead == '\r') ADVANCE(84); if (lookahead == '"') ADVANCE(88); if (lookahead == '\'') ADVANCE(90); if (lookahead == '[') ADVANCE(91); if (lookahead == '{') ADVANCE(93); + if (lookahead == 11 || + lookahead == '\f') ADVANCE(84); if (lookahead == '\t' || + lookahead == '\r' || lookahead == ' ') ADVANCE(92); if (lookahead != 0 && lookahead != '\n') ADVANCE(89); @@ -15356,6 +15353,7 @@ static bool ts_lex(TSLexer *lexer, TSStateId state) { if (lookahead != 0 && lookahead != '\t' && lookahead != '\n' && + lookahead != '\r' && lookahead != ' ') ADVANCE(89); END_STATE(); case 94: @@ -15417,7 +15415,7 @@ static bool ts_lex(TSLexer *lexer, TSStateId state) { ACCEPT_TOKEN(anon_sym_RPAREN); END_STATE(); case 110: - ACCEPT_TOKEN(anon_sym_); + ACCEPT_TOKEN(anon_sym_SPACE); if (lookahead == ' ') ADVANCE(110); END_STATE(); case 111: @@ -15794,7 +15792,7 @@ static bool ts_lex(TSLexer *lexer, TSStateId state) { case 181: ACCEPT_TOKEN(aux_sym_interpreted_string_literal_token1); if (lookahead == '\t' || - lookahead == '\r' || + (11 <= lookahead && lookahead <= '\r') || lookahead == ' ') ADVANCE(181); if (lookahead != 0 && lookahead != '\n' && @@ -16326,7 +16324,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(41), 1, sym_comment, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(201), 1, sym_variable, STATE(260), 1, @@ -16389,7 +16387,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(43), 1, anon_sym_end, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(201), 1, sym_variable, STATE(260), 1, @@ -16450,7 +16448,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(47), 1, anon_sym_end, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(201), 1, sym_variable, STATE(260), 1, @@ -16511,7 +16509,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(51), 1, anon_sym_end, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(201), 1, sym_variable, STATE(260), 1, @@ -16572,7 +16570,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(55), 1, anon_sym_end, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(201), 1, sym_variable, STATE(260), 1, @@ -16633,7 +16631,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(59), 1, anon_sym_end, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(201), 1, sym_variable, STATE(260), 1, @@ -16694,7 +16692,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(63), 1, anon_sym_end, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(201), 1, sym_variable, STATE(260), 1, @@ -16755,7 +16753,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(67), 1, anon_sym_end, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(201), 1, sym_variable, STATE(260), 1, @@ -16816,7 +16814,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(71), 1, anon_sym_end, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(201), 1, sym_variable, STATE(260), 1, @@ -16877,7 +16875,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(75), 1, anon_sym_end, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(201), 1, sym_variable, STATE(260), 1, @@ -16938,7 +16936,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(79), 1, anon_sym_end, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(201), 1, sym_variable, STATE(260), 1, @@ -16999,7 +16997,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(83), 1, anon_sym_end, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(201), 1, sym_variable, STATE(260), 1, @@ -17060,7 +17058,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(87), 1, anon_sym_end, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(201), 1, sym_variable, STATE(260), 1, @@ -17121,7 +17119,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(91), 1, anon_sym_end, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(201), 1, sym_variable, STATE(260), 1, @@ -17180,7 +17178,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(93), 1, anon_sym_end, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(201), 1, sym_variable, STATE(260), 1, @@ -17239,7 +17237,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(95), 1, anon_sym_end, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(201), 1, sym_variable, STATE(260), 1, @@ -17298,7 +17296,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(97), 1, anon_sym_end, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(201), 1, sym_variable, STATE(260), 1, @@ -17357,7 +17355,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(99), 1, anon_sym_end, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(201), 1, sym_variable, STATE(260), 1, @@ -17416,7 +17414,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(101), 1, anon_sym_end, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(201), 1, sym_variable, STATE(260), 1, @@ -17475,7 +17473,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(103), 1, anon_sym_end, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(201), 1, sym_variable, STATE(260), 1, @@ -17534,7 +17532,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(105), 1, anon_sym_end, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(201), 1, sym_variable, STATE(260), 1, @@ -17593,7 +17591,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(107), 1, anon_sym_end, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(201), 1, sym_variable, STATE(260), 1, @@ -17652,7 +17650,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(109), 1, anon_sym_end, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(201), 1, sym_variable, STATE(260), 1, @@ -17711,7 +17709,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(111), 1, anon_sym_end, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(201), 1, sym_variable, STATE(260), 1, @@ -17770,7 +17768,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(113), 1, anon_sym_end, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(201), 1, sym_variable, STATE(260), 1, @@ -17829,7 +17827,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(115), 1, anon_sym_end, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(201), 1, sym_variable, STATE(260), 1, @@ -17888,7 +17886,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(117), 1, anon_sym_end, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(201), 1, sym_variable, STATE(260), 1, @@ -17947,7 +17945,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(119), 1, anon_sym_end, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(201), 1, sym_variable, STATE(260), 1, @@ -18006,7 +18004,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(121), 1, anon_sym_end, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(201), 1, sym_variable, STATE(260), 1, @@ -18065,7 +18063,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(123), 1, anon_sym_end, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(201), 1, sym_variable, STATE(260), 1, @@ -18124,7 +18122,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(125), 1, anon_sym_end, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(201), 1, sym_variable, STATE(260), 1, @@ -18183,7 +18181,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(127), 1, anon_sym_end, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(201), 1, sym_variable, STATE(260), 1, @@ -18242,7 +18240,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(129), 1, anon_sym_end, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(201), 1, sym_variable, STATE(260), 1, @@ -18301,7 +18299,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(131), 1, anon_sym_end, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(201), 1, sym_variable, STATE(260), 1, @@ -18360,7 +18358,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(133), 1, anon_sym_end, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(201), 1, sym_variable, STATE(260), 1, @@ -18419,7 +18417,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(135), 1, anon_sym_end, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(201), 1, sym_variable, STATE(260), 1, @@ -18478,7 +18476,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(137), 1, anon_sym_end, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(201), 1, sym_variable, STATE(260), 1, @@ -18537,7 +18535,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(139), 1, anon_sym_end, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(201), 1, sym_variable, STATE(260), 1, @@ -18596,7 +18594,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(141), 1, anon_sym_end, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(201), 1, sym_variable, STATE(260), 1, @@ -18655,7 +18653,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(143), 1, anon_sym_end, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(201), 1, sym_variable, STATE(260), 1, @@ -18714,7 +18712,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(145), 1, anon_sym_end, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(201), 1, sym_variable, STATE(260), 1, @@ -18773,7 +18771,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(147), 1, anon_sym_end, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(201), 1, sym_variable, STATE(260), 1, @@ -18832,7 +18830,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(149), 1, anon_sym_end, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(201), 1, sym_variable, STATE(260), 1, @@ -18891,7 +18889,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(151), 1, anon_sym_end, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(201), 1, sym_variable, STATE(260), 1, @@ -18950,7 +18948,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(153), 1, anon_sym_end, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(201), 1, sym_variable, STATE(260), 1, @@ -19009,7 +19007,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(155), 1, anon_sym_end, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(201), 1, sym_variable, STATE(260), 1, @@ -19068,7 +19066,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(157), 1, anon_sym_end, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(201), 1, sym_variable, STATE(260), 1, @@ -19127,7 +19125,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(159), 1, anon_sym_end, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(201), 1, sym_variable, STATE(260), 1, @@ -19186,7 +19184,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(161), 1, anon_sym_end, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(201), 1, sym_variable, STATE(260), 1, @@ -19245,7 +19243,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(163), 1, anon_sym_end, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(201), 1, sym_variable, STATE(260), 1, @@ -19302,7 +19300,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(41), 1, sym_comment, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(201), 1, sym_variable, STATE(260), 1, @@ -19337,7 +19335,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(167), 1, anon_sym_LPAREN, ACTIONS(169), 1, - anon_sym_, + anon_sym_SPACE, ACTIONS(171), 1, anon_sym_DOT, ACTIONS(173), 1, @@ -19349,7 +19347,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(181), 1, anon_sym_DQUOTE, STATE(56), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(178), 1, sym_variable, STATE(243), 1, @@ -19412,7 +19410,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(199), 1, sym_comment, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(201), 1, sym_variable, STATE(260), 1, @@ -19455,9 +19453,9 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(181), 1, anon_sym_DQUOTE, ACTIONS(203), 1, - anon_sym_, + anon_sym_SPACE, STATE(56), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(178), 1, sym_variable, STATE(243), 1, @@ -19498,7 +19496,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(167), 1, anon_sym_LPAREN, ACTIONS(169), 1, - anon_sym_, + anon_sym_SPACE, ACTIONS(173), 1, anon_sym_DOT2, ACTIONS(175), 1, @@ -19508,7 +19506,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(181), 1, anon_sym_DQUOTE, STATE(56), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(178), 1, sym_variable, STATE(243), 1, @@ -19559,7 +19557,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(215), 1, anon_sym_DQUOTE, STATE(56), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(178), 1, sym_variable, STATE(243), 1, @@ -19609,7 +19607,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(215), 1, anon_sym_DQUOTE, STATE(56), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(178), 1, sym_variable, STATE(243), 1, @@ -19659,9 +19657,9 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(181), 1, anon_sym_DQUOTE, ACTIONS(219), 1, - anon_sym_, + anon_sym_SPACE, STATE(56), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(178), 1, sym_variable, STATE(243), 1, @@ -19708,9 +19706,9 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(181), 1, anon_sym_DQUOTE, ACTIONS(225), 1, - anon_sym_, + anon_sym_SPACE, STATE(56), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(178), 1, sym_variable, STATE(243), 1, @@ -19757,7 +19755,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(215), 1, anon_sym_DQUOTE, STATE(56), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(178), 1, sym_variable, STATE(243), 1, @@ -19807,7 +19805,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(215), 1, anon_sym_DQUOTE, STATE(56), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(178), 1, sym_variable, STATE(243), 1, @@ -19855,7 +19853,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(215), 1, anon_sym_DQUOTE, STATE(56), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(178), 1, sym_variable, STATE(243), 1, @@ -19903,7 +19901,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(39), 1, anon_sym_DQUOTE, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(111), 1, sym__right_delimiter, STATE(201), 1, @@ -19951,7 +19949,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(39), 1, anon_sym_DQUOTE, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(173), 1, sym__right_delimiter, STATE(201), 1, @@ -19999,7 +19997,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(39), 1, anon_sym_DQUOTE, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(113), 1, sym__right_delimiter, STATE(201), 1, @@ -20047,7 +20045,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(39), 1, anon_sym_DQUOTE, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(201), 1, sym_variable, STATE(226), 1, @@ -20095,7 +20093,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(39), 1, anon_sym_DQUOTE, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(202), 1, sym_variable, STATE(260), 1, @@ -20140,7 +20138,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(39), 1, anon_sym_DQUOTE, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(202), 1, sym_variable, STATE(260), 1, @@ -20185,7 +20183,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(215), 1, anon_sym_DQUOTE, STATE(56), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(178), 1, sym_variable, STATE(243), 1, @@ -20228,7 +20226,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(39), 1, anon_sym_DQUOTE, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(201), 1, sym_variable, STATE(260), 1, @@ -20271,7 +20269,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(215), 1, anon_sym_DQUOTE, STATE(56), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(178), 1, sym_variable, STATE(243), 1, @@ -20314,7 +20312,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(215), 1, anon_sym_DQUOTE, STATE(56), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(178), 1, sym_variable, STATE(243), 1, @@ -20357,7 +20355,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(39), 1, anon_sym_DQUOTE, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(201), 1, sym_variable, STATE(260), 1, @@ -20400,7 +20398,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(215), 1, anon_sym_DQUOTE, STATE(56), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(178), 1, sym_variable, STATE(243), 1, @@ -20443,7 +20441,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(39), 1, anon_sym_DQUOTE, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(201), 1, sym_variable, STATE(260), 1, @@ -20486,7 +20484,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(39), 1, anon_sym_DQUOTE, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(201), 1, sym_variable, STATE(260), 1, @@ -20529,7 +20527,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(39), 1, anon_sym_DQUOTE, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(201), 1, sym_variable, STATE(260), 1, @@ -20572,7 +20570,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(39), 1, anon_sym_DQUOTE, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(201), 1, sym_variable, STATE(260), 1, @@ -20615,7 +20613,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(39), 1, anon_sym_DQUOTE, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(201), 1, sym_variable, STATE(260), 1, @@ -20658,7 +20656,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(39), 1, anon_sym_DQUOTE, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(201), 1, sym_variable, STATE(260), 1, @@ -20701,7 +20699,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(39), 1, anon_sym_DQUOTE, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(201), 1, sym_variable, STATE(260), 1, @@ -20744,7 +20742,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(39), 1, anon_sym_DQUOTE, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(201), 1, sym_variable, STATE(260), 1, @@ -20787,7 +20785,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(39), 1, anon_sym_DQUOTE, STATE(58), 1, - sym_unfished_selector_expression, + sym_unfinished_selector_expression, STATE(201), 1, sym_variable, STATE(260), 1, @@ -22331,7 +22329,7 @@ static const uint16_t ts_small_parse_table[] = { aux_sym_template_repeat1, [7743] = 2, ACTIONS(449), 1, - anon_sym_, + anon_sym_SPACE, ACTIONS(447), 18, anon_sym_PIPE, anon_sym_LPAREN, @@ -22353,7 +22351,7 @@ static const uint16_t ts_small_parse_table[] = { anon_sym_DASH_RBRACE_RBRACE, [7767] = 4, ACTIONS(453), 1, - anon_sym_, + anon_sym_SPACE, ACTIONS(455), 1, sym_identifier, STATE(144), 1, @@ -22377,7 +22375,7 @@ static const uint16_t ts_small_parse_table[] = { anon_sym_DASH_RBRACE_RBRACE, [7795] = 2, ACTIONS(459), 1, - anon_sym_, + anon_sym_SPACE, ACTIONS(457), 18, anon_sym_PIPE, anon_sym_LPAREN, @@ -22399,7 +22397,7 @@ static const uint16_t ts_small_parse_table[] = { anon_sym_DASH_RBRACE_RBRACE, [7819] = 2, ACTIONS(463), 1, - anon_sym_, + anon_sym_SPACE, ACTIONS(461), 18, anon_sym_PIPE, anon_sym_LPAREN, @@ -22561,7 +22559,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(481), 1, sym_identifier, ACTIONS(475), 2, - anon_sym_, + anon_sym_SPACE, anon_sym_DOT, ACTIONS(479), 6, anon_sym_COLON_EQ, @@ -22813,7 +22811,7 @@ static const uint16_t ts_small_parse_table[] = { anon_sym_LBRACE_LBRACE_DASH, [8297] = 5, ACTIONS(169), 1, - anon_sym_, + anon_sym_SPACE, ACTIONS(569), 1, anon_sym_COLON_EQ, ACTIONS(571), 1, @@ -22871,7 +22869,7 @@ static const uint16_t ts_small_parse_table[] = { anon_sym_LBRACE_LBRACE_DASH, [8368] = 2, ACTIONS(503), 2, - anon_sym_, + anon_sym_SPACE, anon_sym_DOT, ACTIONS(591), 6, anon_sym_COLON_EQ, @@ -23452,7 +23450,7 @@ static const uint16_t ts_small_parse_table[] = { anon_sym_LBRACE_LBRACE_DASH, [9052] = 3, ACTIONS(661), 1, - anon_sym_, + anon_sym_SPACE, STATE(246), 1, aux_sym_argument_list_repeat1, ACTIONS(217), 4, @@ -23462,7 +23460,7 @@ static const uint16_t ts_small_parse_table[] = { anon_sym_DASH_RBRACE_RBRACE, [9065] = 2, ACTIONS(665), 2, - anon_sym_, + anon_sym_SPACE, anon_sym_DOT, ACTIONS(663), 4, anon_sym_PIPE, @@ -23473,7 +23471,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(573), 1, anon_sym_DOT, ACTIONS(669), 1, - anon_sym_, + anon_sym_SPACE, ACTIONS(667), 4, anon_sym_PIPE, anon_sym_RPAREN, @@ -23481,7 +23479,7 @@ static const uint16_t ts_small_parse_table[] = { anon_sym_DASH_RBRACE_RBRACE, [9089] = 3, ACTIONS(673), 1, - anon_sym_, + anon_sym_SPACE, ACTIONS(675), 1, sym_identifier, ACTIONS(671), 4, @@ -23493,7 +23491,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(677), 1, anon_sym_PIPE, ACTIONS(681), 1, - anon_sym_, + anon_sym_SPACE, STATE(241), 1, aux_sym_argument_list_repeat1, ACTIONS(679), 3, @@ -23502,7 +23500,7 @@ static const uint16_t ts_small_parse_table[] = { anon_sym_DASH_RBRACE_RBRACE, [9117] = 3, ACTIONS(685), 1, - anon_sym_, + anon_sym_SPACE, STATE(246), 1, aux_sym_argument_list_repeat1, ACTIONS(683), 4, @@ -23512,7 +23510,7 @@ static const uint16_t ts_small_parse_table[] = { anon_sym_DASH_RBRACE_RBRACE, [9130] = 3, ACTIONS(688), 1, - anon_sym_, + anon_sym_SPACE, STATE(246), 1, aux_sym_argument_list_repeat1, ACTIONS(217), 4, @@ -23524,7 +23522,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(677), 1, anon_sym_PIPE, ACTIONS(690), 1, - anon_sym_, + anon_sym_SPACE, STATE(247), 1, aux_sym_argument_list_repeat1, ACTIONS(679), 3, @@ -23535,7 +23533,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(677), 1, anon_sym_PIPE, ACTIONS(694), 1, - anon_sym_, + anon_sym_SPACE, ACTIONS(692), 3, anon_sym_RPAREN, anon_sym_RBRACE_RBRACE, @@ -23544,7 +23542,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(677), 1, anon_sym_PIPE, ACTIONS(698), 1, - anon_sym_, + anon_sym_SPACE, ACTIONS(696), 3, anon_sym_RPAREN, anon_sym_RBRACE_RBRACE, @@ -23559,7 +23557,7 @@ static const uint16_t ts_small_parse_table[] = { anon_sym_DASH_RBRACE_RBRACE, [9192] = 2, ACTIONS(704), 1, - anon_sym_, + anon_sym_SPACE, ACTIONS(702), 4, anon_sym_PIPE, anon_sym_RPAREN, @@ -23567,7 +23565,7 @@ static const uint16_t ts_small_parse_table[] = { anon_sym_DASH_RBRACE_RBRACE, [9202] = 2, ACTIONS(471), 1, - anon_sym_, + anon_sym_SPACE, ACTIONS(473), 4, anon_sym_PIPE, anon_sym_RPAREN, @@ -23575,7 +23573,7 @@ static const uint16_t ts_small_parse_table[] = { anon_sym_DASH_RBRACE_RBRACE, [9212] = 2, ACTIONS(708), 1, - anon_sym_, + anon_sym_SPACE, ACTIONS(706), 4, anon_sym_PIPE, anon_sym_RPAREN, @@ -23583,7 +23581,7 @@ static const uint16_t ts_small_parse_table[] = { anon_sym_DASH_RBRACE_RBRACE, [9222] = 2, ACTIONS(467), 1, - anon_sym_, + anon_sym_SPACE, ACTIONS(469), 4, anon_sym_PIPE, anon_sym_RPAREN, @@ -23591,7 +23589,7 @@ static const uint16_t ts_small_parse_table[] = { anon_sym_DASH_RBRACE_RBRACE, [9232] = 2, ACTIONS(712), 1, - anon_sym_, + anon_sym_SPACE, ACTIONS(710), 4, anon_sym_PIPE, anon_sym_RPAREN, @@ -23612,7 +23610,7 @@ static const uint16_t ts_small_parse_table[] = { ACTIONS(677), 1, anon_sym_PIPE, ACTIONS(720), 1, - anon_sym_, + anon_sym_SPACE, ACTIONS(683), 3, anon_sym_RPAREN, anon_sym_RBRACE_RBRACE, @@ -25002,8 +25000,8 @@ static const TSParseActionEntry ts_parse_actions[] = { [444] = {.entry = {.count = 2, .reusable = false}}, REDUCE(sym__else_if_clause, 4, .dynamic_precedence = 1, .production_id = 11), SHIFT(52), [447] = {.entry = {.count = 1, .reusable = false}}, REDUCE(sym_selector_expression, 3, .production_id = 8), [449] = {.entry = {.count = 1, .reusable = true}}, REDUCE(sym_selector_expression, 3, .production_id = 8), - [451] = {.entry = {.count = 1, .reusable = false}}, REDUCE(sym_unfished_selector_expression, 2, .production_id = 4), - [453] = {.entry = {.count = 1, .reusable = true}}, REDUCE(sym_unfished_selector_expression, 2, .production_id = 4), + [451] = {.entry = {.count = 1, .reusable = false}}, REDUCE(sym_unfinished_selector_expression, 2, .production_id = 4), + [453] = {.entry = {.count = 1, .reusable = true}}, REDUCE(sym_unfinished_selector_expression, 2, .production_id = 4), [455] = {.entry = {.count = 1, .reusable = false}}, SHIFT(147), [457] = {.entry = {.count = 1, .reusable = false}}, REDUCE(sym_field, 2, .production_id = 2), [459] = {.entry = {.count = 1, .reusable = true}}, REDUCE(sym_field, 2, .production_id = 2), @@ -25252,11 +25250,15 @@ static const TSParseActionEntry ts_parse_actions[] = { #ifdef __cplusplus extern "C" { #endif -#ifdef _WIN32 -#define extern __declspec(dllexport) +#ifdef TREE_SITTER_HIDE_SYMBOLS +#define TS_PUBLIC +#elif defined(_WIN32) +#define TS_PUBLIC __declspec(dllexport) +#else +#define TS_PUBLIC __attribute__((visibility("default"))) #endif -extern const TSLanguage *tree_sitter_gotmpl(void) { +TS_PUBLIC const TSLanguage *tree_sitter_gotmpl() { static const TSLanguage language = { .version = LANGUAGE_VERSION, .symbol_count = SYMBOL_COUNT, diff --git a/internal/util/values.go b/internal/util/values.go index 3171f741..ac4e28bd 100644 --- a/internal/util/values.go +++ b/internal/util/values.go @@ -31,7 +31,6 @@ func GetValueCompletion(values chartutil.Values, splittedVar []string) []lsp.Com ) if len(splittedVar) > 0 { - localValues, err = values.Table(tableName) if err != nil { if len(splittedVar) > 1 { @@ -47,17 +46,16 @@ func GetValueCompletion(values chartutil.Values, splittedVar []string) []lsp.Com } else { values = localValues } - } for variable, value := range values { - items = setItem(items, value, variable) + items = append(items, builCompletionItem(value, variable)) } return items } -func setItem(items []lsp.CompletionItem, value interface{}, variable string) []lsp.CompletionItem { +func builCompletionItem(value interface{}, variable string) lsp.CompletionItem { var ( itemKind = lsp.CompletionItemKindVariable valueOf = reflect.ValueOf(value) @@ -80,13 +78,13 @@ func setItem(items []lsp.CompletionItem, value interface{}, variable string) []l itemKind = lsp.CompletionItemKindField } - return append(items, lsp.CompletionItem{ + return lsp.CompletionItem{ Label: variable, InsertText: variable, Documentation: documentation, Detail: valueOf.Kind().String(), Kind: itemKind, - }) + } } func FormatToYAML(field reflect.Value, fieldName string) string { diff --git a/internal/util/yaml_path.go b/internal/util/yaml_path.go deleted file mode 100644 index d07c4e84..00000000 --- a/internal/util/yaml_path.go +++ /dev/null @@ -1,59 +0,0 @@ -package util - -import ( - "fmt" - "strings" -) - -type YamlPath struct { - TableNames []string -} - -func NewYamlPath(yamlPathString string) (YamlPath, error) { - var ( - splitted = strings.Split(yamlPathString, ".") - variableSplitted = []string{} - ) - - // filter out empty strings, that were added by the split - for _, s := range splitted { - if s != "" { - variableSplitted = append(variableSplitted, s) - } - } - if len(variableSplitted) == 0 { - return YamlPath{}, fmt.Errorf("Could not parse yaml path: %s", yamlPathString) - } - // $ always points to the root context so we can safely remove it - // as long the LSP does not know about ranges - if variableSplitted[0] == "$" && len(variableSplitted) > 1 { - variableSplitted = variableSplitted[1:] - } - - return YamlPath{ - TableNames: variableSplitted, - }, nil -} - -func (path YamlPath) GetTail() []string { - return path.TableNames[1:] -} - -func (path YamlPath) IsValuesPath() bool { - return path.TableNames[0] == "Values" -} - -func (path YamlPath) IsChartPath() bool { - return path.TableNames[0] == "Chart" -} - -func (path YamlPath) IsReleasePath() bool { - return path.TableNames[0] == "Release" -} - -func (path YamlPath) IsFilesPath() bool { - return path.TableNames[0] == "Files" -} -func (path YamlPath) IsCapabilitiesPath() bool { - return path.TableNames[0] == "Capabilities" -} diff --git a/testdata/example/templates/completion-test.yaml b/testdata/example/templates/completion-test.yaml index cea82b73..0944f3dd 100644 --- a/testdata/example/templates/completion-test.yaml +++ b/testdata/example/templates/completion-test.yaml @@ -6,7 +6,7 @@ {{ .Chart.N }} {{ . }} -{{ toYaml .Release. }} -{{ toYaml (.Release. ) }} -{{ .Release. }} +{{ if (and .Values. ) }} +{{ end }} +{{ if }}