Skip to content

Commit 98b0565

Browse files
ivanauthmiparnisari
authored andcommitted
Fix duplicate diagnostics in LSP server
Correct ClientCapabilities struct to match LSP spec, detecting pull diagnostics support via textDocument.diagnostic presence. Fixes authzed/spicedb-vscode#41
1 parent 8e2054a commit 98b0565

File tree

4 files changed

+47
-13
lines changed

4 files changed

+47
-13
lines changed

internal/lsp/handlers.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,7 @@ func (s *Server) initialize(_ context.Context, r *jsonrpc2.Request) (any, error)
335335
return nil, err
336336
}
337337

338-
s.requestsDiagnostics = ip.Capabilities.Diagnostics.RefreshSupport
338+
s.requestsDiagnostics = ip.Capabilities.SupportsPullDiagnostics()
339339
log.Debug().
340340
Bool("requestsDiagnostics", s.requestsDiagnostics).
341341
Msg("initialize")

internal/lsp/lsp_test.go

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -287,32 +287,42 @@ func TestRequestAfterShutdown(t *testing.T) {
287287
}
288288

289289
func TestDiagnosticsRefreshSupport(t *testing.T) {
290+
// Initialize with textDocument diagnostic support enabled
290291
tester := newLSPTester(t)
291-
292-
// Initialize with diagnostic refresh support enabled
293292
resp, serverState := sendAndReceive[lsp.InitializeResult](tester, "initialize", InitializeParams{
294293
Capabilities: ClientCapabilities{
295-
Diagnostics: DiagnosticWorkspaceClientCapabilities{
296-
RefreshSupport: true,
294+
TextDocument: &TextDocumentClientCapabilities{
295+
Diagnostic: &DiagnosticClientCapabilities{},
297296
},
298297
},
299298
})
300299
require.Equal(t, serverStateInitialized, serverState)
301300
require.True(t, resp.Capabilities.DocumentFormattingProvider)
302301
require.True(t, tester.server.requestsDiagnostics)
303302

304-
// Initialize without diagnostic refresh support
303+
// Initialize with only workspace diagnostic refresh support (not pull diagnostics)
305304
tester2 := newLSPTester(t)
306305
resp2, serverState2 := sendAndReceive[lsp.InitializeResult](tester2, "initialize", InitializeParams{
307306
Capabilities: ClientCapabilities{
308-
Diagnostics: DiagnosticWorkspaceClientCapabilities{
309-
RefreshSupport: false,
307+
Workspace: &WorkspaceClientCapabilities{
308+
Diagnostics: &DiagnosticWorkspaceClientCapabilities{
309+
RefreshSupport: true,
310+
},
310311
},
311312
},
312313
})
313314
require.Equal(t, serverStateInitialized, serverState2)
314315
require.True(t, resp2.Capabilities.DocumentFormattingProvider)
315316
require.False(t, tester2.server.requestsDiagnostics)
317+
318+
// Initialize without any diagnostic support
319+
tester3 := newLSPTester(t)
320+
resp3, serverState3 := sendAndReceive[lsp.InitializeResult](tester3, "initialize", InitializeParams{
321+
Capabilities: ClientCapabilities{},
322+
})
323+
require.Equal(t, serverStateInitialized, serverState3)
324+
require.True(t, resp3.Capabilities.DocumentFormattingProvider)
325+
require.False(t, tester3.server.requestsDiagnostics)
316326
}
317327

318328
func TestLogJSONPtr(t *testing.T) {

internal/lsp/lspdefs.go

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,15 +53,32 @@ type InitializeParams struct {
5353
}
5454

5555
type ClientCapabilities struct {
56-
Diagnostics DiagnosticWorkspaceClientCapabilities `json:"diagnostics"`
56+
TextDocument *TextDocumentClientCapabilities `json:"textDocument,omitempty"`
57+
Workspace *WorkspaceClientCapabilities `json:"workspace,omitempty"`
58+
}
59+
60+
type TextDocumentClientCapabilities struct {
61+
Diagnostic *DiagnosticClientCapabilities `json:"diagnostic,omitempty"`
62+
}
63+
64+
type DiagnosticClientCapabilities struct {
65+
DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
66+
}
67+
68+
type WorkspaceClientCapabilities struct {
69+
Diagnostics *DiagnosticWorkspaceClientCapabilities `json:"diagnostics,omitempty"`
5770
}
5871

5972
type DiagnosticWorkspaceClientCapabilities struct {
60-
// RefreshSupport indicates whether the client supports the new
61-
// `textDocument/diagnostic` request.
6273
RefreshSupport bool `json:"refreshSupport,omitempty"`
6374
}
6475

76+
// SupportsPullDiagnostics returns true if the client indicated support for
77+
// pull-based diagnostics by including the textDocument.diagnostic capability.
78+
func (c ClientCapabilities) SupportsPullDiagnostics() bool {
79+
return c.TextDocument != nil && c.TextDocument.Diagnostic != nil
80+
}
81+
6582
type Hover struct {
6683
Contents MarkupContent `json:"contents"`
6784
Range *baselsp.Range `json:"range,omitempty"`

internal/lsp/testutil.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,15 @@ type lspTester struct {
4848
func (lt *lspTester) initialize() {
4949
resp, serverState := sendAndReceive[lsp.InitializeResult](lt, "initialize", InitializeParams{
5050
Capabilities: ClientCapabilities{
51-
Diagnostics: DiagnosticWorkspaceClientCapabilities{
52-
RefreshSupport: true,
51+
TextDocument: &TextDocumentClientCapabilities{
52+
Diagnostic: &DiagnosticClientCapabilities{
53+
DynamicRegistration: true,
54+
},
55+
},
56+
Workspace: &WorkspaceClientCapabilities{
57+
Diagnostics: &DiagnosticWorkspaceClientCapabilities{
58+
RefreshSupport: true,
59+
},
5360
},
5461
},
5562
})

0 commit comments

Comments
 (0)