Skip to content

Commit

Permalink
feat(yamlls): add config to enable yamlls per filetype
Browse files Browse the repository at this point in the history
  • Loading branch information
qvalentin committed Jul 9, 2024
1 parent 6cab70b commit 8928133
Show file tree
Hide file tree
Showing 12 changed files with 134 additions and 16 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,8 @@ You can configure helm-ls with lsp workspace configurations.
### yaml-language-server config
- **Enable yaml-language-server**: Toggle support of this feature.
- **Enabled yaml-language-server**: Toggle support of this feature.
- **EnabledForFilesGlob**: For wich files matchig the glob pattern yaml-language-server should be enabled.
- **Path to yaml-language-server**: Specify the executable location.
- **Diagnostics Settings**:
Expand All @@ -181,6 +182,7 @@ settings = {
},
yamlls = {
enabled = true,
enabledForFilesGlob = "*.{yaml,yml}",
diagnosticsLimit = 50,
showDiagnosticsDirectly = false,
path = "yaml-language-server",
Expand Down
2 changes: 1 addition & 1 deletion internal/adapter/yamlls/completion.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
)

func (yamllsConnector Connector) CallCompletion(ctx context.Context, params *lsp.CompletionParams) (*lsp.CompletionList, error) {
if yamllsConnector.server == nil {
if !yamllsConnector.shouldRun(params.TextDocumentPositionParams.TextDocument.URI) {
return &lsp.CompletionList{}, nil
}

Expand Down
5 changes: 5 additions & 0 deletions internal/adapter/yamlls/diagnostics.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,23 +32,28 @@ func (c Connector) PublishDiagnostics(ctx context.Context, params *protocol.Publ

func filterDiagnostics(diagnostics []lsp.Diagnostic, ast *sitter.Tree, content string) (filtered []lsp.Diagnostic) {
filtered = []lsp.Diagnostic{}

for _, diagnostic := range diagnostics {
node := lsplocal.NodeAtPosition(ast, diagnostic.Range.Start)
childNode := lsplocal.FindRelevantChildNode(ast.RootNode(), lsplocal.GetSitterPointForLspPos(diagnostic.Range.Start))

if node.Type() == "text" && childNode.Type() == "text" {
logger.Debug("Diagnostic", diagnostic)
logger.Debug("Node", node.Content([]byte(content)))

if diagnisticIsRelevant(diagnostic, childNode) {
diagnostic.Message = "Yamlls: " + diagnostic.Message
filtered = append(filtered, diagnostic)
}
}
}

return filtered
}

func diagnisticIsRelevant(diagnostic lsp.Diagnostic, node *sitter.Node) bool {
logger.Debug("Checking if diagnostic is relevant", diagnostic.Message)

switch diagnostic.Message {
case "Map keys must be unique":
return !lsplocal.IsInElseBranch(node)
Expand Down
17 changes: 13 additions & 4 deletions internal/adapter/yamlls/documentSync.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,17 @@ func (yamllsConnector Connector) InitiallySyncOpenDocuments(docs []*lsplocal.Doc
if yamllsConnector.server == nil {
return
}

for _, doc := range docs {
if !doc.IsOpen {
continue
}

doc.IsYaml = lsplocal.IsYamlDocument(doc.URI, yamllsConnector.config)
if !yamllsConnector.isRelevantFile(doc.URI) {
continue
}

yamllsConnector.DocumentDidOpen(doc.Ast, lsp.DidOpenTextDocumentParams{
TextDocument: lsp.TextDocumentItem{
URI: doc.URI,
Expand All @@ -28,7 +35,8 @@ func (yamllsConnector Connector) InitiallySyncOpenDocuments(docs []*lsplocal.Doc

func (yamllsConnector Connector) DocumentDidOpen(ast *sitter.Tree, params lsp.DidOpenTextDocumentParams) {
logger.Debug("YamllsConnector DocumentDidOpen", params.TextDocument.URI)
if yamllsConnector.server == nil {

if !yamllsConnector.shouldRun(params.TextDocument.URI) {
return
}
params.TextDocument.Text = lsplocal.TrimTemplate(ast, params.TextDocument.Text)
Expand All @@ -40,9 +48,10 @@ func (yamllsConnector Connector) DocumentDidOpen(ast *sitter.Tree, params lsp.Di
}

func (yamllsConnector Connector) DocumentDidSave(doc *lsplocal.Document, params lsp.DidSaveTextDocumentParams) {
if yamllsConnector.server == nil {
if !yamllsConnector.shouldRun(doc.URI) {
return
}

params.Text = lsplocal.TrimTemplate(doc.Ast, doc.Content)

err := yamllsConnector.server.DidSave(context.Background(), &params)
Expand All @@ -58,7 +67,7 @@ func (yamllsConnector Connector) DocumentDidSave(doc *lsplocal.Document, params
}

func (yamllsConnector Connector) DocumentDidChange(doc *lsplocal.Document, params lsp.DidChangeTextDocumentParams) {
if yamllsConnector.server == nil {
if !yamllsConnector.shouldRun(doc.URI) {
return
}
trimmedText := lsplocal.TrimTemplate(doc.Ast, doc.Content)
Expand Down Expand Up @@ -87,7 +96,7 @@ func (yamllsConnector Connector) DocumentDidChange(doc *lsplocal.Document, param
}

func (yamllsConnector Connector) DocumentDidChangeFullSync(doc *lsplocal.Document, params lsp.DidChangeTextDocumentParams) {
if yamllsConnector.server == nil {
if !yamllsConnector.shouldRun(doc.URI) {
return
}

Expand Down
2 changes: 1 addition & 1 deletion internal/adapter/yamlls/hover.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
// Yamlls can not handle hover if the schema validation returns error,
// thats why we fall back to calling completion
func (yamllsConnector Connector) CallHover(ctx context.Context, params lsp.HoverParams, word string) (*lsp.Hover, error) {
if yamllsConnector.server == nil {
if !yamllsConnector.shouldRun(params.TextDocumentPositionParams.TextDocument.URI) {
return &lsp.Hover{}, nil
}

Expand Down
17 changes: 17 additions & 0 deletions internal/adapter/yamlls/yamlls.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/mrjosh/helm-ls/internal/util"
"go.lsp.dev/jsonrpc2"
"go.lsp.dev/protocol"
lsp "go.lsp.dev/protocol"
"go.uber.org/zap"
)

Expand Down Expand Up @@ -75,3 +76,19 @@ func NewConnector(ctx context.Context, yamllsConfiguration util.YamllsConfigurat
yamllsConnector.server = server
return &yamllsConnector
}

func (yamllsConnector *Connector) isRelevantFile(uri lsp.URI) bool {
doc, ok := yamllsConnector.documents.Get(uri)
if !ok {
logger.Error("Could not find document", uri)
return true
}
return doc.IsYaml
}

func (yamllsConnector *Connector) shouldRun(uri lsp.DocumentURI) bool {
if yamllsConnector.server == nil {
return false
}
return yamllsConnector.isRelevantFile(uri)
}
37 changes: 37 additions & 0 deletions internal/adapter/yamlls/yamlls_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package yamlls

import (
"testing"

lsplocal "github.com/mrjosh/helm-ls/internal/lsp"
"github.com/mrjosh/helm-ls/internal/util"
"github.com/stretchr/testify/assert"
"go.lsp.dev/uri"
)

func TestIsRelevantFile(t *testing.T) {
connector := Connector{
config: util.YamllsConfiguration{
Enabled: true,
},
}

connector.documents = &lsplocal.DocumentStore{}
yamlFile := uri.File("../../../testdata/example/templates/deployment.yaml")
nonYamlFile := uri.File("../../../testdata/example/templates/_helpers.tpl")
connector.documents.Store(yamlFile, util.DefaultConfig)
connector.documents.Store(nonYamlFile, util.DefaultConfig)

assert.True(t, connector.isRelevantFile(yamlFile))
assert.False(t, connector.isRelevantFile(nonYamlFile))
}

func TestShouldRun(t *testing.T) {
connector := Connector{
config: util.YamllsConfiguration{
Enabled: true,
},
}
assert.False(t, connector.shouldRun(uri.File("test.yaml")))
assert.False(t, connector.shouldRun(uri.File("_helpers.tpl")))
}
16 changes: 14 additions & 2 deletions internal/handler/initialization.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ 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"
Expand Down Expand Up @@ -58,17 +59,28 @@ func (h *langHandler) Initialized(ctx context.Context, _ *lsp.InitializedParams)
func (h *langHandler) initializationWithConfig(ctx context.Context) {
configureLogLevel(h.helmlsConfig)
h.chartStore.SetValuesFilesConfig(h.helmlsConfig.ValuesFilesConfig)
configureYamlls(ctx, h)
h.configureYamlls(ctx)
}

func configureYamlls(ctx context.Context, h *langHandler) {
func (h *langHandler) 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 *langHandler) configureYamlls(ctx context.Context) {
config := h.helmlsConfig
if config.YamllsConfiguration.Enabled {
h.configureYamlsEnabledGlob()
h.yamllsConnector = 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.GetAllDocs())
}
}
Expand Down
1 change: 1 addition & 0 deletions internal/lsp/document.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ type Document struct {
DiagnosticsCache DiagnosticsCache
IsOpen bool
SymbolTable *SymbolTable
IsYaml bool
}

// ApplyChanges updates the content of the document from LSP textDocument/didChange events.
Expand Down
12 changes: 12 additions & 0 deletions internal/lsp/document_store.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,19 @@ func (s *DocumentStore) DidOpen(params *lsp.DidOpenTextDocumentParams, helmlsCon
DiagnosticsCache: NewDiagnosticsCache(helmlsConfig),
IsOpen: true,
SymbolTable: NewSymbolTable(ast, []byte(params.TextDocument.Text)),
IsYaml: IsYamlDocument(uri, helmlsConfig.YamllsConfiguration),
}
logger.Debug("Storing doc ", path)
s.documents.Store(path, doc)
return doc, nil
}

func (s *DocumentStore) Store(uri uri.URI, helmlsConfig util.HelmlsConfiguration) error {
_, ok := s.documents.Load(uri.Filename())
if ok {
return nil
}

content, err := os.ReadFile(uri.Filename())
if err != nil {
logger.Error("Could not open file ", uri.Filename(), " ", err)
Expand All @@ -67,6 +73,7 @@ func (s *DocumentStore) Store(uri uri.URI, helmlsConfig util.HelmlsConfiguration
DiagnosticsCache: NewDiagnosticsCache(helmlsConfig),
IsOpen: false,
SymbolTable: NewSymbolTable(ast, content),
IsYaml: IsYamlDocument(uri, helmlsConfig.YamllsConfiguration),
},
)
return nil
Expand All @@ -75,8 +82,13 @@ func (s *DocumentStore) Store(uri uri.URI, helmlsConfig util.HelmlsConfiguration
func (s *DocumentStore) Get(docuri uri.URI) (*Document, bool) {
path := docuri.Filename()
d, ok := s.documents.Load(path)

if !ok {
return nil, false
}
return d.(*Document), ok
}

func IsYamlDocument(uri lsp.URI, yamllsConfiguration util.YamllsConfiguration) bool {
return yamllsConfiguration.EnabledForFilesGlobObject.Match(uri.Filename())
}
17 changes: 17 additions & 0 deletions internal/lsp/document_store_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package lsp

import (
"testing"

"github.com/mrjosh/helm-ls/internal/util"
"github.com/stretchr/testify/assert"
"go.lsp.dev/uri"
)

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))
}
20 changes: 13 additions & 7 deletions internal/util/config.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package util

import "github.com/gobwas/glob"

type HelmlsConfiguration struct {
YamllsConfiguration YamllsConfiguration `json:"yamlls,omitempty"`
ValuesFilesConfig ValuesFilesConfig `json:"valuesFiles,omitempty"`
Expand All @@ -13,8 +15,10 @@ type ValuesFilesConfig struct {
}

type YamllsConfiguration struct {
Enabled bool `json:"enabled,omitempty"`
Path string `json:"path,omitempty"`
Enabled bool `json:"enabled,omitempty"`
EnabledForFilesGlob string `json:"enabledForFilesGlob,omitempty"`
EnabledForFilesGlobObject glob.Glob
Path string `json:"path,omitempty"`
// max diagnostics from yamlls that are shown for a single file
DiagnosticsLimit int `json:"diagnosticsLimit,omitempty"`
// if set to false diagnostics will only be shown after saving the file
Expand All @@ -32,11 +36,13 @@ var DefaultConfig = HelmlsConfiguration{
AdditionalValuesFilesGlobPattern: "values*.yaml",
},
YamllsConfiguration: YamllsConfiguration{
Enabled: true,
Path: "yaml-language-server",
DiagnosticsLimit: 50,
ShowDiagnosticsDirectly: false,
YamllsSettings: DefaultYamllsSettings,
Enabled: true,
EnabledForFilesGlob: "*.{yaml,yml}",
EnabledForFilesGlobObject: glob.MustCompile("*.{yaml,yml}"),
Path: "yaml-language-server",
DiagnosticsLimit: 50,
ShowDiagnosticsDirectly: false,
YamllsSettings: DefaultYamllsSettings,
},
}

Expand Down

0 comments on commit 8928133

Please sign in to comment.