diff --git a/internal/adapter/yamlls/completion.go b/internal/adapter/yamlls/completion.go index b3459259..bb173913 100644 --- a/internal/adapter/yamlls/completion.go +++ b/internal/adapter/yamlls/completion.go @@ -6,7 +6,7 @@ import ( lsp "go.lsp.dev/protocol" ) -func (yamllsConnector Connector) CallCompletion(ctx context.Context, params *lsp.CompletionParams) (*lsp.CompletionList, error) { +func (yamllsConnector *Connector) CallCompletion(ctx context.Context, params *lsp.CompletionParams) (*lsp.CompletionList, error) { if yamllsConnector.server == nil { return &lsp.CompletionList{}, nil } 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/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..76875a34 100644 --- a/internal/handler/completion.go +++ b/internal/handler/completion.go @@ -2,48 +2,25 @@ 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" 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, params.TextDocumentPositionParams), } for _, usecase := range usecases { @@ -52,17 +29,6 @@ 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{} for _, v := range helmdocs.BuiltInObjects { items = append(items, lsp.CompletionItem{ @@ -74,57 +40,3 @@ func (h *langHandler) Completion(ctx context.Context, params *lsp.CompletionPara } 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, - } -} diff --git a/internal/handler/completion_main_test.go b/internal/handler/completion_main_test.go index 14c02320..f40d6f7c 100644 --- a/internal/handler/completion_main_test.go +++ b/internal/handler/completion_main_test.go @@ -23,6 +23,19 @@ func TestCompletionMain(t *testing.T) { notExpectedInsertTexts []string expectedError error }{ + { + 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{ @@ -99,19 +112,6 @@ 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{ 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..c3a88536 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,30 @@ 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 ( + parentNodeType string + nodeType = node.Type() + parentNode = node.Parent() + ) + + 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/references.go b/internal/handler/references.go index d7be4e9d..bc3978ec 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) + genericDocumentUseCase, err := h.NewGenericDocumentUseCase(params.TextDocumentPositionParams, lsplocal.NodeAtPosition) if err != nil { return nil, err } diff --git a/internal/language_features/function_call.go b/internal/language_features/function_call.go index a47cf650..06e21a47 100644 --- a/internal/language_features/function_call.go +++ b/internal/language_features/function_call.go @@ -32,5 +32,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..cc88acc4 100644 --- a/internal/language_features/generic_document_usecase.go +++ b/internal/language_features/generic_document_usecase.go @@ -21,6 +21,7 @@ func (u *GenericDocumentUseCase) NodeContent() string { return u.Node.Content([]byte(u.Document.Content)) } +// Allows for using a custom node selection func (u GenericDocumentUseCase) WithNode(node *sitter.Node) *GenericDocumentUseCase { u.Node = node u.NodeType = node.Type() diff --git a/internal/language_features/includes.go b/internal/language_features/includes.go index 84b0fbd9..5a643908 100644 --- a/internal/language_features/includes.go +++ b/internal/language_features/includes.go @@ -4,6 +4,7 @@ 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" ) @@ -90,14 +91,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, }) diff --git a/internal/language_features/template_context.go b/internal/language_features/template_context.go index 0333bc98..600cee25 100644 --- a/internal/language_features/template_context.go +++ b/internal/language_features/template_context.go @@ -9,6 +9,7 @@ import ( 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/tree-sitter/gotemplate" "github.com/mrjosh/helm-ls/internal/util" "github.com/mrjosh/helm-ls/pkg/chart" @@ -103,13 +104,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}) } } } diff --git a/internal/language_features/template_context_completion.go b/internal/language_features/template_context_completion.go index 6a228938..d37ba686 100644 --- a/internal/language_features/template_context_completion.go +++ b/internal/language_features/template_context_completion.go @@ -15,17 +15,15 @@ func (f *TemplateContextFeature) Completion() (result *lsp.CompletionList, err e } if len(templateContext) == 0 { - result := helmdocs.BuiltInObjects - return protocol.NewCompletionResults(result).ToLSP(), nil + return protocol.CompletionResults{}.WithDocs(helmdocs.BuiltInObjects, lsp.CompletionItemKindConstant).ToList(), nil } if len(templateContext) == 1 { result, ok := helmdocs.BuiltInOjectVals[templateContext[0]] if !ok { - result := helmdocs.BuiltInObjects - return protocol.NewCompletionResults(result).ToLSP(), nil + return protocol.CompletionResults{}.WithDocs(helmdocs.BuiltInObjects, lsp.CompletionItemKindConstant).ToList(), nil } - return protocol.NewCompletionResults(result).ToLSP(), nil + return protocol.CompletionResults{}.WithDocs(result, lsp.CompletionItemKindValue).ToList(), nil } switch templateContext[0] { @@ -35,10 +33,9 @@ func (f *TemplateContextFeature) Completion() (result *lsp.CompletionList, err e // 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.CompletionResults{}.WithDocs(helmdocs.BuiltInObjects, lsp.CompletionItemKindConstant).ToList(), nil } - return protocol.NewCompletionResults(result).ToLSP(), nil + return protocol.CompletionResults{}.WithDocs(result, lsp.CompletionItemKindValue).ToList(), nil } diff --git a/internal/language_features/text.go b/internal/language_features/text.go new file mode 100644 index 00000000..ded87018 --- /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/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 98% rename from internal/util/lsp.go rename to internal/protocol/hover.go index c77636fa..138c7023 100644 --- a/internal/util/lsp.go +++ b/internal/protocol/hover.go @@ -1,4 +1,4 @@ -package util +package protocol import ( "fmt"