From 1cfdee996945546381648232e73e29b4394baf54 Mon Sep 17 00:00:00 2001 From: Anders Eknert Date: Thu, 5 Sep 2024 10:31:37 +0200 Subject: [PATCH] Fix LSP formatting that broke in v0.26.0 (#1055) Fixes #1054 Signed-off-by: Anders Eknert --- internal/lsp/server.go | 7 ++- internal/lsp/server_test.go | 86 +++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+), 1 deletion(-) diff --git a/internal/lsp/server.go b/internal/lsp/server.go index 4b8270ee..78426154 100644 --- a/internal/lsp/server.go +++ b/internal/lsp/server.go @@ -1799,7 +1799,12 @@ func (l *LanguageServer) handleTextDocumentFormatting( f := &fixes.Fmt{OPAFmtOpts: opts} p := uri.ToPath(l.clientIdentifier, params.TextDocument.URI) - fixResults, err := f.Fix(&fixes.FixCandidate{Filename: filepath.Base(p), Contents: []byte(oldContent)}, nil) + fixResults, err := f.Fix( + &fixes.FixCandidate{Filename: filepath.Base(p), Contents: []byte(oldContent)}, + &fixes.RuntimeOptions{ + BaseDir: l.workspacePath(), + }, + ) if err != nil { l.logError(fmt.Errorf("failed to format file: %w", err)) diff --git a/internal/lsp/server_test.go b/internal/lsp/server_test.go index cedf126c..d4c8abb7 100644 --- a/internal/lsp/server_test.go +++ b/internal/lsp/server_test.go @@ -3,6 +3,7 @@ package lsp import ( "bytes" "context" + "encoding/json" "fmt" "io" "net" @@ -731,6 +732,91 @@ func TestProcessBuiltinUpdateExitsOnMissingFile(t *testing.T) { } } +func TestFormatting(t *testing.T) { + t.Parallel() + + tempDir := t.TempDir() + + // set up the server and client connections + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + ls := NewLanguageServer(&LanguageServerOptions{ + ErrorLog: newTestLogger(t), + }) + go ls.StartConfigWorker(ctx) + + clientHandler := func(_ context.Context, _ *jsonrpc2.Conn, req *jsonrpc2.Request) (result any, err error) { + t.Fatalf("unexpected request: %v", req) + + return struct{}{}, nil + } + + connServer, connClient, cleanup := createConnections(ctx, ls.Handle, clientHandler) + defer cleanup() + + ls.SetConn(connServer) + + // 1. Client sends initialize request + request := types.InitializeParams{ + RootURI: fileURIScheme + tempDir, + ClientInfo: types.Client{Name: "go test"}, + } + + var response types.InitializeResult + + err := connClient.Call(ctx, "initialize", request, &response) + if err != nil { + t.Fatalf("failed to send initialize request: %s", err) + } + + mainRegoURI := fileURIScheme + tempDir + mainRegoFileName + + // Simple as possible — opa fmt should just remove a newline + content := `package main + +` + ls.cache.SetFileContents(mainRegoURI, content) + + bs, err := json.Marshal(&types.DocumentFormattingParams{ + TextDocument: types.TextDocumentIdentifier{URI: mainRegoURI}, + Options: types.FormattingOptions{}, + }) + if err != nil { + t.Fatalf("failed to marshal document formatting params: %v", err) + } + + var msg json.RawMessage = bs + + req := &jsonrpc2.Request{Params: &msg} + + res, err := ls.handleTextDocumentFormatting(ctx, connClient, req) + if err != nil { + t.Fatalf("failed to format document: %s", err) + } + + if edits, ok := res.([]types.TextEdit); ok { + if len(edits) != 1 { + t.Fatalf("expected 1 edit, got %d", len(edits)) + } + + expectRange := types.Range{ + Start: types.Position{Line: 1, Character: 0}, + End: types.Position{Line: 2, Character: 0}, + } + + if edits[0].Range != expectRange { + t.Fatalf("expected range to be %v, got %v", expectRange, edits[0].Range) + } + + if edits[0].NewText != "" { + t.Fatalf("expected new text to be empty, got %s", edits[0].NewText) + } + } else { + t.Fatalf("expected edits to be []types.TextEdit, got %T", res) + } +} + // TestLanguageServerParentDirConfig tests that regal config is loaded as it is for the // Regal CLI, and that config files in a parent directory are loaded correctly // even when the workspace is a child directory.