Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wip: generate json schema for completion #116

Open
wants to merge 11 commits into
base: feature/yaml-files-as-documents
Choose a base branch
from
2 changes: 2 additions & 0 deletions internal/adapter/yamlls/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package yamlls

import (
"context"
"fmt"

"go.lsp.dev/protocol"
)
Expand All @@ -13,6 +14,7 @@ func (y Connector) ApplyEdit(ctx context.Context, params *protocol.ApplyWorkspac

// LogMessage implements protocol.Client.
func (y Connector) LogMessage(ctx context.Context, params *protocol.LogMessageParams) (err error) {
logger.Debug(fmt.Sprintf("LogMessage from yamlls: %s %s", params.Type, params.Message))
return nil
}

Expand Down
2 changes: 1 addition & 1 deletion internal/adapter/yamlls/completion_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ func TestYamllsCompletionIntegration(t *testing.T) {
tt := tt1
t.Run(tt.desc, func(t *testing.T) {
t.Parallel()
yamllsConnector, documents, _ := getYamlLsConnector(t, config)
yamllsConnector, documents, _ := getYamlLsConnector(t, config, &DefaultCustomHandler)
openFile(t, documents, tt.file, yamllsConnector)

assert.EventuallyWithT(t, func(c *assert.CollectT) {
Expand Down
84 changes: 84 additions & 0 deletions internal/adapter/yamlls/custom_schema_provider.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package yamlls

import (
"context"
"encoding/json"

"go.lsp.dev/jsonrpc2"
"go.lsp.dev/protocol"
"go.lsp.dev/uri"
"go.uber.org/zap"
)

type CustomHandler struct {
Handler jsonrpc2.Handler
PostInitialize SetupCustomHandler
}

type SetupCustomHandler func(ctx context.Context, conn jsonrpc2.Conn) error

var DefaultCustomHandler = CustomHandler{
jsonrpc2.MethodNotFoundHandler, func(ctx context.Context, conn jsonrpc2.Conn) error { return nil },
}

func NewCustomSchemaHandler(handler jsonrpc2.Handler) *CustomHandler {
customHandler := &CustomHandler{
Handler: handler,
PostInitialize: func(ctx context.Context, conn jsonrpc2.Conn) error {
return conn.Notify(ctx, "yaml/registerCustomSchemaRequest", nil)
},
}

return customHandler
}

type CustomSchemaProvider func(ctx context.Context, uri uri.URI) (uri.URI, error)

func NewCustomSchemaProviderHandler(provider CustomSchemaProvider) jsonrpc2.Handler {
return func(ctx context.Context, reply jsonrpc2.Replier, req jsonrpc2.Request) error {
switch req.Method() {
case "custom/schema/request":

params := []string{}
jsonBytes, err := req.Params().MarshalJSON()
if err != nil {
logger.Error(err)
return reply(ctx, nil, nil)
}

err = json.Unmarshal(jsonBytes, &params)
if err != nil {
logger.Error(err)
return reply(ctx, nil, nil)
}

logger.Println("YamlHandler: custom/schema/request", string(req.Params()))

if len(params) == 0 {
return reply(ctx, nil, nil)
}

schemaURI, err := provider(ctx, uri.New(params[0]))
if err != nil {
return reply(ctx, nil, err)
}
return reply(ctx, schemaURI, nil)
}
return jsonrpc2.MethodNotFoundHandler(ctx, reply, req)
}
}

// CustomNewClient returns the context in which Client is embedded, jsonrpc2.Conn, and the Server.
func (yamllsConnector Connector) CustomNewClient(ctx context.Context, client protocol.Client, stream jsonrpc2.Stream, logger *zap.Logger) (context.Context, jsonrpc2.Conn, protocol.Server) {
ctx = protocol.WithClient(ctx, client)

conn := jsonrpc2.NewConn(stream)
conn.Go(ctx,
protocol.Handlers(
protocol.ClientHandler(client, yamllsConnector.customHandler.Handler),
),
)
server := protocol.ServerDispatcher(conn, logger.Named("server"))

return ctx, conn, server
}
84 changes: 84 additions & 0 deletions internal/adapter/yamlls/custom_schema_provider_integration_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
//go:build integration

package yamlls

import (
"context"
"os"
"path"
"testing"
"time"

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

var TEST_JSON_SCHEMA = `
{
"$id": "https://example.com/address.schema.json",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"description": "An address similar to http://microformats.org/wiki/h-card",
"type": "object",
"properties": {
"postOfficeBox": {
"type": "string"
},
"countryName": {
"type": "string"
}
}
}
`

func TestYamllsCustomSchemaProviderIntegration(t *testing.T) {
config := util.DefaultConfig.YamllsConfiguration
config.Path = "yamlls-debug.sh"

// tempDir := t.TempDir()
// tempDir := "/data/data/com.termux/files/usr/tmp/"
tempDir := "/tmp/"
schemaFile := path.Join(tempDir, "schema.json")
// write schema
err := os.WriteFile(schemaFile, []byte(TEST_JSON_SCHEMA), 0o644)
assert.NoError(t, err)

testFile := path.Join(tempDir, "test.yaml")
err = os.WriteFile(testFile, []byte("c"), 0o644)
assert.NoError(t, err)

customHandler := NewCustomSchemaHandler(
NewCustomSchemaProviderHandler(
func(ctx context.Context, URI uri.URI) (uri.URI, error) {
t.Log("Calling Schema provider")
return uri.File(schemaFile), nil
}))

yamllsConnector, documents, _ := getYamlLsConnector(t, config, customHandler)
openFile(t, documents, testFile, yamllsConnector)

assert.EventuallyWithT(t, func(c *assert.CollectT) {
logger.Println("Calling completion")
result, _ := yamllsConnector.CallCompletion(context.Background(), &lsp.CompletionParams{
TextDocumentPositionParams: lsp.TextDocumentPositionParams{
TextDocument: lsp.TextDocumentIdentifier{
URI: uri.File(testFile),
},
Position: lsp.Position{
Line: 0,
Character: 1,
},
},
})
logger.Println("Called completion")

assert.NotNil(c, result)
if result == nil {
logger.Println("result is nil")
t.Log("result is nil")
return
}
t.Log("result is", result)
}, time.Second*20, time.Second*2)
}
4 changes: 2 additions & 2 deletions internal/adapter/yamlls/diagnostics_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ func TestYamllsDiagnosticsIntegration(t *testing.T) {
Enable: false,
}
config.YamllsSettings = yamllsSettings
yamllsConnector, documents, diagnosticsChan := getYamlLsConnector(t, config)
yamllsConnector, documents, diagnosticsChan := getYamlLsConnector(t, config, &DefaultCustomHandler)

didOpenChan := make(chan string)
go readTestFiles(TEST_DATA_DIR, didOpenChan, doneReadingFilesChan)
Expand Down Expand Up @@ -119,7 +119,7 @@ func TestYamllsDiagnosticsIntegrationWithSchema(t *testing.T) {
diagnosticsChan := make(chan lsp.PublishDiagnosticsParams)

config := util.DefaultConfig.YamllsConfiguration
yamllsConnector, documents, diagnosticsChan := getYamlLsConnector(t, config)
yamllsConnector, documents, diagnosticsChan := getYamlLsConnector(t, config, &DefaultCustomHandler)
file := filepath.Join("..", "..", "..", "testdata", "example", "templates", "service.yaml")
openFile(t, documents, file, yamllsConnector)

Expand Down
89 changes: 8 additions & 81 deletions internal/adapter/yamlls/document_sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,11 @@ package yamlls
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 []*document.TemplateDocument) {
func (yamllsConnector Connector) InitiallySyncOpenYamlDocuments(docs []*document.YamlDocument) {
if yamllsConnector.server == nil {
return
}
Expand All @@ -20,13 +17,7 @@ func (yamllsConnector Connector) InitiallySyncOpenDocuments(docs []*document.Tem
continue
}

doc.IsYaml = yamllsConnector.IsYamllsEnabled(doc.URI)

if !yamllsConnector.isRelevantFile(doc.URI) {
continue
}

yamllsConnector.DocumentDidOpen(doc.Ast, lsp.DidOpenTextDocumentParams{
yamllsConnector.DocumentDidOpen(&lsp.DidOpenTextDocumentParams{
TextDocument: lsp.TextDocumentItem{
URI: doc.URI,
Text: string(doc.Content),
Expand All @@ -35,89 +26,25 @@ func (yamllsConnector Connector) InitiallySyncOpenDocuments(docs []*document.Tem
}
}

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

if !yamllsConnector.shouldRun(params.TextDocument.URI) {
return
}
params.TextDocument.Text = lsplocal.TrimTemplate(ast, []byte(params.TextDocument.Text))

err := yamllsConnector.server.DidOpen(context.Background(), &params)
err := yamllsConnector.server.DidOpen(context.Background(), params)
if err != nil {
logger.Error("Error calling yamlls for didOpen", err)
}
}

func (yamllsConnector Connector) DocumentDidSave(doc *document.TemplateDocument, params lsp.DidSaveTextDocumentParams) {
if !yamllsConnector.shouldRun(doc.URI) {
return
}

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

err := yamllsConnector.server.DidSave(context.Background(), &params)
func (yamllsConnector Connector) DocumentDidSave(params *lsp.DidSaveTextDocumentParams) {
err := yamllsConnector.server.DidSave(context.Background(), params)
if err != nil {
logger.Error("Error calling yamlls for didSave", err)
}

yamllsConnector.DocumentDidChangeFullSync(doc, lsp.DidChangeTextDocumentParams{
TextDocument: lsp.VersionedTextDocumentIdentifier{
TextDocumentIdentifier: params.TextDocument,
},
})
}

func (yamllsConnector Connector) DocumentDidChange(doc *document.TemplateDocument, params lsp.DidChangeTextDocumentParams) {
if !yamllsConnector.shouldRun(doc.URI) {
return
}
trimmedText := lsplocal.TrimTemplate(doc.Ast, doc.Content)

func (yamllsConnector Connector) DocumentDidChange(params *lsp.DidChangeTextDocumentParams) {
logger.Debug("Sending DocumentDidChange previous", params)
for i, change := range params.ContentChanges {
var (
start = util.PositionToIndex(change.Range.Start, []byte(doc.Content))
end = start + len([]byte(change.Text))
)

if end >= len(trimmedText) {
end = len(trimmedText) - 1
}

logger.Debug("Start end", start, end)
logger.Debug("Setting change text to ", trimmedText[start:end])
params.ContentChanges[i].Text = trimmedText[start:end]
}

logger.Debug("Sending DocumentDidChange", params)
err := yamllsConnector.server.DidChange(context.Background(), &params)
err := yamllsConnector.server.DidChange(context.Background(), params)
if err != nil {
logger.Println("Error calling yamlls for didChange", err)
}
}

func (yamllsConnector Connector) DocumentDidChangeFullSync(doc *document.TemplateDocument, params lsp.DidChangeTextDocumentParams) {
if !yamllsConnector.shouldRun(doc.URI) {
return
}

logger.Debug("Sending DocumentDidChange with full sync, current content:", string(doc.Content))
trimmedText := lsplocal.TrimTemplate(doc.Ast.Copy(), doc.Content)

params.ContentChanges = []lsp.TextDocumentContentChangeEvent{
{
Text: trimmedText,
},
}

logger.Println("Sending DocumentDidChange with full sync", params)
err := yamllsConnector.server.DidChange(context.Background(), &params)
if err != nil {
logger.Println("Error calling yamlls for didChange", err)
}
}

func (yamllsConnector Connector) IsYamllsEnabled(uri lsp.URI) bool {
return yamllsConnector.EnabledForFilesGlobObject.Match(uri.Filename())
}
Loading
Loading