Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions internal/lsp/capabilities_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package lsp

import (
"context"
"testing"

"github.com/sourcegraph/jsonrpc2"

"github.com/open-policy-agent/regal/internal/lsp/clients"
"github.com/open-policy-agent/regal/internal/lsp/types"
"github.com/open-policy-agent/regal/internal/lsp/uri"
"github.com/open-policy-agent/regal/internal/testutil"
)

func TestInitializeExperimentalCapabilities(t *testing.T) {
t.Parallel()

ctx, cancel := context.WithCancel(t.Context())
defer cancel()

tempDir := t.TempDir()

clientHandler := func(_ context.Context, _ *jsonrpc2.Conn, _ *jsonrpc2.Request) (any, error) {
return struct{}{}, nil
}

_, connClient := createAndInitServer(t, ctx, tempDir, clientHandler)

request := types.InitializeParams{
RootURI: uri.FromPath(clients.IdentifierGeneric, tempDir),
ClientInfo: types.ClientInfo{Name: "go test"},
}

var response types.InitializeResult
testutil.NoErr(connClient.Call(ctx, "initialize", request, &response))(t)

if response.Capabilities.Experimental == nil {
t.Fatal("expected experimental capabilities to be non-nil")
}

if !response.Capabilities.Experimental.ExplorerProvider {
t.Error("expected explorerProvider to be true")
}

if !response.Capabilities.Experimental.EvalProvider {
t.Error("expected evalProvider to be true")
}

if !response.Capabilities.Experimental.DebugProvider {
t.Error("expected debugProvider to be true")
}
}
5 changes: 5 additions & 0 deletions internal/lsp/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -1968,6 +1968,11 @@ func (l *LanguageServer) handleInitialize(ctx context.Context, params types.Init
},
Full: true,
},
Experimental: &types.ExperimentalCapabilities{
ExplorerProvider: true,
EvalProvider: true,
DebugProvider: true,
},
},
}

Expand Down
55 changes: 35 additions & 20 deletions internal/lsp/types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,26 +70,41 @@ type (
}

ServerCapabilities struct {
CodeLensProvider ResolveProviderOption `json:"codeLensProvider"`
Workspace WorkspaceOptions `json:"workspace"`
DiagnosticProvider DiagnosticOptions `json:"diagnosticProvider"`
CodeActionProvider CodeActionOptions `json:"codeActionProvider"`
ExecuteCommandProvider ExecuteCommandOptions `json:"executeCommandProvider"`
TextDocumentSyncOptions TextDocumentSyncOptions `json:"textDocumentSync"`
CompletionProvider CompletionOptions `json:"completionProvider"`
InlayHintProvider ResolveProviderOption `json:"inlayHintProvider"`
DocumentLinkProvider ResolveProviderOption `json:"documentLinkProvider"`
SignatureHelpProvider SignatureHelpOptions `json:"signatureHelpProvider"`
SemanticTokensProvider SemanticTokensOptions `json:"semanticTokensProvider"`
DocumentHighlightProvider bool `json:"documentHighlightProvider"`
HoverProvider bool `json:"hoverProvider"`
DocumentFormattingProvider bool `json:"documentFormattingProvider"`
FoldingRangeProvider bool `json:"foldingRangeProvider"`
DocumentSymbolProvider bool `json:"documentSymbolProvider"`
WorkspaceSymbolProvider bool `json:"workspaceSymbolProvider"`
DefinitionProvider bool `json:"definitionProvider"`
SelectionRangeProvider bool `json:"selectionRangeProvider"`
LinkedEditingRangeProvider bool `json:"linkedEditingRangeProvider"`
CodeLensProvider ResolveProviderOption `json:"codeLensProvider"`
Workspace WorkspaceOptions `json:"workspace"`
DiagnosticProvider DiagnosticOptions `json:"diagnosticProvider"`
CodeActionProvider CodeActionOptions `json:"codeActionProvider"`
ExecuteCommandProvider ExecuteCommandOptions `json:"executeCommandProvider"`
TextDocumentSyncOptions TextDocumentSyncOptions `json:"textDocumentSync"`
CompletionProvider CompletionOptions `json:"completionProvider"`
InlayHintProvider ResolveProviderOption `json:"inlayHintProvider"`
DocumentLinkProvider ResolveProviderOption `json:"documentLinkProvider"`
SignatureHelpProvider SignatureHelpOptions `json:"signatureHelpProvider"`
SemanticTokensProvider SemanticTokensOptions `json:"semanticTokensProvider"`
DocumentHighlightProvider bool `json:"documentHighlightProvider"`
HoverProvider bool `json:"hoverProvider"`
DocumentFormattingProvider bool `json:"documentFormattingProvider"`
FoldingRangeProvider bool `json:"foldingRangeProvider"`
DocumentSymbolProvider bool `json:"documentSymbolProvider"`
WorkspaceSymbolProvider bool `json:"workspaceSymbolProvider"`
DefinitionProvider bool `json:"definitionProvider"`
SelectionRangeProvider bool `json:"selectionRangeProvider"`
LinkedEditingRangeProvider bool `json:"linkedEditingRangeProvider"`
Experimental *ExperimentalCapabilities `json:"experimental,omitempty"`
}

// ExperimentalCapabilities contains Regal-specific experimental LSP features
// that are not part of the standard LSP specification.
ExperimentalCapabilities struct {
// ExplorerProvider indicates whether the server supports the regal.explorer
// command and regal/showExplorerResult notification.
ExplorerProvider bool `json:"explorerProvider"`
// EvalProvider indicates whether the server supports the regal.eval
// command and regal/showEvalResult request.
EvalProvider bool `json:"evalProvider"`
// DebugProvider indicates whether the server supports the regal.debug
// command and regal/startDebugging request.
DebugProvider bool `json:"debugProvider"`
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm thinking we'll most likely want to move as much of the init handler into Rego sooner rather than later .. which makes me wonder if we want to user snake_case for serialized names instead? 🤔 There's no way to do have this done in Rego without actually naming rules like debugProvider, etc.. and that'll need inline ignores, not to mention of course that it won't be very Rego'y :)

(aside, it'd be pretty cool if metadata annotations could provide hints about how a Rego object should be serialized!)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps, and we do have control of these for the client and the server.

However, others like hoverProvider will need to remain the same regardless of the Go/Rego implementation as that's the spec.

I think my preference for now is to use the same style as the existing field names.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair point!

}

TextDocumentPositionParams struct {
Expand Down
Loading