From d8c6e889ea02269eb138465bc5808ea840b80850 Mon Sep 17 00:00:00 2001 From: qvalentin Date: Thu, 5 Sep 2024 18:39:47 +0200 Subject: [PATCH 01/16] feat: refactor document --- internal/adapter/yamlls/diagnostics.go | 4 +- internal/adapter/yamlls/document_sync.go | 12 ++-- internal/helm_lint/lint.go | 2 +- internal/helm_lint/lint_test.go | 11 ++- .../generic_document_usecase.go | 2 +- internal/lsp/ast.go | 6 +- internal/lsp/ast_diagnostics_test.go | 2 +- internal/lsp/ast_test.go | 2 +- internal/lsp/document.go | 65 ++---------------- internal/lsp/document_store.go | 46 +++++++------ .../lsp/symbol_table_template_context_test.go | 2 +- ...l_table_template_context_variables_test.go | 2 +- internal/lsp/symbol_table_test.go | 10 +-- internal/lsp/symbol_table_variables_test.go | 2 +- internal/lsp/template_document.go | 68 +++++++++++++++++++ internal/lsp/variables_visitor_test.go | 4 +- internal/lsp/yaml_ast.go | 2 +- internal/lsp/yaml_ast_test.go | 6 +- 18 files changed, 138 insertions(+), 110 deletions(-) create mode 100644 internal/lsp/template_document.go diff --git a/internal/adapter/yamlls/diagnostics.go b/internal/adapter/yamlls/diagnostics.go index 7a600a44..ebc6306d 100644 --- a/internal/adapter/yamlls/diagnostics.go +++ b/internal/adapter/yamlls/diagnostics.go @@ -32,7 +32,7 @@ func (c Connector) PublishDiagnostics(ctx context.Context, params *protocol.Publ return nil } -func filterDiagnostics(diagnostics []lsp.Diagnostic, ast *sitter.Tree, content string) (filtered []lsp.Diagnostic) { +func filterDiagnostics(diagnostics []lsp.Diagnostic, ast *sitter.Tree, content []byte) (filtered []lsp.Diagnostic) { filtered = []lsp.Diagnostic{} for _, diagnostic := range diagnostics { @@ -41,7 +41,7 @@ func filterDiagnostics(diagnostics []lsp.Diagnostic, ast *sitter.Tree, content s if node.Type() == "text" && childNode.Type() == "text" { logger.Debug("Diagnostic", diagnostic) - logger.Debug("Node", node.Content([]byte(content))) + logger.Debug("Node", node.Content(content)) if diagnisticIsRelevant(diagnostic, childNode) { diagnostic.Message = "Yamlls: " + diagnostic.Message diff --git a/internal/adapter/yamlls/document_sync.go b/internal/adapter/yamlls/document_sync.go index 45b0e6cc..f18ccb7f 100644 --- a/internal/adapter/yamlls/document_sync.go +++ b/internal/adapter/yamlls/document_sync.go @@ -9,7 +9,7 @@ import ( lsp "go.lsp.dev/protocol" ) -func (yamllsConnector Connector) InitiallySyncOpenDocuments(docs []*lsplocal.Document) { +func (yamllsConnector Connector) InitiallySyncOpenDocuments(docs []*lsplocal.TemplateDocument) { if yamllsConnector.server == nil { return } @@ -27,7 +27,7 @@ func (yamllsConnector Connector) InitiallySyncOpenDocuments(docs []*lsplocal.Doc yamllsConnector.DocumentDidOpen(doc.Ast, lsp.DidOpenTextDocumentParams{ TextDocument: lsp.TextDocumentItem{ URI: doc.URI, - Text: doc.Content, + Text: string(doc.Content), }, }) } @@ -39,7 +39,7 @@ func (yamllsConnector Connector) DocumentDidOpen(ast *sitter.Tree, params lsp.Di if !yamllsConnector.shouldRun(params.TextDocument.URI) { return } - params.TextDocument.Text = lsplocal.TrimTemplate(ast, params.TextDocument.Text) + params.TextDocument.Text = lsplocal.TrimTemplate(ast, []byte(params.TextDocument.Text)) err := yamllsConnector.server.DidOpen(context.Background(), ¶ms) if err != nil { @@ -47,7 +47,7 @@ func (yamllsConnector Connector) DocumentDidOpen(ast *sitter.Tree, params lsp.Di } } -func (yamllsConnector Connector) DocumentDidSave(doc *lsplocal.Document, params lsp.DidSaveTextDocumentParams) { +func (yamllsConnector Connector) DocumentDidSave(doc *lsplocal.TemplateDocument, params lsp.DidSaveTextDocumentParams) { if !yamllsConnector.shouldRun(doc.URI) { return } @@ -66,7 +66,7 @@ func (yamllsConnector Connector) DocumentDidSave(doc *lsplocal.Document, params }) } -func (yamllsConnector Connector) DocumentDidChange(doc *lsplocal.Document, params lsp.DidChangeTextDocumentParams) { +func (yamllsConnector Connector) DocumentDidChange(doc *lsplocal.TemplateDocument, params lsp.DidChangeTextDocumentParams) { if !yamllsConnector.shouldRun(doc.URI) { return } @@ -95,7 +95,7 @@ func (yamllsConnector Connector) DocumentDidChange(doc *lsplocal.Document, param } } -func (yamllsConnector Connector) DocumentDidChangeFullSync(doc *lsplocal.Document, params lsp.DidChangeTextDocumentParams) { +func (yamllsConnector Connector) DocumentDidChangeFullSync(doc *lsplocal.TemplateDocument, params lsp.DidChangeTextDocumentParams) { if !yamllsConnector.shouldRun(doc.URI) { return } diff --git a/internal/helm_lint/lint.go b/internal/helm_lint/lint.go index 8672a1b0..50a4c47d 100644 --- a/internal/helm_lint/lint.go +++ b/internal/helm_lint/lint.go @@ -19,7 +19,7 @@ import ( var logger = log.GetLogger() -func GetDiagnosticsNotifications(chart *charts.Chart, doc *lsplocal.Document) []lsp.PublishDiagnosticsParams { +func GetDiagnosticsNotifications(chart *charts.Chart, doc *lsplocal.TemplateDocument) []lsp.PublishDiagnosticsParams { vals := chart.ValuesFiles.MainValuesFile.Values if chart.ValuesFiles.OverlayValuesFile != nil { vals = chartutil.CoalesceTables(chart.ValuesFiles.OverlayValuesFile.Values, chart.ValuesFiles.MainValuesFile.Values) diff --git a/internal/helm_lint/lint_test.go b/internal/helm_lint/lint_test.go index 540ecb95..9cf4fb71 100644 --- a/internal/helm_lint/lint_test.go +++ b/internal/helm_lint/lint_test.go @@ -26,7 +26,11 @@ func TestLintNotifications(t *testing.T) { AdditionalValuesFiles: []*charts.ValuesFile{}, }, } - diagnostics := GetDiagnosticsNotifications(&chart, &lsplocal.Document{URI: uri.File("../../testdata/example/templates/deployment-no-templates.yaml")}) + diagnostics := GetDiagnosticsNotifications(&chart, &lsplocal.TemplateDocument{ + Document: lsplocal.Document{ + URI: uri.File("../../testdata/example/templates/deployment-no-templates.yaml"), + }, + }) assert.NotEmpty(t, diagnostics) assert.Len(t, diagnostics, 3) @@ -51,7 +55,10 @@ func TestLintNotificationsIncludesEmptyDiagnosticsForFixedIssues(t *testing.T) { AdditionalValuesFiles: []*charts.ValuesFile{}, }, } - diagnostics := GetDiagnosticsNotifications(&chart, &lsplocal.Document{URI: uri.File("../../testdata/example/templates/deployment-no-templates.yaml")}) + diagnostics := GetDiagnosticsNotifications(&chart, &lsplocal.TemplateDocument{ + Document: lsplocal.Document{URI: uri.File("../../testdata/example/templates/deployment-no-templates.yaml")}, + }, + ) uris := []string{} for _, notification := range diagnostics { diff --git a/internal/language_features/generic_document_usecase.go b/internal/language_features/generic_document_usecase.go index 23afbbf9..3943cd98 100644 --- a/internal/language_features/generic_document_usecase.go +++ b/internal/language_features/generic_document_usecase.go @@ -7,7 +7,7 @@ import ( ) type GenericDocumentUseCase struct { - Document *lsplocal.Document + Document *lsplocal.TemplateDocument DocumentStore *lsplocal.DocumentStore Chart *charts.Chart Node *sitter.Node diff --git a/internal/lsp/ast.go b/internal/lsp/ast.go index e82b8c81..b32f5122 100644 --- a/internal/lsp/ast.go +++ b/internal/lsp/ast.go @@ -8,10 +8,10 @@ import ( lsp "go.lsp.dev/protocol" ) -func ParseAst(oldTree *sitter.Tree, content string) *sitter.Tree { +func ParseAst(oldTree *sitter.Tree, content []byte) *sitter.Tree { parser := sitter.NewParser() parser.SetLanguage(gotemplate.GetLanguage()) - tree, _ := parser.ParseCtx(context.Background(), oldTree, []byte(content)) + tree, _ := parser.ParseCtx(context.Background(), oldTree, content) return tree } @@ -69,7 +69,7 @@ func isPointLargerOrEq(a sitter.Point, b sitter.Point) bool { return a.Row > b.Row } -func (d *Document) ApplyChangesToAst(newContent string) { +func (d *TemplateDocument) ApplyChangesToAst(newContent []byte) { d.Ast = ParseAst(nil, newContent) } diff --git a/internal/lsp/ast_diagnostics_test.go b/internal/lsp/ast_diagnostics_test.go index c3354598..c9183518 100644 --- a/internal/lsp/ast_diagnostics_test.go +++ b/internal/lsp/ast_diagnostics_test.go @@ -8,7 +8,7 @@ import ( func TestIsInElseBranch(t *testing.T) { template := `{{if pipeline}} t1 {{ else if pipeline }} t2 {{ else if pipeline2 }} t3 {{ else }} t4 {{ end }}` - ast := ParseAst(nil, template) + ast := ParseAst(nil, []byte(template)) // (template [0, 0] - [1, 0] // (if_action [0, 0] - [0, 95] // condition: (function_call [0, 5] - [0, 13] diff --git a/internal/lsp/ast_test.go b/internal/lsp/ast_test.go index de22a9fa..87718612 100644 --- a/internal/lsp/ast_test.go +++ b/internal/lsp/ast_test.go @@ -16,7 +16,7 @@ func TestFindRelevantChildNodeCompletio(t *testing.T) { {{ .Chart.N }} {{ . }} ` - ast := ParseAst(nil, template) + ast := ParseAst(nil, []byte(template)) logger.Println("RootNode:", ast.RootNode().String()) diff --git a/internal/lsp/document.go b/internal/lsp/document.go index cbdbd695..b9e6d7db 100644 --- a/internal/lsp/document.go +++ b/internal/lsp/document.go @@ -3,11 +3,9 @@ package lsp import ( "bytes" "fmt" - "strings" "github.com/mrjosh/helm-ls/internal/log" "github.com/mrjosh/helm-ls/internal/util" - sitter "github.com/smacker/go-tree-sitter" lsp "go.lsp.dev/protocol" ) @@ -15,19 +13,13 @@ var logger = log.GetLogger() // Document represents an opened file. type Document struct { - URI lsp.DocumentURI - Path string - NeedsRefreshDiagnostics bool - Content string - lines []string - Ast *sitter.Tree - DiagnosticsCache DiagnosticsCache - IsOpen bool - SymbolTable *SymbolTable - IsYaml bool + URI lsp.DocumentURI + Path string + Content []byte + lines []string + IsOpen bool } -// ApplyChanges updates the content of the document from LSP textDocument/didChange events. func (d *Document) ApplyChanges(changes []lsp.TextDocumentContentChangeEvent) { defer func() { if r := recover(); r != nil { @@ -35,7 +27,7 @@ func (d *Document) ApplyChanges(changes []lsp.TextDocumentContentChangeEvent) { } }() - content := []byte(d.Content) + content := d.Content for _, change := range changes { start, end := util.PositionToIndex(change.Range.Start, content), util.PositionToIndex(change.Range.End, content) @@ -45,49 +37,6 @@ func (d *Document) ApplyChanges(changes []lsp.TextDocumentContentChangeEvent) { buf.Write(content[end:]) content = buf.Bytes() } - d.Content = string(content) - - d.ApplyChangesToAst(d.Content) - d.SymbolTable = NewSymbolTable(d.Ast, content) - + d.Content = content d.lines = nil } - -// WordAt returns the word found at the given location. -func (d *Document) WordAt(pos lsp.Position) string { - logger.Debug(pos) - - line, ok := d.getLine(int(pos.Line)) - if !ok { - return "" - } - return util.WordAt(line, int(pos.Character)) -} - -// getLine returns the line at the given index. -func (d *Document) getLine(index int) (string, bool) { - lines := d.getLines() - if index < 0 || index > len(lines) { - return "", false - } - return lines[index], true -} - -// getLines returns all the lines in the document. -func (d *Document) getLines() []string { - if d.lines == nil { - // We keep \r on purpose, to avoid messing up position conversions. - d.lines = strings.Split(d.Content, "\n") - } - return d.lines -} - -// GetContent implements PossibleDependencyFile. -func (d *Document) GetContent() []byte { - return []byte(d.Content) -} - -// GetPath implements PossibleDependencyFile. -func (d *Document) GetPath() string { - return d.Path -} diff --git a/internal/lsp/document_store.go b/internal/lsp/document_store.go index b7cb0a41..e7f36af3 100644 --- a/internal/lsp/document_store.go +++ b/internal/lsp/document_store.go @@ -20,28 +20,30 @@ func NewDocumentStore() *DocumentStore { } } -func (s *DocumentStore) GetAllDocs() []*Document { - var docs []*Document +func (s *DocumentStore) GetAllDocs() []*TemplateDocument { + var docs []*TemplateDocument s.documents.Range(func(_, v interface{}) bool { - docs = append(docs, v.(*Document)) + docs = append(docs, v.(*TemplateDocument)) return true }) return docs } -func (s *DocumentStore) DidOpen(params *lsp.DidOpenTextDocumentParams, helmlsConfig util.HelmlsConfiguration) (*Document, error) { +func (s *DocumentStore) DidOpen(params *lsp.DidOpenTextDocumentParams, helmlsConfig util.HelmlsConfiguration) (*TemplateDocument, 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 := ParseAst(nil, []byte(params.TextDocument.Text)) + doc := &TemplateDocument{ + Document: Document{ + URI: uri, + Path: path, + Content: []byte(params.TextDocument.Text), + IsOpen: true, + }, Ast: ast, DiagnosticsCache: NewDiagnosticsCache(helmlsConfig), - IsOpen: true, SymbolTable: NewSymbolTable(ast, []byte(params.TextDocument.Text)), IsYaml: IsYamlDocument(uri, helmlsConfig.YamllsConfiguration), } @@ -50,35 +52,37 @@ func (s *DocumentStore) DidOpen(params *lsp.DidOpenTextDocumentParams, helmlsCon return doc, nil } -func (s *DocumentStore) Store(filename string, content []byte, helmlsConfig util.HelmlsConfiguration) { - _, ok := s.documents.Load(filename) +func (s *DocumentStore) Store(path string, content []byte, helmlsConfig util.HelmlsConfiguration) { + _, ok := s.documents.Load(path) if ok { return } - ast := ParseAst(nil, string(content)) - fileURI := uri.File(filename) + ast := ParseAst(nil, content) + fileURI := uri.File(path) s.documents.Store(fileURI.Filename(), - &Document{ - URI: fileURI, - Path: filename, - Content: string(content), + &TemplateDocument{ + Document: Document{ + URI: fileURI, + Path: path, + Content: content, + IsOpen: false, + }, Ast: ast, DiagnosticsCache: NewDiagnosticsCache(helmlsConfig), - IsOpen: false, SymbolTable: NewSymbolTable(ast, content), IsYaml: IsYamlDocument(fileURI, helmlsConfig.YamllsConfiguration), }, ) } -func (s *DocumentStore) Get(docuri uri.URI) (*Document, bool) { +func (s *DocumentStore) Get(docuri uri.URI) (*TemplateDocument, bool) { path := docuri.Filename() d, ok := s.documents.Load(path) if !ok { return nil, false } - return d.(*Document), ok + return d.(*TemplateDocument), ok } func IsYamlDocument(uri lsp.URI, yamllsConfiguration util.YamllsConfiguration) bool { diff --git a/internal/lsp/symbol_table_template_context_test.go b/internal/lsp/symbol_table_template_context_test.go index e9e12312..06b241cb 100644 --- a/internal/lsp/symbol_table_template_context_test.go +++ b/internal/lsp/symbol_table_template_context_test.go @@ -52,7 +52,7 @@ func TestGetContextForSelectorExpression(t *testing.T) { } for _, tC := range testCases { t.Run(tC.desc, func(t *testing.T) { - ast := ParseAst(nil, tC.template) + ast := ParseAst(nil, []byte(tC.template)) node := ast.RootNode().Child(1) assert.Equal(t, tC.nodeContent, node.Content([]byte(tC.template))) diff --git a/internal/lsp/symbol_table_template_context_variables_test.go b/internal/lsp/symbol_table_template_context_variables_test.go index b5e6c584..ce2f7518 100644 --- a/internal/lsp/symbol_table_template_context_variables_test.go +++ b/internal/lsp/symbol_table_template_context_variables_test.go @@ -24,7 +24,7 @@ func TestResolveVariablesInTemplateContext(t *testing.T) { t.Run(tt.template, func(t *testing.T) { col := strings.Index(tt.template, "^") buf := strings.Replace(tt.template, "^", "", 1) - ast := ParseAst(nil, tt.template) + ast := ParseAst(nil, []byte(tt.template)) symbolTable := NewSymbolTable(ast, []byte(buf)) result, err := symbolTable.ResolveVariablesInTemplateContext( diff --git a/internal/lsp/symbol_table_test.go b/internal/lsp/symbol_table_test.go index 96d30fa5..e53d9480 100644 --- a/internal/lsp/symbol_table_test.go +++ b/internal/lsp/symbol_table_test.go @@ -19,7 +19,7 @@ func TestSymbolTableForIncludeDefinitions(t *testing.T) { {{ end }} ` - ast := ParseAst(nil, content) + ast := ParseAst(nil, []byte(content)) symbolTable := NewSymbolTable(ast, []byte(content)) @@ -68,7 +68,7 @@ func TestSymbolTableForValues(t *testing.T) { {{ end }} ` - ast := ParseAst(nil, content) + ast := ParseAst(nil, []byte(content)) symbolTable := NewSymbolTable(ast, []byte(content)) type expectedValue struct { @@ -187,9 +187,9 @@ func TestSymbolTableForValuesTestFile(t *testing.T) { if err != nil { t.Fatal("Could not read test file", err) } - ast := ParseAst(nil, string(content)) + ast := ParseAst(nil, content) - symbolTable := NewSymbolTable(ast, []byte(content)) + symbolTable := NewSymbolTable(ast, content) type expectedValue struct { path []string startPoint sitter.Point @@ -324,7 +324,7 @@ func TestSymbolTableForValuesSingleTests(t *testing.T) { for _, v := range testCases { t.Run(v.template, func(t *testing.T) { - ast := ParseAst(nil, v.template) + ast := ParseAst(nil, []byte(v.template)) symbolTable := NewSymbolTable(ast, []byte(v.template)) values := symbolTable.GetTemplateContextRanges(v.path) points := []sitter.Point{} diff --git a/internal/lsp/symbol_table_variables_test.go b/internal/lsp/symbol_table_variables_test.go index 405ceea2..de14034d 100644 --- a/internal/lsp/symbol_table_variables_test.go +++ b/internal/lsp/symbol_table_variables_test.go @@ -77,7 +77,7 @@ func TestGetVariableDefinition(t *testing.T) { } for _, tC := range testCases { t.Run(tC.template, func(t *testing.T) { - ast := ParseAst(nil, tC.template) + ast := ParseAst(nil, []byte(tC.template)) symbolTable := NewSymbolTable(ast, []byte(tC.template)) result, err := symbolTable.getVariableDefinition(tC.variableName, tC.accessRange) assert.Equal(t, tC.expectedError, err) diff --git a/internal/lsp/template_document.go b/internal/lsp/template_document.go new file mode 100644 index 00000000..59d5ea8d --- /dev/null +++ b/internal/lsp/template_document.go @@ -0,0 +1,68 @@ +package lsp + +import ( + "strings" + + "github.com/mrjosh/helm-ls/internal/util" + sitter "github.com/smacker/go-tree-sitter" + lsp "go.lsp.dev/protocol" +) + +// TemplateDocument represents an opened file. +type TemplateDocument struct { + Document + NeedsRefreshDiagnostics bool + Ast *sitter.Tree + DiagnosticsCache DiagnosticsCache + SymbolTable *SymbolTable + IsYaml bool +} + +// ApplyChanges updates the content of the document from LSP textDocument/didChange events. +func (d *TemplateDocument) ApplyChanges(changes []lsp.TextDocumentContentChangeEvent) { + d.Document.ApplyChanges(changes) + + d.ApplyChangesToAst(d.Content) + d.SymbolTable = NewSymbolTable(d.Ast, d.Content) + + d.lines = nil +} + +// WordAt returns the word found at the given location. +func (d *TemplateDocument) WordAt(pos lsp.Position) string { + logger.Debug(pos) + + line, ok := d.getLine(int(pos.Line)) + if !ok { + return "" + } + return util.WordAt(line, int(pos.Character)) +} + +// getLine returns the line at the given index. +func (d *TemplateDocument) getLine(index int) (string, bool) { + lines := d.getLines() + if index < 0 || index > len(lines) { + return "", false + } + return lines[index], true +} + +// getLines returns all the lines in the document. +func (d *TemplateDocument) getLines() []string { + if d.lines == nil { + // We keep \r on purpose, to avoid messing up position conversions. + d.lines = strings.Split(string(d.Content), "\n") + } + return d.lines +} + +// GetContent implements PossibleDependencyFile. +func (d *TemplateDocument) GetContent() []byte { + return d.Content +} + +// GetPath implements PossibleDependencyFile. +func (d *TemplateDocument) GetPath() string { + return d.Path +} diff --git a/internal/lsp/variables_visitor_test.go b/internal/lsp/variables_visitor_test.go index 30e88af2..f21f69ed 100644 --- a/internal/lsp/variables_visitor_test.go +++ b/internal/lsp/variables_visitor_test.go @@ -70,7 +70,7 @@ func TestSymbolTableForVariableDefinitions(t *testing.T) { for _, v := range testCases { t.Run(v.template, func(t *testing.T) { - ast := ParseAst(nil, v.template) + ast := ParseAst(nil, []byte(v.template)) symbolTable := NewSymbolTable(ast, []byte(v.template)) assert.Equal(t, v.expectedVariableDefinitions, symbolTable.variableDefinitions, fmt.Sprintf("Ast was %s", ast.RootNode())) @@ -97,7 +97,7 @@ func TestSymbolTableForVariableUsages(t *testing.T) { for _, v := range testCases { t.Run(v.template, func(t *testing.T) { - ast := ParseAst(nil, v.template) + ast := ParseAst(nil, []byte(v.template)) symbolTable := NewSymbolTable(ast, []byte(v.template)) assert.Equal(t, v.expectedVariableUsages, symbolTable.variableUsages, fmt.Sprintf("Ast was %s", ast.RootNode())) diff --git a/internal/lsp/yaml_ast.go b/internal/lsp/yaml_ast.go index 8d3f03d1..9b0f54a3 100644 --- a/internal/lsp/yaml_ast.go +++ b/internal/lsp/yaml_ast.go @@ -32,7 +32,7 @@ func getTextNodeRanges(gotemplateNode *sitter.Node) []sitter.Range { // This is done by keeping only the text nodes // which is easier then removing the template nodes // since template nodes could contain other nodes -func TrimTemplate(gotemplateTree *sitter.Tree, content string) string { +func TrimTemplate(gotemplateTree *sitter.Tree, content []byte) string { ranges := getTextNodeRanges(gotemplateTree.RootNode()) result := make([]byte, len(content)) for i := range result { diff --git a/internal/lsp/yaml_ast_test.go b/internal/lsp/yaml_ast_test.go index 05b4bded..02d13e3f 100644 --- a/internal/lsp/yaml_ast_test.go +++ b/internal/lsp/yaml_ast_test.go @@ -78,7 +78,7 @@ b: not`, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got := getTextNodeRanges(ParseAst(nil, tt.args.gotemplateString).RootNode()) + got := getTextNodeRanges(ParseAst(nil, []byte(tt.args.gotemplateString)).RootNode()) assert.Equal(t, tt.want, got) }) } @@ -121,8 +121,8 @@ yaml: test } for _, tt := range tests { t.Run(tt.documentText, func(t *testing.T) { - gotemplateTree := ParseAst(nil, tt.documentText) - got := TrimTemplate(gotemplateTree, tt.documentText) + gotemplateTree := ParseAst(nil, []byte(tt.documentText)) + got := TrimTemplate(gotemplateTree, []byte(tt.documentText)) assert.Equal(t, tt.trimmedText, got) }) } From 8e400c2b39e8c18ae9d07c2df5ca094fd8d4f446 Mon Sep 17 00:00:00 2001 From: qvalentin Date: Thu, 5 Sep 2024 19:26:41 +0200 Subject: [PATCH 02/16] feat: refactor document creation --- internal/adapter/yamlls/diagnostics.go | 2 +- internal/adapter/yamlls/document_sync.go | 2 +- internal/adapter/yamlls/yamlls.go | 2 +- internal/handler/generic_document_usecase.go | 2 +- internal/handler/initialization.go | 2 +- internal/handler/text_document.go | 11 ++--- internal/handler/text_document_test.go | 4 +- .../generic_template_context.go | 2 +- internal/language_features/includes.go | 8 +-- .../language_features/template_context.go | 2 +- internal/lsp/document.go | 30 ++++++++++++ internal/lsp/document_store.go | 49 ++++--------------- internal/lsp/document_store_test.go | 8 +-- internal/lsp/document_test.go | 8 +-- internal/lsp/template_document.go | 38 +++++++------- 15 files changed, 81 insertions(+), 89 deletions(-) diff --git a/internal/adapter/yamlls/diagnostics.go b/internal/adapter/yamlls/diagnostics.go index ebc6306d..07d01c2b 100644 --- a/internal/adapter/yamlls/diagnostics.go +++ b/internal/adapter/yamlls/diagnostics.go @@ -13,7 +13,7 @@ import ( ) func (c Connector) PublishDiagnostics(ctx context.Context, params *protocol.PublishDiagnosticsParams) (err error) { - doc, ok := c.documents.Get(params.URI) + doc, ok := c.documents.GetTemplateDoc(params.URI) if !ok { logger.Println("Error handling diagnostic. Could not get document: " + params.URI.Filename()) return fmt.Errorf("Could not get document: %s", params.URI.Filename()) diff --git a/internal/adapter/yamlls/document_sync.go b/internal/adapter/yamlls/document_sync.go index f18ccb7f..1db81942 100644 --- a/internal/adapter/yamlls/document_sync.go +++ b/internal/adapter/yamlls/document_sync.go @@ -19,7 +19,7 @@ func (yamllsConnector Connector) InitiallySyncOpenDocuments(docs []*lsplocal.Tem continue } - doc.IsYaml = lsplocal.IsYamlDocument(doc.URI, yamllsConnector.config) + doc.IsYaml = lsplocal.IsYamllsEnabled(doc.URI, yamllsConnector.config) if !yamllsConnector.isRelevantFile(doc.URI) { continue } diff --git a/internal/adapter/yamlls/yamlls.go b/internal/adapter/yamlls/yamlls.go index e711b8c3..2d1d215b 100644 --- a/internal/adapter/yamlls/yamlls.go +++ b/internal/adapter/yamlls/yamlls.go @@ -82,7 +82,7 @@ func NewConnector(ctx context.Context, yamllsConfiguration util.YamllsConfigurat } func (yamllsConnector *Connector) isRelevantFile(uri lsp.URI) bool { - doc, ok := yamllsConnector.documents.Get(uri) + doc, ok := yamllsConnector.documents.GetTemplateDoc(uri) if !ok { logger.Error("Could not find document", uri) return true diff --git a/internal/handler/generic_document_usecase.go b/internal/handler/generic_document_usecase.go index 14e1ec61..3b97fa06 100644 --- a/internal/handler/generic_document_usecase.go +++ b/internal/handler/generic_document_usecase.go @@ -12,7 +12,7 @@ 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) + doc, ok := h.documents.GetTemplateDoc(params.TextDocument.URI) if !ok { return &languagefeatures.GenericDocumentUseCase{}, errors.New("Could not get document: " + params.TextDocument.URI.Filename()) } diff --git a/internal/handler/initialization.go b/internal/handler/initialization.go index 7a4ba313..c7fd35d5 100644 --- a/internal/handler/initialization.go +++ b/internal/handler/initialization.go @@ -81,7 +81,7 @@ func (h *langHandler) configureYamlls(ctx context.Context) { logger.Error("Error initializing yamlls", err) } - h.yamllsConnector.InitiallySyncOpenDocuments(h.documents.GetAllDocs()) + h.yamllsConnector.InitiallySyncOpenDocuments(h.documents.GetAllTemplateDocs()) } } diff --git a/internal/handler/text_document.go b/internal/handler/text_document.go index 942c9924..86e17c3e 100644 --- a/internal/handler/text_document.go +++ b/internal/handler/text_document.go @@ -21,17 +21,12 @@ func (h *langHandler) DidOpen(ctx context.Context, params *lsp.DidOpenTextDocume h.yamllsConnector.DocumentDidOpen(doc.Ast, *params) - doc, ok := h.documents.Get(params.TextDocument.URI) - if !ok { - return errors.New("Could not get document: " + params.TextDocument.URI.Filename()) - } chart, err := h.chartStore.GetChartOrParentForDoc(doc.URI) if err != nil { logger.Error("Error getting chart info for file", doc.URI, err) } - notifications := helmlint.GetDiagnosticsNotifications(chart, doc) - defer h.publishDiagnostics(ctx, notifications) + defer h.publishDiagnostics(ctx, helmlint.GetDiagnosticsNotifications(chart, doc)) return nil } @@ -41,7 +36,7 @@ func (h *langHandler) DidClose(_ context.Context, _ *lsp.DidCloseTextDocumentPar } func (h *langHandler) DidSave(ctx context.Context, params *lsp.DidSaveTextDocumentParams) (err error) { - doc, ok := h.documents.Get(params.TextDocument.URI) + doc, ok := h.documents.GetTemplateDoc(params.TextDocument.URI) if !ok { return errors.New("Could not get document: " + params.TextDocument.URI.Filename()) } @@ -59,7 +54,7 @@ func (h *langHandler) DidSave(ctx context.Context, params *lsp.DidSaveTextDocume } func (h *langHandler) DidChange(_ context.Context, params *lsp.DidChangeTextDocumentParams) (err error) { - doc, ok := h.documents.Get(params.TextDocument.URI) + doc, ok := h.documents.GetTemplateDoc(params.TextDocument.URI) if !ok { return errors.New("Could not get document: " + params.TextDocument.URI.Filename()) } diff --git a/internal/handler/text_document_test.go b/internal/handler/text_document_test.go index 1a1319e4..9cffc7f0 100644 --- a/internal/handler/text_document_test.go +++ b/internal/handler/text_document_test.go @@ -39,7 +39,7 @@ func TestLoadDocsOnNewChart(t *testing.T) { h.LoadDocsOnNewChart(charts.NewChart(rootURI, util.DefaultConfig.ValuesFilesConfig)) for _, file := range templateFiles { - doc, ok := h.documents.Get(uri.File(file)) + doc, ok := h.documents.GetTemplateDoc(uri.File(file)) assert.True(t, ok) assert.NotNil(t, doc) assert.False(t, doc.IsOpen) @@ -73,7 +73,7 @@ func TestLoadDocsOnNewChartDoesNotOverwrite(t *testing.T) { h.LoadDocsOnNewChart(charts.NewChart(rootURI, util.DefaultConfig.ValuesFilesConfig)) - doc, ok := h.documents.Get(uri.File(templateFile)) + doc, ok := h.documents.GetTemplateDoc(uri.File(templateFile)) assert.True(t, ok) assert.NotNil(t, doc) // The document should still be open because it's already in the store diff --git a/internal/language_features/generic_template_context.go b/internal/language_features/generic_template_context.go index cfc800de..d0704a87 100644 --- a/internal/language_features/generic_template_context.go +++ b/internal/language_features/generic_template_context.go @@ -20,7 +20,7 @@ func (f *GenericTemplateContextFeature) getTemplateContext() (lsplocal.TemplateC func (f *GenericTemplateContextFeature) getReferencesFromSymbolTable(templateContext lsplocal.TemplateContext) []lsp.Location { locations := []lsp.Location{} - for _, doc := range f.GenericDocumentUseCase.DocumentStore.GetAllDocs() { + for _, doc := range f.GenericDocumentUseCase.DocumentStore.GetAllTemplateDocs() { referenceRanges := doc.SymbolTable.GetTemplateContextRanges(templateContext) for _, referenceRange := range referenceRanges { locations = append(locations, util.RangeToLocation(doc.URI, referenceRange)) diff --git a/internal/language_features/includes.go b/internal/language_features/includes.go index 1d8ab8e7..ebb592d5 100644 --- a/internal/language_features/includes.go +++ b/internal/language_features/includes.go @@ -86,7 +86,7 @@ func (f *IncludesDefinitionFeature) References() (result []lsp.Location, err err func (f *IncludesFeature) getReferenceLocations(includeName string) []lsp.Location { locations := []lsp.Location{} - for _, doc := range f.GenericDocumentUseCase.DocumentStore.GetAllDocs() { + for _, doc := range f.GenericDocumentUseCase.DocumentStore.GetAllTemplateDocs() { referenceRanges := doc.SymbolTable.GetIncludeReference(includeName) for _, referenceRange := range referenceRanges { locations = append(locations, util.RangeToLocation(doc.URI, referenceRange)) @@ -101,7 +101,7 @@ func (f *IncludesFeature) getReferenceLocations(includeName string) []lsp.Locati func (f *IncludesFeature) getDefinitionLocations(includeName string) []lsp.Location { locations := []lsp.Location{} - for _, doc := range f.GenericDocumentUseCase.DocumentStore.GetAllDocs() { + for _, doc := range f.GenericDocumentUseCase.DocumentStore.GetAllTemplateDocs() { referenceRanges := doc.SymbolTable.GetIncludeDefinitions(includeName) for _, referenceRange := range referenceRanges { locations = append(locations, util.RangeToLocation(doc.URI, referenceRange)) @@ -116,7 +116,7 @@ func (f *IncludesFeature) getDefinitionLocations(includeName string) []lsp.Locat func (f *IncludesFeature) getDefinitionsHover(includeName string) protocol.HoverResultsWithFiles { result := protocol.HoverResultsWithFiles{} - for _, doc := range f.GenericDocumentUseCase.DocumentStore.GetAllDocs() { + for _, doc := range f.GenericDocumentUseCase.DocumentStore.GetAllTemplateDocs() { referenceRanges := doc.SymbolTable.GetIncludeDefinitions(includeName) for _, referenceRange := range referenceRanges { node := doc.Ast.RootNode().NamedDescendantForPointRange(referenceRange.StartPoint, referenceRange.EndPoint) @@ -152,7 +152,7 @@ func (f *IncludesCallFeature) Definition() (result []lsp.Location, err error) { func (f *IncludesCallFeature) Completion() (*lsp.CompletionList, error) { items := []lsp.CompletionItem{} - for _, doc := range f.GenericDocumentUseCase.DocumentStore.GetAllDocs() { + for _, doc := range f.GenericDocumentUseCase.DocumentStore.GetAllTemplateDocs() { inlcudeDefinitionNames := doc.SymbolTable.GetAllIncludeDefinitionsNames() for _, includeDefinitionName := range inlcudeDefinitionNames { items = append(items, lsp.CompletionItem{ diff --git a/internal/language_features/template_context.go b/internal/language_features/template_context.go index 8b61ea91..38e6dbf2 100644 --- a/internal/language_features/template_context.go +++ b/internal/language_features/template_context.go @@ -55,7 +55,7 @@ func (f *TemplateContextFeature) Definition() (result []lsp.Location, err error) func (f *TemplateContextFeature) getReferenceLocations(templateContext lsplocal.TemplateContext) []lsp.Location { locations := []lsp.Location{} - for _, doc := range f.GenericDocumentUseCase.DocumentStore.GetAllDocs() { + for _, doc := range f.GenericDocumentUseCase.DocumentStore.GetAllTemplateDocs() { referenceRanges := doc.SymbolTable.GetTemplateContextRanges(templateContext) for _, referenceRange := range referenceRanges { locations = append(locations, util.RangeToLocation(doc.URI, referenceRange)) diff --git a/internal/lsp/document.go b/internal/lsp/document.go index b9e6d7db..19ed3a1d 100644 --- a/internal/lsp/document.go +++ b/internal/lsp/document.go @@ -3,10 +3,12 @@ package lsp import ( "bytes" "fmt" + "strings" "github.com/mrjosh/helm-ls/internal/log" "github.com/mrjosh/helm-ls/internal/util" lsp "go.lsp.dev/protocol" + "go.lsp.dev/uri" ) var logger = log.GetLogger() @@ -20,6 +22,15 @@ type Document struct { IsOpen bool } +func NewDocument(fileURI uri.URI, content []byte, isOpen bool) *Document { + return &Document{ + URI: fileURI, + Path: fileURI.Filename(), + Content: content, + IsOpen: isOpen, + } +} + func (d *Document) ApplyChanges(changes []lsp.TextDocumentContentChangeEvent) { defer func() { if r := recover(); r != nil { @@ -40,3 +51,22 @@ func (d *Document) ApplyChanges(changes []lsp.TextDocumentContentChangeEvent) { d.Content = content d.lines = nil } + +// getLines returns all the lines in the document. +func (d *Document) getLines() []string { + if d.lines == nil { + // We keep \r on purpose, to avoid messing up position conversions. + d.lines = strings.Split(string(d.Content), "\n") + } + return d.lines +} + +// GetContent implements PossibleDependencyFile. +func (d *Document) GetContent() []byte { + return d.Content +} + +// GetPath implements PossibleDependencyFile. +func (d *Document) GetPath() string { + return d.Path +} diff --git a/internal/lsp/document_store.go b/internal/lsp/document_store.go index e7f36af3..b86d84c1 100644 --- a/internal/lsp/document_store.go +++ b/internal/lsp/document_store.go @@ -20,33 +20,12 @@ func NewDocumentStore() *DocumentStore { } } -func (s *DocumentStore) GetAllDocs() []*TemplateDocument { - var docs []*TemplateDocument - s.documents.Range(func(_, v interface{}) bool { - docs = append(docs, v.(*TemplateDocument)) - return true - }) - return docs -} - func (s *DocumentStore) DidOpen(params *lsp.DidOpenTextDocumentParams, helmlsConfig util.HelmlsConfiguration) (*TemplateDocument, 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, []byte(params.TextDocument.Text)) - doc := &TemplateDocument{ - Document: Document{ - URI: uri, - Path: path, - Content: []byte(params.TextDocument.Text), - IsOpen: true, - }, - Ast: ast, - DiagnosticsCache: NewDiagnosticsCache(helmlsConfig), - SymbolTable: NewSymbolTable(ast, []byte(params.TextDocument.Text)), - IsYaml: IsYamlDocument(uri, helmlsConfig.YamllsConfiguration), - } + doc := NewTemplateDocument(uri, []byte(params.TextDocument.Text), true, helmlsConfig) logger.Debug("Storing doc ", path) s.documents.Store(path, doc) return doc, nil @@ -57,25 +36,12 @@ func (s *DocumentStore) Store(path string, content []byte, helmlsConfig util.Hel if ok { return } - ast := ParseAst(nil, content) fileURI := uri.File(path) s.documents.Store(fileURI.Filename(), - &TemplateDocument{ - Document: Document{ - URI: fileURI, - Path: path, - Content: content, - IsOpen: false, - }, - Ast: ast, - DiagnosticsCache: NewDiagnosticsCache(helmlsConfig), - SymbolTable: NewSymbolTable(ast, content), - IsYaml: IsYamlDocument(fileURI, helmlsConfig.YamllsConfiguration), - }, - ) + NewTemplateDocument(fileURI, content, false, helmlsConfig)) } -func (s *DocumentStore) Get(docuri uri.URI) (*TemplateDocument, bool) { +func (s *DocumentStore) GetTemplateDoc(docuri uri.URI) (*TemplateDocument, bool) { path := docuri.Filename() d, ok := s.documents.Load(path) @@ -85,6 +51,11 @@ func (s *DocumentStore) Get(docuri uri.URI) (*TemplateDocument, bool) { return d.(*TemplateDocument), ok } -func IsYamlDocument(uri lsp.URI, yamllsConfiguration util.YamllsConfiguration) bool { - return yamllsConfiguration.EnabledForFilesGlobObject.Match(uri.Filename()) +func (s *DocumentStore) GetAllTemplateDocs() []*TemplateDocument { + var docs []*TemplateDocument + s.documents.Range(func(_, v interface{}) bool { + docs = append(docs, v.(*TemplateDocument)) + return true + }) + return docs } diff --git a/internal/lsp/document_store_test.go b/internal/lsp/document_store_test.go index 31ad645b..5149c65f 100644 --- a/internal/lsp/document_store_test.go +++ b/internal/lsp/document_store_test.go @@ -10,8 +10,8 @@ import ( func TestIsYamlDocument(t *testing.T) { assert := assert.New(t) - assert.True(IsYamlDocument(uri.File("test.yaml"), util.DefaultConfig.YamllsConfiguration)) - assert.False(IsYamlDocument(uri.File("test.tpl"), util.DefaultConfig.YamllsConfiguration)) - assert.True(IsYamlDocument(uri.File("../../testdata/example/templates/hpa.yaml"), util.DefaultConfig.YamllsConfiguration)) - assert.False(IsYamlDocument(uri.File("../../testdata/example/templates/_helpers.tpl"), util.DefaultConfig.YamllsConfiguration)) + assert.True(IsYamllsEnabled(uri.File("test.yaml"), util.DefaultConfig.YamllsConfiguration)) + assert.False(IsYamllsEnabled(uri.File("test.tpl"), util.DefaultConfig.YamllsConfiguration)) + assert.True(IsYamllsEnabled(uri.File("../../testdata/example/templates/hpa.yaml"), util.DefaultConfig.YamllsConfiguration)) + assert.False(IsYamllsEnabled(uri.File("../../testdata/example/templates/_helpers.tpl"), util.DefaultConfig.YamllsConfiguration)) } diff --git a/internal/lsp/document_test.go b/internal/lsp/document_test.go index c09d0ca3..d92119c5 100644 --- a/internal/lsp/document_test.go +++ b/internal/lsp/document_test.go @@ -14,9 +14,9 @@ func TestDocumentStore(t *testing.T) { sut := NewDocumentStore() - assert.Empty(sut.GetAllDocs()) + assert.Empty(sut.GetAllTemplateDocs()) - doc, ok := sut.Get(uri.File("test")) + doc, ok := sut.GetTemplateDoc(uri.File("test")) assert.Nil(doc) assert.False(ok) @@ -29,9 +29,9 @@ func TestDocumentStore(t *testing.T) { }, }, util.DefaultConfig) - assert.Len(sut.GetAllDocs(), 1) + assert.Len(sut.GetAllTemplateDocs(), 1) - doc, ok = sut.Get(uri.File("test.yaml")) + doc, ok = sut.GetTemplateDoc(uri.File("test.yaml")) assert.NotNil(doc) assert.True(ok) } diff --git a/internal/lsp/template_document.go b/internal/lsp/template_document.go index 59d5ea8d..3d8dee27 100644 --- a/internal/lsp/template_document.go +++ b/internal/lsp/template_document.go @@ -1,11 +1,10 @@ package lsp import ( - "strings" - "github.com/mrjosh/helm-ls/internal/util" sitter "github.com/smacker/go-tree-sitter" lsp "go.lsp.dev/protocol" + "go.lsp.dev/uri" ) // TemplateDocument represents an opened file. @@ -18,6 +17,18 @@ type TemplateDocument struct { IsYaml bool } +func NewTemplateDocument(fileURI uri.URI, content []byte, isOpen bool, helmlsConfig util.HelmlsConfiguration) *TemplateDocument { + ast := ParseAst(nil, content) + return &TemplateDocument{ + Document: *NewDocument(fileURI, content, isOpen), + NeedsRefreshDiagnostics: false, + Ast: ast, + DiagnosticsCache: NewDiagnosticsCache(helmlsConfig), + SymbolTable: NewSymbolTable(ast, content), + IsYaml: IsYamllsEnabled(fileURI, helmlsConfig.YamllsConfiguration), + } +} + // ApplyChanges updates the content of the document from LSP textDocument/didChange events. func (d *TemplateDocument) ApplyChanges(changes []lsp.TextDocumentContentChangeEvent) { d.Document.ApplyChanges(changes) @@ -29,7 +40,7 @@ func (d *TemplateDocument) ApplyChanges(changes []lsp.TextDocumentContentChangeE } // WordAt returns the word found at the given location. -func (d *TemplateDocument) WordAt(pos lsp.Position) string { +func (d *Document) WordAt(pos lsp.Position) string { logger.Debug(pos) line, ok := d.getLine(int(pos.Line)) @@ -40,7 +51,7 @@ func (d *TemplateDocument) WordAt(pos lsp.Position) string { } // getLine returns the line at the given index. -func (d *TemplateDocument) getLine(index int) (string, bool) { +func (d *Document) getLine(index int) (string, bool) { lines := d.getLines() if index < 0 || index > len(lines) { return "", false @@ -48,21 +59,6 @@ func (d *TemplateDocument) getLine(index int) (string, bool) { return lines[index], true } -// getLines returns all the lines in the document. -func (d *TemplateDocument) getLines() []string { - if d.lines == nil { - // We keep \r on purpose, to avoid messing up position conversions. - d.lines = strings.Split(string(d.Content), "\n") - } - return d.lines -} - -// GetContent implements PossibleDependencyFile. -func (d *TemplateDocument) GetContent() []byte { - return d.Content -} - -// GetPath implements PossibleDependencyFile. -func (d *TemplateDocument) GetPath() string { - return d.Path +func IsYamllsEnabled(uri lsp.URI, yamllsConfiguration util.YamllsConfiguration) bool { + return yamllsConfiguration.EnabledForFilesGlobObject.Match(uri.Filename()) } From b4b2134f3a3c6f84599efc7667fc48f30288aefc Mon Sep 17 00:00:00 2001 From: qvalentin Date: Thu, 5 Sep 2024 19:38:12 +0200 Subject: [PATCH 03/16] wip --- internal/lsp/document_store.go | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/internal/lsp/document_store.go b/internal/lsp/document_store.go index b86d84c1..584c99e7 100644 --- a/internal/lsp/document_store.go +++ b/internal/lsp/document_store.go @@ -11,12 +11,17 @@ import ( // documentStore holds opened documents. type DocumentStore struct { - documents sync.Map + templateDocuments sync.Map + documents map[string]*sync.Map } func NewDocumentStore() *DocumentStore { return &DocumentStore{ - documents: sync.Map{}, + documents: map[string]*sync.Map{ + ("yaml" + ""): new(sync.Map), + "helm": new(sync.Map), + }, + templateDocuments: sync.Map{}, } } @@ -27,23 +32,23 @@ func (s *DocumentStore) DidOpen(params *lsp.DidOpenTextDocumentParams, helmlsCon path := uri.Filename() doc := NewTemplateDocument(uri, []byte(params.TextDocument.Text), true, helmlsConfig) logger.Debug("Storing doc ", path) - s.documents.Store(path, doc) + s.templateDocuments.Store(path, doc) return doc, nil } func (s *DocumentStore) Store(path string, content []byte, helmlsConfig util.HelmlsConfiguration) { - _, ok := s.documents.Load(path) + _, ok := s.templateDocuments.Load(path) if ok { return } fileURI := uri.File(path) - s.documents.Store(fileURI.Filename(), + s.templateDocuments.Store(fileURI.Filename(), NewTemplateDocument(fileURI, content, false, helmlsConfig)) } func (s *DocumentStore) GetTemplateDoc(docuri uri.URI) (*TemplateDocument, bool) { path := docuri.Filename() - d, ok := s.documents.Load(path) + d, ok := s.templateDocuments.Load(path) if !ok { return nil, false @@ -53,7 +58,7 @@ func (s *DocumentStore) GetTemplateDoc(docuri uri.URI) (*TemplateDocument, bool) func (s *DocumentStore) GetAllTemplateDocs() []*TemplateDocument { var docs []*TemplateDocument - s.documents.Range(func(_, v interface{}) bool { + s.templateDocuments.Range(func(_, v interface{}) bool { docs = append(docs, v.(*TemplateDocument)) return true }) From d75f01a236a2c647333948193fb76eb815914cc4 Mon Sep 17 00:00:00 2001 From: qvalentin Date: Fri, 6 Sep 2024 15:10:06 +0200 Subject: [PATCH 04/16] wip --- .../adapter/yamlls/integration_test_utils.go | 5 ++- internal/adapter/yamlls/yamlls_test.go | 4 +- internal/handler/completion_main_test.go | 2 +- internal/handler/definition_test.go | 6 +-- internal/handler/hover_main_test.go | 2 +- internal/handler/references_test.go | 6 +-- internal/handler/text_document.go | 33 +++++++++-------- internal/handler/text_document_test.go | 2 +- internal/lsp/document.go | 4 ++ internal/lsp/document_store.go | 37 ++++++++++++++----- internal/lsp/document_test.go | 2 +- internal/lsp/template_document.go | 4 ++ 12 files changed, 68 insertions(+), 39 deletions(-) diff --git a/internal/adapter/yamlls/integration_test_utils.go b/internal/adapter/yamlls/integration_test_utils.go index 33aae38f..4db794ff 100644 --- a/internal/adapter/yamlls/integration_test_utils.go +++ b/internal/adapter/yamlls/integration_test_utils.go @@ -81,6 +81,7 @@ func openFile(t *testing.T, documents *lsplocal.DocumentStore, path string, yaml Text: string(content), }, } - doc, err := documents.DidOpen(&d, util.DefaultConfig) - yamllsConnector.DocumentDidOpen(doc.Ast, d) + _, err = documents.DidOpenTemplateDocument(&d, util.DefaultConfig) + // doc, err := documents.DidOpen(&d, util.DefaultConfig) TODO: fix this + // yamllsConnector.DocumentDidOpen(doc.Ast, d) } diff --git a/internal/adapter/yamlls/yamlls_test.go b/internal/adapter/yamlls/yamlls_test.go index b1a42d16..4fb05cd0 100644 --- a/internal/adapter/yamlls/yamlls_test.go +++ b/internal/adapter/yamlls/yamlls_test.go @@ -27,8 +27,8 @@ func TestIsRelevantFile(t *testing.T) { nonYamlFileContent, err := os.ReadFile(nonYamlFile) assert.NoError(t, err) - connector.documents.Store(yamlFile, yamlFileContent, util.DefaultConfig) - connector.documents.Store(nonYamlFile, nonYamlFileContent, util.DefaultConfig) + connector.documents.StoreTemplateDocument(yamlFile, yamlFileContent, util.DefaultConfig) + connector.documents.StoreTemplateDocument(nonYamlFile, nonYamlFileContent, util.DefaultConfig) assert.True(t, connector.isRelevantFile(uri.File(yamlFile))) assert.False(t, connector.isRelevantFile(uri.File(nonYamlFile))) diff --git a/internal/handler/completion_main_test.go b/internal/handler/completion_main_test.go index 449350c7..b64c33ca 100644 --- a/internal/handler/completion_main_test.go +++ b/internal/handler/completion_main_test.go @@ -225,7 +225,7 @@ func completionTestCall(fileURI uri.URI, buf string, pos lsp.Position) (*lsp.Com Text: buf, }, } - documents.DidOpen(&d, util.DefaultConfig) + documents.DidOpenTemplateDocument(&d, util.DefaultConfig) h := &langHandler{ chartStore: charts.NewChartStore(uri.File("."), charts.NewChart, func(chart *charts.Chart) {}), documents: documents, diff --git a/internal/handler/definition_test.go b/internal/handler/definition_test.go index 064e5c41..f64e758e 100644 --- a/internal/handler/definition_test.go +++ b/internal/handler/definition_test.go @@ -79,7 +79,7 @@ func genericDefinitionTest(t *testing.T, position lsp.Position, expectedLocation Text: string(testFileContent), }, } - documents.DidOpen(&d, util.DefaultConfig) + documents.DidOpenTemplateDocument(&d, util.DefaultConfig) chartStore := charts.NewChartStore(rootUri, charts.NewChart, addChartCallback) chartStore.Charts = map[uri.URI]*charts.Chart{rootUri: testChart} h := &langHandler{ @@ -274,7 +274,7 @@ func genericDefinitionTestMultipleValuesFiles(t *testing.T, position lsp.Positio Text: string(testFileContent), }, } - documents.DidOpen(&d, util.DefaultConfig) + documents.DidOpenTemplateDocument(&d, util.DefaultConfig) chartStore := charts.NewChartStore(rootUri, charts.NewChart, addChartCallback) chartStore.Charts = map[uri.URI]*charts.Chart{rootUri: chart} h := &langHandler{ @@ -366,7 +366,7 @@ func TestDefinitionSingleLine(t *testing.T) { Text: buf, }, } - documents.DidOpen(&d, util.DefaultConfig) + documents.DidOpenTemplateDocument(&d, util.DefaultConfig) h := &langHandler{ chartStore: charts.NewChartStore(rootUri, charts.NewChart, addChartCallback), documents: documents, diff --git a/internal/handler/hover_main_test.go b/internal/handler/hover_main_test.go index 54bda929..d722de2f 100644 --- a/internal/handler/hover_main_test.go +++ b/internal/handler/hover_main_test.go @@ -182,7 +182,7 @@ func TestHoverMain(t *testing.T) { Text: string(content), }, } - documents.DidOpen(&d, util.DefaultConfig) + documents.DidOpenTemplateDocument(&d, util.DefaultConfig) h := &langHandler{ chartStore: charts.NewChartStore(uri.File("."), charts.NewChart, addChartCallback), diff --git a/internal/handler/references_test.go b/internal/handler/references_test.go index 07136e1c..7e9f2b5a 100644 --- a/internal/handler/references_test.go +++ b/internal/handler/references_test.go @@ -94,7 +94,7 @@ func TestRefercesTemplateContext(t *testing.T) { Text: string(content), }, } - documents.DidOpen(&d, util.DefaultConfig) + documents.DidOpenTemplateDocument(&d, util.DefaultConfig) h := &langHandler{ chartStore: charts.NewChartStore(uri.File("."), charts.NewChart, addChartCallback), documents: documents, @@ -161,7 +161,7 @@ func TestRefercesTemplateContextWithTestFile(t *testing.T) { Text: string(content), }, } - documents.DidOpen(&d, util.DefaultConfig) + documents.DidOpenTemplateDocument(&d, util.DefaultConfig) h := &langHandler{ chartStore: charts.NewChartStore(uri.File("."), charts.NewChart, addChartCallback), documents: documents, @@ -219,7 +219,7 @@ func TestRefercesSingleLines(t *testing.T) { Text: buf, }, } - documents.DidOpen(&d, util.DefaultConfig) + documents.DidOpenTemplateDocument(&d, util.DefaultConfig) h := &langHandler{ chartStore: charts.NewChartStore(uri.File("."), charts.NewChart, addChartCallback), documents: documents, diff --git a/internal/handler/text_document.go b/internal/handler/text_document.go index 86e17c3e..a56dc969 100644 --- a/internal/handler/text_document.go +++ b/internal/handler/text_document.go @@ -13,20 +13,23 @@ import ( ) func (h *langHandler) DidOpen(ctx context.Context, params *lsp.DidOpenTextDocumentParams) (err error) { - doc, err := h.documents.DidOpen(params, h.helmlsConfig) - if err != nil { - logger.Error(err) - return err - } + if lsplocal.IsTemplateDocumentLangID(params.TextDocument.LanguageID) { + doc, err := h.documents.DidOpenTemplateDocument(params, h.helmlsConfig) + if err != nil { + logger.Error(err) + return err + } - h.yamllsConnector.DocumentDidOpen(doc.Ast, *params) + h.yamllsConnector.DocumentDidOpen(doc.Ast, *params) - chart, err := h.chartStore.GetChartOrParentForDoc(doc.URI) - if err != nil { - logger.Error("Error getting chart info for file", doc.URI, err) - } + chart, err := h.chartStore.GetChartOrParentForDoc(doc.URI) + if err != nil { + logger.Error("Error getting chart info for file", doc.URI, err) + } + + defer h.publishDiagnostics(ctx, helmlint.GetDiagnosticsNotifications(chart, doc)) - defer h.publishDiagnostics(ctx, helmlint.GetDiagnosticsNotifications(chart, doc)) + } return nil } @@ -59,11 +62,10 @@ func (h *langHandler) DidChange(_ context.Context, params *lsp.DidChangeTextDocu return errors.New("Could not get document: " + params.TextDocument.URI.Filename()) } - shouldSendFullUpdateToYamlls := false - // Synchronise changes into the doc's ContentChanges doc.ApplyChanges(params.ContentChanges) + shouldSendFullUpdateToYamlls := false for _, change := range params.ContentChanges { node := lsplocal.NodeAtPosition(doc.Ast, change.Range.Start) if node.Type() != "text" { @@ -71,7 +73,6 @@ func (h *langHandler) DidChange(_ context.Context, params *lsp.DidChangeTextDocu break } } - if shouldSendFullUpdateToYamlls { h.yamllsConnector.DocumentDidChangeFullSync(doc, *params) } else { @@ -104,11 +105,11 @@ func (h *langHandler) LoadDocsOnNewChart(chart *charts.Chart) { } for _, file := range chart.HelmChart.Templates { - h.documents.Store(filepath.Join(chart.RootURI.Filename(), file.Name), file.Data, h.helmlsConfig) + h.documents.StoreTemplateDocument(filepath.Join(chart.RootURI.Filename(), file.Name), file.Data, h.helmlsConfig) } for _, file := range chart.GetDependeciesTemplates() { logger.Debug(fmt.Sprintf("Storing dependency %s", file.Path)) - h.documents.Store(file.Path, file.Content, h.helmlsConfig) + h.documents.StoreTemplateDocument(file.Path, file.Content, h.helmlsConfig) } } diff --git a/internal/handler/text_document_test.go b/internal/handler/text_document_test.go index 9cffc7f0..59b4d08f 100644 --- a/internal/handler/text_document_test.go +++ b/internal/handler/text_document_test.go @@ -65,7 +65,7 @@ func TestLoadDocsOnNewChartDoesNotOverwrite(t *testing.T) { helmlsConfig: util.DefaultConfig, } - docs.DidOpen(&lsp.DidOpenTextDocumentParams{ + docs.DidOpenTemplateDocument(&lsp.DidOpenTextDocumentParams{ TextDocument: lsp.TextDocumentItem{ URI: uri.File(templateFile), }, diff --git a/internal/lsp/document.go b/internal/lsp/document.go index 19ed3a1d..a5a024e7 100644 --- a/internal/lsp/document.go +++ b/internal/lsp/document.go @@ -70,3 +70,7 @@ func (d *Document) GetContent() []byte { func (d *Document) GetPath() string { return d.Path } + +type TextDocument interface { + ApplyChanges([]lsp.TextDocumentContentChangeEvent) +} diff --git a/internal/lsp/document_store.go b/internal/lsp/document_store.go index 584c99e7..b106e8d7 100644 --- a/internal/lsp/document_store.go +++ b/internal/lsp/document_store.go @@ -9,6 +9,11 @@ import ( "go.lsp.dev/uri" ) +var ( + helmDocumentType = "helm" + yamlDocumentType = "yaml" +) + // documentStore holds opened documents. type DocumentStore struct { templateDocuments sync.Map @@ -18,31 +23,45 @@ type DocumentStore struct { func NewDocumentStore() *DocumentStore { return &DocumentStore{ documents: map[string]*sync.Map{ - ("yaml" + ""): new(sync.Map), - "helm": new(sync.Map), + helmDocumentType: new(sync.Map), + yamlDocumentType: new(sync.Map), }, templateDocuments: sync.Map{}, } } -func (s *DocumentStore) DidOpen(params *lsp.DidOpenTextDocumentParams, helmlsConfig util.HelmlsConfiguration) (*TemplateDocument, error) { - logger.Debug(fmt.Sprintf("Opening document %s with langID %s", params.TextDocument.URI, params.TextDocument.LanguageID)) - +func (s *DocumentStore) DidOpenTemplateDocument( + params *lsp.DidOpenTextDocumentParams, helmlsConfig util.HelmlsConfiguration, +) (*TemplateDocument, error) { uri := params.TextDocument.URI path := uri.Filename() doc := NewTemplateDocument(uri, []byte(params.TextDocument.Text), true, helmlsConfig) logger.Debug("Storing doc ", path) - s.templateDocuments.Store(path, doc) + s.documents[helmDocumentType].Store(path, doc) return doc, nil } -func (s *DocumentStore) Store(path string, content []byte, helmlsConfig util.HelmlsConfiguration) { - _, ok := s.templateDocuments.Load(path) +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() + if IsTemplateDocumentLangID(params.TextDocument.LanguageID) { + doc := NewTemplateDocument(uri, []byte(params.TextDocument.Text), true, helmlsConfig) + logger.Debug("Storing doc ", path) + s.documents[helmDocumentType].Store(path, doc) + // return doc, nil + } + return nil, fmt.Errorf("unsupported document type: %s", params.TextDocument.LanguageID) +} + +func (s *DocumentStore) StoreTemplateDocument(path string, content []byte, helmlsConfig util.HelmlsConfiguration) { + _, ok := s.documents[helmDocumentType].Load(path) if ok { return } fileURI := uri.File(path) - s.templateDocuments.Store(fileURI.Filename(), + s.documents[helmDocumentType].Store(fileURI.Filename(), NewTemplateDocument(fileURI, content, false, helmlsConfig)) } diff --git a/internal/lsp/document_test.go b/internal/lsp/document_test.go index d92119c5..27545d10 100644 --- a/internal/lsp/document_test.go +++ b/internal/lsp/document_test.go @@ -20,7 +20,7 @@ func TestDocumentStore(t *testing.T) { assert.Nil(doc) assert.False(ok) - sut.DidOpen(&protocol.DidOpenTextDocumentParams{ + sut.DidOpenTemplateDocument(&protocol.DidOpenTextDocumentParams{ TextDocument: protocol.TextDocumentItem{ URI: uri.File("test.yaml"), LanguageID: "helm", diff --git a/internal/lsp/template_document.go b/internal/lsp/template_document.go index 3d8dee27..82a5460b 100644 --- a/internal/lsp/template_document.go +++ b/internal/lsp/template_document.go @@ -62,3 +62,7 @@ func (d *Document) getLine(index int) (string, bool) { func IsYamllsEnabled(uri lsp.URI, yamllsConfiguration util.YamllsConfiguration) bool { return yamllsConfiguration.EnabledForFilesGlobObject.Match(uri.Filename()) } + +func IsTemplateDocumentLangID(langID lsp.LanguageIdentifier) bool { + return langID == "helm" +} From fa5d4e44c30724e1262a90c71e8e767bd94e746a Mon Sep 17 00:00:00 2001 From: qvalentin Date: Fri, 6 Sep 2024 16:52:28 +0200 Subject: [PATCH 05/16] fix: nil pointer --- internal/adapter/yamlls/yamlls_test.go | 2 +- internal/lsp/document_store.go | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/internal/adapter/yamlls/yamlls_test.go b/internal/adapter/yamlls/yamlls_test.go index 4fb05cd0..cfe6c50a 100644 --- a/internal/adapter/yamlls/yamlls_test.go +++ b/internal/adapter/yamlls/yamlls_test.go @@ -17,7 +17,7 @@ func TestIsRelevantFile(t *testing.T) { }, } - connector.documents = &lsplocal.DocumentStore{} + connector.documents = lsplocal.NewDocumentStore() yamlFile := "../../../testdata/example/templates/deployment.yaml" nonYamlFile := "../../../testdata/example/templates/_helpers.tpl" diff --git a/internal/lsp/document_store.go b/internal/lsp/document_store.go index b106e8d7..f6819430 100644 --- a/internal/lsp/document_store.go +++ b/internal/lsp/document_store.go @@ -16,8 +16,7 @@ var ( // documentStore holds opened documents. type DocumentStore struct { - templateDocuments sync.Map - documents map[string]*sync.Map + documents map[string]*sync.Map } func NewDocumentStore() *DocumentStore { @@ -26,7 +25,6 @@ func NewDocumentStore() *DocumentStore { helmDocumentType: new(sync.Map), yamlDocumentType: new(sync.Map), }, - templateDocuments: sync.Map{}, } } @@ -67,7 +65,7 @@ func (s *DocumentStore) StoreTemplateDocument(path string, content []byte, helml func (s *DocumentStore) GetTemplateDoc(docuri uri.URI) (*TemplateDocument, bool) { path := docuri.Filename() - d, ok := s.templateDocuments.Load(path) + d, ok := s.documents[helmDocumentType].Load(path) if !ok { return nil, false @@ -77,7 +75,7 @@ func (s *DocumentStore) GetTemplateDoc(docuri uri.URI) (*TemplateDocument, bool) func (s *DocumentStore) GetAllTemplateDocs() []*TemplateDocument { var docs []*TemplateDocument - s.templateDocuments.Range(func(_, v interface{}) bool { + s.documents[helmDocumentType].Range(func(_, v interface{}) bool { docs = append(docs, v.(*TemplateDocument)) return true }) From 145304657d9f51c3c06ccb5289e54941eacb140f Mon Sep 17 00:00:00 2001 From: qvalentin Date: Sat, 7 Sep 2024 17:14:14 +0200 Subject: [PATCH 06/16] fix test --- internal/adapter/yamlls/integration_test_utils.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/internal/adapter/yamlls/integration_test_utils.go b/internal/adapter/yamlls/integration_test_utils.go index 4db794ff..93ec06c8 100644 --- a/internal/adapter/yamlls/integration_test_utils.go +++ b/internal/adapter/yamlls/integration_test_utils.go @@ -81,7 +81,6 @@ func openFile(t *testing.T, documents *lsplocal.DocumentStore, path string, yaml Text: string(content), }, } - _, err = documents.DidOpenTemplateDocument(&d, util.DefaultConfig) - // doc, err := documents.DidOpen(&d, util.DefaultConfig) TODO: fix this - // yamllsConnector.DocumentDidOpen(doc.Ast, d) + doc, err := documents.DidOpenTemplateDocument(&d, util.DefaultConfig) + yamllsConnector.DocumentDidOpen(doc.Ast, d) } From de8d54e7672f8af32e4ab3c61a6e8b94b90e1fa4 Mon Sep 17 00:00:00 2001 From: qvalentin Date: Sun, 6 Oct 2024 13:51:14 +0200 Subject: [PATCH 07/16] wip: seperate handlers per language --- internal/handler/completion.go | 32 +------ internal/handler/configuration.go | 4 +- internal/handler/configuration_test.go | 8 +- internal/handler/definition.go | 2 +- internal/handler/diagnostics.go | 2 +- internal/handler/handler.go | 95 ++++++++++--------- internal/handler/hover.go | 2 +- internal/handler/initialization.go | 12 +-- internal/handler/lang_handler.go | 18 ++++ internal/handler/references.go | 2 +- internal/handler/symbol.go | 2 +- .../handler/template_handler/completion.go | 46 +++++++++ .../completion_main_test.go | 10 +- .../handler/template_handler/definition.go | 32 +++++++ .../definition_chart_test.go | 13 ++- .../{ => template_handler}/definition_test.go | 8 +- .../generic_document_usecase.go | 4 +- .../{ => template_handler}/helpers_test.go | 2 +- internal/handler/template_handler/hover.go | 43 +++++++++ .../{ => template_handler}/hover_main_test.go | 30 +++--- .../handler/template_handler/references.go | 31 ++++++ .../{ => template_handler}/references_test.go | 10 +- internal/handler/template_handler/symbol.go | 12 +++ .../template_handler/template_handler.go | 16 ++++ internal/handler/text_document.go | 31 ++---- internal/handler/text_document_test.go | 6 +- internal/handler/watched_files.go | 6 +- internal/lsp/document_store.go | 17 ++++ 28 files changed, 336 insertions(+), 160 deletions(-) create mode 100644 internal/handler/lang_handler.go create mode 100644 internal/handler/template_handler/completion.go rename internal/handler/{ => template_handler}/completion_main_test.go (96%) create mode 100644 internal/handler/template_handler/definition.go rename internal/handler/{ => template_handler}/definition_chart_test.go (93%) rename internal/handler/{ => template_handler}/definition_test.go (99%) rename internal/handler/{ => template_handler}/generic_document_usecase.go (94%) rename internal/handler/{ => template_handler}/helpers_test.go (93%) create mode 100644 internal/handler/template_handler/hover.go rename internal/handler/{ => template_handler}/hover_main_test.go (82%) create mode 100644 internal/handler/template_handler/references.go rename internal/handler/{ => template_handler}/references_test.go (97%) create mode 100644 internal/handler/template_handler/symbol.go create mode 100644 internal/handler/template_handler/template_handler.go diff --git a/internal/handler/completion.go b/internal/handler/completion.go index 93eb4e80..2fff4cd5 100644 --- a/internal/handler/completion.go +++ b/internal/handler/completion.go @@ -11,36 +11,8 @@ import ( helmdocs "github.com/mrjosh/helm-ls/internal/documentation/helm" ) -func (h *langHandler) Completion(ctx context.Context, params *lsp.CompletionParams) (result *lsp.CompletionList, err error) { +func (h *ServerHandler) 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, lsplocal.NestedNodeAtPositionForCompletion) - if err != nil { - return nil, err - } - - usecases := []languagefeatures.CompletionUseCase{ - languagefeatures.NewTemplateContextFeature(genericDocumentUseCase), - languagefeatures.NewFunctionCallFeature(genericDocumentUseCase), - languagefeatures.NewTextFeature(ctx, genericDocumentUseCase, h.yamllsConnector, ¶ms.TextDocumentPositionParams), - languagefeatures.NewIncludesCallFeature(genericDocumentUseCase), - } - - for _, usecase := range usecases { - if usecase.AppropriateForNode() { - return usecase.Completion() - } - } - - // If no usecase matched, we assume we are at {{ }} - // and provide the basic BuiltInObjects and functions - items := []helmdocs.HelmDocumentation{} - for _, v := range helmdocs.BuiltInObjects { - v.Name = "." + v.Name - items = append(items, v) - } - - return protocol.CompletionResults{}. - WithDocs(items, lsp.CompletionItemKindConstant). - WithDocs(helmdocs.AllFuncs, lsp.CompletionItemKindFunction).ToList(), nil + return h.selectLangHandler(ctx, params).Completion(ctx, params) } diff --git a/internal/handler/configuration.go b/internal/handler/configuration.go index a2602839..19086143 100644 --- a/internal/handler/configuration.go +++ b/internal/handler/configuration.go @@ -10,13 +10,13 @@ import ( lsp "go.lsp.dev/protocol" ) -func (h *langHandler) DidChangeConfiguration(ctx context.Context, params *lsp.DidChangeConfigurationParams) (err error) { +func (h *ServerHandler) DidChangeConfiguration(ctx context.Context, params *lsp.DidChangeConfigurationParams) (err error) { // go h.retrieveWorkspaceConfiguration(ctx) logger.Println("Changing workspace config is not implemented") return nil } -func (h *langHandler) retrieveWorkspaceConfiguration(ctx context.Context) { +func (h *ServerHandler) retrieveWorkspaceConfiguration(ctx context.Context) { logger.Debug("Calling workspace/configuration") configurationParams := lsp.ConfigurationParams{ Items: []lsp.ConfigurationItem{{Section: "helm-ls"}}, diff --git a/internal/handler/configuration_test.go b/internal/handler/configuration_test.go index 012a0f2c..8a7b86e4 100644 --- a/internal/handler/configuration_test.go +++ b/internal/handler/configuration_test.go @@ -19,7 +19,7 @@ var configurationParams = lsp.ConfigurationParams{Items: []lsp.ConfigurationItem func TestConfigurationWorks(t *testing.T) { mockClient := mocks.NewMockClient(t) - handler := &langHandler{ + handler := &ServerHandler{ helmlsConfig: util.DefaultConfig, chartStore: charts.NewChartStore(uri.File("/"), charts.NewChart, addChartCallback), } @@ -41,7 +41,7 @@ func TestConfigurationWorks(t *testing.T) { func TestConfigurationWorksForEmptyConfig(t *testing.T) { mockClient := mocks.NewMockClient(t) - handler := &langHandler{ + handler := &ServerHandler{ helmlsConfig: util.DefaultConfig, chartStore: charts.NewChartStore(uri.File("/"), charts.NewChart, addChartCallback), } @@ -60,7 +60,7 @@ func TestConfigurationWorksForEmptyConfig(t *testing.T) { func TestConfigurationWorksForError(t *testing.T) { mockClient := mocks.NewMockClient(t) - handler := &langHandler{ + handler := &ServerHandler{ helmlsConfig: util.DefaultConfig, chartStore: charts.NewChartStore(uri.File("/"), charts.NewChart, addChartCallback), } @@ -82,7 +82,7 @@ func TestConfigurationWorksForError(t *testing.T) { func TestConfigurationWorksForJsonError(t *testing.T) { mockClient := mocks.NewMockClient(t) - handler := &langHandler{ + handler := &ServerHandler{ helmlsConfig: util.DefaultConfig, chartStore: charts.NewChartStore(uri.File("/"), charts.NewChart, addChartCallback), } diff --git a/internal/handler/definition.go b/internal/handler/definition.go index 7cd2259a..9f24f35b 100644 --- a/internal/handler/definition.go +++ b/internal/handler/definition.go @@ -8,7 +8,7 @@ import ( lsp "go.lsp.dev/protocol" ) -func (h *langHandler) Definition(_ context.Context, params *lsp.DefinitionParams) (result []lsp.Location, err error) { +func (h *ServerHandler) Definition(_ context.Context, params *lsp.DefinitionParams) (result []lsp.Location, err error) { genericDocumentUseCase, err := h.NewGenericDocumentUseCase(params.TextDocumentPositionParams, lsplocal.NodeAtPosition) if err != nil { return nil, err diff --git a/internal/handler/diagnostics.go b/internal/handler/diagnostics.go index f10293d8..cbd02451 100644 --- a/internal/handler/diagnostics.go +++ b/internal/handler/diagnostics.go @@ -6,7 +6,7 @@ import ( lsp "go.lsp.dev/protocol" ) -func (h *langHandler) publishDiagnostics(ctx context.Context, notifications []lsp.PublishDiagnosticsParams) { +func (h *ServerHandler) publishDiagnostics(ctx context.Context, notifications []lsp.PublishDiagnosticsParams) { for _, notification := range notifications { logger.Debug("Publishing diagnostics notification ", notification) err := h.client.PublishDiagnostics(ctx, ¬ification) diff --git a/internal/handler/handler.go b/internal/handler/handler.go index 6ad1a426..2abf7661 100644 --- a/internal/handler/handler.go +++ b/internal/handler/handler.go @@ -18,7 +18,7 @@ import ( var logger = log.GetLogger() -type langHandler struct { +type ServerHandler struct { client protocol.Client connPool jsonrpc2.Conn linterName string @@ -26,6 +26,7 @@ type langHandler struct { chartStore *charts.ChartStore yamllsConnector *yamlls.Connector helmlsConfig util.HelmlsConfiguration + langHandlers map[string]LangHandler } func StartHandler(stream io.ReadWriteCloser) { @@ -43,9 +44,9 @@ func StartHandler(stream io.ReadWriteCloser) { <-conn.Done() } -func newHandler(connPool jsonrpc2.Conn, client protocol.Client) *langHandler { +func newHandler(connPool jsonrpc2.Conn, client protocol.Client) *ServerHandler { documents := lsplocal.NewDocumentStore() - handler := &langHandler{ + handler := &ServerHandler{ client: client, linterName: "helm-lint", connPool: connPool, @@ -59,263 +60,263 @@ func newHandler(connPool jsonrpc2.Conn, client protocol.Client) *langHandler { } // CodeAction implements protocol.Server. -func (h *langHandler) CodeAction(ctx context.Context, params *lsp.CodeActionParams) (result []lsp.CodeAction, err error) { +func (h *ServerHandler) CodeAction(ctx context.Context, params *lsp.CodeActionParams) (result []lsp.CodeAction, err error) { logger.Error("Code action unimplemented") return nil, nil } // CodeLens implements protocol.Server. -func (h *langHandler) CodeLens(ctx context.Context, params *lsp.CodeLensParams) (result []lsp.CodeLens, err error) { +func (h *ServerHandler) CodeLens(ctx context.Context, params *lsp.CodeLensParams) (result []lsp.CodeLens, err error) { logger.Error("Code lens unimplemented") return nil, nil } // CodeLensRefresh implements protocol.Server. -func (h *langHandler) CodeLensRefresh(ctx context.Context) (err error) { +func (h *ServerHandler) CodeLensRefresh(ctx context.Context) (err error) { logger.Error("Code lens refresh unimplemented") return nil } // CodeLensResolve implements protocol.Server. -func (h *langHandler) CodeLensResolve(ctx context.Context, params *lsp.CodeLens) (result *lsp.CodeLens, err error) { +func (h *ServerHandler) CodeLensResolve(ctx context.Context, params *lsp.CodeLens) (result *lsp.CodeLens, err error) { logger.Error("Code lens resolve unimplemented") return nil, nil } // ColorPresentation implements protocol.Server. -func (h *langHandler) ColorPresentation(ctx context.Context, params *lsp.ColorPresentationParams) (result []lsp.ColorPresentation, err error) { +func (h *ServerHandler) ColorPresentation(ctx context.Context, params *lsp.ColorPresentationParams) (result []lsp.ColorPresentation, err error) { logger.Error("Color presentation unimplemented") return nil, nil } // CompletionResolve implements protocol.Server. -func (h *langHandler) CompletionResolve(ctx context.Context, params *lsp.CompletionItem) (result *lsp.CompletionItem, err error) { +func (h *ServerHandler) CompletionResolve(ctx context.Context, params *lsp.CompletionItem) (result *lsp.CompletionItem, err error) { logger.Error("Completion resolve unimplemented") return nil, nil } // Declaration implements protocol.Server. -func (h *langHandler) Declaration(ctx context.Context, params *lsp.DeclarationParams) (result []lsp.Location, err error) { +func (h *ServerHandler) Declaration(ctx context.Context, params *lsp.DeclarationParams) (result []lsp.Location, err error) { logger.Error("Declaration unimplemented") return nil, nil } // DidChangeWorkspaceFolders implements protocol.Server. -func (h *langHandler) DidChangeWorkspaceFolders(ctx context.Context, params *lsp.DidChangeWorkspaceFoldersParams) (err error) { +func (h *ServerHandler) DidChangeWorkspaceFolders(ctx context.Context, params *lsp.DidChangeWorkspaceFoldersParams) (err error) { logger.Error("DidChangeWorkspaceFolders unimplemented") return nil } // DocumentColor implements protocol.Server. -func (h *langHandler) DocumentColor(ctx context.Context, params *lsp.DocumentColorParams) (result []lsp.ColorInformation, err error) { +func (h *ServerHandler) DocumentColor(ctx context.Context, params *lsp.DocumentColorParams) (result []lsp.ColorInformation, err error) { logger.Error("Document color unimplemented") return nil, nil } // DocumentHighlight implements protocol.Server. -func (h *langHandler) DocumentHighlight(ctx context.Context, params *lsp.DocumentHighlightParams) (result []lsp.DocumentHighlight, err error) { +func (h *ServerHandler) DocumentHighlight(ctx context.Context, params *lsp.DocumentHighlightParams) (result []lsp.DocumentHighlight, err error) { logger.Error("Document highlight unimplemented") return nil, nil } // DocumentLink implements protocol.Server. -func (h *langHandler) DocumentLink(ctx context.Context, params *lsp.DocumentLinkParams) (result []lsp.DocumentLink, err error) { +func (h *ServerHandler) DocumentLink(ctx context.Context, params *lsp.DocumentLinkParams) (result []lsp.DocumentLink, err error) { logger.Error("Document link unimplemented") return nil, nil } // DocumentLinkResolve implements protocol.Server. -func (h *langHandler) DocumentLinkResolve(ctx context.Context, params *lsp.DocumentLink) (result *lsp.DocumentLink, err error) { +func (h *ServerHandler) DocumentLinkResolve(ctx context.Context, params *lsp.DocumentLink) (result *lsp.DocumentLink, err error) { logger.Error("Document link resolve unimplemented") return nil, nil } // ExecuteCommand implements protocol.Server. -func (h *langHandler) ExecuteCommand(ctx context.Context, params *lsp.ExecuteCommandParams) (result interface{}, err error) { +func (h *ServerHandler) ExecuteCommand(ctx context.Context, params *lsp.ExecuteCommandParams) (result interface{}, err error) { logger.Error("Execute command unimplemented") return nil, nil } // Exit implements protocol.Server. -func (h *langHandler) Exit(ctx context.Context) (err error) { +func (h *ServerHandler) Exit(ctx context.Context) (err error) { return nil } // FoldingRanges implements protocol.Server. -func (h *langHandler) FoldingRanges(ctx context.Context, params *lsp.FoldingRangeParams) (result []lsp.FoldingRange, err error) { +func (h *ServerHandler) FoldingRanges(ctx context.Context, params *lsp.FoldingRangeParams) (result []lsp.FoldingRange, err error) { logger.Error("Folding ranges unimplemented") return nil, nil } // Formatting implements protocol.Server. -func (h *langHandler) Formatting(ctx context.Context, params *lsp.DocumentFormattingParams) (result []lsp.TextEdit, err error) { +func (h *ServerHandler) Formatting(ctx context.Context, params *lsp.DocumentFormattingParams) (result []lsp.TextEdit, err error) { logger.Error("Formatting unimplemented") return nil, nil } // Implementation implements protocol.Server. -func (h *langHandler) Implementation(ctx context.Context, params *lsp.ImplementationParams) (result []lsp.Location, err error) { +func (h *ServerHandler) Implementation(ctx context.Context, params *lsp.ImplementationParams) (result []lsp.Location, err error) { logger.Error("Implementation unimplemented") return nil, nil } // IncomingCalls implements protocol.Server. -func (h *langHandler) IncomingCalls(ctx context.Context, params *lsp.CallHierarchyIncomingCallsParams) (result []lsp.CallHierarchyIncomingCall, err error) { +func (h *ServerHandler) IncomingCalls(ctx context.Context, params *lsp.CallHierarchyIncomingCallsParams) (result []lsp.CallHierarchyIncomingCall, err error) { logger.Error("Incoming calls unimplemented") return nil, nil } // LinkedEditingRange implements protocol.Server. -func (h *langHandler) LinkedEditingRange(ctx context.Context, params *lsp.LinkedEditingRangeParams) (result *lsp.LinkedEditingRanges, err error) { +func (h *ServerHandler) LinkedEditingRange(ctx context.Context, params *lsp.LinkedEditingRangeParams) (result *lsp.LinkedEditingRanges, err error) { logger.Error("Linked editing range unimplemented") return nil, nil } // LogTrace implements protocol.Server. -func (h *langHandler) LogTrace(ctx context.Context, params *lsp.LogTraceParams) (err error) { +func (h *ServerHandler) LogTrace(ctx context.Context, params *lsp.LogTraceParams) (err error) { logger.Error("Log trace unimplemented") return nil } // Moniker implements protocol.Server. -func (h *langHandler) Moniker(ctx context.Context, params *lsp.MonikerParams) (result []lsp.Moniker, err error) { +func (h *ServerHandler) Moniker(ctx context.Context, params *lsp.MonikerParams) (result []lsp.Moniker, err error) { logger.Error("Moniker unimplemented") return nil, nil } // OnTypeFormatting implements protocol.Server. -func (h *langHandler) OnTypeFormatting(ctx context.Context, params *lsp.DocumentOnTypeFormattingParams) (result []lsp.TextEdit, err error) { +func (h *ServerHandler) OnTypeFormatting(ctx context.Context, params *lsp.DocumentOnTypeFormattingParams) (result []lsp.TextEdit, err error) { logger.Error("On type formatting unimplemented") return nil, nil } // OutgoingCalls implements protocol.Server. -func (h *langHandler) OutgoingCalls(ctx context.Context, params *lsp.CallHierarchyOutgoingCallsParams) (result []lsp.CallHierarchyOutgoingCall, err error) { +func (h *ServerHandler) OutgoingCalls(ctx context.Context, params *lsp.CallHierarchyOutgoingCallsParams) (result []lsp.CallHierarchyOutgoingCall, err error) { logger.Error("Outgoing calls unimplemented") return nil, nil } // PrepareCallHierarchy implements protocol.Server. -func (h *langHandler) PrepareCallHierarchy(ctx context.Context, params *lsp.CallHierarchyPrepareParams) (result []lsp.CallHierarchyItem, err error) { +func (h *ServerHandler) PrepareCallHierarchy(ctx context.Context, params *lsp.CallHierarchyPrepareParams) (result []lsp.CallHierarchyItem, err error) { logger.Error("Prepare call hierarchy unimplemented") return nil, nil } // PrepareRename implements protocol.Server. -func (h *langHandler) PrepareRename(ctx context.Context, params *lsp.PrepareRenameParams) (result *lsp.Range, err error) { +func (h *ServerHandler) PrepareRename(ctx context.Context, params *lsp.PrepareRenameParams) (result *lsp.Range, err error) { logger.Error("Prepare rename unimplemented") return nil, nil } // RangeFormatting implements protocol.Server. -func (h *langHandler) RangeFormatting(ctx context.Context, params *lsp.DocumentRangeFormattingParams) (result []lsp.TextEdit, err error) { +func (h *ServerHandler) RangeFormatting(ctx context.Context, params *lsp.DocumentRangeFormattingParams) (result []lsp.TextEdit, err error) { logger.Error("Range formatting unimplemented") return nil, nil } // Rename implements protocol.Server. -func (h *langHandler) Rename(ctx context.Context, params *lsp.RenameParams) (result *lsp.WorkspaceEdit, err error) { +func (h *ServerHandler) Rename(ctx context.Context, params *lsp.RenameParams) (result *lsp.WorkspaceEdit, err error) { logger.Error("Rename unimplemented") return nil, nil } // Request implements protocol.Server. -func (h *langHandler) Request(ctx context.Context, method string, params interface{}) (result interface{}, err error) { +func (h *ServerHandler) Request(ctx context.Context, method string, params interface{}) (result interface{}, err error) { logger.Error("Request unimplemented") return nil, nil } // SemanticTokensFull implements protocol.Server. -func (h *langHandler) SemanticTokensFull(ctx context.Context, params *lsp.SemanticTokensParams) (result *lsp.SemanticTokens, err error) { +func (h *ServerHandler) SemanticTokensFull(ctx context.Context, params *lsp.SemanticTokensParams) (result *lsp.SemanticTokens, err error) { logger.Error("Semantic tokens full unimplemented") return nil, nil } // SemanticTokensFullDelta implements protocol.Server. -func (h *langHandler) SemanticTokensFullDelta(ctx context.Context, params *lsp.SemanticTokensDeltaParams) (result interface{}, err error) { +func (h *ServerHandler) SemanticTokensFullDelta(ctx context.Context, params *lsp.SemanticTokensDeltaParams) (result interface{}, err error) { logger.Error("Semantic tokens full delta unimplemented") return nil, nil } // SemanticTokensRange implements protocol.Server. -func (h *langHandler) SemanticTokensRange(ctx context.Context, params *lsp.SemanticTokensRangeParams) (result *lsp.SemanticTokens, err error) { +func (h *ServerHandler) SemanticTokensRange(ctx context.Context, params *lsp.SemanticTokensRangeParams) (result *lsp.SemanticTokens, err error) { logger.Error("Semantic tokens range unimplemented") return nil, nil } // SemanticTokensRefresh implements protocol.Server. -func (h *langHandler) SemanticTokensRefresh(ctx context.Context) (err error) { +func (h *ServerHandler) SemanticTokensRefresh(ctx context.Context) (err error) { logger.Error("Semantic tokens refresh unimplemented") return nil } // SetTrace implements protocol.Server. -func (h *langHandler) SetTrace(ctx context.Context, params *lsp.SetTraceParams) (err error) { +func (h *ServerHandler) SetTrace(ctx context.Context, params *lsp.SetTraceParams) (err error) { logger.Error("Set trace unimplemented") return nil } // ShowDocument implements protocol.Server. -func (h *langHandler) ShowDocument(ctx context.Context, params *lsp.ShowDocumentParams) (result *lsp.ShowDocumentResult, err error) { +func (h *ServerHandler) ShowDocument(ctx context.Context, params *lsp.ShowDocumentParams) (result *lsp.ShowDocumentResult, err error) { logger.Error("Show document unimplemented") return nil, nil } // Shutdown implements protocol.Server. -func (h *langHandler) Shutdown(ctx context.Context) (err error) { +func (h *ServerHandler) Shutdown(ctx context.Context) (err error) { return h.connPool.Close() } // SignatureHelp implements protocol.Server. -func (h *langHandler) SignatureHelp(ctx context.Context, params *lsp.SignatureHelpParams) (result *lsp.SignatureHelp, err error) { +func (h *ServerHandler) SignatureHelp(ctx context.Context, params *lsp.SignatureHelpParams) (result *lsp.SignatureHelp, err error) { logger.Error("Signature help unimplemented") return nil, nil } // Symbols implements protocol.Server. -func (h *langHandler) Symbols(ctx context.Context, params *lsp.WorkspaceSymbolParams) (result []lsp.SymbolInformation, err error) { +func (h *ServerHandler) Symbols(ctx context.Context, params *lsp.WorkspaceSymbolParams) (result []lsp.SymbolInformation, err error) { logger.Error("Symbols unimplemented") return nil, nil } // TypeDefinition implements protocol.Server. -func (h *langHandler) TypeDefinition(ctx context.Context, params *lsp.TypeDefinitionParams) (result []lsp.Location, err error) { +func (h *ServerHandler) TypeDefinition(ctx context.Context, params *lsp.TypeDefinitionParams) (result []lsp.Location, err error) { logger.Error("Type definition unimplemented") return nil, nil } // WillCreateFiles implements protocol.Server. -func (h *langHandler) WillCreateFiles(ctx context.Context, params *lsp.CreateFilesParams) (result *lsp.WorkspaceEdit, err error) { +func (h *ServerHandler) WillCreateFiles(ctx context.Context, params *lsp.CreateFilesParams) (result *lsp.WorkspaceEdit, err error) { logger.Error("Will create files unimplemented") return nil, nil } // WillDeleteFiles implements protocol.Server. -func (h *langHandler) WillDeleteFiles(ctx context.Context, params *lsp.DeleteFilesParams) (result *lsp.WorkspaceEdit, err error) { +func (h *ServerHandler) WillDeleteFiles(ctx context.Context, params *lsp.DeleteFilesParams) (result *lsp.WorkspaceEdit, err error) { logger.Error("Will delete files unimplemented") return nil, nil } // WillRenameFiles implements protocol.Server. -func (h *langHandler) WillRenameFiles(ctx context.Context, params *lsp.RenameFilesParams) (result *lsp.WorkspaceEdit, err error) { +func (h *ServerHandler) WillRenameFiles(ctx context.Context, params *lsp.RenameFilesParams) (result *lsp.WorkspaceEdit, err error) { logger.Error("Will rename files unimplemented") return nil, nil } // WillSave implements protocol.Server. -func (h *langHandler) WillSave(ctx context.Context, params *lsp.WillSaveTextDocumentParams) (err error) { +func (h *ServerHandler) WillSave(ctx context.Context, params *lsp.WillSaveTextDocumentParams) (err error) { logger.Error("Will save unimplemented") return nil } // WillSaveWaitUntil implements protocol.Server. -func (h *langHandler) WillSaveWaitUntil(ctx context.Context, params *lsp.WillSaveTextDocumentParams) (result []lsp.TextEdit, err error) { +func (h *ServerHandler) WillSaveWaitUntil(ctx context.Context, params *lsp.WillSaveTextDocumentParams) (result []lsp.TextEdit, err error) { logger.Error("Will save wait until unimplemented") return nil, nil } // WorkDoneProgressCancel implements protocol.Server. -func (h *langHandler) WorkDoneProgressCancel(ctx context.Context, params *lsp.WorkDoneProgressCancelParams) (err error) { +func (h *ServerHandler) WorkDoneProgressCancel(ctx context.Context, params *lsp.WorkDoneProgressCancelParams) (err error) { logger.Error("Work done progress cancel unimplemented") return nil } diff --git a/internal/handler/hover.go b/internal/handler/hover.go index 7c60374a..e236ea62 100644 --- a/internal/handler/hover.go +++ b/internal/handler/hover.go @@ -11,7 +11,7 @@ import ( lsp "go.lsp.dev/protocol" ) -func (h *langHandler) Hover(ctx context.Context, params *lsp.HoverParams) (result *lsp.Hover, err error) { +func (h *ServerHandler) Hover(ctx context.Context, params *lsp.HoverParams) (result *lsp.Hover, err error) { genericDocumentUseCase, err := h.NewGenericDocumentUseCase(params.TextDocumentPositionParams, lsplocal.NodeAtPosition) if err != nil { return nil, err diff --git a/internal/handler/initialization.go b/internal/handler/initialization.go index c7fd35d5..699bcf65 100644 --- a/internal/handler/initialization.go +++ b/internal/handler/initialization.go @@ -13,7 +13,7 @@ import ( "go.lsp.dev/uri" ) -func (h *langHandler) Initialize(ctx context.Context, params *lsp.InitializeParams) (result *lsp.InitializeResult, err error) { +func (h *ServerHandler) Initialize(ctx context.Context, params *lsp.InitializeParams) (result *lsp.InitializeResult, err error) { var workspaceURI uri.URI if len(params.WorkspaceFolders) != 0 { @@ -51,18 +51,18 @@ func (h *langHandler) Initialize(ctx context.Context, params *lsp.InitializePara }, nil } -func (h *langHandler) Initialized(ctx context.Context, _ *lsp.InitializedParams) (err error) { +func (h *ServerHandler) Initialized(ctx context.Context, _ *lsp.InitializedParams) (err error) { h.retrieveWorkspaceConfiguration(ctx) return nil } -func (h *langHandler) initializationWithConfig(ctx context.Context) { +func (h *ServerHandler) initializationWithConfig(ctx context.Context) { configureLogLevel(h.helmlsConfig) h.chartStore.SetValuesFilesConfig(h.helmlsConfig.ValuesFilesConfig) h.configureYamlls(ctx) } -func (h *langHandler) configureYamlsEnabledGlob() { +func (h *ServerHandler) configureYamlsEnabledGlob() { globObject, err := glob.Compile(h.helmlsConfig.YamllsConfiguration.EnabledForFilesGlob) if err != nil { logger.Error("Error compiling glob for yamlls EnabledForFilesGlob", err) @@ -71,7 +71,7 @@ func (h *langHandler) configureYamlsEnabledGlob() { h.helmlsConfig.YamllsConfiguration.EnabledForFilesGlobObject = globObject } -func (h *langHandler) configureYamlls(ctx context.Context) { +func (h *ServerHandler) configureYamlls(ctx context.Context) { config := h.helmlsConfig if config.YamllsConfiguration.Enabled { h.configureYamlsEnabledGlob() @@ -96,7 +96,7 @@ func configureLogLevel(helmlsConfig util.HelmlsConfiguration) { } } -func (h *langHandler) AddChartCallback(chart *charts.Chart) { +func (h *ServerHandler) AddChartCallback(chart *charts.Chart) { h.NewChartWithWatchedFiles(chart) go h.LoadDocsOnNewChart(chart) } diff --git a/internal/handler/lang_handler.go b/internal/handler/lang_handler.go new file mode 100644 index 00000000..1502a1f9 --- /dev/null +++ b/internal/handler/lang_handler.go @@ -0,0 +1,18 @@ +package handler + +import ( + "context" + + lsp "go.lsp.dev/protocol" +) + +type LangHandler interface { + Completion(ctx context.Context, params *lsp.CompletionParams) (result *lsp.CompletionList, err error) + References(ctx context.Context, params *lsp.ReferenceParams) (result []lsp.Location, err error) +} + +func (h *ServerHandler) selectLangHandler(ctx context.Context, params *lsp.TextDocumentPositionParams) (LangHandler, error) { + langID := h.documents.GetLanguageID(params.TextDocument.URI) + + return h.langHandlers[langID], nil +} diff --git a/internal/handler/references.go b/internal/handler/references.go index 542ffe95..499b6b95 100644 --- a/internal/handler/references.go +++ b/internal/handler/references.go @@ -8,7 +8,7 @@ import ( lsp "go.lsp.dev/protocol" ) -func (h *langHandler) References(_ context.Context, params *lsp.ReferenceParams) (result []lsp.Location, err error) { +func (h *ServerHandler) 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/symbol.go b/internal/handler/symbol.go index 29886bdc..90a13a06 100644 --- a/internal/handler/symbol.go +++ b/internal/handler/symbol.go @@ -7,6 +7,6 @@ import ( ) // DocumentSymbol implements protocol.Server. -func (h *langHandler) DocumentSymbol(ctx context.Context, params *lsp.DocumentSymbolParams) (result []interface{}, err error) { +func (h *ServerHandler) DocumentSymbol(ctx context.Context, params *lsp.DocumentSymbolParams) (result []interface{}, err error) { return h.yamllsConnector.CallDocumentSymbol(ctx, params) } diff --git a/internal/handler/template_handler/completion.go b/internal/handler/template_handler/completion.go new file mode 100644 index 00000000..4dba2592 --- /dev/null +++ b/internal/handler/template_handler/completion.go @@ -0,0 +1,46 @@ +package templatehandler + +import ( + "context" + + languagefeatures "github.com/mrjosh/helm-ls/internal/language_features" + lsplocal "github.com/mrjosh/helm-ls/internal/lsp" + "github.com/mrjosh/helm-ls/internal/protocol" + lsp "go.lsp.dev/protocol" + + helmdocs "github.com/mrjosh/helm-ls/internal/documentation/helm" +) + +func (h *TemplateHandler) 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, lsplocal.NestedNodeAtPositionForCompletion) + if err != nil { + return nil, err + } + + usecases := []languagefeatures.CompletionUseCase{ + languagefeatures.NewTemplateContextFeature(genericDocumentUseCase), + languagefeatures.NewFunctionCallFeature(genericDocumentUseCase), + languagefeatures.NewTextFeature(ctx, genericDocumentUseCase, h.yamllsConnector, ¶ms.TextDocumentPositionParams), + languagefeatures.NewIncludesCallFeature(genericDocumentUseCase), + } + + for _, usecase := range usecases { + if usecase.AppropriateForNode() { + return usecase.Completion() + } + } + + // If no usecase matched, we assume we are at {{ }} + // and provide the basic BuiltInObjects and functions + items := []helmdocs.HelmDocumentation{} + for _, v := range helmdocs.BuiltInObjects { + v.Name = "." + v.Name + items = append(items, v) + } + + 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/template_handler/completion_main_test.go similarity index 96% rename from internal/handler/completion_main_test.go rename to internal/handler/template_handler/completion_main_test.go index b64c33ca..2107e94a 100644 --- a/internal/handler/completion_main_test.go +++ b/internal/handler/template_handler/completion_main_test.go @@ -1,4 +1,4 @@ -package handler +package templatehandler import ( "context" @@ -129,7 +129,7 @@ func TestCompletionMain(t *testing.T) { } for _, tt := range testCases { t.Run(tt.desc, func(t *testing.T) { - path := "../../testdata/example/templates/completion-test.yaml" + path := "../../../testdata/example/templates/completion-test.yaml" fileURI := uri.File(path) content, err := os.ReadFile(path) @@ -189,8 +189,8 @@ func TestCompletionMainSingleLines(t *testing.T) { t.Run(tt.templateWithMark, func(t *testing.T) { pos, buf := getPositionForMarkedTestLine(tt.templateWithMark) - // to get the correct values file ../../testdata/example/values.yaml - fileURI := uri.File("../../testdata/example/templates/completion-test.yaml") + // to get the correct values file ../../../testdata/example/values.yaml + fileURI := uri.File("../../../testdata/example/templates/completion-test.yaml") result, err := completionTestCall(fileURI, buf, pos) assert.NotNil(t, result) @@ -226,7 +226,7 @@ func completionTestCall(fileURI uri.URI, buf string, pos lsp.Position) (*lsp.Com }, } documents.DidOpenTemplateDocument(&d, util.DefaultConfig) - h := &langHandler{ + h := &TemplateHandler{ chartStore: charts.NewChartStore(uri.File("."), charts.NewChart, func(chart *charts.Chart) {}), documents: documents, yamllsConnector: &yamlls.Connector{}, diff --git a/internal/handler/template_handler/definition.go b/internal/handler/template_handler/definition.go new file mode 100644 index 00000000..53d5fdb9 --- /dev/null +++ b/internal/handler/template_handler/definition.go @@ -0,0 +1,32 @@ +package templatehandler + +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 *TemplateHandler) Definition(_ context.Context, params *lsp.DefinitionParams) (result []lsp.Location, err error) { + genericDocumentUseCase, err := h.NewGenericDocumentUseCase(params.TextDocumentPositionParams, lsplocal.NodeAtPosition) + if err != nil { + return nil, err + } + + usecases := []languagefeatures.DefinitionUseCase{ + languagefeatures.NewBuiltInObjectsFeature(genericDocumentUseCase), // has to be before template context + languagefeatures.NewVariablesFeature(genericDocumentUseCase), + languagefeatures.NewTemplateContextFeature(genericDocumentUseCase), + languagefeatures.NewIncludesCallFeature(genericDocumentUseCase), + } + + for _, usecase := range usecases { + if usecase.AppropriateForNode() { + result, err := usecase.Definition() + return result, err + } + } + + return nil, nil +} diff --git a/internal/handler/definition_chart_test.go b/internal/handler/template_handler/definition_chart_test.go similarity index 93% rename from internal/handler/definition_chart_test.go rename to internal/handler/template_handler/definition_chart_test.go index 1de28335..401901c4 100644 --- a/internal/handler/definition_chart_test.go +++ b/internal/handler/template_handler/definition_chart_test.go @@ -1,4 +1,4 @@ -package handler +package templatehandler import ( "context" @@ -18,9 +18,9 @@ import ( ) var ( - rootUri = uri.File("../../testdata/dependenciesExample/") - fileURI = uri.File("../../testdata/dependenciesExample/templates/deployment.yaml") - fileURIInSubchart = uri.File("../../testdata/dependenciesExample/charts/subchartexample/templates/subchart.yaml") + rootUri = uri.File("../../../testdata/dependenciesExample/") + fileURI = uri.File("../../../testdata/dependenciesExample/templates/deployment.yaml") + fileURIInSubchart = uri.File("../../../testdata/dependenciesExample/charts/subchartexample/templates/subchart.yaml") ) type testCase struct { @@ -167,16 +167,15 @@ func TestDefinitionChart(t *testing.T) { addChartCallback := func(chart *charts.Chart) {} chartStore := charts.NewChartStore(rootUri, charts.NewChart, addChartCallback) _, err = chartStore.GetChartForURI(rootUri) - h := &langHandler{ + h := &TemplateHandler{ chartStore: chartStore, documents: documents, yamllsConnector: &yamlls.Connector{}, - helmlsConfig: util.DefaultConfig, } assert.NoError(t, err) - h.LoadDocsOnNewChart(chart) + documents.LoadDocsOnNewChart(chart, util.DefaultConfig) locations, err := h.Definition(context.TODO(), &lsp.DefinitionParams{ TextDocumentPositionParams: lsp.TextDocumentPositionParams{ diff --git a/internal/handler/definition_test.go b/internal/handler/template_handler/definition_test.go similarity index 99% rename from internal/handler/definition_test.go rename to internal/handler/template_handler/definition_test.go index f64e758e..3d4c4704 100644 --- a/internal/handler/definition_test.go +++ b/internal/handler/template_handler/definition_test.go @@ -1,4 +1,4 @@ -package handler +package templatehandler import ( "context" @@ -82,7 +82,7 @@ func genericDefinitionTest(t *testing.T, position lsp.Position, expectedLocation documents.DidOpenTemplateDocument(&d, util.DefaultConfig) chartStore := charts.NewChartStore(rootUri, charts.NewChart, addChartCallback) chartStore.Charts = map[uri.URI]*charts.Chart{rootUri: testChart} - h := &langHandler{ + h := &TemplateHandler{ chartStore: chartStore, documents: documents, yamllsConnector: &yamlls.Connector{}, @@ -277,7 +277,7 @@ func genericDefinitionTestMultipleValuesFiles(t *testing.T, position lsp.Positio documents.DidOpenTemplateDocument(&d, util.DefaultConfig) chartStore := charts.NewChartStore(rootUri, charts.NewChart, addChartCallback) chartStore.Charts = map[uri.URI]*charts.Chart{rootUri: chart} - h := &langHandler{ + h := &TemplateHandler{ chartStore: chartStore, documents: documents, yamllsConnector: &yamlls.Connector{}, @@ -367,7 +367,7 @@ func TestDefinitionSingleLine(t *testing.T) { }, } documents.DidOpenTemplateDocument(&d, util.DefaultConfig) - h := &langHandler{ + h := &TemplateHandler{ chartStore: charts.NewChartStore(rootUri, charts.NewChart, addChartCallback), documents: documents, } diff --git a/internal/handler/generic_document_usecase.go b/internal/handler/template_handler/generic_document_usecase.go similarity index 94% rename from internal/handler/generic_document_usecase.go rename to internal/handler/template_handler/generic_document_usecase.go index 3b97fa06..3ca8e7ca 100644 --- a/internal/handler/generic_document_usecase.go +++ b/internal/handler/template_handler/generic_document_usecase.go @@ -1,4 +1,4 @@ -package handler +package templatehandler import ( "errors" @@ -8,7 +8,7 @@ import ( lsp "go.lsp.dev/protocol" ) -func (h *langHandler) NewGenericDocumentUseCase( +func (h *TemplateHandler) NewGenericDocumentUseCase( params lsp.TextDocumentPositionParams, nodeSelection func(ast *sitter.Tree, position lsp.Position) (node *sitter.Node), ) (*languagefeatures.GenericDocumentUseCase, error) { diff --git a/internal/handler/helpers_test.go b/internal/handler/template_handler/helpers_test.go similarity index 93% rename from internal/handler/helpers_test.go rename to internal/handler/template_handler/helpers_test.go index f9fd365f..0209d38a 100644 --- a/internal/handler/helpers_test.go +++ b/internal/handler/template_handler/helpers_test.go @@ -1,4 +1,4 @@ -package handler +package templatehandler import ( "strings" diff --git a/internal/handler/template_handler/hover.go b/internal/handler/template_handler/hover.go new file mode 100644 index 00000000..7a256255 --- /dev/null +++ b/internal/handler/template_handler/hover.go @@ -0,0 +1,43 @@ +package templatehandler + +import ( + "context" + + languagefeatures "github.com/mrjosh/helm-ls/internal/language_features" + lsplocal "github.com/mrjosh/helm-ls/internal/lsp" + "github.com/mrjosh/helm-ls/internal/protocol" + "github.com/mrjosh/helm-ls/internal/tree-sitter/gotemplate" + + lsp "go.lsp.dev/protocol" +) + +func (h *TemplateHandler) Hover(ctx context.Context, params *lsp.HoverParams) (result *lsp.Hover, err error) { + genericDocumentUseCase, err := h.NewGenericDocumentUseCase(params.TextDocumentPositionParams, lsplocal.NodeAtPosition) + if err != nil { + return nil, err + } + + wordRange := lsplocal.GetLspRangeForNode(genericDocumentUseCase.Node) + + usecases := []languagefeatures.HoverUseCase{ + languagefeatures.NewBuiltInObjectsFeature(genericDocumentUseCase), // has to be before template context + languagefeatures.NewTemplateContextFeature(genericDocumentUseCase), + languagefeatures.NewIncludesCallFeature(genericDocumentUseCase), + languagefeatures.NewFunctionCallFeature(genericDocumentUseCase), + } + + for _, usecase := range usecases { + if usecase.AppropriateForNode() { + result, err := usecase.Hover() + return protocol.BuildHoverResponse(result, wordRange), err + } + } + + if genericDocumentUseCase.NodeType == gotemplate.NodeTypeText { + word := genericDocumentUseCase.Document.WordAt(params.Position) + response, err := h.yamllsConnector.CallHover(ctx, *params, word) + return response, err + } + + return nil, err +} diff --git a/internal/handler/hover_main_test.go b/internal/handler/template_handler/hover_main_test.go similarity index 82% rename from internal/handler/hover_main_test.go rename to internal/handler/template_handler/hover_main_test.go index d722de2f..1bb1d603 100644 --- a/internal/handler/hover_main_test.go +++ b/internal/handler/template_handler/hover_main_test.go @@ -1,4 +1,4 @@ -package handler +package templatehandler import ( "context" @@ -30,7 +30,7 @@ func TestHoverMain(t *testing.T) { Line: 85, Character: 26, }, - expected: fmt.Sprintf("### %s\n%s\n", filepath.Join("..", "..", "testdata", "example", "values.yaml"), "```yaml\nvalue\n```"), + expected: fmt.Sprintf("### %s\n%s\n", filepath.Join("..", "..", "..", "testdata", "example", "values.yaml"), "```yaml\nvalue\n```"), expectedError: nil, }, { @@ -39,7 +39,7 @@ func TestHoverMain(t *testing.T) { Line: 74, Character: 50, }, - expected: fmt.Sprintf("### %s\n%s\n", filepath.Join("..", "..", "testdata", "example", "values.yaml"), "```yaml\nfirst:\n some: value\nsecond:\n some: value\n```"), + expected: fmt.Sprintf("### %s\n%s\n", filepath.Join("..", "..", "..", "testdata", "example", "values.yaml"), "```yaml\nfirst:\n some: value\nsecond:\n some: value\n```"), expectedError: nil, }, { @@ -48,7 +48,7 @@ func TestHoverMain(t *testing.T) { Line: 80, Character: 31, }, - expected: fmt.Sprintf("### %s\n%s\n", filepath.Join("..", "..", "testdata", "example", "values.yaml"), "```yaml\nvalue\n```"), + expected: fmt.Sprintf("### %s\n%s\n", filepath.Join("..", "..", "..", "testdata", "example", "values.yaml"), "```yaml\nvalue\n```"), expectedError: nil, }, { @@ -57,7 +57,7 @@ func TestHoverMain(t *testing.T) { Line: 17, Character: 19, }, - expected: fmt.Sprintf("### %s\n%s\n", filepath.Join("..", "..", "testdata", "example", "values.yaml"), "```yaml\n{}\n```"), + expected: fmt.Sprintf("### %s\n%s\n", filepath.Join("..", "..", "..", "testdata", "example", "values.yaml"), "```yaml\n{}\n```"), expectedError: nil, }, { @@ -84,7 +84,7 @@ func TestHoverMain(t *testing.T) { Line: 25, Character: 28, }, - expected: fmt.Sprintf("### %s\n%s\n", filepath.Join("..", "..", "testdata", "example", "values.yaml"), "```yaml\nimagePullSecrets: []\n```"), + expected: fmt.Sprintf("### %s\n%s\n", filepath.Join("..", "..", "..", "testdata", "example", "values.yaml"), "```yaml\nimagePullSecrets: []\n```"), expectedError: nil, }, { @@ -129,7 +129,7 @@ func TestHoverMain(t *testing.T) { Line: 71, Character: 35, }, - expected: fmt.Sprintf("### %s\n%s\n", filepath.Join("..", "..", "testdata", "example", "values.yaml"), "```yaml\ningress.hosts:\n- host: chart-example.local\n paths:\n - path: /\n pathType: ImplementationSpecific\n```"), + expected: fmt.Sprintf("### %s\n%s\n", filepath.Join("..", "..", "..", "testdata", "example", "values.yaml"), "```yaml\ningress.hosts:\n- host: chart-example.local\n paths:\n - path: /\n pathType: ImplementationSpecific\n```"), expectedError: nil, }, { @@ -138,7 +138,7 @@ func TestHoverMain(t *testing.T) { Line: 8, Character: 28, }, - expected: fmt.Sprintf("### %s\n%s\n", filepath.Join("..", "..", "testdata", "example", "values.yaml"), "```yaml\n1\n```"), + expected: fmt.Sprintf("### %s\n%s\n", filepath.Join("..", "..", "..", "testdata", "example", "values.yaml"), "```yaml\n1\n```"), expectedError: nil, }, { @@ -167,7 +167,7 @@ func TestHoverMain(t *testing.T) { t.Run(tt.desc, func(t *testing.T) { documents := lsplocal.NewDocumentStore() - path := "../../testdata/example/templates/deployment.yaml" + path := "../../../testdata/example/templates/deployment.yaml" fileURI := uri.File(path) content, err := os.ReadFile(path) @@ -184,15 +184,17 @@ func TestHoverMain(t *testing.T) { } documents.DidOpenTemplateDocument(&d, util.DefaultConfig) - h := &langHandler{ - chartStore: charts.NewChartStore(uri.File("."), charts.NewChart, addChartCallback), + chart_store := charts.NewChartStore(uri.File("."), charts.NewChart, addChartCallback) + h := &TemplateHandler{ + chartStore: chart_store, documents: documents, yamllsConnector: &yamlls.Connector{}, - helmlsConfig: util.DefaultConfig, } - h.chartStore = charts.NewChartStore(uri.File("."), charts.NewChart, h.AddChartCallback) + h.chartStore = charts.NewChartStore(uri.File("."), charts.NewChart, func(chart *charts.Chart) { + documents.LoadDocsOnNewChart(chart, util.DefaultConfig) + }) chart, _ := h.chartStore.GetChartOrParentForDoc(fileURI) - h.LoadDocsOnNewChart(chart) + documents.LoadDocsOnNewChart(chart, util.DefaultConfig) result, err := h.Hover(context.Background(), &lsp.HoverParams{ TextDocumentPositionParams: lsp.TextDocumentPositionParams{ TextDocument: lsp.TextDocumentIdentifier{ diff --git a/internal/handler/template_handler/references.go b/internal/handler/template_handler/references.go new file mode 100644 index 00000000..8869966e --- /dev/null +++ b/internal/handler/template_handler/references.go @@ -0,0 +1,31 @@ +package templatehandler + +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 *TemplateHandler) 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 + } + + usecases := []languagefeatures.ReferencesUseCase{ + languagefeatures.NewIncludesDefinitionFeature(genericDocumentUseCase), + languagefeatures.NewIncludesCallFeature(genericDocumentUseCase), + languagefeatures.NewTemplateContextFeature(genericDocumentUseCase), + languagefeatures.NewVariablesFeature(genericDocumentUseCase), + } + + for _, usecase := range usecases { + if usecase.AppropriateForNode() { + return usecase.References() + } + } + + return nil, nil +} diff --git a/internal/handler/references_test.go b/internal/handler/template_handler/references_test.go similarity index 97% rename from internal/handler/references_test.go rename to internal/handler/template_handler/references_test.go index 7e9f2b5a..3daa783f 100644 --- a/internal/handler/references_test.go +++ b/internal/handler/template_handler/references_test.go @@ -1,4 +1,4 @@ -package handler +package templatehandler import ( "context" @@ -95,7 +95,7 @@ func TestRefercesTemplateContext(t *testing.T) { }, } documents.DidOpenTemplateDocument(&d, util.DefaultConfig) - h := &langHandler{ + h := &TemplateHandler{ chartStore: charts.NewChartStore(uri.File("."), charts.NewChart, addChartCallback), documents: documents, yamllsConnector: &yamlls.Connector{}, @@ -145,7 +145,7 @@ func TestRefercesTemplateContextWithTestFile(t *testing.T) { t.Run(tt.desc, func(t *testing.T) { documents := lsplocal.NewDocumentStore() - path := "../../testdata/example/templates/deployment.yaml" + path := "../../../testdata/example/templates/deployment.yaml" fileURI := uri.File(path) content, err := os.ReadFile(path) @@ -162,7 +162,7 @@ func TestRefercesTemplateContextWithTestFile(t *testing.T) { }, } documents.DidOpenTemplateDocument(&d, util.DefaultConfig) - h := &langHandler{ + h := &TemplateHandler{ chartStore: charts.NewChartStore(uri.File("."), charts.NewChart, addChartCallback), documents: documents, yamllsConnector: &yamlls.Connector{}, @@ -220,7 +220,7 @@ func TestRefercesSingleLines(t *testing.T) { }, } documents.DidOpenTemplateDocument(&d, util.DefaultConfig) - h := &langHandler{ + h := &TemplateHandler{ chartStore: charts.NewChartStore(uri.File("."), charts.NewChart, addChartCallback), documents: documents, yamllsConnector: &yamlls.Connector{}, diff --git a/internal/handler/template_handler/symbol.go b/internal/handler/template_handler/symbol.go new file mode 100644 index 00000000..f9570396 --- /dev/null +++ b/internal/handler/template_handler/symbol.go @@ -0,0 +1,12 @@ +package templatehandler + +import ( + "context" + + lsp "go.lsp.dev/protocol" +) + +// DocumentSymbol implements protocol.Server. +func (h *TemplateHandler) DocumentSymbol(ctx context.Context, params *lsp.DocumentSymbolParams) (result []interface{}, err error) { + return h.yamllsConnector.CallDocumentSymbol(ctx, params) +} diff --git a/internal/handler/template_handler/template_handler.go b/internal/handler/template_handler/template_handler.go new file mode 100644 index 00000000..de8528a8 --- /dev/null +++ b/internal/handler/template_handler/template_handler.go @@ -0,0 +1,16 @@ +package templatehandler + +import ( + "github.com/mrjosh/helm-ls/internal/adapter/yamlls" + "github.com/mrjosh/helm-ls/internal/charts" + "github.com/mrjosh/helm-ls/internal/log" + lsplocal "github.com/mrjosh/helm-ls/internal/lsp" +) + +var logger = log.GetLogger() + +type TemplateHandler struct { + documents *lsplocal.DocumentStore + chartStore *charts.ChartStore + yamllsConnector *yamlls.Connector +} diff --git a/internal/handler/text_document.go b/internal/handler/text_document.go index a56dc969..f8db1345 100644 --- a/internal/handler/text_document.go +++ b/internal/handler/text_document.go @@ -3,8 +3,6 @@ package handler import ( "context" "errors" - "fmt" - "path/filepath" "github.com/mrjosh/helm-ls/internal/charts" helmlint "github.com/mrjosh/helm-ls/internal/helm_lint" @@ -12,7 +10,7 @@ import ( lsp "go.lsp.dev/protocol" ) -func (h *langHandler) DidOpen(ctx context.Context, params *lsp.DidOpenTextDocumentParams) (err error) { +func (h *ServerHandler) DidOpen(ctx context.Context, params *lsp.DidOpenTextDocumentParams) (err error) { if lsplocal.IsTemplateDocumentLangID(params.TextDocument.LanguageID) { doc, err := h.documents.DidOpenTemplateDocument(params, h.helmlsConfig) if err != nil { @@ -34,11 +32,11 @@ func (h *langHandler) DidOpen(ctx context.Context, params *lsp.DidOpenTextDocume return nil } -func (h *langHandler) DidClose(_ context.Context, _ *lsp.DidCloseTextDocumentParams) (err error) { +func (h *ServerHandler) DidClose(_ context.Context, _ *lsp.DidCloseTextDocumentParams) (err error) { return nil } -func (h *langHandler) DidSave(ctx context.Context, params *lsp.DidSaveTextDocumentParams) (err error) { +func (h *ServerHandler) DidSave(ctx context.Context, params *lsp.DidSaveTextDocumentParams) (err error) { doc, ok := h.documents.GetTemplateDoc(params.TextDocument.URI) if !ok { return errors.New("Could not get document: " + params.TextDocument.URI.Filename()) @@ -56,7 +54,7 @@ func (h *langHandler) DidSave(ctx context.Context, params *lsp.DidSaveTextDocume return nil } -func (h *langHandler) DidChange(_ context.Context, params *lsp.DidChangeTextDocumentParams) (err error) { +func (h *ServerHandler) DidChange(_ context.Context, params *lsp.DidChangeTextDocumentParams) (err error) { doc, ok := h.documents.GetTemplateDoc(params.TextDocument.URI) if !ok { return errors.New("Could not get document: " + params.TextDocument.URI.Filename()) @@ -82,34 +80,23 @@ func (h *langHandler) DidChange(_ context.Context, params *lsp.DidChangeTextDocu return nil } -func (h *langHandler) DidCreateFiles(ctx context.Context, params *lsp.CreateFilesParams) (err error) { +func (h *ServerHandler) DidCreateFiles(ctx context.Context, params *lsp.CreateFilesParams) (err error) { logger.Error("DidCreateFiles unimplemented") return nil } // DidDeleteFiles implements protocol.Server. -func (h *langHandler) DidDeleteFiles(ctx context.Context, params *lsp.DeleteFilesParams) (err error) { +func (h *ServerHandler) DidDeleteFiles(ctx context.Context, params *lsp.DeleteFilesParams) (err error) { logger.Error("DidDeleteFiles unimplemented") return nil } // DidRenameFiles implements protocol.Server. -func (h *langHandler) DidRenameFiles(ctx context.Context, params *lsp.RenameFilesParams) (err error) { +func (h *ServerHandler) DidRenameFiles(ctx context.Context, params *lsp.RenameFilesParams) (err error) { logger.Error("DidRenameFiles unimplemented") return nil } -func (h *langHandler) LoadDocsOnNewChart(chart *charts.Chart) { - if chart.HelmChart == nil { - return - } - - for _, file := range chart.HelmChart.Templates { - h.documents.StoreTemplateDocument(filepath.Join(chart.RootURI.Filename(), file.Name), file.Data, h.helmlsConfig) - } - - for _, file := range chart.GetDependeciesTemplates() { - logger.Debug(fmt.Sprintf("Storing dependency %s", file.Path)) - h.documents.StoreTemplateDocument(file.Path, file.Content, h.helmlsConfig) - } +func (h *ServerHandler) LoadDocsOnNewChart(chart *charts.Chart) { + h.documents.LoadDocsOnNewChart(chart, h.helmlsConfig) } diff --git a/internal/handler/text_document_test.go b/internal/handler/text_document_test.go index 59b4d08f..4771f843 100644 --- a/internal/handler/text_document_test.go +++ b/internal/handler/text_document_test.go @@ -31,7 +31,7 @@ func TestLoadDocsOnNewChart(t *testing.T) { assert.NoError(t, err) } - h := &langHandler{ + h := &ServerHandler{ documents: lsplocal.NewDocumentStore(), helmlsConfig: util.DefaultConfig, } @@ -60,7 +60,7 @@ func TestLoadDocsOnNewChartDoesNotOverwrite(t *testing.T) { assert.NoError(t, err) docs := lsplocal.NewDocumentStore() - h := &langHandler{ + h := &ServerHandler{ documents: docs, helmlsConfig: util.DefaultConfig, } @@ -85,7 +85,7 @@ func TestLoadDocsOnNewChartWorksForMissingTemplateDir(t *testing.T) { rootURI := uri.File(tempDir) docs := lsplocal.NewDocumentStore() - h := &langHandler{ + h := &ServerHandler{ documents: docs, helmlsConfig: util.DefaultConfig, } diff --git a/internal/handler/watched_files.go b/internal/handler/watched_files.go index 3acd9504..7a9bb19b 100644 --- a/internal/handler/watched_files.go +++ b/internal/handler/watched_files.go @@ -10,7 +10,7 @@ import ( "go.lsp.dev/jsonrpc2" ) -func (h *langHandler) NewChartWithWatchedFiles(chart *charts.Chart) { +func (h *ServerHandler) NewChartWithWatchedFiles(chart *charts.Chart) { logger.Debug("NewChartWithWatchedFiles ", chart.RootURI) uris := make([]uri.URI, 0) @@ -21,7 +21,7 @@ func (h *langHandler) NewChartWithWatchedFiles(chart *charts.Chart) { go h.RegisterWatchedFiles(context.Background(), h.connPool, uris) } -func (h *langHandler) RegisterWatchedFiles(ctx context.Context, conn jsonrpc2.Conn, files []uri.URI) { +func (h *ServerHandler) RegisterWatchedFiles(ctx context.Context, conn jsonrpc2.Conn, files []uri.URI) { if conn == nil { return } @@ -49,7 +49,7 @@ func (h *langHandler) RegisterWatchedFiles(ctx context.Context, conn jsonrpc2.Co } } -func (h *langHandler) DidChangeWatchedFiles(ctx context.Context, params *lsp.DidChangeWatchedFilesParams) (err error) { +func (h *ServerHandler) DidChangeWatchedFiles(ctx context.Context, params *lsp.DidChangeWatchedFilesParams) (err error) { for _, change := range params.Changes { h.chartStore.ReloadValuesFile(change.URI) } diff --git a/internal/lsp/document_store.go b/internal/lsp/document_store.go index f6819430..927cd557 100644 --- a/internal/lsp/document_store.go +++ b/internal/lsp/document_store.go @@ -2,8 +2,10 @@ package lsp import ( "fmt" + "path/filepath" "sync" + "github.com/mrjosh/helm-ls/internal/charts" "github.com/mrjosh/helm-ls/internal/util" lsp "go.lsp.dev/protocol" "go.lsp.dev/uri" @@ -81,3 +83,18 @@ func (s *DocumentStore) GetAllTemplateDocs() []*TemplateDocument { }) return docs } + +func (s *DocumentStore) LoadDocsOnNewChart(chart *charts.Chart, helmlsConfig util.HelmlsConfiguration) { + if chart.HelmChart == nil { + return + } + + for _, file := range chart.HelmChart.Templates { + s.StoreTemplateDocument(filepath.Join(chart.RootURI.Filename(), file.Name), file.Data, helmlsConfig) + } + + for _, file := range chart.GetDependeciesTemplates() { + logger.Debug(fmt.Sprintf("Storing dependency %s", file.Path)) + s.StoreTemplateDocument(file.Path, file.Content, helmlsConfig) + } +} From e328687f7cf2409f96806ee00b1efeb585183404 Mon Sep 17 00:00:00 2001 From: qvalentin Date: Sun, 6 Oct 2024 18:34:34 +0200 Subject: [PATCH 08/16] feat: selectLangHandler --- internal/handler/completion.go | 11 +++-- internal/handler/configuration_test.go | 5 ++- internal/handler/definition.go | 25 +++-------- internal/handler/handler.go | 25 ++++++++++- internal/handler/hover.go | 34 ++------------ internal/handler/initialization.go | 4 +- internal/handler/lang_handler.go | 20 +++++++-- internal/handler/references.go | 24 +++------- internal/handler/symbol.go | 8 +++- .../template_handler/hover_main_test.go | 4 +- .../template_handler/template_handler.go | 16 +++++++ internal/lsp/document.go | 22 +++++++--- internal/lsp/document_store.go | 44 +++++++++++-------- internal/lsp/template_document.go | 4 ++ 14 files changed, 137 insertions(+), 109 deletions(-) diff --git a/internal/handler/completion.go b/internal/handler/completion.go index 2fff4cd5..6543a977 100644 --- a/internal/handler/completion.go +++ b/internal/handler/completion.go @@ -3,16 +3,15 @@ package handler import ( "context" - languagefeatures "github.com/mrjosh/helm-ls/internal/language_features" - lsplocal "github.com/mrjosh/helm-ls/internal/lsp" - "github.com/mrjosh/helm-ls/internal/protocol" lsp "go.lsp.dev/protocol" - - helmdocs "github.com/mrjosh/helm-ls/internal/documentation/helm" ) func (h *ServerHandler) Completion(ctx context.Context, params *lsp.CompletionParams) (result *lsp.CompletionList, err error) { logger.Debug("Running completion with params", params) - return h.selectLangHandler(ctx, params).Completion(ctx, params) + handler, err := h.selectLangHandler(ctx, params.TextDocument.URI) + if err != nil { + return nil, err + } + return handler.Completion(ctx, params) } diff --git a/internal/handler/configuration_test.go b/internal/handler/configuration_test.go index 8a7b86e4..e506a1d6 100644 --- a/internal/handler/configuration_test.go +++ b/internal/handler/configuration_test.go @@ -15,7 +15,10 @@ import ( "go.lsp.dev/uri" ) -var configurationParams = lsp.ConfigurationParams{Items: []lsp.ConfigurationItem{{Section: "helm-ls"}}} +var ( + addChartCallback = func(chart *charts.Chart) {} + configurationParams = lsp.ConfigurationParams{Items: []lsp.ConfigurationItem{{Section: "helm-ls"}}} +) func TestConfigurationWorks(t *testing.T) { mockClient := mocks.NewMockClient(t) diff --git a/internal/handler/definition.go b/internal/handler/definition.go index 9f24f35b..82d2c402 100644 --- a/internal/handler/definition.go +++ b/internal/handler/definition.go @@ -3,30 +3,15 @@ package handler 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 *ServerHandler) Definition(_ context.Context, params *lsp.DefinitionParams) (result []lsp.Location, err error) { - genericDocumentUseCase, err := h.NewGenericDocumentUseCase(params.TextDocumentPositionParams, lsplocal.NodeAtPosition) +func (h *ServerHandler) Definition(ctx context.Context, params *lsp.DefinitionParams) (result []lsp.Location, err error) { + logger.Debug("Running Definition with params", params) + + handler, err := h.selectLangHandler(ctx, params.TextDocument.URI) if err != nil { return nil, err } - - usecases := []languagefeatures.DefinitionUseCase{ - languagefeatures.NewBuiltInObjectsFeature(genericDocumentUseCase), // has to be before template context - languagefeatures.NewVariablesFeature(genericDocumentUseCase), - languagefeatures.NewTemplateContextFeature(genericDocumentUseCase), - languagefeatures.NewIncludesCallFeature(genericDocumentUseCase), - } - - for _, usecase := range usecases { - if usecase.AppropriateForNode() { - result, err := usecase.Definition() - return result, err - } - } - - return nil, nil + return handler.Definition(ctx, params) } diff --git a/internal/handler/handler.go b/internal/handler/handler.go index 2abf7661..eec024cf 100644 --- a/internal/handler/handler.go +++ b/internal/handler/handler.go @@ -6,6 +6,7 @@ import ( "github.com/mrjosh/helm-ls/internal/adapter/yamlls" "github.com/mrjosh/helm-ls/internal/charts" + templatehandler "github.com/mrjosh/helm-ls/internal/handler/template_handler" lsplocal "github.com/mrjosh/helm-ls/internal/lsp" "github.com/mrjosh/helm-ls/internal/util" "go.lsp.dev/jsonrpc2" @@ -26,7 +27,7 @@ type ServerHandler struct { chartStore *charts.ChartStore yamllsConnector *yamlls.Connector helmlsConfig util.HelmlsConfiguration - langHandlers map[string]LangHandler + langHandlers map[lsplocal.DocumentType]LangHandler } func StartHandler(stream io.ReadWriteCloser) { @@ -46,19 +47,39 @@ func StartHandler(stream io.ReadWriteCloser) { func newHandler(connPool jsonrpc2.Conn, client protocol.Client) *ServerHandler { documents := lsplocal.NewDocumentStore() + initalYamllsConnector := &yamlls.Connector{} handler := &ServerHandler{ client: client, linterName: "helm-lint", connPool: connPool, documents: documents, helmlsConfig: util.DefaultConfig, - yamllsConnector: &yamlls.Connector{}, + yamllsConnector: initalYamllsConnector, + langHandlers: map[lsplocal.DocumentType]LangHandler{ + lsplocal.TemplateDocumentType: templatehandler.NewTemplateHandler(documents, nil, initalYamllsConnector), + }, } logger.Printf("helm-lint-langserver: connections opened") return handler } +func (h *ServerHandler) setChartStrore(chartStore *charts.ChartStore) { + h.chartStore = chartStore + + for _, handler := range h.langHandlers { + handler.SetChartStore(chartStore) + } +} + +func (h *ServerHandler) setYamllsConnector(yamllsConnector *yamlls.Connector) { + h.yamllsConnector = yamllsConnector + + for _, handler := range h.langHandlers { + handler.SetYamllsConnector(yamllsConnector) + } +} + // CodeAction implements protocol.Server. func (h *ServerHandler) CodeAction(ctx context.Context, params *lsp.CodeActionParams) (result []lsp.CodeAction, err error) { logger.Error("Code action unimplemented") diff --git a/internal/handler/hover.go b/internal/handler/hover.go index e236ea62..fc49278f 100644 --- a/internal/handler/hover.go +++ b/internal/handler/hover.go @@ -3,41 +3,15 @@ package handler import ( "context" - languagefeatures "github.com/mrjosh/helm-ls/internal/language_features" - lsplocal "github.com/mrjosh/helm-ls/internal/lsp" - "github.com/mrjosh/helm-ls/internal/protocol" - "github.com/mrjosh/helm-ls/internal/tree-sitter/gotemplate" - lsp "go.lsp.dev/protocol" ) func (h *ServerHandler) Hover(ctx context.Context, params *lsp.HoverParams) (result *lsp.Hover, err error) { - genericDocumentUseCase, err := h.NewGenericDocumentUseCase(params.TextDocumentPositionParams, lsplocal.NodeAtPosition) + logger.Debug("Running hover with params", params) + + handler, err := h.selectLangHandler(ctx, params.TextDocument.URI) if err != nil { return nil, err } - - wordRange := lsplocal.GetLspRangeForNode(genericDocumentUseCase.Node) - - usecases := []languagefeatures.HoverUseCase{ - languagefeatures.NewBuiltInObjectsFeature(genericDocumentUseCase), // has to be before template context - languagefeatures.NewTemplateContextFeature(genericDocumentUseCase), - languagefeatures.NewIncludesCallFeature(genericDocumentUseCase), - languagefeatures.NewFunctionCallFeature(genericDocumentUseCase), - } - - for _, usecase := range usecases { - if usecase.AppropriateForNode() { - result, err := usecase.Hover() - return protocol.BuildHoverResponse(result, wordRange), err - } - } - - if genericDocumentUseCase.NodeType == gotemplate.NodeTypeText { - word := genericDocumentUseCase.Document.WordAt(params.Position) - response, err := h.yamllsConnector.CallHover(ctx, *params, word) - return response, err - } - - return nil, err + return handler.Hover(ctx, params) } diff --git a/internal/handler/initialization.go b/internal/handler/initialization.go index 699bcf65..d4f6fb46 100644 --- a/internal/handler/initialization.go +++ b/internal/handler/initialization.go @@ -28,7 +28,7 @@ func (h *ServerHandler) Initialize(ctx context.Context, params *lsp.InitializePa } logger.Debug("Initializing chartStore") - h.chartStore = charts.NewChartStore(workspaceURI, charts.NewChart, h.AddChartCallback) + h.setChartStrore(charts.NewChartStore(workspaceURI, charts.NewChart, h.AddChartCallback)) logger.Debug("Initializing done") return &lsp.InitializeResult{ @@ -75,7 +75,7 @@ func (h *ServerHandler) configureYamlls(ctx context.Context) { config := h.helmlsConfig if config.YamllsConfiguration.Enabled { h.configureYamlsEnabledGlob() - h.yamllsConnector = yamlls.NewConnector(ctx, config.YamllsConfiguration, h.client, h.documents) + h.setYamllsConnector(yamlls.NewConnector(ctx, config.YamllsConfiguration, h.client, h.documents)) err := h.yamllsConnector.CallInitialize(ctx, h.chartStore.RootURI) if err != nil { logger.Error("Error initializing yamlls", err) diff --git a/internal/handler/lang_handler.go b/internal/handler/lang_handler.go index 1502a1f9..df1181cc 100644 --- a/internal/handler/lang_handler.go +++ b/internal/handler/lang_handler.go @@ -2,17 +2,31 @@ package handler import ( "context" + "fmt" + "github.com/mrjosh/helm-ls/internal/adapter/yamlls" + "github.com/mrjosh/helm-ls/internal/charts" lsp "go.lsp.dev/protocol" + "go.lsp.dev/uri" ) type LangHandler interface { Completion(ctx context.Context, params *lsp.CompletionParams) (result *lsp.CompletionList, err error) References(ctx context.Context, params *lsp.ReferenceParams) (result []lsp.Location, err error) + Hover(ctx context.Context, params *lsp.HoverParams) (result *lsp.Hover, err error) + Definition(ctx context.Context, params *lsp.DefinitionParams) (result []lsp.Location, err error) + DocumentSymbol(ctx context.Context, params *lsp.DocumentSymbolParams) (result []interface{}, err error) + + SetChartStore(chartStore *charts.ChartStore) + SetYamllsConnector(yamllsConnector *yamlls.Connector) } -func (h *ServerHandler) selectLangHandler(ctx context.Context, params *lsp.TextDocumentPositionParams) (LangHandler, error) { - langID := h.documents.GetLanguageID(params.TextDocument.URI) +func (h *ServerHandler) selectLangHandler(ctx context.Context, uri uri.URI) (LangHandler, error) { + documentType, ok := h.documents.GetDocumentType(uri) + + if !ok { + return nil, fmt.Errorf("document %s not found or has invalid language", uri) + } - return h.langHandlers[langID], nil + return h.langHandlers[documentType], nil } diff --git a/internal/handler/references.go b/internal/handler/references.go index 499b6b95..bf33875c 100644 --- a/internal/handler/references.go +++ b/internal/handler/references.go @@ -3,29 +3,15 @@ package handler 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 *ServerHandler) References(_ context.Context, params *lsp.ReferenceParams) (result []lsp.Location, err error) { - genericDocumentUseCase, err := h.NewGenericDocumentUseCase(params.TextDocumentPositionParams, lsplocal.NodeAtPosition) +func (h *ServerHandler) References(ctx context.Context, params *lsp.ReferenceParams) (result []lsp.Location, err error) { + logger.Debug("Running references with params", params) + + handler, err := h.selectLangHandler(ctx, params.TextDocument.URI) if err != nil { return nil, err } - - usecases := []languagefeatures.ReferencesUseCase{ - languagefeatures.NewIncludesDefinitionFeature(genericDocumentUseCase), - languagefeatures.NewIncludesCallFeature(genericDocumentUseCase), - languagefeatures.NewTemplateContextFeature(genericDocumentUseCase), - languagefeatures.NewVariablesFeature(genericDocumentUseCase), - } - - for _, usecase := range usecases { - if usecase.AppropriateForNode() { - return usecase.References() - } - } - - return nil, nil + return handler.References(ctx, params) } diff --git a/internal/handler/symbol.go b/internal/handler/symbol.go index 90a13a06..770daa92 100644 --- a/internal/handler/symbol.go +++ b/internal/handler/symbol.go @@ -8,5 +8,11 @@ import ( // DocumentSymbol implements protocol.Server. func (h *ServerHandler) DocumentSymbol(ctx context.Context, params *lsp.DocumentSymbolParams) (result []interface{}, err error) { - return h.yamllsConnector.CallDocumentSymbol(ctx, params) + logger.Debug("Running DocumentSymbol with params", params) + + handler, err := h.selectLangHandler(ctx, params.TextDocument.URI) + if err != nil { + return nil, err + } + return handler.DocumentSymbol(ctx, params) } diff --git a/internal/handler/template_handler/hover_main_test.go b/internal/handler/template_handler/hover_main_test.go index 1bb1d603..ca5dfa6b 100644 --- a/internal/handler/template_handler/hover_main_test.go +++ b/internal/handler/template_handler/hover_main_test.go @@ -190,9 +190,9 @@ func TestHoverMain(t *testing.T) { documents: documents, yamllsConnector: &yamlls.Connector{}, } - h.chartStore = charts.NewChartStore(uri.File("."), charts.NewChart, func(chart *charts.Chart) { + h.SetChartStore(charts.NewChartStore(uri.File("."), charts.NewChart, func(chart *charts.Chart) { documents.LoadDocsOnNewChart(chart, util.DefaultConfig) - }) + })) chart, _ := h.chartStore.GetChartOrParentForDoc(fileURI) documents.LoadDocsOnNewChart(chart, util.DefaultConfig) result, err := h.Hover(context.Background(), &lsp.HoverParams{ diff --git a/internal/handler/template_handler/template_handler.go b/internal/handler/template_handler/template_handler.go index de8528a8..b8ac5ba5 100644 --- a/internal/handler/template_handler/template_handler.go +++ b/internal/handler/template_handler/template_handler.go @@ -14,3 +14,19 @@ type TemplateHandler struct { chartStore *charts.ChartStore yamllsConnector *yamlls.Connector } + +func NewTemplateHandler(documents *lsplocal.DocumentStore, chartStore *charts.ChartStore, yamllsConnector *yamlls.Connector) *TemplateHandler { + return &TemplateHandler{ + documents: documents, + chartStore: chartStore, + yamllsConnector: yamllsConnector, + } +} + +func (h *TemplateHandler) SetChartStore(chartStore *charts.ChartStore) { + h.chartStore = chartStore +} + +func (h *TemplateHandler) SetYamllsConnector(yamllsConnector *yamlls.Connector) { + h.yamllsConnector = yamllsConnector +} diff --git a/internal/lsp/document.go b/internal/lsp/document.go index a5a024e7..2e1736c1 100644 --- a/internal/lsp/document.go +++ b/internal/lsp/document.go @@ -14,12 +14,24 @@ import ( var logger = log.GetLogger() // Document represents an opened file. +type DocumentType string + +const ( + TemplateDocumentType DocumentType = "helm" + YamlDocumentType = `yaml` +) + type Document struct { - URI lsp.DocumentURI - Path string - Content []byte - lines []string - IsOpen bool + URI lsp.DocumentURI + DocumentType DocumentType + Path string + Content []byte + lines []string + IsOpen bool +} + +type DocumentInterface interface { + GetDocumentType() DocumentType } func NewDocument(fileURI uri.URI, content []byte, isOpen bool) *Document { diff --git a/internal/lsp/document_store.go b/internal/lsp/document_store.go index 927cd557..bc8efa5c 100644 --- a/internal/lsp/document_store.go +++ b/internal/lsp/document_store.go @@ -11,22 +11,14 @@ import ( "go.lsp.dev/uri" ) -var ( - helmDocumentType = "helm" - yamlDocumentType = "yaml" -) - // documentStore holds opened documents. type DocumentStore struct { - documents map[string]*sync.Map + documents sync.Map } func NewDocumentStore() *DocumentStore { return &DocumentStore{ - documents: map[string]*sync.Map{ - helmDocumentType: new(sync.Map), - yamlDocumentType: new(sync.Map), - }, + documents: sync.Map{}, } } @@ -37,10 +29,11 @@ func (s *DocumentStore) DidOpenTemplateDocument( path := uri.Filename() doc := NewTemplateDocument(uri, []byte(params.TextDocument.Text), true, helmlsConfig) logger.Debug("Storing doc ", path) - s.documents[helmDocumentType].Store(path, doc) + s.documents.Store(path, doc) return doc, nil } +// unused 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)) @@ -49,36 +42,41 @@ func (s *DocumentStore) DidOpen(params *lsp.DidOpenTextDocumentParams, helmlsCon if IsTemplateDocumentLangID(params.TextDocument.LanguageID) { doc := NewTemplateDocument(uri, []byte(params.TextDocument.Text), true, helmlsConfig) logger.Debug("Storing doc ", path) - s.documents[helmDocumentType].Store(path, doc) + s.documents.Store(path, doc) // return doc, nil } return nil, fmt.Errorf("unsupported document type: %s", params.TextDocument.LanguageID) } func (s *DocumentStore) StoreTemplateDocument(path string, content []byte, helmlsConfig util.HelmlsConfiguration) { - _, ok := s.documents[helmDocumentType].Load(path) + _, ok := s.documents.Load(path) if ok { return } fileURI := uri.File(path) - s.documents[helmDocumentType].Store(fileURI.Filename(), + s.documents.Store(fileURI.Filename(), NewTemplateDocument(fileURI, content, false, helmlsConfig)) } func (s *DocumentStore) GetTemplateDoc(docuri uri.URI) (*TemplateDocument, bool) { path := docuri.Filename() - d, ok := s.documents[helmDocumentType].Load(path) + d, ok := s.documents.Load(path) if !ok { return nil, false } - return d.(*TemplateDocument), ok + doc, ok := d.(*TemplateDocument) + return doc, ok } func (s *DocumentStore) GetAllTemplateDocs() []*TemplateDocument { var docs []*TemplateDocument - s.documents[helmDocumentType].Range(func(_, v interface{}) bool { - docs = append(docs, v.(*TemplateDocument)) + s.documents.Range(func(_, v interface{}) bool { + doc, ok := v.(*TemplateDocument) + if !ok { + return true + } + docs = append(docs, doc) return true }) return docs @@ -98,3 +96,13 @@ func (s *DocumentStore) LoadDocsOnNewChart(chart *charts.Chart, helmlsConfig uti s.StoreTemplateDocument(file.Path, file.Content, helmlsConfig) } } + +func (s *DocumentStore) GetDocumentType(uri uri.URI) (DocumentType, bool) { + path := uri.Filename() + d, ok := s.documents.Load(path) + if !ok { + return DocumentType(""), false + } + doc, ok := d.(DocumentInterface) + return doc.GetDocumentType(), ok +} diff --git a/internal/lsp/template_document.go b/internal/lsp/template_document.go index 82a5460b..59a5deba 100644 --- a/internal/lsp/template_document.go +++ b/internal/lsp/template_document.go @@ -17,6 +17,10 @@ type TemplateDocument struct { IsYaml bool } +func (d *TemplateDocument) GetDocumentType() DocumentType { + return TemplateDocumentType +} + func NewTemplateDocument(fileURI uri.URI, content []byte, isOpen bool, helmlsConfig util.HelmlsConfiguration) *TemplateDocument { ast := ParseAst(nil, content) return &TemplateDocument{ From 3f5370b9e57adf8bd1b2beca649b24bb32980f53 Mon Sep 17 00:00:00 2001 From: qvalentin Date: Sun, 6 Oct 2024 19:26:32 +0200 Subject: [PATCH 09/16] feat: doc sync for different languages --- internal/handler/lang_handler.go | 10 ++++ .../handler/template_handler/diagnostics.go | 20 +++++++ .../handler/template_handler/text_document.go | 56 +++++++++++++++++++ internal/handler/text_document.go | 54 ++++-------------- internal/lsp/document.go | 11 ++++ internal/lsp/document_store.go | 10 ++++ 6 files changed, 119 insertions(+), 42 deletions(-) create mode 100644 internal/handler/template_handler/diagnostics.go create mode 100644 internal/handler/template_handler/text_document.go diff --git a/internal/handler/lang_handler.go b/internal/handler/lang_handler.go index df1181cc..0d6389fb 100644 --- a/internal/handler/lang_handler.go +++ b/internal/handler/lang_handler.go @@ -6,6 +6,7 @@ import ( "github.com/mrjosh/helm-ls/internal/adapter/yamlls" "github.com/mrjosh/helm-ls/internal/charts" + "github.com/mrjosh/helm-ls/internal/util" lsp "go.lsp.dev/protocol" "go.lsp.dev/uri" ) @@ -17,6 +18,15 @@ type LangHandler interface { Definition(ctx context.Context, params *lsp.DefinitionParams) (result []lsp.Location, err error) DocumentSymbol(ctx context.Context, params *lsp.DocumentSymbolParams) (result []interface{}, err error) + // DidOpen is called when a document is opened. This function has to add the document to the document store + DidOpen(ctx context.Context, params *lsp.DidOpenTextDocumentParams, helmlsConfig util.HelmlsConfiguration) (err error) + // DidSave is called when a document is saved, it must not update the document store + DidSave(ctx context.Context, params *lsp.DidSaveTextDocumentParams) (err error) + // DidChange is called when a document is changed, it must not update the document store + DidChange(ctx context.Context, params *lsp.DidChangeTextDocumentParams) (err error) + + GetDiagnostics(uri lsp.DocumentURI) []lsp.PublishDiagnosticsParams + SetChartStore(chartStore *charts.ChartStore) SetYamllsConnector(yamllsConnector *yamlls.Connector) } diff --git a/internal/handler/template_handler/diagnostics.go b/internal/handler/template_handler/diagnostics.go new file mode 100644 index 00000000..80004fd9 --- /dev/null +++ b/internal/handler/template_handler/diagnostics.go @@ -0,0 +1,20 @@ +package templatehandler + +import ( + helmlint "github.com/mrjosh/helm-ls/internal/helm_lint" + lsp "go.lsp.dev/protocol" +) + +func (h *TemplateHandler) GetDiagnostics(uri lsp.DocumentURI) []lsp.PublishDiagnosticsParams { + doc, ok := h.documents.GetTemplateDoc(uri) + if !ok { + logger.Error("Could not get document: " + uri.Filename()) + return []lsp.PublishDiagnosticsParams{} + } + chart, err := h.chartStore.GetChartOrParentForDoc(doc.URI) + if err != nil { + logger.Error("Error getting chart info for file", doc.URI, err) + } + notifications := helmlint.GetDiagnosticsNotifications(chart, doc) + return notifications +} diff --git a/internal/handler/template_handler/text_document.go b/internal/handler/template_handler/text_document.go new file mode 100644 index 00000000..e36113e3 --- /dev/null +++ b/internal/handler/template_handler/text_document.go @@ -0,0 +1,56 @@ +package templatehandler + +import ( + "context" + "errors" + + lsplocal "github.com/mrjosh/helm-ls/internal/lsp" + "github.com/mrjosh/helm-ls/internal/util" + lsp "go.lsp.dev/protocol" +) + +func (h *TemplateHandler) DidOpen(ctx context.Context, params *lsp.DidOpenTextDocumentParams, helmlsConfig util.HelmlsConfiguration) (err error) { + doc, err := h.documents.DidOpenTemplateDocument(params, helmlsConfig) + if err != nil { + logger.Error(err) + return err + } + + h.yamllsConnector.DocumentDidOpen(doc.Ast, *params) + + return nil +} + +func (h *TemplateHandler) DidSave(ctx context.Context, params *lsp.DidSaveTextDocumentParams) (err error) { + doc, ok := h.documents.GetTemplateDoc(params.TextDocument.URI) + if !ok { + return errors.New("Could not get document: " + params.TextDocument.URI.Filename()) + } + + h.yamllsConnector.DocumentDidSave(doc, *params) + + return nil +} + +func (h *TemplateHandler) DidChange(ctx context.Context, params *lsp.DidChangeTextDocumentParams) (err error) { + doc, ok := h.documents.GetTemplateDoc(params.TextDocument.URI) + if !ok { + return errors.New("Could not get document: " + params.TextDocument.URI.Filename()) + } + + shouldSendFullUpdateToYamlls := false + for _, change := range params.ContentChanges { + node := lsplocal.NodeAtPosition(doc.Ast, change.Range.Start) + if node.Type() != "text" { + shouldSendFullUpdateToYamlls = true + break + } + } + if shouldSendFullUpdateToYamlls { + h.yamllsConnector.DocumentDidChangeFullSync(doc, *params) + } else { + h.yamllsConnector.DocumentDidChange(doc, *params) + } + + return nil +} diff --git a/internal/handler/text_document.go b/internal/handler/text_document.go index f8db1345..fb7ff0e2 100644 --- a/internal/handler/text_document.go +++ b/internal/handler/text_document.go @@ -5,29 +5,16 @@ import ( "errors" "github.com/mrjosh/helm-ls/internal/charts" - helmlint "github.com/mrjosh/helm-ls/internal/helm_lint" lsplocal "github.com/mrjosh/helm-ls/internal/lsp" lsp "go.lsp.dev/protocol" ) func (h *ServerHandler) DidOpen(ctx context.Context, params *lsp.DidOpenTextDocumentParams) (err error) { - if lsplocal.IsTemplateDocumentLangID(params.TextDocument.LanguageID) { - doc, err := h.documents.DidOpenTemplateDocument(params, h.helmlsConfig) - if err != nil { - logger.Error(err) - return err - } + handler := h.langHandlers[lsplocal.TemplateDocumentTypeForLangID(params.TextDocument.LanguageID)] - h.yamllsConnector.DocumentDidOpen(doc.Ast, *params) + handler.DidOpen(ctx, params, h.helmlsConfig) - chart, err := h.chartStore.GetChartOrParentForDoc(doc.URI) - if err != nil { - logger.Error("Error getting chart info for file", doc.URI, err) - } - - defer h.publishDiagnostics(ctx, helmlint.GetDiagnosticsNotifications(chart, doc)) - - } + defer h.publishDiagnostics(ctx, handler.GetDiagnostics(params.TextDocument.URI)) return nil } @@ -37,46 +24,29 @@ func (h *ServerHandler) DidClose(_ context.Context, _ *lsp.DidCloseTextDocumentP } func (h *ServerHandler) DidSave(ctx context.Context, params *lsp.DidSaveTextDocumentParams) (err error) { - doc, ok := h.documents.GetTemplateDoc(params.TextDocument.URI) - if !ok { - return errors.New("Could not get document: " + params.TextDocument.URI.Filename()) - } - chart, err := h.chartStore.GetChartOrParentForDoc(doc.URI) + handler, err := h.selectLangHandler(ctx, params.TextDocument.URI) if err != nil { - logger.Error("Error getting chart info for file", doc.URI, err) + return err } - h.yamllsConnector.DocumentDidSave(doc, *params) - notifications := helmlint.GetDiagnosticsNotifications(chart, doc) + handler.DidSave(ctx, params) - defer h.publishDiagnostics(ctx, notifications) + defer h.publishDiagnostics(ctx, handler.GetDiagnostics(params.TextDocument.URI)) return nil } -func (h *ServerHandler) DidChange(_ context.Context, params *lsp.DidChangeTextDocumentParams) (err error) { - doc, ok := h.documents.GetTemplateDoc(params.TextDocument.URI) +func (h *ServerHandler) DidChange(ctx context.Context, params *lsp.DidChangeTextDocumentParams) (err error) { + handler, err := h.selectLangHandler(ctx, params.TextDocument.URI) + handler.DidChange(ctx, params) + + doc, ok := h.documents.GetSyncDocument(params.TextDocument.URI) if !ok { return errors.New("Could not get document: " + params.TextDocument.URI.Filename()) } - // Synchronise changes into the doc's ContentChanges doc.ApplyChanges(params.ContentChanges) - shouldSendFullUpdateToYamlls := false - for _, change := range params.ContentChanges { - node := lsplocal.NodeAtPosition(doc.Ast, change.Range.Start) - if node.Type() != "text" { - shouldSendFullUpdateToYamlls = true - break - } - } - if shouldSendFullUpdateToYamlls { - h.yamllsConnector.DocumentDidChangeFullSync(doc, *params) - } else { - h.yamllsConnector.DocumentDidChange(doc, *params) - } - return nil } diff --git a/internal/lsp/document.go b/internal/lsp/document.go index 2e1736c1..7de9bc72 100644 --- a/internal/lsp/document.go +++ b/internal/lsp/document.go @@ -21,6 +21,16 @@ const ( YamlDocumentType = `yaml` ) +func TemplateDocumentTypeForLangID(langID lsp.LanguageIdentifier) DocumentType { + if strings.Contains(string(langID), `yaml`) { + return YamlDocumentType + } + if strings.Contains(string(langID), `helm`) { + return TemplateDocumentType + } + return TemplateDocumentType +} + type Document struct { URI lsp.DocumentURI DocumentType DocumentType @@ -32,6 +42,7 @@ type Document struct { type DocumentInterface interface { GetDocumentType() DocumentType + ApplyChanges([]lsp.TextDocumentContentChangeEvent) } func NewDocument(fileURI uri.URI, content []byte, isOpen bool) *Document { diff --git a/internal/lsp/document_store.go b/internal/lsp/document_store.go index bc8efa5c..c06aa0aa 100644 --- a/internal/lsp/document_store.go +++ b/internal/lsp/document_store.go @@ -106,3 +106,13 @@ func (s *DocumentStore) GetDocumentType(uri uri.URI) (DocumentType, bool) { doc, ok := d.(DocumentInterface) return doc.GetDocumentType(), ok } + +func (s *DocumentStore) GetSyncDocument(uri uri.URI) (DocumentInterface, bool) { + path := uri.Filename() + d, ok := s.documents.Load(path) + if !ok { + return nil, false + } + doc, ok := d.(DocumentInterface) + return doc, ok +} From 92054f83d78439536ae6aa83b5a090004d01825d Mon Sep 17 00:00:00 2001 From: qvalentin Date: Sun, 6 Oct 2024 21:21:02 +0200 Subject: [PATCH 10/16] refactor: yamlls setup in handler --- internal/adapter/yamlls/document_sync.go | 7 +++- internal/adapter/yamlls/yamlls.go | 10 +++--- internal/handler/handler.go | 22 ++++++------ internal/handler/initialization.go | 26 ++------------ internal/handler/lang_handler.go | 9 +++-- .../handler/template_handler/configure.go | 36 +++++++++++++++++++ .../template_handler/template_handler.go | 13 +++++-- 7 files changed, 76 insertions(+), 47 deletions(-) create mode 100644 internal/handler/template_handler/configure.go diff --git a/internal/adapter/yamlls/document_sync.go b/internal/adapter/yamlls/document_sync.go index 1db81942..2c47dc96 100644 --- a/internal/adapter/yamlls/document_sync.go +++ b/internal/adapter/yamlls/document_sync.go @@ -19,7 +19,8 @@ func (yamllsConnector Connector) InitiallySyncOpenDocuments(docs []*lsplocal.Tem continue } - doc.IsYaml = lsplocal.IsYamllsEnabled(doc.URI, yamllsConnector.config) + doc.IsYaml = yamllsConnector.IsYamllsEnabled(doc.URI) + if !yamllsConnector.isRelevantFile(doc.URI) { continue } @@ -115,3 +116,7 @@ func (yamllsConnector Connector) DocumentDidChangeFullSync(doc *lsplocal.Templat logger.Println("Error calling yamlls for didChange", err) } } + +func (yamllsConnector Connector) IsYamllsEnabled(uri lsp.URI) bool { + return yamllsConnector.EnabledForFilesGlobObject.Match(uri.Filename()) +} diff --git a/internal/adapter/yamlls/yamlls.go b/internal/adapter/yamlls/yamlls.go index 2d1d215b..759d4401 100644 --- a/internal/adapter/yamlls/yamlls.go +++ b/internal/adapter/yamlls/yamlls.go @@ -6,6 +6,7 @@ import ( "os" "os/exec" + "github.com/gobwas/glob" "github.com/mrjosh/helm-ls/internal/log" lsplocal "github.com/mrjosh/helm-ls/internal/lsp" "github.com/mrjosh/helm-ls/internal/util" @@ -18,10 +19,11 @@ import ( var logger = log.GetLogger() type Connector struct { - config util.YamllsConfiguration - server protocol.Server - documents *lsplocal.DocumentStore - client protocol.Client + config util.YamllsConfiguration + server protocol.Server + documents *lsplocal.DocumentStore + client protocol.Client + EnabledForFilesGlobObject glob.Glob } func NewConnector(ctx context.Context, yamllsConfiguration util.YamllsConfiguration, client protocol.Client, documents *lsplocal.DocumentStore) *Connector { diff --git a/internal/handler/handler.go b/internal/handler/handler.go index eec024cf..b4d70702 100644 --- a/internal/handler/handler.go +++ b/internal/handler/handler.go @@ -40,23 +40,21 @@ func StartHandler(stream io.ReadWriteCloser) { logger, ) server.connPool = conn - server.client = client + server.setClient(client) <-conn.Done() } func newHandler(connPool jsonrpc2.Conn, client protocol.Client) *ServerHandler { documents := lsplocal.NewDocumentStore() - initalYamllsConnector := &yamlls.Connector{} handler := &ServerHandler{ - client: client, - linterName: "helm-lint", - connPool: connPool, - documents: documents, - helmlsConfig: util.DefaultConfig, - yamllsConnector: initalYamllsConnector, + client: client, + linterName: "helm-lint", + connPool: connPool, + documents: documents, + helmlsConfig: util.DefaultConfig, langHandlers: map[lsplocal.DocumentType]LangHandler{ - lsplocal.TemplateDocumentType: templatehandler.NewTemplateHandler(documents, nil, initalYamllsConnector), + lsplocal.TemplateDocumentType: templatehandler.NewTemplateHandler(client, documents, nil), }, } logger.Printf("helm-lint-langserver: connections opened") @@ -72,11 +70,11 @@ func (h *ServerHandler) setChartStrore(chartStore *charts.ChartStore) { } } -func (h *ServerHandler) setYamllsConnector(yamllsConnector *yamlls.Connector) { - h.yamllsConnector = yamllsConnector +func (h *ServerHandler) setClient(client protocol.Client) { + h.client = client for _, handler := range h.langHandlers { - handler.SetYamllsConnector(yamllsConnector) + handler.SetClient(client) } } diff --git a/internal/handler/initialization.go b/internal/handler/initialization.go index d4f6fb46..9a494f49 100644 --- a/internal/handler/initialization.go +++ b/internal/handler/initialization.go @@ -4,8 +4,6 @@ import ( "context" "os" - "github.com/gobwas/glob" - "github.com/mrjosh/helm-ls/internal/adapter/yamlls" "github.com/mrjosh/helm-ls/internal/charts" "github.com/mrjosh/helm-ls/internal/util" "github.com/sirupsen/logrus" @@ -59,29 +57,9 @@ func (h *ServerHandler) Initialized(ctx context.Context, _ *lsp.InitializedParam func (h *ServerHandler) initializationWithConfig(ctx context.Context) { configureLogLevel(h.helmlsConfig) h.chartStore.SetValuesFilesConfig(h.helmlsConfig.ValuesFilesConfig) - h.configureYamlls(ctx) -} - -func (h *ServerHandler) configureYamlsEnabledGlob() { - globObject, err := glob.Compile(h.helmlsConfig.YamllsConfiguration.EnabledForFilesGlob) - if err != nil { - logger.Error("Error compiling glob for yamlls EnabledForFilesGlob", err) - globObject = util.DefaultConfig.YamllsConfiguration.EnabledForFilesGlobObject - } - h.helmlsConfig.YamllsConfiguration.EnabledForFilesGlobObject = globObject -} - -func (h *ServerHandler) configureYamlls(ctx context.Context) { - config := h.helmlsConfig - if config.YamllsConfiguration.Enabled { - h.configureYamlsEnabledGlob() - h.setYamllsConnector(yamlls.NewConnector(ctx, config.YamllsConfiguration, h.client, h.documents)) - err := h.yamllsConnector.CallInitialize(ctx, h.chartStore.RootURI) - if err != nil { - logger.Error("Error initializing yamlls", err) - } - h.yamllsConnector.InitiallySyncOpenDocuments(h.documents.GetAllTemplateDocs()) + for _, handler := range h.langHandlers { + handler.Configure(ctx, h.helmlsConfig) } } diff --git a/internal/handler/lang_handler.go b/internal/handler/lang_handler.go index 0d6389fb..a2ea60af 100644 --- a/internal/handler/lang_handler.go +++ b/internal/handler/lang_handler.go @@ -4,9 +4,9 @@ import ( "context" "fmt" - "github.com/mrjosh/helm-ls/internal/adapter/yamlls" "github.com/mrjosh/helm-ls/internal/charts" "github.com/mrjosh/helm-ls/internal/util" + "go.lsp.dev/protocol" lsp "go.lsp.dev/protocol" "go.lsp.dev/uri" ) @@ -25,13 +25,16 @@ type LangHandler interface { // DidChange is called when a document is changed, it must not update the document store DidChange(ctx context.Context, params *lsp.DidChangeTextDocumentParams) (err error) + Configure(ctx context.Context, helmlsConfig util.HelmlsConfiguration) GetDiagnostics(uri lsp.DocumentURI) []lsp.PublishDiagnosticsParams + // SetChartStore is called once the chart store has been initialized SetChartStore(chartStore *charts.ChartStore) - SetYamllsConnector(yamllsConnector *yamlls.Connector) + // SetChartStore is called once the client has been initialized + SetClient(client protocol.Client) } -func (h *ServerHandler) selectLangHandler(ctx context.Context, uri uri.URI) (LangHandler, error) { +func (h *ServerHandler) selectLangHandler(_ context.Context, uri uri.URI) (LangHandler, error) { documentType, ok := h.documents.GetDocumentType(uri) if !ok { diff --git a/internal/handler/template_handler/configure.go b/internal/handler/template_handler/configure.go new file mode 100644 index 00000000..31e951e1 --- /dev/null +++ b/internal/handler/template_handler/configure.go @@ -0,0 +1,36 @@ +package templatehandler + +import ( + "context" + + "github.com/gobwas/glob" + "github.com/mrjosh/helm-ls/internal/adapter/yamlls" + "github.com/mrjosh/helm-ls/internal/util" +) + +func (h *TemplateHandler) Configure(ctx context.Context, helmlsConfig util.HelmlsConfiguration) { + h.configureYamlls(ctx, helmlsConfig) +} + +func (h *TemplateHandler) configureYamlsEnabledGlob(helmlsConfig util.HelmlsConfiguration) { + globObject, err := glob.Compile(helmlsConfig.YamllsConfiguration.EnabledForFilesGlob) + if err != nil { + logger.Error("Error compiling glob for yamlls EnabledForFilesGlob", err) + globObject = util.DefaultConfig.YamllsConfiguration.EnabledForFilesGlobObject + } + h.yamllsConnector.EnabledForFilesGlobObject = globObject +} + +func (h *TemplateHandler) configureYamlls(ctx context.Context, helmlsConfig util.HelmlsConfiguration) { + config := helmlsConfig + if config.YamllsConfiguration.Enabled { + h.configureYamlsEnabledGlob(helmlsConfig) + h.setYamllsConnector(yamlls.NewConnector(ctx, config.YamllsConfiguration, h.client, h.documents)) + err := h.yamllsConnector.CallInitialize(ctx, h.chartStore.RootURI) + if err != nil { + logger.Error("Error initializing yamlls", err) + } + + h.yamllsConnector.InitiallySyncOpenDocuments(h.documents.GetAllTemplateDocs()) + } +} diff --git a/internal/handler/template_handler/template_handler.go b/internal/handler/template_handler/template_handler.go index b8ac5ba5..377ad5db 100644 --- a/internal/handler/template_handler/template_handler.go +++ b/internal/handler/template_handler/template_handler.go @@ -5,21 +5,24 @@ import ( "github.com/mrjosh/helm-ls/internal/charts" "github.com/mrjosh/helm-ls/internal/log" lsplocal "github.com/mrjosh/helm-ls/internal/lsp" + "go.lsp.dev/protocol" ) var logger = log.GetLogger() type TemplateHandler struct { + client protocol.Client documents *lsplocal.DocumentStore chartStore *charts.ChartStore yamllsConnector *yamlls.Connector } -func NewTemplateHandler(documents *lsplocal.DocumentStore, chartStore *charts.ChartStore, yamllsConnector *yamlls.Connector) *TemplateHandler { +func NewTemplateHandler(client protocol.Client, documents *lsplocal.DocumentStore, chartStore *charts.ChartStore) *TemplateHandler { return &TemplateHandler{ + client: client, documents: documents, chartStore: chartStore, - yamllsConnector: yamllsConnector, + yamllsConnector: &yamlls.Connector{}, } } @@ -27,6 +30,10 @@ func (h *TemplateHandler) SetChartStore(chartStore *charts.ChartStore) { h.chartStore = chartStore } -func (h *TemplateHandler) SetYamllsConnector(yamllsConnector *yamlls.Connector) { +func (h *TemplateHandler) SetClient(client protocol.Client) { + h.client = client +} + +func (h *TemplateHandler) setYamllsConnector(yamllsConnector *yamlls.Connector) { h.yamllsConnector = yamllsConnector } From d1cda91b7c47dba36d0093014a3329f09853ea56 Mon Sep 17 00:00:00 2001 From: qvalentin Date: Mon, 14 Oct 2024 18:20:06 +0200 Subject: [PATCH 11/16] feat: start with yaml document --- internal/handler/handler.go | 19 ++--- internal/handler/text_document.go | 6 ++ .../handler/yaml_handler/text_document.go | 28 ++++++++ internal/handler/yaml_handler/yaml_handler.go | 69 +++++++++++++++++++ internal/lsp/document.go | 20 ++++++ internal/lsp/document_store.go | 30 +++++--- internal/lsp/template_document.go | 22 +----- internal/lsp/yaml_document.go | 29 ++++++++ 8 files changed, 182 insertions(+), 41 deletions(-) create mode 100644 internal/handler/yaml_handler/text_document.go create mode 100644 internal/handler/yaml_handler/yaml_handler.go create mode 100644 internal/lsp/yaml_document.go diff --git a/internal/handler/handler.go b/internal/handler/handler.go index b4d70702..6c41103f 100644 --- a/internal/handler/handler.go +++ b/internal/handler/handler.go @@ -4,9 +4,9 @@ import ( "context" "io" - "github.com/mrjosh/helm-ls/internal/adapter/yamlls" "github.com/mrjosh/helm-ls/internal/charts" templatehandler "github.com/mrjosh/helm-ls/internal/handler/template_handler" + yamlhandler "github.com/mrjosh/helm-ls/internal/handler/yaml_handler" lsplocal "github.com/mrjosh/helm-ls/internal/lsp" "github.com/mrjosh/helm-ls/internal/util" "go.lsp.dev/jsonrpc2" @@ -20,14 +20,13 @@ import ( var logger = log.GetLogger() type ServerHandler struct { - client protocol.Client - connPool jsonrpc2.Conn - linterName string - documents *lsplocal.DocumentStore - chartStore *charts.ChartStore - yamllsConnector *yamlls.Connector - helmlsConfig util.HelmlsConfiguration - langHandlers map[lsplocal.DocumentType]LangHandler + client protocol.Client + connPool jsonrpc2.Conn + linterName string + documents *lsplocal.DocumentStore + chartStore *charts.ChartStore + helmlsConfig util.HelmlsConfiguration + langHandlers map[lsplocal.DocumentType]LangHandler } func StartHandler(stream io.ReadWriteCloser) { @@ -47,6 +46,7 @@ func StartHandler(stream io.ReadWriteCloser) { func newHandler(connPool jsonrpc2.Conn, client protocol.Client) *ServerHandler { documents := lsplocal.NewDocumentStore() + var x LangHandler = yamlhandler.NewYamlHandler(client, documents, nil) handler := &ServerHandler{ client: client, linterName: "helm-lint", @@ -55,6 +55,7 @@ func newHandler(connPool jsonrpc2.Conn, client protocol.Client) *ServerHandler { helmlsConfig: util.DefaultConfig, langHandlers: map[lsplocal.DocumentType]LangHandler{ lsplocal.TemplateDocumentType: templatehandler.NewTemplateHandler(client, documents, nil), + lsplocal.YamlDocumentType: x, }, } logger.Printf("helm-lint-langserver: connections opened") diff --git a/internal/handler/text_document.go b/internal/handler/text_document.go index fb7ff0e2..f691fa96 100644 --- a/internal/handler/text_document.go +++ b/internal/handler/text_document.go @@ -12,6 +12,12 @@ import ( func (h *ServerHandler) DidOpen(ctx context.Context, params *lsp.DidOpenTextDocumentParams) (err error) { handler := h.langHandlers[lsplocal.TemplateDocumentTypeForLangID(params.TextDocument.LanguageID)] + if handler == nil { + message := "Language not supported: " + string(params.TextDocument.LanguageID) + logger.Error(message) + return errors.New(message) + } + handler.DidOpen(ctx, params, h.helmlsConfig) defer h.publishDiagnostics(ctx, handler.GetDiagnostics(params.TextDocument.URI)) diff --git a/internal/handler/yaml_handler/text_document.go b/internal/handler/yaml_handler/text_document.go new file mode 100644 index 00000000..5b70fda3 --- /dev/null +++ b/internal/handler/yaml_handler/text_document.go @@ -0,0 +1,28 @@ +package yamlhandler + +import ( + "context" + + "github.com/mrjosh/helm-ls/internal/util" + "go.lsp.dev/protocol" +) + +// DidChange implements handler.LangHandler. +func (h *YamlHandler) DidChange(ctx context.Context, params *protocol.DidChangeTextDocumentParams) (err error) { + panic("unimplemented") +} + +// DidOpen implements handler.LangHandler. +func (h *YamlHandler) DidOpen(ctx context.Context, params *protocol.DidOpenTextDocumentParams, helmlsConfig util.HelmlsConfiguration) (err error) { + _, err = h.documents.DidOpenTemplateDocument(params, helmlsConfig) + if err != nil { + logger.Error(err) + return err + } + return nil +} + +// DidSave implements handler.LangHandler. +func (h *YamlHandler) DidSave(ctx context.Context, params *protocol.DidSaveTextDocumentParams) (err error) { + return nil +} diff --git a/internal/handler/yaml_handler/yaml_handler.go b/internal/handler/yaml_handler/yaml_handler.go new file mode 100644 index 00000000..7e1d0e59 --- /dev/null +++ b/internal/handler/yaml_handler/yaml_handler.go @@ -0,0 +1,69 @@ +package yamlhandler + +import ( + "context" + + "github.com/mrjosh/helm-ls/internal/adapter/yamlls" + "github.com/mrjosh/helm-ls/internal/charts" + "github.com/mrjosh/helm-ls/internal/log" + lsplocal "github.com/mrjosh/helm-ls/internal/lsp" + "github.com/mrjosh/helm-ls/internal/util" + "go.lsp.dev/protocol" + "go.lsp.dev/uri" +) + +var logger = log.GetLogger() + +type YamlHandler struct { + documents *lsplocal.DocumentStore + chartStore *charts.ChartStore + yamllsConnector *yamlls.Connector +} + +// Completion implements handler.LangHandler. +func (h *YamlHandler) Completion(ctx context.Context, params *protocol.CompletionParams) (result *protocol.CompletionList, err error) { + panic("unimplemented") +} + +// Configure implements handler.LangHandler. +func (h *YamlHandler) Configure(ctx context.Context, helmlsConfig util.HelmlsConfiguration) {} + +// Definition implements handler.LangHandler. +func (h *YamlHandler) Definition(ctx context.Context, params *protocol.DefinitionParams) (result []protocol.Location, err error) { + panic("unimplemented") +} + +// DocumentSymbol implements handler.LangHandler. +func (h *YamlHandler) DocumentSymbol(ctx context.Context, params *protocol.DocumentSymbolParams) (result []interface{}, err error) { + panic("unimplemented") +} + +// GetDiagnostics implements handler.LangHandler. +func (h *YamlHandler) GetDiagnostics(uri uri.URI) []protocol.PublishDiagnosticsParams { + panic("unimplemented") +} + +// Hover implements handler.LangHandler. +func (h *YamlHandler) Hover(ctx context.Context, params *protocol.HoverParams) (result *protocol.Hover, err error) { + panic("unimplemented") +} + +// References implements handler.LangHandler. +func (h *YamlHandler) References(ctx context.Context, params *protocol.ReferenceParams) (result []protocol.Location, err error) { + panic("unimplemented") +} + +// SetClient implements handler.LangHandler. +func (h *YamlHandler) SetClient(client protocol.Client) {} + +func NewYamlHandler(client protocol.Client, documents *lsplocal.DocumentStore, chartStore *charts.ChartStore) *YamlHandler { + return &YamlHandler{ + documents: documents, + chartStore: chartStore, + yamllsConnector: &yamlls.Connector{}, + } +} + +func (h *YamlHandler) SetChartStore(chartStore *charts.ChartStore) { + h.chartStore = chartStore +} diff --git a/internal/lsp/document.go b/internal/lsp/document.go index 7de9bc72..5db04425 100644 --- a/internal/lsp/document.go +++ b/internal/lsp/document.go @@ -97,3 +97,23 @@ func (d *Document) GetPath() string { type TextDocument interface { ApplyChanges([]lsp.TextDocumentContentChangeEvent) } + +// WordAt returns the word found at the given location. +func (d *Document) WordAt(pos lsp.Position) string { + logger.Debug(pos) + + line, ok := d.getLine(int(pos.Line)) + if !ok { + return "" + } + return util.WordAt(line, int(pos.Character)) +} + +// getLine returns the line at the given index. +func (d *Document) getLine(index int) (string, bool) { + lines := d.getLines() + if index < 0 || index > len(lines) { + return "", false + } + return lines[index], true +} diff --git a/internal/lsp/document_store.go b/internal/lsp/document_store.go index c06aa0aa..23491d05 100644 --- a/internal/lsp/document_store.go +++ b/internal/lsp/document_store.go @@ -33,19 +33,15 @@ func (s *DocumentStore) DidOpenTemplateDocument( return doc, nil } -// unused -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)) - +func (s *DocumentStore) DidOpenYamlDocument( + params *lsp.DidOpenTextDocumentParams, helmlsConfig util.HelmlsConfiguration, +) (*YamlDocument, error) { uri := params.TextDocument.URI path := uri.Filename() - if IsTemplateDocumentLangID(params.TextDocument.LanguageID) { - doc := NewTemplateDocument(uri, []byte(params.TextDocument.Text), true, helmlsConfig) - logger.Debug("Storing doc ", path) - s.documents.Store(path, doc) - // return doc, nil - } - return nil, fmt.Errorf("unsupported document type: %s", params.TextDocument.LanguageID) + doc := NewYamlDocument(uri, []byte(params.TextDocument.Text), true, helmlsConfig) + logger.Debug("Storing doc ", path) + s.documents.Store(path, doc) + return doc, nil } func (s *DocumentStore) StoreTemplateDocument(path string, content []byte, helmlsConfig util.HelmlsConfiguration) { @@ -69,6 +65,18 @@ func (s *DocumentStore) GetTemplateDoc(docuri uri.URI) (*TemplateDocument, bool) return doc, ok } +func (s *DocumentStore) GetYamlDoc(docuri uri.URI) (*YamlDocument, bool) { + path := docuri.Filename() + d, ok := s.documents.Load(path) + + if !ok { + return nil, false + } + + doc, ok := d.(*YamlDocument) + return doc, ok +} + func (s *DocumentStore) GetAllTemplateDocs() []*TemplateDocument { var docs []*TemplateDocument s.documents.Range(func(_, v interface{}) bool { diff --git a/internal/lsp/template_document.go b/internal/lsp/template_document.go index 59a5deba..5bfe8501 100644 --- a/internal/lsp/template_document.go +++ b/internal/lsp/template_document.go @@ -7,7 +7,7 @@ import ( "go.lsp.dev/uri" ) -// TemplateDocument represents an opened file. +// TemplateDocument represents an helm template file. type TemplateDocument struct { Document NeedsRefreshDiagnostics bool @@ -43,26 +43,6 @@ func (d *TemplateDocument) ApplyChanges(changes []lsp.TextDocumentContentChangeE d.lines = nil } -// WordAt returns the word found at the given location. -func (d *Document) WordAt(pos lsp.Position) string { - logger.Debug(pos) - - line, ok := d.getLine(int(pos.Line)) - if !ok { - return "" - } - return util.WordAt(line, int(pos.Character)) -} - -// getLine returns the line at the given index. -func (d *Document) getLine(index int) (string, bool) { - lines := d.getLines() - if index < 0 || index > len(lines) { - return "", false - } - return lines[index], true -} - func IsYamllsEnabled(uri lsp.URI, yamllsConfiguration util.YamllsConfiguration) bool { return yamllsConfiguration.EnabledForFilesGlobObject.Match(uri.Filename()) } diff --git a/internal/lsp/yaml_document.go b/internal/lsp/yaml_document.go new file mode 100644 index 00000000..893055c9 --- /dev/null +++ b/internal/lsp/yaml_document.go @@ -0,0 +1,29 @@ +package lsp + +import ( + "github.com/mrjosh/helm-ls/internal/util" + lsp "go.lsp.dev/protocol" + "go.lsp.dev/uri" +) + +// TemplateDocument represents an helm template file. +type YamlDocument struct { + Document +} + +func (d *YamlDocument) GetDocumentType() DocumentType { + return YamlDocumentType +} + +func NewYamlDocument(fileURI uri.URI, content []byte, isOpen bool, helmlsConfig util.HelmlsConfiguration) *YamlDocument { + return &YamlDocument{ + Document: *NewDocument(fileURI, content, isOpen), + } +} + +// ApplyChanges updates the content of the document from LSP textDocument/didChange events. +func (d *YamlDocument) ApplyChanges(changes []lsp.TextDocumentContentChangeEvent) { + d.Document.ApplyChanges(changes) + + d.lines = nil +} From fd01dc875705e4547c8d9f236bf2916b9bf13a1b Mon Sep 17 00:00:00 2001 From: qvalentin Date: Mon, 14 Oct 2024 19:55:32 +0200 Subject: [PATCH 12/16] fix: order of updating doc to yamlls and local --- internal/adapter/yamlls/document_sync.go | 2 +- internal/adapter/yamlls/hover.go | 2 ++ internal/handler/lang_handler.go | 4 ++-- internal/handler/template_handler/text_document.go | 2 +- internal/handler/text_document.go | 6 ++---- internal/handler/yaml_handler/text_document.go | 10 +++++----- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/internal/adapter/yamlls/document_sync.go b/internal/adapter/yamlls/document_sync.go index 2c47dc96..38a932e6 100644 --- a/internal/adapter/yamlls/document_sync.go +++ b/internal/adapter/yamlls/document_sync.go @@ -101,7 +101,7 @@ func (yamllsConnector Connector) DocumentDidChangeFullSync(doc *lsplocal.Templat return } - logger.Debug("Sending DocumentDidChange with full sync, current content:", doc.Content) + logger.Debug("Sending DocumentDidChange with full sync, current content:", string(doc.Content)) trimmedText := lsplocal.TrimTemplate(doc.Ast.Copy(), doc.Content) params.ContentChanges = []lsp.TextDocumentContentChangeEvent{ diff --git a/internal/adapter/yamlls/hover.go b/internal/adapter/yamlls/hover.go index 6c9d7fb0..01b695a6 100644 --- a/internal/adapter/yamlls/hover.go +++ b/internal/adapter/yamlls/hover.go @@ -53,6 +53,8 @@ func (yamllsConnector Connector) getHoverFromCompletion(ctx context.Context, par } } + logger.Debug("Got completion for hover from yamlls", completionList) + return protocol.BuildHoverResponse(documentation, resultRange), nil } diff --git a/internal/handler/lang_handler.go b/internal/handler/lang_handler.go index a2ea60af..c5ab09b1 100644 --- a/internal/handler/lang_handler.go +++ b/internal/handler/lang_handler.go @@ -22,8 +22,8 @@ type LangHandler interface { DidOpen(ctx context.Context, params *lsp.DidOpenTextDocumentParams, helmlsConfig util.HelmlsConfiguration) (err error) // DidSave is called when a document is saved, it must not update the document store DidSave(ctx context.Context, params *lsp.DidSaveTextDocumentParams) (err error) - // DidChange is called when a document is changed, it must not update the document store - DidChange(ctx context.Context, params *lsp.DidChangeTextDocumentParams) (err error) + // PostDidChange is called when a document is changed, it must not update the document store + PostDidChange(ctx context.Context, params *lsp.DidChangeTextDocumentParams) (err error) Configure(ctx context.Context, helmlsConfig util.HelmlsConfiguration) GetDiagnostics(uri lsp.DocumentURI) []lsp.PublishDiagnosticsParams diff --git a/internal/handler/template_handler/text_document.go b/internal/handler/template_handler/text_document.go index e36113e3..bc660d0e 100644 --- a/internal/handler/template_handler/text_document.go +++ b/internal/handler/template_handler/text_document.go @@ -32,7 +32,7 @@ func (h *TemplateHandler) DidSave(ctx context.Context, params *lsp.DidSaveTextDo return nil } -func (h *TemplateHandler) DidChange(ctx context.Context, params *lsp.DidChangeTextDocumentParams) (err error) { +func (h *TemplateHandler) PostDidChange(ctx context.Context, params *lsp.DidChangeTextDocumentParams) (err error) { doc, ok := h.documents.GetTemplateDoc(params.TextDocument.URI) if !ok { return errors.New("Could not get document: " + params.TextDocument.URI.Filename()) diff --git a/internal/handler/text_document.go b/internal/handler/text_document.go index f691fa96..e4bdcc52 100644 --- a/internal/handler/text_document.go +++ b/internal/handler/text_document.go @@ -43,9 +43,6 @@ func (h *ServerHandler) DidSave(ctx context.Context, params *lsp.DidSaveTextDocu } func (h *ServerHandler) DidChange(ctx context.Context, params *lsp.DidChangeTextDocumentParams) (err error) { - handler, err := h.selectLangHandler(ctx, params.TextDocument.URI) - handler.DidChange(ctx, params) - doc, ok := h.documents.GetSyncDocument(params.TextDocument.URI) if !ok { return errors.New("Could not get document: " + params.TextDocument.URI.Filename()) @@ -53,7 +50,8 @@ func (h *ServerHandler) DidChange(ctx context.Context, params *lsp.DidChangeText // Synchronise changes into the doc's ContentChanges doc.ApplyChanges(params.ContentChanges) - return nil + handler, err := h.selectLangHandler(ctx, params.TextDocument.URI) + return handler.PostDidChange(ctx, params) } func (h *ServerHandler) DidCreateFiles(ctx context.Context, params *lsp.CreateFilesParams) (err error) { diff --git a/internal/handler/yaml_handler/text_document.go b/internal/handler/yaml_handler/text_document.go index 5b70fda3..a616a5ae 100644 --- a/internal/handler/yaml_handler/text_document.go +++ b/internal/handler/yaml_handler/text_document.go @@ -7,11 +7,6 @@ import ( "go.lsp.dev/protocol" ) -// DidChange implements handler.LangHandler. -func (h *YamlHandler) DidChange(ctx context.Context, params *protocol.DidChangeTextDocumentParams) (err error) { - panic("unimplemented") -} - // DidOpen implements handler.LangHandler. func (h *YamlHandler) DidOpen(ctx context.Context, params *protocol.DidOpenTextDocumentParams, helmlsConfig util.HelmlsConfiguration) (err error) { _, err = h.documents.DidOpenTemplateDocument(params, helmlsConfig) @@ -26,3 +21,8 @@ func (h *YamlHandler) DidOpen(ctx context.Context, params *protocol.DidOpenTextD func (h *YamlHandler) DidSave(ctx context.Context, params *protocol.DidSaveTextDocumentParams) (err error) { return nil } + +// DidChange implements handler.LangHandler. +func (h *YamlHandler) PostDidChange(ctx context.Context, params *protocol.DidChangeTextDocumentParams) (err error) { + return nil +} From 3e39bb60a428675bdd060bb2caca6bb89fa50469 Mon Sep 17 00:00:00 2001 From: qvalentin Date: Tue, 15 Oct 2024 21:01:54 +0200 Subject: [PATCH 13/16] feat(yaml): diagnostics + start with hover --- internal/handler/yaml_handler/diagnostics.go | 76 +++++++++++++++++++ internal/handler/yaml_handler/hover.go | 27 +++++++ .../handler/yaml_handler/text_document.go | 2 +- .../handler/yaml_handler/unimplemented.go | 12 +++ internal/handler/yaml_handler/yaml_handler.go | 19 +---- internal/log/log.go | 12 ++- internal/lsp/template_document.go | 2 - internal/lsp/yaml_document.go | 25 +++++- internal/lsp/yaml_document_test.go | 24 ++++++ internal/util/yaml.go | 19 +++++ internal/util/yaml_test.go | 16 ++++ 11 files changed, 211 insertions(+), 23 deletions(-) create mode 100644 internal/handler/yaml_handler/diagnostics.go create mode 100644 internal/handler/yaml_handler/hover.go create mode 100644 internal/handler/yaml_handler/unimplemented.go create mode 100644 internal/lsp/yaml_document_test.go diff --git a/internal/handler/yaml_handler/diagnostics.go b/internal/handler/yaml_handler/diagnostics.go new file mode 100644 index 00000000..83155cc6 --- /dev/null +++ b/internal/handler/yaml_handler/diagnostics.go @@ -0,0 +1,76 @@ +package yamlhandler + +import ( + "fmt" + "regexp" + "strconv" + + "go.lsp.dev/protocol" + "go.lsp.dev/uri" +) + +// GetDiagnostics implements handler.LangHandler. +func (h *YamlHandler) GetDiagnostics(uri uri.URI) []protocol.PublishDiagnosticsParams { + doc, ok := h.documents.GetYamlDoc(uri) + + if !ok { + return nil + } + + if doc.ParseErr == nil { + logger.Debug("YamlHandler: No parse error") + return []protocol.PublishDiagnosticsParams{{ + URI: uri, + Diagnostics: []protocol.Diagnostic{}, + }} + } + + errString := doc.ParseErr.Error() + + // find "line 4" in string + + re, err := regexp.Compile("line ([0-9]+): (.*)") + if err != nil { + fmt.Println("Error compiling regex:", err) + return nil + } + + matches := re.FindStringSubmatch(errString) + + if len(matches) < 2 { + return nil + } + + // convert to int + + line, err := strconv.Atoi(matches[1]) + if err != nil { + fmt.Println("Error converting string to int:", err) + return nil + } + + return []protocol.PublishDiagnosticsParams{ + { + URI: uri, + Diagnostics: []protocol.Diagnostic{ + { + Range: protocol.Range{ + Start: protocol.Position{ + Line: uint32(line - 1), + Character: 0, + }, + End: protocol.Position{ + Line: uint32(line), + Character: 0, + }, + }, + Source: "", + Message: matches[2], + Tags: []protocol.DiagnosticTag{}, + RelatedInformation: []protocol.DiagnosticRelatedInformation{}, + Data: nil, + }, + }, + }, + } +} diff --git a/internal/handler/yaml_handler/hover.go b/internal/handler/yaml_handler/hover.go new file mode 100644 index 00000000..b2513065 --- /dev/null +++ b/internal/handler/yaml_handler/hover.go @@ -0,0 +1,27 @@ +package yamlhandler + +import ( + "context" + "fmt" + + "github.com/mrjosh/helm-ls/internal/protocol" + "github.com/mrjosh/helm-ls/internal/util" + lsp "go.lsp.dev/protocol" +) + +// Hover implements handler.LangHandler. +func (h *YamlHandler) Hover(ctx context.Context, params *lsp.HoverParams) (result *lsp.Hover, err error) { + doc, ok := h.documents.GetYamlDoc(params.TextDocument.URI) + + if !ok { + return nil, fmt.Errorf("no document for %s", params.TextDocument.URI) + } + + node := util.GetNodeForPosition(&doc.Node, params.Position) + + if node == nil { + return nil, fmt.Errorf("no node found") + } + + return protocol.BuildHoverResponse(node.Value, lsp.Range{}), doc.ParseErr +} diff --git a/internal/handler/yaml_handler/text_document.go b/internal/handler/yaml_handler/text_document.go index a616a5ae..8e60f036 100644 --- a/internal/handler/yaml_handler/text_document.go +++ b/internal/handler/yaml_handler/text_document.go @@ -9,7 +9,7 @@ import ( // DidOpen implements handler.LangHandler. func (h *YamlHandler) DidOpen(ctx context.Context, params *protocol.DidOpenTextDocumentParams, helmlsConfig util.HelmlsConfiguration) (err error) { - _, err = h.documents.DidOpenTemplateDocument(params, helmlsConfig) + _, err = h.documents.DidOpenYamlDocument(params, helmlsConfig) if err != nil { logger.Error(err) return err diff --git a/internal/handler/yaml_handler/unimplemented.go b/internal/handler/yaml_handler/unimplemented.go new file mode 100644 index 00000000..e743f111 --- /dev/null +++ b/internal/handler/yaml_handler/unimplemented.go @@ -0,0 +1,12 @@ +package yamlhandler + +import ( + "context" + + "go.lsp.dev/protocol" +) + +// DocumentSymbol implements handler.LangHandler. +func (h *YamlHandler) DocumentSymbol(ctx context.Context, params *protocol.DocumentSymbolParams) (result []interface{}, err error) { + return nil, nil +} diff --git a/internal/handler/yaml_handler/yaml_handler.go b/internal/handler/yaml_handler/yaml_handler.go index 7e1d0e59..5a77d4c9 100644 --- a/internal/handler/yaml_handler/yaml_handler.go +++ b/internal/handler/yaml_handler/yaml_handler.go @@ -9,7 +9,6 @@ import ( lsplocal "github.com/mrjosh/helm-ls/internal/lsp" "github.com/mrjosh/helm-ls/internal/util" "go.lsp.dev/protocol" - "go.lsp.dev/uri" ) var logger = log.GetLogger() @@ -22,7 +21,8 @@ type YamlHandler struct { // Completion implements handler.LangHandler. func (h *YamlHandler) Completion(ctx context.Context, params *protocol.CompletionParams) (result *protocol.CompletionList, err error) { - panic("unimplemented") + // TODO + return nil, nil } // Configure implements handler.LangHandler. @@ -33,21 +33,6 @@ func (h *YamlHandler) Definition(ctx context.Context, params *protocol.Definitio panic("unimplemented") } -// DocumentSymbol implements handler.LangHandler. -func (h *YamlHandler) DocumentSymbol(ctx context.Context, params *protocol.DocumentSymbolParams) (result []interface{}, err error) { - panic("unimplemented") -} - -// GetDiagnostics implements handler.LangHandler. -func (h *YamlHandler) GetDiagnostics(uri uri.URI) []protocol.PublishDiagnosticsParams { - panic("unimplemented") -} - -// Hover implements handler.LangHandler. -func (h *YamlHandler) Hover(ctx context.Context, params *protocol.HoverParams) (result *protocol.Hover, err error) { - panic("unimplemented") -} - // References implements handler.LangHandler. func (h *YamlHandler) References(ctx context.Context, params *protocol.ReferenceParams) (result []protocol.Location, err error) { panic("unimplemented") diff --git a/internal/log/log.go b/internal/log/log.go index b90407f6..b049775a 100644 --- a/internal/log/log.go +++ b/internal/log/log.go @@ -28,7 +28,17 @@ func GetLogger() logger { } func createLogger() logger { + logrus.SetReportCaller(true) logger := logrus.New() - logger.SetFormatter(&logrus.JSONFormatter{}) + + formatter := &logrus.JSONFormatter{ + FieldMap: logrus.FieldMap{ + logrus.FieldKeyTime: "@timestamp", + logrus.FieldKeyLevel: "@level", + logrus.FieldKeyMsg: "@message", + logrus.FieldKeyFunc: "@caller", + }, + } + logger.SetFormatter(formatter) return logger } diff --git a/internal/lsp/template_document.go b/internal/lsp/template_document.go index 5bfe8501..22f1ba7d 100644 --- a/internal/lsp/template_document.go +++ b/internal/lsp/template_document.go @@ -39,8 +39,6 @@ func (d *TemplateDocument) ApplyChanges(changes []lsp.TextDocumentContentChangeE d.ApplyChangesToAst(d.Content) d.SymbolTable = NewSymbolTable(d.Ast, d.Content) - - d.lines = nil } func IsYamllsEnabled(uri lsp.URI, yamllsConfiguration util.YamllsConfiguration) bool { diff --git a/internal/lsp/yaml_document.go b/internal/lsp/yaml_document.go index 893055c9..62e8af1a 100644 --- a/internal/lsp/yaml_document.go +++ b/internal/lsp/yaml_document.go @@ -4,11 +4,15 @@ import ( "github.com/mrjosh/helm-ls/internal/util" lsp "go.lsp.dev/protocol" "go.lsp.dev/uri" + "gopkg.in/yaml.v3" ) // TemplateDocument represents an helm template file. type YamlDocument struct { Document + Node yaml.Node + ParsedYaml map[string]interface{} + ParseErr error } func (d *YamlDocument) GetDocumentType() DocumentType { @@ -16,8 +20,18 @@ func (d *YamlDocument) GetDocumentType() DocumentType { } func NewYamlDocument(fileURI uri.URI, content []byte, isOpen bool, helmlsConfig util.HelmlsConfiguration) *YamlDocument { + node, err := util.ReadYamlToNode(content) + + logger.Debug("Parsing yaml", fileURI.Filename(), string(content), node.Value, err) + + var parsedYaml map[string]interface{} + + err = yaml.Unmarshal(content, &parsedYaml) return &YamlDocument{ - Document: *NewDocument(fileURI, content, isOpen), + Document: *NewDocument(fileURI, content, isOpen), + Node: node, + ParsedYaml: parsedYaml, + ParseErr: err, } } @@ -25,5 +39,12 @@ func NewYamlDocument(fileURI uri.URI, content []byte, isOpen bool, helmlsConfig func (d *YamlDocument) ApplyChanges(changes []lsp.TextDocumentContentChangeEvent) { d.Document.ApplyChanges(changes) - d.lines = nil + node, err := util.ReadYamlToNode(d.Content) + + var parsedYaml map[string]interface{} + err = yaml.Unmarshal(d.Content, &parsedYaml) + + d.Node = node + d.ParsedYaml = parsedYaml + d.ParseErr = err } diff --git a/internal/lsp/yaml_document_test.go b/internal/lsp/yaml_document_test.go new file mode 100644 index 00000000..f69723ec --- /dev/null +++ b/internal/lsp/yaml_document_test.go @@ -0,0 +1,24 @@ +package lsp + +import ( + "testing" + + "github.com/mrjosh/helm-ls/internal/util" + "github.com/stretchr/testify/assert" + "go.lsp.dev/uri" +) + +func TestNewYamlDocument(t *testing.T) { + doc := NewYamlDocument(uri.File("test"), []byte("test: value"), true, util.DefaultConfig) + assert.Equal(t, uri.File("test"), doc.URI) + assert.Equal(t, []byte("test: value"), doc.Content) + assert.Equal(t, true, doc.IsOpen) + + brokenYaml := ` +test: fdsf + +broken + ` + doc = NewYamlDocument(uri.File("test"), []byte(brokenYaml), true, util.DefaultConfig) + assert.Error(t, doc.ParseErr) +} diff --git a/internal/util/yaml.go b/internal/util/yaml.go index 77f614b0..69ea7a39 100644 --- a/internal/util/yaml.go +++ b/internal/util/yaml.go @@ -74,6 +74,25 @@ func getPositionOfNodeAfterRange(node *yamlv3.Node, query []string) (lsp.Positio return lsp.Position{}, fmt.Errorf("could not find Position of %s in values. Found no match", query) } +func GetNodeForPosition(node *yamlv3.Node, position lsp.Position) *yamlv3.Node { + if node.IsZero() { + return nil + } + + if node.Value != "" && node.Line == int(position.Line+1) && node.Column <= int(position.Character-1) { + return node + } + + for _, nestedNode := range node.Content { + nestedResult := GetNodeForPosition(nestedNode, position) + if nestedResult != nil { + return nestedResult + } + } + + return nil +} + // ReadYamlToNode will parse a YAML file into a yaml Node. func ReadYamlToNode(data []byte) (node yamlv3.Node, err error) { err = yamlv3.Unmarshal(data, &node) diff --git a/internal/util/yaml_test.go b/internal/util/yaml_test.go index 210c32d7..f8f927a3 100644 --- a/internal/util/yaml_test.go +++ b/internal/util/yaml_test.go @@ -82,3 +82,19 @@ func TestGetPositionOfNodeTable(t *testing.T) { }) } } + +func TestGetNodeForPosition(t *testing.T) { + data, err := os.ReadFile("./yaml_test_input.yaml") + if err != nil { + t.Fatalf("error reading test input file: %v", err) + } + + var node yaml.Node + err = yaml.Unmarshal(data, &node) + if err != nil { + t.Fatalf("error parsing YAML: %v", err) + } + + result := GetNodeForPosition(&node, lsp.Position{Line: 9, Character: 3}) + assert.Equal(t, "repository", result.Value) +} From 3c2d914266561a12c7a684459302475f69fa8b6d Mon Sep 17 00:00:00 2001 From: qvalentin Date: Sun, 27 Oct 2024 15:08:56 +0100 Subject: [PATCH 14/16] fix: off one errors in GetNodeForPosition --- internal/util/yaml.go | 2 +- internal/util/yaml_test.go | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/internal/util/yaml.go b/internal/util/yaml.go index 69ea7a39..4162ad0d 100644 --- a/internal/util/yaml.go +++ b/internal/util/yaml.go @@ -79,7 +79,7 @@ func GetNodeForPosition(node *yamlv3.Node, position lsp.Position) *yamlv3.Node { return nil } - if node.Value != "" && node.Line == int(position.Line+1) && node.Column <= int(position.Character-1) { + if node.Value != "" && node.Line == int(position.Line+1) && node.Column <= int(position.Character+1) { return node } diff --git a/internal/util/yaml_test.go b/internal/util/yaml_test.go index f8f927a3..da6608fd 100644 --- a/internal/util/yaml_test.go +++ b/internal/util/yaml_test.go @@ -95,6 +95,7 @@ func TestGetNodeForPosition(t *testing.T) { t.Fatalf("error parsing YAML: %v", err) } - result := GetNodeForPosition(&node, lsp.Position{Line: 9, Character: 3}) + result := GetNodeForPosition(&node, lsp.Position{Line: 8, Character: 3}) + assert.NotNil(t, result) assert.Equal(t, "repository", result.Value) } From 855df2860363b809af94af0c77b94d0c9671687f Mon Sep 17 00:00:00 2001 From: qvalentin Date: Sun, 10 Nov 2024 16:39:51 +0100 Subject: [PATCH 15/16] refactor: split up lsp package --- internal/adapter/yamlls/diagnostics.go | 5 ++- .../yamlls/diagnostics_integration_test.go | 4 +- internal/adapter/yamlls/document_sync.go | 9 +++-- .../adapter/yamlls/integration_test_utils.go | 8 ++-- internal/adapter/yamlls/yamlls.go | 6 +-- internal/adapter/yamlls/yamlls_test.go | 4 +- internal/handler/handler.go | 14 +++---- .../handler/template_handler/completion.go | 4 +- .../template_handler/completion_main_test.go | 4 +- .../handler/template_handler/definition.go | 4 +- .../template_handler/definition_chart_test.go | 4 +- .../template_handler/definition_test.go | 8 ++-- internal/handler/template_handler/hover.go | 6 +-- .../template_handler/hover_main_test.go | 4 +- .../handler/template_handler/references.go | 4 +- .../template_handler/references_test.go | 8 ++-- .../template_handler/template_handler.go | 6 +-- .../handler/template_handler/text_document.go | 4 +- internal/handler/text_document.go | 4 +- internal/handler/text_document_test.go | 8 ++-- internal/handler/yaml_handler/yaml_handler.go | 6 +-- internal/helm_lint/lint.go | 4 +- internal/helm_lint/lint_test.go | 10 ++--- .../language_features/built_in_objects.go | 4 +- .../generic_document_usecase.go | 6 +-- .../generic_template_context.go | 8 ++-- internal/language_features/includes.go | 6 +-- .../language_features/template_context.go | 8 ++-- .../template_context_completion.go | 6 +-- internal/lsp/ast_diagnostics_test.go | 5 +-- internal/lsp/ast_test.go | 5 ++- internal/lsp/ast_variable.go | 3 ++ .../lsp/{ => document}/diagnostics_cache.go | 3 +- .../{ => document}/diagnostics_cache_test.go | 5 ++- internal/lsp/{ => document}/document.go | 2 +- internal/lsp/{ => document}/document_store.go | 2 +- .../lsp/{ => document}/document_store_test.go | 2 +- internal/lsp/{ => document}/document_test.go | 2 +- .../lsp/{ => document}/template_document.go | 16 +++++--- internal/lsp/{ => document}/yaml_document.go | 2 +- .../lsp/{ => document}/yaml_document_test.go | 2 +- .../lsp/{ => symbol_table}/symbol_table.go | 5 ++- .../symbol_table_includes.go | 6 +-- .../symbol_table_template_context.go | 11 +++--- .../symbol_table_template_context_test.go | 5 ++- ...symbol_table_template_context_variables.go | 2 +- ...l_table_template_context_variables_test.go | 5 ++- .../{ => symbol_table}/symbol_table_test.go | 37 ++++++++++--------- .../symbol_table_variables.go | 2 +- .../symbol_table_variables_test.go | 5 ++- .../{ => symbol_table}/variables_visitor.go | 2 +- .../variables_visitor_test.go | 7 ++-- internal/lsp/{ => symbol_table}/visitor.go | 2 +- internal/lsp/{ => template_ast}/ast.go | 6 +-- internal/lsp/yaml_ast.go | 12 +----- internal/lsp/yaml_ast_test.go | 5 ++- internal/util/points.go | 9 +++++ 57 files changed, 183 insertions(+), 163 deletions(-) rename internal/lsp/{ => document}/diagnostics_cache.go (98%) rename internal/lsp/{ => document}/diagnostics_cache_test.go (99%) rename internal/lsp/{ => document}/document.go (99%) rename internal/lsp/{ => document}/document_store.go (99%) rename internal/lsp/{ => document}/document_store_test.go (97%) rename internal/lsp/{ => document}/document_test.go (97%) rename internal/lsp/{ => document}/template_document.go (74%) rename internal/lsp/{ => document}/yaml_document.go (98%) rename internal/lsp/{ => document}/yaml_document_test.go (96%) rename internal/lsp/{ => symbol_table}/symbol_table.go (97%) rename internal/lsp/{ => symbol_table}/symbol_table_includes.go (94%) rename internal/lsp/{ => symbol_table}/symbol_table_template_context.go (93%) rename internal/lsp/{ => symbol_table}/symbol_table_template_context_test.go (92%) rename internal/lsp/{ => symbol_table}/symbol_table_template_context_variables.go (98%) rename internal/lsp/{ => symbol_table}/symbol_table_template_context_variables_test.go (90%) rename internal/lsp/{ => symbol_table}/symbol_table_test.go (92%) rename internal/lsp/{ => symbol_table}/symbol_table_variables.go (99%) rename internal/lsp/{ => symbol_table}/symbol_table_variables_test.go (92%) rename internal/lsp/{ => symbol_table}/variables_visitor.go (99%) rename internal/lsp/{ => symbol_table}/variables_visitor_test.go (94%) rename internal/lsp/{ => symbol_table}/visitor.go (99%) rename internal/lsp/{ => template_ast}/ast.go (95%) diff --git a/internal/adapter/yamlls/diagnostics.go b/internal/adapter/yamlls/diagnostics.go index 07d01c2b..e3b06c0c 100644 --- a/internal/adapter/yamlls/diagnostics.go +++ b/internal/adapter/yamlls/diagnostics.go @@ -7,6 +7,7 @@ import ( "strings" lsplocal "github.com/mrjosh/helm-ls/internal/lsp" + templateast "github.com/mrjosh/helm-ls/internal/lsp/template_ast" sitter "github.com/smacker/go-tree-sitter" "go.lsp.dev/protocol" lsp "go.lsp.dev/protocol" @@ -36,8 +37,8 @@ func filterDiagnostics(diagnostics []lsp.Diagnostic, ast *sitter.Tree, content [ filtered = []lsp.Diagnostic{} for _, diagnostic := range diagnostics { - node := lsplocal.NodeAtPosition(ast, diagnostic.Range.Start) - childNode := lsplocal.FindRelevantChildNode(ast.RootNode(), lsplocal.GetSitterPointForLspPos(diagnostic.Range.Start)) + node := templateast.NodeAtPosition(ast, diagnostic.Range.Start) + childNode := templateast.FindRelevantChildNode(ast.RootNode(), templateast.GetSitterPointForLspPos(diagnostic.Range.Start)) if node.Type() == "text" && childNode.Type() == "text" { logger.Debug("Diagnostic", diagnostic) diff --git a/internal/adapter/yamlls/diagnostics_integration_test.go b/internal/adapter/yamlls/diagnostics_integration_test.go index 345053e9..65237db0 100644 --- a/internal/adapter/yamlls/diagnostics_integration_test.go +++ b/internal/adapter/yamlls/diagnostics_integration_test.go @@ -11,7 +11,7 @@ import ( "testing" "time" - lsplocal "github.com/mrjosh/helm-ls/internal/lsp" + "github.com/mrjosh/helm-ls/internal/lsp/document" "github.com/mrjosh/helm-ls/internal/util" "github.com/stretchr/testify/assert" "go.lsp.dev/protocol" @@ -44,7 +44,7 @@ func readTestFiles(dir string, channel chan<- string, doneChan chan<- int) { doneChan <- count } -func sendTestFilesToYamlls(documents *lsplocal.DocumentStore, yamllsConnector *Connector, +func sendTestFilesToYamlls(documents *document.DocumentStore, yamllsConnector *Connector, doneReadingFilesChan <-chan int, doneSendingFilesChan chan<- int, filesChan <-chan string, diff --git a/internal/adapter/yamlls/document_sync.go b/internal/adapter/yamlls/document_sync.go index 38a932e6..a6d1583d 100644 --- a/internal/adapter/yamlls/document_sync.go +++ b/internal/adapter/yamlls/document_sync.go @@ -4,12 +4,13 @@ import ( "context" lsplocal "github.com/mrjosh/helm-ls/internal/lsp" + "github.com/mrjosh/helm-ls/internal/lsp/document" "github.com/mrjosh/helm-ls/internal/util" sitter "github.com/smacker/go-tree-sitter" lsp "go.lsp.dev/protocol" ) -func (yamllsConnector Connector) InitiallySyncOpenDocuments(docs []*lsplocal.TemplateDocument) { +func (yamllsConnector Connector) InitiallySyncOpenDocuments(docs []*document.TemplateDocument) { if yamllsConnector.server == nil { return } @@ -48,7 +49,7 @@ func (yamllsConnector Connector) DocumentDidOpen(ast *sitter.Tree, params lsp.Di } } -func (yamllsConnector Connector) DocumentDidSave(doc *lsplocal.TemplateDocument, params lsp.DidSaveTextDocumentParams) { +func (yamllsConnector Connector) DocumentDidSave(doc *document.TemplateDocument, params lsp.DidSaveTextDocumentParams) { if !yamllsConnector.shouldRun(doc.URI) { return } @@ -67,7 +68,7 @@ func (yamllsConnector Connector) DocumentDidSave(doc *lsplocal.TemplateDocument, }) } -func (yamllsConnector Connector) DocumentDidChange(doc *lsplocal.TemplateDocument, params lsp.DidChangeTextDocumentParams) { +func (yamllsConnector Connector) DocumentDidChange(doc *document.TemplateDocument, params lsp.DidChangeTextDocumentParams) { if !yamllsConnector.shouldRun(doc.URI) { return } @@ -96,7 +97,7 @@ func (yamllsConnector Connector) DocumentDidChange(doc *lsplocal.TemplateDocumen } } -func (yamllsConnector Connector) DocumentDidChangeFullSync(doc *lsplocal.TemplateDocument, params lsp.DidChangeTextDocumentParams) { +func (yamllsConnector Connector) DocumentDidChangeFullSync(doc *document.TemplateDocument, params lsp.DidChangeTextDocumentParams) { if !yamllsConnector.shouldRun(doc.URI) { return } diff --git a/internal/adapter/yamlls/integration_test_utils.go b/internal/adapter/yamlls/integration_test_utils.go index 93ec06c8..9bca680a 100644 --- a/internal/adapter/yamlls/integration_test_utils.go +++ b/internal/adapter/yamlls/integration_test_utils.go @@ -9,7 +9,7 @@ import ( "strings" "testing" - lsplocal "github.com/mrjosh/helm-ls/internal/lsp" + "github.com/mrjosh/helm-ls/internal/lsp/document" "github.com/mrjosh/helm-ls/internal/util" "go.lsp.dev/jsonrpc2" "go.lsp.dev/protocol" @@ -47,9 +47,9 @@ func (proc readWriteCloseMock) Close() error { return nil } -func getYamlLsConnector(t *testing.T, config util.YamllsConfiguration) (*Connector, *lsplocal.DocumentStore, chan lsp.PublishDiagnosticsParams) { +func getYamlLsConnector(t *testing.T, config util.YamllsConfiguration) (*Connector, *document.DocumentStore, chan lsp.PublishDiagnosticsParams) { dir := t.TempDir() - documents := lsplocal.NewDocumentStore() + documents := document.NewDocumentStore() diagnosticsChan := make(chan lsp.PublishDiagnosticsParams) con := jsonrpc2.NewConn(jsonrpc2.NewStream(readWriteCloseMock{diagnosticsChan})) zapLogger, _ := zap.NewProduction() @@ -66,7 +66,7 @@ func getYamlLsConnector(t *testing.T, config util.YamllsConfiguration) (*Connect return yamllsConnector, documents, diagnosticsChan } -func openFile(t *testing.T, documents *lsplocal.DocumentStore, path string, yamllsConnector *Connector) { +func openFile(t *testing.T, documents *document.DocumentStore, path string, yamllsConnector *Connector) { fileURI := uri.File(path) content, err := os.ReadFile(path) diff --git a/internal/adapter/yamlls/yamlls.go b/internal/adapter/yamlls/yamlls.go index 759d4401..3b90c434 100644 --- a/internal/adapter/yamlls/yamlls.go +++ b/internal/adapter/yamlls/yamlls.go @@ -8,7 +8,7 @@ import ( "github.com/gobwas/glob" "github.com/mrjosh/helm-ls/internal/log" - lsplocal "github.com/mrjosh/helm-ls/internal/lsp" + "github.com/mrjosh/helm-ls/internal/lsp/document" "github.com/mrjosh/helm-ls/internal/util" "go.lsp.dev/jsonrpc2" "go.lsp.dev/protocol" @@ -21,12 +21,12 @@ var logger = log.GetLogger() type Connector struct { config util.YamllsConfiguration server protocol.Server - documents *lsplocal.DocumentStore + documents *document.DocumentStore client protocol.Client EnabledForFilesGlobObject glob.Glob } -func NewConnector(ctx context.Context, yamllsConfiguration util.YamllsConfiguration, client protocol.Client, documents *lsplocal.DocumentStore) *Connector { +func NewConnector(ctx context.Context, yamllsConfiguration util.YamllsConfiguration, client protocol.Client, documents *document.DocumentStore) *Connector { yamllsCmd := exec.Command(yamllsConfiguration.Path, "--stdio") stdin, err := yamllsCmd.StdinPipe() diff --git a/internal/adapter/yamlls/yamlls_test.go b/internal/adapter/yamlls/yamlls_test.go index cfe6c50a..9b82b28f 100644 --- a/internal/adapter/yamlls/yamlls_test.go +++ b/internal/adapter/yamlls/yamlls_test.go @@ -4,7 +4,7 @@ import ( "os" "testing" - lsplocal "github.com/mrjosh/helm-ls/internal/lsp" + "github.com/mrjosh/helm-ls/internal/lsp/document" "github.com/mrjosh/helm-ls/internal/util" "github.com/stretchr/testify/assert" "go.lsp.dev/uri" @@ -17,7 +17,7 @@ func TestIsRelevantFile(t *testing.T) { }, } - connector.documents = lsplocal.NewDocumentStore() + connector.documents = document.NewDocumentStore() yamlFile := "../../../testdata/example/templates/deployment.yaml" nonYamlFile := "../../../testdata/example/templates/_helpers.tpl" diff --git a/internal/handler/handler.go b/internal/handler/handler.go index 6c41103f..fa2e08c9 100644 --- a/internal/handler/handler.go +++ b/internal/handler/handler.go @@ -7,7 +7,7 @@ import ( "github.com/mrjosh/helm-ls/internal/charts" templatehandler "github.com/mrjosh/helm-ls/internal/handler/template_handler" yamlhandler "github.com/mrjosh/helm-ls/internal/handler/yaml_handler" - lsplocal "github.com/mrjosh/helm-ls/internal/lsp" + "github.com/mrjosh/helm-ls/internal/lsp/document" "github.com/mrjosh/helm-ls/internal/util" "go.lsp.dev/jsonrpc2" "go.lsp.dev/protocol" @@ -23,10 +23,10 @@ type ServerHandler struct { client protocol.Client connPool jsonrpc2.Conn linterName string - documents *lsplocal.DocumentStore + documents *document.DocumentStore chartStore *charts.ChartStore helmlsConfig util.HelmlsConfiguration - langHandlers map[lsplocal.DocumentType]LangHandler + langHandlers map[document.DocumentType]LangHandler } func StartHandler(stream io.ReadWriteCloser) { @@ -45,7 +45,7 @@ func StartHandler(stream io.ReadWriteCloser) { } func newHandler(connPool jsonrpc2.Conn, client protocol.Client) *ServerHandler { - documents := lsplocal.NewDocumentStore() + documents := document.NewDocumentStore() var x LangHandler = yamlhandler.NewYamlHandler(client, documents, nil) handler := &ServerHandler{ client: client, @@ -53,9 +53,9 @@ func newHandler(connPool jsonrpc2.Conn, client protocol.Client) *ServerHandler { connPool: connPool, documents: documents, helmlsConfig: util.DefaultConfig, - langHandlers: map[lsplocal.DocumentType]LangHandler{ - lsplocal.TemplateDocumentType: templatehandler.NewTemplateHandler(client, documents, nil), - lsplocal.YamlDocumentType: x, + langHandlers: map[document.DocumentType]LangHandler{ + document.TemplateDocumentType: templatehandler.NewTemplateHandler(client, documents, nil), + document.YamlDocumentType: x, }, } logger.Printf("helm-lint-langserver: connections opened") diff --git a/internal/handler/template_handler/completion.go b/internal/handler/template_handler/completion.go index 4dba2592..64c3ab81 100644 --- a/internal/handler/template_handler/completion.go +++ b/internal/handler/template_handler/completion.go @@ -4,7 +4,7 @@ import ( "context" languagefeatures "github.com/mrjosh/helm-ls/internal/language_features" - lsplocal "github.com/mrjosh/helm-ls/internal/lsp" + templateast "github.com/mrjosh/helm-ls/internal/lsp/template_ast" "github.com/mrjosh/helm-ls/internal/protocol" lsp "go.lsp.dev/protocol" @@ -14,7 +14,7 @@ import ( func (h *TemplateHandler) 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, lsplocal.NestedNodeAtPositionForCompletion) + genericDocumentUseCase, err := h.NewGenericDocumentUseCase(params.TextDocumentPositionParams, templateast.NestedNodeAtPositionForCompletion) if err != nil { return nil, err } diff --git a/internal/handler/template_handler/completion_main_test.go b/internal/handler/template_handler/completion_main_test.go index 2107e94a..5ab94e5a 100644 --- a/internal/handler/template_handler/completion_main_test.go +++ b/internal/handler/template_handler/completion_main_test.go @@ -9,7 +9,7 @@ import ( "github.com/mrjosh/helm-ls/internal/adapter/yamlls" "github.com/mrjosh/helm-ls/internal/charts" helmdocs "github.com/mrjosh/helm-ls/internal/documentation/helm" - lsplocal "github.com/mrjosh/helm-ls/internal/lsp" + "github.com/mrjosh/helm-ls/internal/lsp/document" "github.com/mrjosh/helm-ls/internal/util" "github.com/stretchr/testify/assert" lsp "go.lsp.dev/protocol" @@ -216,7 +216,7 @@ func TestCompletionMainSingleLines(t *testing.T) { } func completionTestCall(fileURI uri.URI, buf string, pos lsp.Position) (*lsp.CompletionList, error) { - documents := lsplocal.NewDocumentStore() + documents := document.NewDocumentStore() d := lsp.DidOpenTextDocumentParams{ TextDocument: lsp.TextDocumentItem{ URI: fileURI, diff --git a/internal/handler/template_handler/definition.go b/internal/handler/template_handler/definition.go index 53d5fdb9..4a0485a6 100644 --- a/internal/handler/template_handler/definition.go +++ b/internal/handler/template_handler/definition.go @@ -4,12 +4,12 @@ import ( "context" languagefeatures "github.com/mrjosh/helm-ls/internal/language_features" - lsplocal "github.com/mrjosh/helm-ls/internal/lsp" + templateast "github.com/mrjosh/helm-ls/internal/lsp/template_ast" lsp "go.lsp.dev/protocol" ) func (h *TemplateHandler) Definition(_ context.Context, params *lsp.DefinitionParams) (result []lsp.Location, err error) { - genericDocumentUseCase, err := h.NewGenericDocumentUseCase(params.TextDocumentPositionParams, lsplocal.NodeAtPosition) + genericDocumentUseCase, err := h.NewGenericDocumentUseCase(params.TextDocumentPositionParams, templateast.NodeAtPosition) if err != nil { return nil, err } diff --git a/internal/handler/template_handler/definition_chart_test.go b/internal/handler/template_handler/definition_chart_test.go index 401901c4..36c09b2c 100644 --- a/internal/handler/template_handler/definition_chart_test.go +++ b/internal/handler/template_handler/definition_chart_test.go @@ -10,7 +10,7 @@ import ( "github.com/mrjosh/helm-ls/internal/adapter/yamlls" "github.com/mrjosh/helm-ls/internal/charts" - lsplocal "github.com/mrjosh/helm-ls/internal/lsp" + "github.com/mrjosh/helm-ls/internal/lsp/document" "github.com/mrjosh/helm-ls/internal/util" "github.com/stretchr/testify/assert" lsp "go.lsp.dev/protocol" @@ -160,7 +160,7 @@ func TestDefinitionChart(t *testing.T) { t.Fatal(fmt.Sprintf("%s is not in the file %s", tc.templateLineWithMarker, fileURI.Filename())) } - documents := lsplocal.NewDocumentStore() + documents := document.NewDocumentStore() chart := charts.NewChart(rootUri, util.DefaultConfig.ValuesFilesConfig) diff --git a/internal/handler/template_handler/definition_test.go b/internal/handler/template_handler/definition_test.go index 3d4c4704..fa1d8b12 100644 --- a/internal/handler/template_handler/definition_test.go +++ b/internal/handler/template_handler/definition_test.go @@ -8,7 +8,7 @@ import ( "github.com/mrjosh/helm-ls/internal/adapter/yamlls" "github.com/mrjosh/helm-ls/internal/charts" - lsplocal "github.com/mrjosh/helm-ls/internal/lsp" + "github.com/mrjosh/helm-ls/internal/lsp/document" "github.com/mrjosh/helm-ls/internal/util" "github.com/stretchr/testify/assert" "go.lsp.dev/protocol" @@ -54,7 +54,7 @@ func genericDefinitionTest(t *testing.T, position lsp.Position, expectedLocation t.Fatal(err) } - documents := lsplocal.NewDocumentStore() + documents := document.NewDocumentStore() fileURI := testDocumentTemplateURI rootUri := uri.File("/") @@ -244,7 +244,7 @@ func genericDefinitionTestMultipleValuesFiles(t *testing.T, position lsp.Positio if err != nil { t.Fatal(err) } - documents := lsplocal.NewDocumentStore() + documents := document.NewDocumentStore() fileURI := testDocumentTemplateURI rootUri := uri.File("/") @@ -356,7 +356,7 @@ func TestDefinitionSingleLine(t *testing.T) { expectedColEnd := strings.Index(buf, "§") buf = strings.Replace(buf, "§", "", 1) - documents := lsplocal.NewDocumentStore() + documents := document.NewDocumentStore() fileURI := testDocumentTemplateURI rootUri := uri.File("/") diff --git a/internal/handler/template_handler/hover.go b/internal/handler/template_handler/hover.go index 7a256255..8a33a87f 100644 --- a/internal/handler/template_handler/hover.go +++ b/internal/handler/template_handler/hover.go @@ -4,7 +4,7 @@ import ( "context" languagefeatures "github.com/mrjosh/helm-ls/internal/language_features" - lsplocal "github.com/mrjosh/helm-ls/internal/lsp" + templateast "github.com/mrjosh/helm-ls/internal/lsp/template_ast" "github.com/mrjosh/helm-ls/internal/protocol" "github.com/mrjosh/helm-ls/internal/tree-sitter/gotemplate" @@ -12,12 +12,12 @@ import ( ) func (h *TemplateHandler) Hover(ctx context.Context, params *lsp.HoverParams) (result *lsp.Hover, err error) { - genericDocumentUseCase, err := h.NewGenericDocumentUseCase(params.TextDocumentPositionParams, lsplocal.NodeAtPosition) + genericDocumentUseCase, err := h.NewGenericDocumentUseCase(params.TextDocumentPositionParams, templateast.NodeAtPosition) if err != nil { return nil, err } - wordRange := lsplocal.GetLspRangeForNode(genericDocumentUseCase.Node) + wordRange := templateast.GetLspRangeForNode(genericDocumentUseCase.Node) usecases := []languagefeatures.HoverUseCase{ languagefeatures.NewBuiltInObjectsFeature(genericDocumentUseCase), // has to be before template context diff --git a/internal/handler/template_handler/hover_main_test.go b/internal/handler/template_handler/hover_main_test.go index ca5dfa6b..69743003 100644 --- a/internal/handler/template_handler/hover_main_test.go +++ b/internal/handler/template_handler/hover_main_test.go @@ -10,7 +10,7 @@ import ( "github.com/mrjosh/helm-ls/internal/adapter/yamlls" "github.com/mrjosh/helm-ls/internal/charts" - lsplocal "github.com/mrjosh/helm-ls/internal/lsp" + "github.com/mrjosh/helm-ls/internal/lsp/document" "github.com/mrjosh/helm-ls/internal/util" "github.com/stretchr/testify/assert" lsp "go.lsp.dev/protocol" @@ -165,7 +165,7 @@ func TestHoverMain(t *testing.T) { } for _, tt := range testCases { t.Run(tt.desc, func(t *testing.T) { - documents := lsplocal.NewDocumentStore() + documents := document.NewDocumentStore() path := "../../../testdata/example/templates/deployment.yaml" fileURI := uri.File(path) diff --git a/internal/handler/template_handler/references.go b/internal/handler/template_handler/references.go index 8869966e..486fdd24 100644 --- a/internal/handler/template_handler/references.go +++ b/internal/handler/template_handler/references.go @@ -4,12 +4,12 @@ import ( "context" languagefeatures "github.com/mrjosh/helm-ls/internal/language_features" - lsplocal "github.com/mrjosh/helm-ls/internal/lsp" + templateast "github.com/mrjosh/helm-ls/internal/lsp/template_ast" lsp "go.lsp.dev/protocol" ) func (h *TemplateHandler) References(_ context.Context, params *lsp.ReferenceParams) (result []lsp.Location, err error) { - genericDocumentUseCase, err := h.NewGenericDocumentUseCase(params.TextDocumentPositionParams, lsplocal.NodeAtPosition) + genericDocumentUseCase, err := h.NewGenericDocumentUseCase(params.TextDocumentPositionParams, templateast.NodeAtPosition) if err != nil { return nil, err } diff --git a/internal/handler/template_handler/references_test.go b/internal/handler/template_handler/references_test.go index 3daa783f..42bfff35 100644 --- a/internal/handler/template_handler/references_test.go +++ b/internal/handler/template_handler/references_test.go @@ -7,7 +7,7 @@ import ( "github.com/mrjosh/helm-ls/internal/adapter/yamlls" "github.com/mrjosh/helm-ls/internal/charts" - lsplocal "github.com/mrjosh/helm-ls/internal/lsp" + "github.com/mrjosh/helm-ls/internal/lsp/document" "github.com/mrjosh/helm-ls/internal/util" "github.com/stretchr/testify/assert" "go.lsp.dev/protocol" @@ -81,7 +81,7 @@ func TestRefercesTemplateContext(t *testing.T) { for _, tt := range testCases { t.Run(tt.desc, func(t *testing.T) { - documents := lsplocal.NewDocumentStore() + documents := document.NewDocumentStore() path := "/tmp/testfile.yaml" fileURI := uri.File(path) @@ -143,7 +143,7 @@ func TestRefercesTemplateContextWithTestFile(t *testing.T) { for _, tt := range testCases { t.Run(tt.desc, func(t *testing.T) { - documents := lsplocal.NewDocumentStore() + documents := document.NewDocumentStore() path := "../../../testdata/example/templates/deployment.yaml" fileURI := uri.File(path) @@ -207,7 +207,7 @@ func TestRefercesSingleLines(t *testing.T) { for _, tt := range testCases { t.Run(tt.templateWithMark, func(t *testing.T) { - documents := lsplocal.NewDocumentStore() + documents := document.NewDocumentStore() pos, buf := getPositionForMarkedTestLine(tt.templateWithMark) fileURI := uri.File("fake-testfile.yaml") diff --git a/internal/handler/template_handler/template_handler.go b/internal/handler/template_handler/template_handler.go index 377ad5db..df4204a6 100644 --- a/internal/handler/template_handler/template_handler.go +++ b/internal/handler/template_handler/template_handler.go @@ -4,7 +4,7 @@ import ( "github.com/mrjosh/helm-ls/internal/adapter/yamlls" "github.com/mrjosh/helm-ls/internal/charts" "github.com/mrjosh/helm-ls/internal/log" - lsplocal "github.com/mrjosh/helm-ls/internal/lsp" + "github.com/mrjosh/helm-ls/internal/lsp/document" "go.lsp.dev/protocol" ) @@ -12,12 +12,12 @@ var logger = log.GetLogger() type TemplateHandler struct { client protocol.Client - documents *lsplocal.DocumentStore + documents *document.DocumentStore chartStore *charts.ChartStore yamllsConnector *yamlls.Connector } -func NewTemplateHandler(client protocol.Client, documents *lsplocal.DocumentStore, chartStore *charts.ChartStore) *TemplateHandler { +func NewTemplateHandler(client protocol.Client, documents *document.DocumentStore, chartStore *charts.ChartStore) *TemplateHandler { return &TemplateHandler{ client: client, documents: documents, diff --git a/internal/handler/template_handler/text_document.go b/internal/handler/template_handler/text_document.go index bc660d0e..a823c398 100644 --- a/internal/handler/template_handler/text_document.go +++ b/internal/handler/template_handler/text_document.go @@ -4,7 +4,7 @@ import ( "context" "errors" - lsplocal "github.com/mrjosh/helm-ls/internal/lsp" + templateast "github.com/mrjosh/helm-ls/internal/lsp/template_ast" "github.com/mrjosh/helm-ls/internal/util" lsp "go.lsp.dev/protocol" ) @@ -40,7 +40,7 @@ func (h *TemplateHandler) PostDidChange(ctx context.Context, params *lsp.DidChan shouldSendFullUpdateToYamlls := false for _, change := range params.ContentChanges { - node := lsplocal.NodeAtPosition(doc.Ast, change.Range.Start) + node := templateast.NodeAtPosition(doc.Ast, change.Range.Start) if node.Type() != "text" { shouldSendFullUpdateToYamlls = true break diff --git a/internal/handler/text_document.go b/internal/handler/text_document.go index e4bdcc52..7a37fda6 100644 --- a/internal/handler/text_document.go +++ b/internal/handler/text_document.go @@ -5,12 +5,12 @@ import ( "errors" "github.com/mrjosh/helm-ls/internal/charts" - lsplocal "github.com/mrjosh/helm-ls/internal/lsp" + "github.com/mrjosh/helm-ls/internal/lsp/document" lsp "go.lsp.dev/protocol" ) func (h *ServerHandler) DidOpen(ctx context.Context, params *lsp.DidOpenTextDocumentParams) (err error) { - handler := h.langHandlers[lsplocal.TemplateDocumentTypeForLangID(params.TextDocument.LanguageID)] + handler := h.langHandlers[document.TemplateDocumentTypeForLangID(params.TextDocument.LanguageID)] if handler == nil { message := "Language not supported: " + string(params.TextDocument.LanguageID) diff --git a/internal/handler/text_document_test.go b/internal/handler/text_document_test.go index 4771f843..c7b3ed6b 100644 --- a/internal/handler/text_document_test.go +++ b/internal/handler/text_document_test.go @@ -6,7 +6,7 @@ import ( "testing" "github.com/mrjosh/helm-ls/internal/charts" - lsplocal "github.com/mrjosh/helm-ls/internal/lsp" + "github.com/mrjosh/helm-ls/internal/lsp/document" "github.com/mrjosh/helm-ls/internal/util" "github.com/stretchr/testify/assert" lsp "go.lsp.dev/protocol" @@ -32,7 +32,7 @@ func TestLoadDocsOnNewChart(t *testing.T) { } h := &ServerHandler{ - documents: lsplocal.NewDocumentStore(), + documents: document.NewDocumentStore(), helmlsConfig: util.DefaultConfig, } @@ -59,7 +59,7 @@ func TestLoadDocsOnNewChartDoesNotOverwrite(t *testing.T) { err = os.WriteFile(templateFile, []byte("This is a template file"), 0o644) assert.NoError(t, err) - docs := lsplocal.NewDocumentStore() + docs := document.NewDocumentStore() h := &ServerHandler{ documents: docs, helmlsConfig: util.DefaultConfig, @@ -84,7 +84,7 @@ func TestLoadDocsOnNewChartWorksForMissingTemplateDir(t *testing.T) { tempDir := t.TempDir() rootURI := uri.File(tempDir) - docs := lsplocal.NewDocumentStore() + docs := document.NewDocumentStore() h := &ServerHandler{ documents: docs, helmlsConfig: util.DefaultConfig, diff --git a/internal/handler/yaml_handler/yaml_handler.go b/internal/handler/yaml_handler/yaml_handler.go index 5a77d4c9..f877da5b 100644 --- a/internal/handler/yaml_handler/yaml_handler.go +++ b/internal/handler/yaml_handler/yaml_handler.go @@ -6,7 +6,7 @@ import ( "github.com/mrjosh/helm-ls/internal/adapter/yamlls" "github.com/mrjosh/helm-ls/internal/charts" "github.com/mrjosh/helm-ls/internal/log" - lsplocal "github.com/mrjosh/helm-ls/internal/lsp" + "github.com/mrjosh/helm-ls/internal/lsp/document" "github.com/mrjosh/helm-ls/internal/util" "go.lsp.dev/protocol" ) @@ -14,7 +14,7 @@ import ( var logger = log.GetLogger() type YamlHandler struct { - documents *lsplocal.DocumentStore + documents *document.DocumentStore chartStore *charts.ChartStore yamllsConnector *yamlls.Connector } @@ -41,7 +41,7 @@ func (h *YamlHandler) References(ctx context.Context, params *protocol.Reference // SetClient implements handler.LangHandler. func (h *YamlHandler) SetClient(client protocol.Client) {} -func NewYamlHandler(client protocol.Client, documents *lsplocal.DocumentStore, chartStore *charts.ChartStore) *YamlHandler { +func NewYamlHandler(client protocol.Client, documents *document.DocumentStore, chartStore *charts.ChartStore) *YamlHandler { return &YamlHandler{ documents: documents, chartStore: chartStore, diff --git a/internal/helm_lint/lint.go b/internal/helm_lint/lint.go index 50a4c47d..e7bd3f53 100644 --- a/internal/helm_lint/lint.go +++ b/internal/helm_lint/lint.go @@ -8,7 +8,7 @@ import ( "github.com/mrjosh/helm-ls/internal/charts" "github.com/mrjosh/helm-ls/internal/log" - lsplocal "github.com/mrjosh/helm-ls/internal/lsp" + "github.com/mrjosh/helm-ls/internal/lsp/document" "github.com/mrjosh/helm-ls/internal/util" lsp "go.lsp.dev/protocol" "go.lsp.dev/uri" @@ -19,7 +19,7 @@ import ( var logger = log.GetLogger() -func GetDiagnosticsNotifications(chart *charts.Chart, doc *lsplocal.TemplateDocument) []lsp.PublishDiagnosticsParams { +func GetDiagnosticsNotifications(chart *charts.Chart, doc *document.TemplateDocument) []lsp.PublishDiagnosticsParams { vals := chart.ValuesFiles.MainValuesFile.Values if chart.ValuesFiles.OverlayValuesFile != nil { vals = chartutil.CoalesceTables(chart.ValuesFiles.OverlayValuesFile.Values, chart.ValuesFiles.MainValuesFile.Values) diff --git a/internal/helm_lint/lint_test.go b/internal/helm_lint/lint_test.go index 9cf4fb71..111529dc 100644 --- a/internal/helm_lint/lint_test.go +++ b/internal/helm_lint/lint_test.go @@ -4,7 +4,7 @@ import ( "testing" "github.com/mrjosh/helm-ls/internal/charts" - lsplocal "github.com/mrjosh/helm-ls/internal/lsp" + "github.com/mrjosh/helm-ls/internal/lsp/document" "github.com/stretchr/testify/assert" "go.lsp.dev/uri" "helm.sh/helm/v3/pkg/chartutil" @@ -26,8 +26,8 @@ func TestLintNotifications(t *testing.T) { AdditionalValuesFiles: []*charts.ValuesFile{}, }, } - diagnostics := GetDiagnosticsNotifications(&chart, &lsplocal.TemplateDocument{ - Document: lsplocal.Document{ + diagnostics := GetDiagnosticsNotifications(&chart, &document.TemplateDocument{ + Document: document.Document{ URI: uri.File("../../testdata/example/templates/deployment-no-templates.yaml"), }, }) @@ -55,8 +55,8 @@ func TestLintNotificationsIncludesEmptyDiagnosticsForFixedIssues(t *testing.T) { AdditionalValuesFiles: []*charts.ValuesFile{}, }, } - diagnostics := GetDiagnosticsNotifications(&chart, &lsplocal.TemplateDocument{ - Document: lsplocal.Document{URI: uri.File("../../testdata/example/templates/deployment-no-templates.yaml")}, + diagnostics := GetDiagnosticsNotifications(&chart, &document.TemplateDocument{ + Document: document.Document{URI: uri.File("../../testdata/example/templates/deployment-no-templates.yaml")}, }, ) diff --git a/internal/language_features/built_in_objects.go b/internal/language_features/built_in_objects.go index 3acc79ff..247fd2a0 100644 --- a/internal/language_features/built_in_objects.go +++ b/internal/language_features/built_in_objects.go @@ -2,7 +2,7 @@ package languagefeatures import ( helmdocs "github.com/mrjosh/helm-ls/internal/documentation/helm" - lsplocal "github.com/mrjosh/helm-ls/internal/lsp" + symboltable "github.com/mrjosh/helm-ls/internal/lsp/symbol_table" "github.com/mrjosh/helm-ls/internal/tree-sitter/gotemplate" lsp "go.lsp.dev/protocol" ) @@ -51,7 +51,7 @@ func (f *BuiltInObjectsFeature) References() (result []lsp.Location, err error) return append(locations, f.getDefinitionLocations(templateContext)...), err } -func (f *BuiltInObjectsFeature) getDefinitionLocations(templateContext lsplocal.TemplateContext) []lsp.Location { +func (f *BuiltInObjectsFeature) getDefinitionLocations(templateContext symboltable.TemplateContext) []lsp.Location { locations := []lsp.Location{} switch templateContext[0] { diff --git a/internal/language_features/generic_document_usecase.go b/internal/language_features/generic_document_usecase.go index 3943cd98..abcb4130 100644 --- a/internal/language_features/generic_document_usecase.go +++ b/internal/language_features/generic_document_usecase.go @@ -2,13 +2,13 @@ package languagefeatures import ( "github.com/mrjosh/helm-ls/internal/charts" - lsplocal "github.com/mrjosh/helm-ls/internal/lsp" + "github.com/mrjosh/helm-ls/internal/lsp/document" sitter "github.com/smacker/go-tree-sitter" ) type GenericDocumentUseCase struct { - Document *lsplocal.TemplateDocument - DocumentStore *lsplocal.DocumentStore + Document *document.TemplateDocument + DocumentStore *document.DocumentStore Chart *charts.Chart Node *sitter.Node ChartStore *charts.ChartStore diff --git a/internal/language_features/generic_template_context.go b/internal/language_features/generic_template_context.go index d0704a87..10d73d08 100644 --- a/internal/language_features/generic_template_context.go +++ b/internal/language_features/generic_template_context.go @@ -4,7 +4,7 @@ import ( "fmt" helmdocs "github.com/mrjosh/helm-ls/internal/documentation/helm" - lsplocal "github.com/mrjosh/helm-ls/internal/lsp" + symboltable "github.com/mrjosh/helm-ls/internal/lsp/symbol_table" "github.com/mrjosh/helm-ls/internal/util" lsp "go.lsp.dev/protocol" ) @@ -13,11 +13,11 @@ type GenericTemplateContextFeature struct { *GenericDocumentUseCase } -func (f *GenericTemplateContextFeature) getTemplateContext() (lsplocal.TemplateContext, error) { - return f.GenericDocumentUseCase.Document.SymbolTable.GetTemplateContext(lsplocal.GetRangeForNode(f.Node)) +func (f *GenericTemplateContextFeature) getTemplateContext() (symboltable.TemplateContext, error) { + return f.GenericDocumentUseCase.Document.SymbolTable.GetTemplateContext(util.GetRangeForNode(f.Node)) } -func (f *GenericTemplateContextFeature) getReferencesFromSymbolTable(templateContext lsplocal.TemplateContext) []lsp.Location { +func (f *GenericTemplateContextFeature) getReferencesFromSymbolTable(templateContext symboltable.TemplateContext) []lsp.Location { locations := []lsp.Location{} for _, doc := range f.GenericDocumentUseCase.DocumentStore.GetAllTemplateDocs() { diff --git a/internal/language_features/includes.go b/internal/language_features/includes.go index ebb592d5..22fbac8d 100644 --- a/internal/language_features/includes.go +++ b/internal/language_features/includes.go @@ -4,7 +4,7 @@ import ( lsp "go.lsp.dev/protocol" "github.com/mrjosh/helm-ls/internal/charts" - lsplocal "github.com/mrjosh/helm-ls/internal/lsp" + symboltable "github.com/mrjosh/helm-ls/internal/lsp/symbol_table" "github.com/mrjosh/helm-ls/internal/protocol" "github.com/mrjosh/helm-ls/internal/tree-sitter/gotemplate" "github.com/mrjosh/helm-ls/internal/util" @@ -26,7 +26,7 @@ func (f *IncludesCallFeature) AppropriateForNode() bool { if functionCallNode == nil { return false } - _, err := lsplocal.ParseIncludeFunctionCall(functionCallNode, []byte(f.GenericDocumentUseCase.Document.Content)) + _, err := symboltable.ParseIncludeFunctionCall(functionCallNode, []byte(f.GenericDocumentUseCase.Document.Content)) return err == nil } @@ -76,7 +76,7 @@ func (f *IncludesCallFeature) References() (result []lsp.Location, err error) { func (f *IncludesCallFeature) getIncludeName() (string, error) { functionCallNode := f.getFunctionCallNode() - return lsplocal.ParseIncludeFunctionCall(functionCallNode, []byte(f.GenericDocumentUseCase.Document.Content)) + return symboltable.ParseIncludeFunctionCall(functionCallNode, []byte(f.GenericDocumentUseCase.Document.Content)) } func (f *IncludesDefinitionFeature) References() (result []lsp.Location, err error) { diff --git a/internal/language_features/template_context.go b/internal/language_features/template_context.go index 38e6dbf2..78eddec1 100644 --- a/internal/language_features/template_context.go +++ b/internal/language_features/template_context.go @@ -9,7 +9,7 @@ import ( "github.com/mrjosh/helm-ls/internal/charts" helmdocs "github.com/mrjosh/helm-ls/internal/documentation/helm" - lsplocal "github.com/mrjosh/helm-ls/internal/lsp" + symboltable "github.com/mrjosh/helm-ls/internal/lsp/symbol_table" "github.com/mrjosh/helm-ls/internal/protocol" "github.com/mrjosh/helm-ls/internal/tree-sitter/gotemplate" "github.com/mrjosh/helm-ls/internal/util" @@ -53,7 +53,7 @@ func (f *TemplateContextFeature) Definition() (result []lsp.Location, err error) return f.getDefinitionLocations(templateContext), nil } -func (f *TemplateContextFeature) getReferenceLocations(templateContext lsplocal.TemplateContext) []lsp.Location { +func (f *TemplateContextFeature) getReferenceLocations(templateContext symboltable.TemplateContext) []lsp.Location { locations := []lsp.Location{} for _, doc := range f.GenericDocumentUseCase.DocumentStore.GetAllTemplateDocs() { referenceRanges := doc.SymbolTable.GetTemplateContextRanges(templateContext) @@ -65,7 +65,7 @@ func (f *TemplateContextFeature) getReferenceLocations(templateContext lsplocal. return append(locations, f.getDefinitionLocations(templateContext)...) } -func (f *TemplateContextFeature) getDefinitionLocations(templateContext lsplocal.TemplateContext) []lsp.Location { +func (f *TemplateContextFeature) getDefinitionLocations(templateContext symboltable.TemplateContext) []lsp.Location { locations := []lsp.Location{} switch templateContext[0] { @@ -108,7 +108,7 @@ func (f *TemplateContextFeature) Hover() (string, error) { return templateContext.Format(), err } -func (f *TemplateContextFeature) valuesHover(templateContext lsplocal.TemplateContext) (string, error) { +func (f *TemplateContextFeature) valuesHover(templateContext symboltable.TemplateContext) (string, error) { var ( valuesFiles = f.Chart.ResolveValueFiles(templateContext, f.ChartStore) hoverResults = protocol.HoverResultsWithFiles{} diff --git a/internal/language_features/template_context_completion.go b/internal/language_features/template_context_completion.go index 815539d1..ede89e35 100644 --- a/internal/language_features/template_context_completion.go +++ b/internal/language_features/template_context_completion.go @@ -5,7 +5,7 @@ import ( "strings" helmdocs "github.com/mrjosh/helm-ls/internal/documentation/helm" - lsplocal "github.com/mrjosh/helm-ls/internal/lsp" + symboltable "github.com/mrjosh/helm-ls/internal/lsp/symbol_table" "github.com/mrjosh/helm-ls/internal/protocol" "github.com/mrjosh/helm-ls/internal/util" lsp "go.lsp.dev/protocol" @@ -44,7 +44,7 @@ func (f *TemplateContextFeature) Completion() (*lsp.CompletionList, error) { } // handels the completion for .Capabilities.KubeVersion.^ where the result should not contain KubeVersion again -func trimPrefixForNestedDocs(nestedDocs []helmdocs.HelmDocumentation, templateContext lsplocal.TemplateContext) []helmdocs.HelmDocumentation { +func trimPrefixForNestedDocs(nestedDocs []helmdocs.HelmDocumentation, templateContext symboltable.TemplateContext) []helmdocs.HelmDocumentation { adjustedDocs := []helmdocs.HelmDocumentation{} for _, v := range nestedDocs { if strings.HasPrefix(v.Name, templateContext.Tail().Format()) { @@ -55,7 +55,7 @@ func trimPrefixForNestedDocs(nestedDocs []helmdocs.HelmDocumentation, templateCo return adjustedDocs } -func (f *TemplateContextFeature) valuesCompletion(templateContext lsplocal.TemplateContext) (*lsp.CompletionList, error) { +func (f *TemplateContextFeature) valuesCompletion(templateContext symboltable.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() { diff --git a/internal/lsp/ast_diagnostics_test.go b/internal/lsp/ast_diagnostics_test.go index c9183518..f22417d9 100644 --- a/internal/lsp/ast_diagnostics_test.go +++ b/internal/lsp/ast_diagnostics_test.go @@ -3,12 +3,13 @@ package lsp import ( "testing" + templateast "github.com/mrjosh/helm-ls/internal/lsp/template_ast" sitter "github.com/smacker/go-tree-sitter" ) func TestIsInElseBranch(t *testing.T) { template := `{{if pipeline}} t1 {{ else if pipeline }} t2 {{ else if pipeline2 }} t3 {{ else }} t4 {{ end }}` - ast := ParseAst(nil, []byte(template)) + ast := templateast.ParseAst(nil, []byte(template)) // (template [0, 0] - [1, 0] // (if_action [0, 0] - [0, 95] // condition: (function_call [0, 5] - [0, 13] @@ -22,8 +23,6 @@ func TestIsInElseBranch(t *testing.T) { // option: (text [0, 68] - [0, 71]) // alternative: (text [0, 82] - [0, 85]))) - logger.Println("RootNode:", ast.RootNode().String()) - t1_start := sitter.Point{Row: 0, Column: 16} t1 := ast.RootNode().NamedDescendantForPointRange(t1_start, t1_start) t2_start := sitter.Point{Row: 0, Column: 42} diff --git a/internal/lsp/ast_test.go b/internal/lsp/ast_test.go index 87718612..b6e17dd9 100644 --- a/internal/lsp/ast_test.go +++ b/internal/lsp/ast_test.go @@ -3,6 +3,7 @@ package lsp import ( "testing" + templateast "github.com/mrjosh/helm-ls/internal/lsp/template_ast" sitter "github.com/smacker/go-tree-sitter" "github.com/stretchr/testify/assert" ) @@ -16,11 +17,11 @@ func TestFindRelevantChildNodeCompletio(t *testing.T) { {{ .Chart.N }} {{ . }} ` - ast := ParseAst(nil, []byte(template)) + ast := templateast.ParseAst(nil, []byte(template)) logger.Println("RootNode:", ast.RootNode().String()) - node := FindRelevantChildNodeCompletion(ast.RootNode(), sitter.Point{ + node := templateast.FindRelevantChildNodeCompletion(ast.RootNode(), sitter.Point{ Row: 0, Column: 11, }) diff --git a/internal/lsp/ast_variable.go b/internal/lsp/ast_variable.go index f0fb2cfa..60dfca02 100644 --- a/internal/lsp/ast_variable.go +++ b/internal/lsp/ast_variable.go @@ -1,10 +1,13 @@ package lsp import ( + "github.com/mrjosh/helm-ls/internal/log" "github.com/mrjosh/helm-ls/internal/tree-sitter/gotemplate" sitter "github.com/smacker/go-tree-sitter" ) +var logger = log.GetLogger() + func GetVariableDefinition(variableName string, node *sitter.Node, template string) *sitter.Node { if node == nil { return nil diff --git a/internal/lsp/diagnostics_cache.go b/internal/lsp/document/diagnostics_cache.go similarity index 98% rename from internal/lsp/diagnostics_cache.go rename to internal/lsp/document/diagnostics_cache.go index 2dba0f25..23e48240 100644 --- a/internal/lsp/diagnostics_cache.go +++ b/internal/lsp/document/diagnostics_cache.go @@ -1,4 +1,4 @@ -package lsp +package document import ( "github.com/mrjosh/helm-ls/internal/util" @@ -42,7 +42,6 @@ func (d DiagnosticsCache) GetMergedDiagnostics() (merged []lsp.Diagnostic) { } func (d *DiagnosticsCache) ShouldShowDiagnosticsOnNewYamlDiagnostics() bool { - return d.yamlDiagnosticsCountReduced || // show the diagnostics when the count is reduced, this means an error was fixed and it should be shown to the user d.helmlsConfig.YamllsConfiguration.ShowDiagnosticsDirectly || // show the diagnostics directly when the user configured to show them d.gotYamlDiagnosticsTimes < 3 // show the diagnostics, when it are the initial diagnostics that are sent after opening a file. Initial diagnostics are sent twice from yamlls diff --git a/internal/lsp/diagnostics_cache_test.go b/internal/lsp/document/diagnostics_cache_test.go similarity index 99% rename from internal/lsp/diagnostics_cache_test.go rename to internal/lsp/document/diagnostics_cache_test.go index f2e83e1e..609dab25 100644 --- a/internal/lsp/diagnostics_cache_test.go +++ b/internal/lsp/document/diagnostics_cache_test.go @@ -1,11 +1,12 @@ -package lsp +package document import ( + "testing" + "github.com/mrjosh/helm-ls/internal/util" "github.com/stretchr/testify/assert" lsp "go.lsp.dev/protocol" - "testing" ) func TestDiagnosticsCache_SetYamlDiagnostics(t *testing.T) { diff --git a/internal/lsp/document.go b/internal/lsp/document/document.go similarity index 99% rename from internal/lsp/document.go rename to internal/lsp/document/document.go index 5db04425..5fff7deb 100644 --- a/internal/lsp/document.go +++ b/internal/lsp/document/document.go @@ -1,4 +1,4 @@ -package lsp +package document import ( "bytes" diff --git a/internal/lsp/document_store.go b/internal/lsp/document/document_store.go similarity index 99% rename from internal/lsp/document_store.go rename to internal/lsp/document/document_store.go index 23491d05..8ca1701a 100644 --- a/internal/lsp/document_store.go +++ b/internal/lsp/document/document_store.go @@ -1,4 +1,4 @@ -package lsp +package document import ( "fmt" diff --git a/internal/lsp/document_store_test.go b/internal/lsp/document/document_store_test.go similarity index 97% rename from internal/lsp/document_store_test.go rename to internal/lsp/document/document_store_test.go index 5149c65f..8fa9e9c3 100644 --- a/internal/lsp/document_store_test.go +++ b/internal/lsp/document/document_store_test.go @@ -1,4 +1,4 @@ -package lsp +package document import ( "testing" diff --git a/internal/lsp/document_test.go b/internal/lsp/document/document_test.go similarity index 97% rename from internal/lsp/document_test.go rename to internal/lsp/document/document_test.go index 27545d10..0b447a40 100644 --- a/internal/lsp/document_test.go +++ b/internal/lsp/document/document_test.go @@ -1,4 +1,4 @@ -package lsp +package document import ( "testing" diff --git a/internal/lsp/template_document.go b/internal/lsp/document/template_document.go similarity index 74% rename from internal/lsp/template_document.go rename to internal/lsp/document/template_document.go index 22f1ba7d..b5b6f32e 100644 --- a/internal/lsp/template_document.go +++ b/internal/lsp/document/template_document.go @@ -1,6 +1,8 @@ -package lsp +package document import ( + symboltable "github.com/mrjosh/helm-ls/internal/lsp/symbol_table" + templateast "github.com/mrjosh/helm-ls/internal/lsp/template_ast" "github.com/mrjosh/helm-ls/internal/util" sitter "github.com/smacker/go-tree-sitter" lsp "go.lsp.dev/protocol" @@ -13,7 +15,7 @@ type TemplateDocument struct { NeedsRefreshDiagnostics bool Ast *sitter.Tree DiagnosticsCache DiagnosticsCache - SymbolTable *SymbolTable + SymbolTable *symboltable.SymbolTable IsYaml bool } @@ -22,13 +24,13 @@ func (d *TemplateDocument) GetDocumentType() DocumentType { } func NewTemplateDocument(fileURI uri.URI, content []byte, isOpen bool, helmlsConfig util.HelmlsConfiguration) *TemplateDocument { - ast := ParseAst(nil, content) + ast := templateast.ParseAst(nil, content) return &TemplateDocument{ Document: *NewDocument(fileURI, content, isOpen), NeedsRefreshDiagnostics: false, Ast: ast, DiagnosticsCache: NewDiagnosticsCache(helmlsConfig), - SymbolTable: NewSymbolTable(ast, content), + SymbolTable: symboltable.NewSymbolTable(ast, content), IsYaml: IsYamllsEnabled(fileURI, helmlsConfig.YamllsConfiguration), } } @@ -38,7 +40,11 @@ func (d *TemplateDocument) ApplyChanges(changes []lsp.TextDocumentContentChangeE d.Document.ApplyChanges(changes) d.ApplyChangesToAst(d.Content) - d.SymbolTable = NewSymbolTable(d.Ast, d.Content) + d.SymbolTable = symboltable.NewSymbolTable(d.Ast, d.Content) +} + +func (d *TemplateDocument) ApplyChangesToAst(newContent []byte) { + d.Ast = templateast.ParseAst(nil, newContent) } func IsYamllsEnabled(uri lsp.URI, yamllsConfiguration util.YamllsConfiguration) bool { diff --git a/internal/lsp/yaml_document.go b/internal/lsp/document/yaml_document.go similarity index 98% rename from internal/lsp/yaml_document.go rename to internal/lsp/document/yaml_document.go index 62e8af1a..28433c55 100644 --- a/internal/lsp/yaml_document.go +++ b/internal/lsp/document/yaml_document.go @@ -1,4 +1,4 @@ -package lsp +package document import ( "github.com/mrjosh/helm-ls/internal/util" diff --git a/internal/lsp/yaml_document_test.go b/internal/lsp/document/yaml_document_test.go similarity index 96% rename from internal/lsp/yaml_document_test.go rename to internal/lsp/document/yaml_document_test.go index f69723ec..1d1539c7 100644 --- a/internal/lsp/yaml_document_test.go +++ b/internal/lsp/document/yaml_document_test.go @@ -1,4 +1,4 @@ -package lsp +package document import ( "testing" diff --git a/internal/lsp/symbol_table.go b/internal/lsp/symbol_table/symbol_table.go similarity index 97% rename from internal/lsp/symbol_table.go rename to internal/lsp/symbol_table/symbol_table.go index 1dd7e578..61b13e0a 100644 --- a/internal/lsp/symbol_table.go +++ b/internal/lsp/symbol_table/symbol_table.go @@ -1,12 +1,15 @@ -package lsp +package symboltable import ( "fmt" "strings" + "github.com/mrjosh/helm-ls/internal/log" sitter "github.com/smacker/go-tree-sitter" ) +var logger = log.GetLogger() + type TemplateContext []string func (t TemplateContext) Format() string { diff --git a/internal/lsp/symbol_table_includes.go b/internal/lsp/symbol_table/symbol_table_includes.go similarity index 94% rename from internal/lsp/symbol_table_includes.go rename to internal/lsp/symbol_table/symbol_table_includes.go index 22d6b794..44e40e30 100644 --- a/internal/lsp/symbol_table_includes.go +++ b/internal/lsp/symbol_table/symbol_table_includes.go @@ -1,4 +1,4 @@ -package lsp +package symboltable import ( "fmt" @@ -23,7 +23,7 @@ func NewIncludeDefinitionsVisitor(symbolTable *SymbolTable, content []byte) *Inc func (v *IncludeDefinitionsVisitor) Enter(node *sitter.Node) { if node.Type() == gotemplate.NodeTypeDefineAction { content := node.ChildByFieldName("name").Content(v.content) - v.symbolTable.AddIncludeDefinition(util.RemoveQuotes(content), GetRangeForNode(node)) + v.symbolTable.AddIncludeDefinition(util.RemoveQuotes(content), util.GetRangeForNode(node)) } if node.Type() == gotemplate.NodeTypeFunctionCall { @@ -37,7 +37,7 @@ func (v *IncludeDefinitionsVisitor) enterFunctionCall(node *sitter.Node) { return } - v.symbolTable.AddIncludeReference(includeName, GetRangeForNode(node)) + v.symbolTable.AddIncludeReference(includeName, util.GetRangeForNode(node)) } func ParseIncludeFunctionCall(node *sitter.Node, content []byte) (string, error) { diff --git a/internal/lsp/symbol_table_template_context.go b/internal/lsp/symbol_table/symbol_table_template_context.go similarity index 93% rename from internal/lsp/symbol_table_template_context.go rename to internal/lsp/symbol_table/symbol_table_template_context.go index 7886f8ff..0ee0138b 100644 --- a/internal/lsp/symbol_table_template_context.go +++ b/internal/lsp/symbol_table/symbol_table_template_context.go @@ -1,7 +1,8 @@ -package lsp +package symboltable import ( "github.com/mrjosh/helm-ls/internal/tree-sitter/gotemplate" + "github.com/mrjosh/helm-ls/internal/util" sitter "github.com/smacker/go-tree-sitter" ) @@ -54,13 +55,13 @@ func (v *TemplateContextVisitor) Enter(node *sitter.Node) { nodeType := node.Type() switch nodeType { case gotemplate.NodeTypeDot: - v.symbolTable.AddTemplateContext(v.currentContext, GetRangeForNode(node)) + v.symbolTable.AddTemplateContext(v.currentContext, util.GetRangeForNode(node)) case gotemplate.NodeTypeFieldIdentifier: content := node.Content(v.content) - v.symbolTable.AddTemplateContext(append(v.currentContext, content), GetRangeForNode(node)) + v.symbolTable.AddTemplateContext(append(v.currentContext, content), util.GetRangeForNode(node)) case gotemplate.NodeTypeField: content := node.ChildByFieldName("name").Content(v.content) - v.symbolTable.AddTemplateContext(append(v.currentContext, content), GetRangeForNode(node.ChildByFieldName("name"))) + v.symbolTable.AddTemplateContext(append(v.currentContext, content), util.GetRangeForNode(node.ChildByFieldName("name"))) case gotemplate.NodeTypeUnfinishedSelectorExpression: operandNode := node.ChildByFieldName("operand") content := getContextForSelectorExpression(operandNode, v.content) @@ -68,7 +69,7 @@ func (v *TemplateContextVisitor) Enter(node *sitter.Node) { content = append(v.currentContext, content...) } v.symbolTable.AddTemplateContext(append(content, ""), - GetRangeForNode(node.Child(int(node.ChildCount())-1))) + util.GetRangeForNode(node.Child(int(node.ChildCount())-1))) case gotemplate.NodeTypeSelectorExpression: operandNode := node.ChildByFieldName("operand") if operandNode.Type() == gotemplate.NodeTypeVariable { diff --git a/internal/lsp/symbol_table_template_context_test.go b/internal/lsp/symbol_table/symbol_table_template_context_test.go similarity index 92% rename from internal/lsp/symbol_table_template_context_test.go rename to internal/lsp/symbol_table/symbol_table_template_context_test.go index 06b241cb..6d8998fe 100644 --- a/internal/lsp/symbol_table_template_context_test.go +++ b/internal/lsp/symbol_table/symbol_table_template_context_test.go @@ -1,8 +1,9 @@ -package lsp +package symboltable import ( "testing" + templateast "github.com/mrjosh/helm-ls/internal/lsp/template_ast" "github.com/stretchr/testify/assert" ) @@ -52,7 +53,7 @@ func TestGetContextForSelectorExpression(t *testing.T) { } for _, tC := range testCases { t.Run(tC.desc, func(t *testing.T) { - ast := ParseAst(nil, []byte(tC.template)) + ast := templateast.ParseAst(nil, []byte(tC.template)) node := ast.RootNode().Child(1) assert.Equal(t, tC.nodeContent, node.Content([]byte(tC.template))) diff --git a/internal/lsp/symbol_table_template_context_variables.go b/internal/lsp/symbol_table/symbol_table_template_context_variables.go similarity index 98% rename from internal/lsp/symbol_table_template_context_variables.go rename to internal/lsp/symbol_table/symbol_table_template_context_variables.go index 65f41d8f..888efe2a 100644 --- a/internal/lsp/symbol_table_template_context_variables.go +++ b/internal/lsp/symbol_table/symbol_table_template_context_variables.go @@ -1,4 +1,4 @@ -package lsp +package symboltable import ( "fmt" diff --git a/internal/lsp/symbol_table_template_context_variables_test.go b/internal/lsp/symbol_table/symbol_table_template_context_variables_test.go similarity index 90% rename from internal/lsp/symbol_table_template_context_variables_test.go rename to internal/lsp/symbol_table/symbol_table_template_context_variables_test.go index ce2f7518..339aeea6 100644 --- a/internal/lsp/symbol_table_template_context_variables_test.go +++ b/internal/lsp/symbol_table/symbol_table_template_context_variables_test.go @@ -1,9 +1,10 @@ -package lsp +package symboltable import ( "strings" "testing" + templateast "github.com/mrjosh/helm-ls/internal/lsp/template_ast" sitter "github.com/smacker/go-tree-sitter" "github.com/stretchr/testify/assert" ) @@ -24,7 +25,7 @@ func TestResolveVariablesInTemplateContext(t *testing.T) { t.Run(tt.template, func(t *testing.T) { col := strings.Index(tt.template, "^") buf := strings.Replace(tt.template, "^", "", 1) - ast := ParseAst(nil, []byte(tt.template)) + ast := templateast.ParseAst(nil, []byte(tt.template)) symbolTable := NewSymbolTable(ast, []byte(buf)) result, err := symbolTable.ResolveVariablesInTemplateContext( diff --git a/internal/lsp/symbol_table_test.go b/internal/lsp/symbol_table/symbol_table_test.go similarity index 92% rename from internal/lsp/symbol_table_test.go rename to internal/lsp/symbol_table/symbol_table_test.go index e53d9480..d42486e5 100644 --- a/internal/lsp/symbol_table_test.go +++ b/internal/lsp/symbol_table/symbol_table_test.go @@ -1,9 +1,10 @@ -package lsp +package symboltable import ( "os" "testing" + templateast "github.com/mrjosh/helm-ls/internal/lsp/template_ast" sitter "github.com/smacker/go-tree-sitter" "github.com/stretchr/testify/assert" ) @@ -19,24 +20,26 @@ func TestSymbolTableForIncludeDefinitions(t *testing.T) { {{ end }} ` - ast := ParseAst(nil, []byte(content)) + ast := templateast.ParseAst(nil, []byte(content)) symbolTable := NewSymbolTable(ast, []byte(content)) assert.Len(t, symbolTable.includeDefinitions, 2) - assert.Equal(t, symbolTable.includeDefinitions["bar"], []sitter.Range{{ - StartPoint: sitter.Point{ - Row: 5, - Column: 0, - }, - EndPoint: sitter.Point{ - Row: 7, - Column: 10, + assert.Equal(t, symbolTable.includeDefinitions["bar"], []sitter.Range{ + { + StartPoint: sitter.Point{ + Row: 5, + Column: 0, + }, + EndPoint: sitter.Point{ + Row: 7, + Column: 10, + }, + StartByte: 56, + EndByte: 110, }, - StartByte: 56, - EndByte: 110, - }}) + }) } func TestSymbolTableForValues(t *testing.T) { @@ -68,7 +71,7 @@ func TestSymbolTableForValues(t *testing.T) { {{ end }} ` - ast := ParseAst(nil, []byte(content)) + ast := templateast.ParseAst(nil, []byte(content)) symbolTable := NewSymbolTable(ast, []byte(content)) type expectedValue struct { @@ -181,13 +184,13 @@ func TestSymbolTableForValues(t *testing.T) { } func TestSymbolTableForValuesTestFile(t *testing.T) { - path := "../../testdata/example/templates/deployment.yaml" + path := "../../../testdata/example/templates/deployment.yaml" content, err := os.ReadFile(path) if err != nil { t.Fatal("Could not read test file", err) } - ast := ParseAst(nil, content) + ast := templateast.ParseAst(nil, content) symbolTable := NewSymbolTable(ast, content) type expectedValue struct { @@ -324,7 +327,7 @@ func TestSymbolTableForValuesSingleTests(t *testing.T) { for _, v := range testCases { t.Run(v.template, func(t *testing.T) { - ast := ParseAst(nil, []byte(v.template)) + ast := templateast.ParseAst(nil, []byte(v.template)) symbolTable := NewSymbolTable(ast, []byte(v.template)) values := symbolTable.GetTemplateContextRanges(v.path) points := []sitter.Point{} diff --git a/internal/lsp/symbol_table_variables.go b/internal/lsp/symbol_table/symbol_table_variables.go similarity index 99% rename from internal/lsp/symbol_table_variables.go rename to internal/lsp/symbol_table/symbol_table_variables.go index 45249499..c992e7ff 100644 --- a/internal/lsp/symbol_table_variables.go +++ b/internal/lsp/symbol_table/symbol_table_variables.go @@ -1,4 +1,4 @@ -package lsp +package symboltable import ( "fmt" diff --git a/internal/lsp/symbol_table_variables_test.go b/internal/lsp/symbol_table/symbol_table_variables_test.go similarity index 92% rename from internal/lsp/symbol_table_variables_test.go rename to internal/lsp/symbol_table/symbol_table_variables_test.go index de14034d..f21172f1 100644 --- a/internal/lsp/symbol_table_variables_test.go +++ b/internal/lsp/symbol_table/symbol_table_variables_test.go @@ -1,9 +1,10 @@ -package lsp +package symboltable import ( "fmt" "testing" + templateast "github.com/mrjosh/helm-ls/internal/lsp/template_ast" sitter "github.com/smacker/go-tree-sitter" "github.com/stretchr/testify/assert" ) @@ -77,7 +78,7 @@ func TestGetVariableDefinition(t *testing.T) { } for _, tC := range testCases { t.Run(tC.template, func(t *testing.T) { - ast := ParseAst(nil, []byte(tC.template)) + ast := templateast.ParseAst(nil, []byte(tC.template)) symbolTable := NewSymbolTable(ast, []byte(tC.template)) result, err := symbolTable.getVariableDefinition(tC.variableName, tC.accessRange) assert.Equal(t, tC.expectedError, err) diff --git a/internal/lsp/variables_visitor.go b/internal/lsp/symbol_table/variables_visitor.go similarity index 99% rename from internal/lsp/variables_visitor.go rename to internal/lsp/symbol_table/variables_visitor.go index cf245cc9..42d43f0c 100644 --- a/internal/lsp/variables_visitor.go +++ b/internal/lsp/symbol_table/variables_visitor.go @@ -1,4 +1,4 @@ -package lsp +package symboltable import ( "github.com/mrjosh/helm-ls/internal/tree-sitter/gotemplate" diff --git a/internal/lsp/variables_visitor_test.go b/internal/lsp/symbol_table/variables_visitor_test.go similarity index 94% rename from internal/lsp/variables_visitor_test.go rename to internal/lsp/symbol_table/variables_visitor_test.go index f21f69ed..231a3702 100644 --- a/internal/lsp/variables_visitor_test.go +++ b/internal/lsp/symbol_table/variables_visitor_test.go @@ -1,9 +1,10 @@ -package lsp +package symboltable import ( "fmt" "testing" + templateast "github.com/mrjosh/helm-ls/internal/lsp/template_ast" sitter "github.com/smacker/go-tree-sitter" "github.com/stretchr/testify/assert" ) @@ -70,7 +71,7 @@ func TestSymbolTableForVariableDefinitions(t *testing.T) { for _, v := range testCases { t.Run(v.template, func(t *testing.T) { - ast := ParseAst(nil, []byte(v.template)) + ast := templateast.ParseAst(nil, []byte(v.template)) symbolTable := NewSymbolTable(ast, []byte(v.template)) assert.Equal(t, v.expectedVariableDefinitions, symbolTable.variableDefinitions, fmt.Sprintf("Ast was %s", ast.RootNode())) @@ -97,7 +98,7 @@ func TestSymbolTableForVariableUsages(t *testing.T) { for _, v := range testCases { t.Run(v.template, func(t *testing.T) { - ast := ParseAst(nil, []byte(v.template)) + ast := templateast.ParseAst(nil, []byte(v.template)) symbolTable := NewSymbolTable(ast, []byte(v.template)) assert.Equal(t, v.expectedVariableUsages, symbolTable.variableUsages, fmt.Sprintf("Ast was %s", ast.RootNode())) diff --git a/internal/lsp/visitor.go b/internal/lsp/symbol_table/visitor.go similarity index 99% rename from internal/lsp/visitor.go rename to internal/lsp/symbol_table/visitor.go index e93922fc..99e4b9c1 100644 --- a/internal/lsp/visitor.go +++ b/internal/lsp/symbol_table/visitor.go @@ -1,4 +1,4 @@ -package lsp +package symboltable import ( "github.com/mrjosh/helm-ls/internal/tree-sitter/gotemplate" diff --git a/internal/lsp/ast.go b/internal/lsp/template_ast/ast.go similarity index 95% rename from internal/lsp/ast.go rename to internal/lsp/template_ast/ast.go index b32f5122..ec779de9 100644 --- a/internal/lsp/ast.go +++ b/internal/lsp/template_ast/ast.go @@ -1,4 +1,4 @@ -package lsp +package templateast import ( "context" @@ -69,10 +69,6 @@ func isPointLargerOrEq(a sitter.Point, b sitter.Point) bool { return a.Row > b.Row } -func (d *TemplateDocument) ApplyChangesToAst(newContent []byte) { - d.Ast = ParseAst(nil, newContent) -} - func GetLspRangeForNode(node *sitter.Node) lsp.Range { start := node.StartPoint() end := node.EndPoint() diff --git a/internal/lsp/yaml_ast.go b/internal/lsp/yaml_ast.go index 9b0f54a3..2076fea2 100644 --- a/internal/lsp/yaml_ast.go +++ b/internal/lsp/yaml_ast.go @@ -2,25 +2,17 @@ package lsp import ( "github.com/mrjosh/helm-ls/internal/tree-sitter/gotemplate" + "github.com/mrjosh/helm-ls/internal/util" sitter "github.com/smacker/go-tree-sitter" ) -func GetRangeForNode(node *sitter.Node) sitter.Range { - return sitter.Range{ - StartPoint: node.StartPoint(), - EndPoint: node.EndPoint(), - StartByte: node.StartByte(), - EndByte: node.EndByte(), - } -} - func getTextNodeRanges(gotemplateNode *sitter.Node) []sitter.Range { textNodes := []sitter.Range{} for i := 0; i < int(gotemplateNode.ChildCount()); i++ { child := gotemplateNode.Child(i) if child.Type() == gotemplate.NodeTypeText { - textNodes = append(textNodes, GetRangeForNode(child)) + textNodes = append(textNodes, util.GetRangeForNode(child)) } else { textNodes = append(textNodes, getTextNodeRanges(child)...) } diff --git a/internal/lsp/yaml_ast_test.go b/internal/lsp/yaml_ast_test.go index 02d13e3f..4d3435a4 100644 --- a/internal/lsp/yaml_ast_test.go +++ b/internal/lsp/yaml_ast_test.go @@ -3,6 +3,7 @@ package lsp import ( "testing" + templateast "github.com/mrjosh/helm-ls/internal/lsp/template_ast" sitter "github.com/smacker/go-tree-sitter" "github.com/stretchr/testify/assert" ) @@ -78,7 +79,7 @@ b: not`, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got := getTextNodeRanges(ParseAst(nil, []byte(tt.args.gotemplateString)).RootNode()) + got := getTextNodeRanges(templateast.ParseAst(nil, []byte(tt.args.gotemplateString)).RootNode()) assert.Equal(t, tt.want, got) }) } @@ -121,7 +122,7 @@ yaml: test } for _, tt := range tests { t.Run(tt.documentText, func(t *testing.T) { - gotemplateTree := ParseAst(nil, []byte(tt.documentText)) + gotemplateTree := templateast.ParseAst(nil, []byte(tt.documentText)) got := TrimTemplate(gotemplateTree, []byte(tt.documentText)) assert.Equal(t, tt.trimmedText, got) }) diff --git a/internal/util/points.go b/internal/util/points.go index cdec6cc6..3e11c9ca 100644 --- a/internal/util/points.go +++ b/internal/util/points.go @@ -23,3 +23,12 @@ func RangeToLocation(URI uri.URI, range_ sitter.Range) lsp.Location { }, } } + +func GetRangeForNode(node *sitter.Node) sitter.Range { + return sitter.Range{ + StartPoint: node.StartPoint(), + EndPoint: node.EndPoint(), + StartByte: node.StartByte(), + EndByte: node.EndByte(), + } +} From 3a30c3d11bccafed9829e490bdf56c639f7a9045 Mon Sep 17 00:00:00 2001 From: qvalentin Date: Mon, 11 Nov 2024 15:07:11 +0100 Subject: [PATCH 16/16] fix: remove duplicate code --- internal/lsp/symbol_table/symbol_table_variables.go | 7 +------ internal/lsp/symbol_table/variables_visitor.go | 2 +- internal/util/ranges.go | 9 --------- 3 files changed, 2 insertions(+), 16 deletions(-) diff --git a/internal/lsp/symbol_table/symbol_table_variables.go b/internal/lsp/symbol_table/symbol_table_variables.go index c992e7ff..e0045d76 100644 --- a/internal/lsp/symbol_table/symbol_table_variables.go +++ b/internal/lsp/symbol_table/symbol_table_variables.go @@ -50,12 +50,7 @@ func (s *SymbolTable) GetVariableDefinitionForNode(node *sitter.Node, content [] if err != nil { return VariableDefinition{}, err } - return s.getVariableDefinition(name, sitter.Range{ - StartPoint: node.StartPoint(), - EndPoint: node.EndPoint(), - StartByte: node.StartByte(), - EndByte: node.EndByte(), - }) + return s.getVariableDefinition(name, util.GetRangeForNode(node)) } func (s *SymbolTable) GetVariableReferencesForNode(node *sitter.Node, content []byte) (ranges []sitter.Range, err error) { diff --git a/internal/lsp/symbol_table/variables_visitor.go b/internal/lsp/symbol_table/variables_visitor.go index 42d43f0c..bf761a38 100644 --- a/internal/lsp/symbol_table/variables_visitor.go +++ b/internal/lsp/symbol_table/variables_visitor.go @@ -115,7 +115,7 @@ func (v *VariablesVisitor) addVariableDefinition(variableType VariableType, defi } func (v *VariablesVisitor) addVariableUsage(node *sitter.Node) { - v.symbolTable.AddVariableUsage(node.Content(v.content), util.NodeToRange(node)) + v.symbolTable.AddVariableUsage(node.Content(v.content), util.GetRangeForNode(node)) } func (v *VariablesVisitor) EnterContextShift(_ *sitter.Node, _ string) {} diff --git a/internal/util/ranges.go b/internal/util/ranges.go index d9756630..a256de57 100644 --- a/internal/util/ranges.go +++ b/internal/util/ranges.go @@ -5,12 +5,3 @@ import sitter "github.com/smacker/go-tree-sitter" func RangeContainsRange(surrounding, including sitter.Range) bool { return surrounding.StartByte <= including.StartByte && surrounding.EndByte >= including.EndByte } - -func NodeToRange(node *sitter.Node) sitter.Range { - return sitter.Range{ - StartPoint: node.StartPoint(), - EndPoint: node.EndPoint(), - StartByte: node.StartByte(), - EndByte: node.EndByte(), - } -}