Skip to content

Commit

Permalink
refactor(lsp): use lsp server and client interfaces
Browse files Browse the repository at this point in the history
  • Loading branch information
qvalentin committed Mar 10, 2024
1 parent 3fa321e commit 2f1443a
Show file tree
Hide file tree
Showing 24 changed files with 528 additions and 366 deletions.
11 changes: 2 additions & 9 deletions cmds/serve.go
Original file line number Diff line number Diff line change
@@ -1,25 +1,18 @@
package cmds

import (
"context"
"os"

"github.com/mrjosh/helm-ls/internal/handler"
"github.com/spf13/cobra"
"go.lsp.dev/jsonrpc2"
)

func newServeCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "serve",
Short: "Start helm lint language server",
RunE: func(cmd *cobra.Command, args []string) error {

conn := jsonrpc2.NewConn(jsonrpc2.NewStream(stdrwc{}))
handler := handler.NewHandler(conn)
handlerSrv := jsonrpc2.HandlerServer(handler)

return handlerSrv.ServeStream(context.Background(), conn)
Run: func(cmd *cobra.Command, args []string) {
handler.StartHandler(stdrwc{})
},
}

Expand Down
57 changes: 57 additions & 0 deletions internal/adapter/yamlls/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package yamlls

import (
"context"

"go.lsp.dev/protocol"
)

// ApplyEdit implements protocol.Client.
func (y Connector) ApplyEdit(ctx context.Context, params *protocol.ApplyWorkspaceEditParams) (result bool, err error) {

Check failure on line 10 in internal/adapter/yamlls/client.go

View workflow job for this annotation

GitHub Actions / lint (1.21.5, ubuntu-latest)

unused-parameter: parameter 'ctx' seems to be unused, consider removing or renaming it as _ (revive)
return true, nil
}

// LogMessage implements protocol.Client.
func (y Connector) LogMessage(ctx context.Context, params *protocol.LogMessageParams) (err error) {
return nil
}

// Progress implements protocol.Client.
func (y Connector) Progress(ctx context.Context, params *protocol.ProgressParams) (err error) {
return nil
}

// RegisterCapability implements protocol.Client.
func (y Connector) RegisterCapability(ctx context.Context, params *protocol.RegistrationParams) (err error) {
return nil
}

// ShowMessage implements protocol.Client.
func (y Connector) ShowMessage(ctx context.Context, params *protocol.ShowMessageParams) (err error) {
return y.client.ShowMessage(ctx, params)
}

// ShowMessageRequest implements protocol.Client.
func (y Connector) ShowMessageRequest(ctx context.Context, params *protocol.ShowMessageRequestParams) (result *protocol.MessageActionItem, err error) {
return nil, nil
}

// Telemetry implements protocol.Client.
func (y Connector) Telemetry(ctx context.Context, params interface{}) (err error) {
return nil
}

// UnregisterCapability implements protocol.Client.
func (y Connector) UnregisterCapability(ctx context.Context, params *protocol.UnregistrationParams) (err error) {
return nil
}

// WorkDoneProgressCreate implements protocol.Client.
func (y Connector) WorkDoneProgressCreate(ctx context.Context, params *protocol.WorkDoneProgressCreateParams) (err error) {
return nil
}

// WorkspaceFolders implements protocol.Client.
func (y Connector) WorkspaceFolders(ctx context.Context) (result []protocol.WorkspaceFolder, err error) {
return nil, nil
}
16 changes: 3 additions & 13 deletions internal/adapter/yamlls/completion.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,14 @@ package yamlls

import (
"context"
"reflect"

lsp "go.lsp.dev/protocol"
)

func (yamllsConnector Connector) CallCompletion(ctx context.Context, params lsp.CompletionParams) *lsp.CompletionList {
func (yamllsConnector Connector) CallCompletion(ctx context.Context, params *lsp.CompletionParams) (*lsp.CompletionList, error) {
if yamllsConnector.Conn == nil {
return &lsp.CompletionList{}
return &lsp.CompletionList{}, nil
}

logger.Println("Calling yamlls for completions")
var response = reflect.New(reflect.TypeOf(lsp.CompletionList{})).Interface()
_, err := (*yamllsConnector.Conn).Call(ctx, lsp.MethodTextDocumentCompletion, params, response)
if err != nil {
logger.Error("Error Calling yamlls for completions", err)
return &lsp.CompletionList{}
}

logger.Debug("Got completions from yamlls", response)
return response.(*lsp.CompletionList)
return yamllsConnector.server.Completion(ctx, params)
}
22 changes: 11 additions & 11 deletions internal/adapter/yamlls/configuration.go
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
package yamlls

import (
"encoding/json"
"context"

"go.lsp.dev/jsonrpc2"
lsp "go.lsp.dev/protocol"
"go.lsp.dev/protocol"
)

func (yamllsConnector Connector) handleConfiguration(req jsonrpc2.Request) []interface{} {
var params lsp.ConfigurationParams
if err := json.Unmarshal(req.Params(), &params); err != nil {
logger.Error("Error parsing configuration request from yamlls", err)
}
logger.Debug("Yamlls ConfigurationParams", params)
settings := []interface{}{yamllsConnector.config.YamllsSettings}
return settings
// Configuration implements protocol.Client.
func (y Connector) Configuration(ctx context.Context, params *protocol.ConfigurationParams) (result []interface{}, err error) {

Check failure on line 10 in internal/adapter/yamlls/configuration.go

View workflow job for this annotation

GitHub Actions / lint (1.21.5, ubuntu-latest)

unused-parameter: parameter 'ctx' seems to be unused, consider removing or renaming it as _ (revive)
settings := []interface{}{y.config.YamllsSettings}
return settings, nil
}

func (y Connector) DidChangeConfiguration() (err error) {
ctx := context.Background()
return y.server.DidChangeConfiguration(ctx, &protocol.DidChangeConfigurationParams{})
}
16 changes: 6 additions & 10 deletions internal/adapter/yamlls/diagnostics.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,15 @@ package yamlls

import (
"context"
"encoding/json"

lsplocal "github.com/mrjosh/helm-ls/internal/lsp"
sitter "github.com/smacker/go-tree-sitter"
"go.lsp.dev/jsonrpc2"
"go.lsp.dev/protocol"
lsp "go.lsp.dev/protocol"
)

func (yamllsConnector *Connector) handleDiagnostics(req jsonrpc2.Request, clientConn jsonrpc2.Conn, documents *lsplocal.DocumentStore) {
var params lsp.PublishDiagnosticsParams
if err := json.Unmarshal(req.Params(), &params); err != nil {
logger.Println("Error handling diagnostic", err)
}

doc, ok := documents.Get(params.URI)
func (c Connector) PublishDiagnostics(ctx context.Context, params *protocol.PublishDiagnosticsParams) (err error) {
doc, ok := c.documents.Get(params.URI)
if !ok {
logger.Println("Error handling diagnostic. Could not get document: " + params.URI.Filename())
}
Expand All @@ -25,11 +19,13 @@ func (yamllsConnector *Connector) handleDiagnostics(req jsonrpc2.Request, client
if doc.DiagnosticsCache.ShouldShowDiagnosticsOnNewYamlDiagnostics() {
logger.Debug("Publishing yamlls diagnostics")
params.Diagnostics = doc.DiagnosticsCache.GetMergedDiagnostics()
err := clientConn.Notify(context.Background(), lsp.MethodTextDocumentPublishDiagnostics, &params)
err := c.client.PublishDiagnostics(ctx, params)
if err != nil {
logger.Println("Error calling yamlls for diagnostics", err)
}
}

return nil
}

func filterDiagnostics(diagnostics []lsp.Diagnostic, ast *sitter.Tree, content string) (filtered []lsp.Diagnostic) {
Expand Down
8 changes: 6 additions & 2 deletions internal/adapter/yamlls/diagnostics_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@ import (
"github.com/mrjosh/helm-ls/internal/util"
"github.com/stretchr/testify/assert"
"go.lsp.dev/jsonrpc2"
"go.lsp.dev/protocol"
lsp "go.lsp.dev/protocol"
"go.lsp.dev/uri"
"go.uber.org/zap"
)

// must be relative to this file
Expand Down Expand Up @@ -90,7 +92,7 @@ func sendTestFilesToYamlls(documents *lsplocal.DocumentStore, yamllsConnector *C
for {
select {
case d := <-filesChan:
documents.DidOpen(d, util.DefaultConfig)
documents.DidOpen(&d, util.DefaultConfig)
tree := lsplocal.ParseAst(nil, d.TextDocument.Text)
yamllsConnector.DocumentDidOpen(tree, d)
ownCount++
Expand All @@ -112,6 +114,8 @@ func TestYamllsDiagnosticsIntegration(t *testing.T) {
dir := t.TempDir()
documents := lsplocal.NewDocumentStore()
con := jsonrpc2.NewConn(jsonrpc2.NewStream(readWriteCloseMock{diagnosticsChan}))
zapLogger, _ := zap.NewProduction()
client := protocol.ClientDispatcher(con, zapLogger)
config := util.DefaultConfig.YamllsConfiguration

yamllsSettings := util.DefaultYamllsSettings
Expand All @@ -122,7 +126,7 @@ func TestYamllsDiagnosticsIntegration(t *testing.T) {
Enable: false,
}
config.YamllsSettings = yamllsSettings
yamllsConnector := NewConnector(config, con, documents)
yamllsConnector := NewConnector(config, client, documents)

if yamllsConnector.Conn == nil {
t.Fatal("Could not connect to yaml-language-server")
Expand Down
25 changes: 0 additions & 25 deletions internal/adapter/yamlls/handler.go
Original file line number Diff line number Diff line change
@@ -1,26 +1 @@
package yamlls

import (
"context"

lsplocal "github.com/mrjosh/helm-ls/internal/lsp"
"go.lsp.dev/jsonrpc2"
lsp "go.lsp.dev/protocol"
)

func (yamllsConnector *Connector) yamllsHandler(clientConn jsonrpc2.Conn, documents *lsplocal.DocumentStore) jsonrpc2.Handler {
return func(ctx context.Context, reply jsonrpc2.Replier, req jsonrpc2.Request) error {

switch req.Method() {
case lsp.MethodTextDocumentPublishDiagnostics:
yamllsConnector.handleDiagnostics(req, clientConn, documents)
case lsp.MethodWorkspaceConfiguration:
settings := yamllsConnector.handleConfiguration(req)
return reply(ctx, settings, nil)
default:
logger.Debug("Method not handled by yamlls handler: ", req.Method())
}

return reply(ctx, true, nil)
}
}
31 changes: 9 additions & 22 deletions internal/adapter/yamlls/hover.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package yamlls

import (
"context"
"reflect"

"github.com/mrjosh/helm-ls/internal/util"
lsp "go.lsp.dev/protocol"
Expand All @@ -15,51 +14,39 @@ func (yamllsConnector Connector) CallHover(ctx context.Context, params lsp.Hover
return &lsp.Hover{}, nil
}

hoverResponse, err := (yamllsConnector).getHoverFromHover(ctx, params)
hoverResponse, err := yamllsConnector.server.Hover(ctx, &params)
if err != nil {
return hoverResponse, err
}

if hoverResponse.Contents.Value != "" {
if hoverResponse != nil && hoverResponse.Contents.Value != "" {
return hoverResponse, nil
}
return (yamllsConnector).getHoverFromCompletion(ctx, params, word)
}

func (yamllsConnector Connector) getHoverFromHover(ctx context.Context, params lsp.HoverParams) (*lsp.Hover, error) {

var hoverResponse = reflect.New(reflect.TypeOf(lsp.Hover{})).Interface()
_, err := (*yamllsConnector.Conn).Call(ctx, lsp.MethodTextDocumentHover, params, hoverResponse)
if err != nil {
logger.Error("Error calling yamlls for hover", err)
return &lsp.Hover{}, err
}
logger.Debug("Got hover from yamlls", hoverResponse.(*lsp.Hover).Contents.Value)
return hoverResponse.(*lsp.Hover), nil
}

func (yamllsConnector Connector) getHoverFromCompletion(ctx context.Context, params lsp.HoverParams, word string) (*lsp.Hover, error) {
var (
err error
documentation string
completionResponse = reflect.New(reflect.TypeOf(lsp.CompletionList{})).Interface()
completionParams = lsp.CompletionParams{
err error
documentation string
completionParams = lsp.CompletionParams{
TextDocumentPositionParams: params.TextDocumentPositionParams,
}
)
_, err = (*yamllsConnector.Conn).Call(ctx, lsp.MethodTextDocumentCompletion, completionParams, completionResponse)

completionList, err := yamllsConnector.server.Completion(ctx, &completionParams)
if err != nil {
logger.Error("Error calling yamlls for Completion", err)
return &lsp.Hover{}, err
}

for _, completionItem := range completionResponse.(*lsp.CompletionList).Items {
for _, completionItem := range completionList.Items {
if completionItem.InsertText == word {
documentation = completionItem.Documentation.(string)
break
}
}

response := util.BuildHoverResponse(documentation, lsp.Range{})
return &response, nil
return response, nil
}
20 changes: 2 additions & 18 deletions internal/adapter/yamlls/initization.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
"go.lsp.dev/uri"
)

func (yamllsConnector Connector) CallInitialize(workspaceURI uri.URI) {
func (yamllsConnector Connector) CallInitialize(workspaceURI uri.URI) (result *lsp.InitializeResult, err error) {
if yamllsConnector.Conn == nil {
return
}
Expand All @@ -21,21 +21,5 @@ func (yamllsConnector Connector) CallInitialize(workspaceURI uri.URI) {
},
}

var response interface{}
_, err := (*yamllsConnector.Conn).Call(context.Background(), lsp.MethodInitialize, params, response)
if err != nil {
logger.Error("Error calling yamlls for initialize", err)
return
}
err = (*yamllsConnector.Conn).Notify(context.Background(), lsp.MethodInitialized, params)

if err != nil {
logger.Error("Error calling yamlls for initialized", err)
}

changeConfigurationParams := lsp.DidChangeConfigurationParams{}
err = (*yamllsConnector.Conn).Notify(context.Background(), lsp.MethodWorkspaceDidChangeConfiguration, changeConfigurationParams)
if err != nil {
logger.Error("Error calling yamlls for didChangeConfiguration", err)
}
return yamllsConnector.server.Initialize(context.Background(), &params)
}
25 changes: 17 additions & 8 deletions internal/adapter/yamlls/yamlls.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,22 @@ import (
lsplocal "github.com/mrjosh/helm-ls/internal/lsp"
"github.com/mrjosh/helm-ls/internal/util"
"go.lsp.dev/jsonrpc2"
"go.lsp.dev/protocol"
"go.uber.org/zap"
)

var logger = log.GetLogger()

type Connector struct {
Conn *jsonrpc2.Conn
config util.YamllsConfiguration
Conn *jsonrpc2.Conn
config util.YamllsConfiguration
server protocol.Server
documents *lsplocal.DocumentStore
client protocol.Client
}

func NewConnector(yamllsConfiguration util.YamllsConfiguration, clientConn jsonrpc2.Conn, documents *lsplocal.DocumentStore) *Connector {
yamllsCmd := exec.Command(yamllsConfiguration.Path, "--stdio")
func NewConnector(yamllsConfiguration util.YamllsConfiguration, client protocol.Client, documents *lsplocal.DocumentStore) *Connector {
yamllsCmd := exec.Command("yamlls-debug.sh", "--stdio")

stdin, err := yamllsCmd.StdinPipe()
if err != nil {
Expand Down Expand Up @@ -50,10 +55,14 @@ func NewConnector(yamllsConfiguration util.YamllsConfiguration, clientConn jsonr
return &Connector{}
}
}
var yamllsConnector = Connector{}
conn := jsonrpc2.NewConn(jsonrpc2.NewStream(readWriteCloser))
yamllsConnector.config = yamllsConfiguration
conn.Go(context.Background(), yamllsConnector.yamllsHandler(clientConn, documents))
yamllsConnector := Connector{documents: documents, config: yamllsConfiguration, client: client}

ctx := context.Background()
zapLogger, _ := zap.NewProduction()
ctx, conn, server := protocol.NewClient(ctx, yamllsConnector, jsonrpc2.NewStream(readWriteCloser), zapLogger)

Check failure on line 62 in internal/adapter/yamlls/yamlls.go

View workflow job for this annotation

GitHub Actions / lint (1.21.5, ubuntu-latest)

ineffectual assignment to ctx (ineffassign)

// conn.Go(context.Background(), yamllsConnector.yamllsHandler(clientConn, documents))
yamllsConnector.Conn = &conn
yamllsConnector.server = server
return &yamllsConnector
}
Loading

0 comments on commit 2f1443a

Please sign in to comment.