Skip to content

Commit 9784f08

Browse files
authored
Merge pull request #736 from jupyter-lsp/improve-diagnostics
Add support for diagnostic tags from LSP 3.15
2 parents 7ae3c05 + 2b6b539 commit 9784f08

File tree

7 files changed

+151
-67
lines changed

7 files changed

+151
-67
lines changed

atest/05_Features/Diagnostics.robot

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
*** Settings ***
2+
Suite Setup Setup Suite For Screenshots diagnostics
3+
Force Tags feature:diagnostics
4+
Test Setup Setup Notebook Python Diagnostic.ipynb
5+
Test Teardown Clean Up After Working With File Diagnostic.ipynb
6+
Resource ../Keywords.robot
7+
8+
# note: diagnostics are also tested in 01_Editor and 04_Interface/DiagnosticsPanel.robot
9+
10+
*** Test Cases ***
11+
Diagnostics with deprecated tag have strike-through decoration
12+
Wait Until Page Contains Element css:.cm-lsp-diagnostic[title*="is deprecated"] timeout=25s
13+
Page Should Contain Element css:.cm-lsp-diagnostic-tag-Deprecated

atest/examples/Diagnostic.ipynb

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,25 @@
4848
"# Foo\n",
4949
"above, one `hint`"
5050
]
51+
},
52+
{
53+
"cell_type": "code",
54+
"execution_count": null,
55+
"metadata": {},
56+
"outputs": [],
57+
"source": [
58+
"%%javascript\n",
59+
"/**\n",
60+
" * @deprecated\n",
61+
" */\n",
62+
"function oldFunc() {}\n",
63+
"oldFunc"
64+
]
5165
}
5266
],
5367
"metadata": {
5468
"kernelspec": {
55-
"display_name": "Python 3",
69+
"display_name": "Python 3 (ipykernel)",
5670
"language": "python",
5771
"name": "python3"
5872
},

packages/jupyterlab-lsp/src/connection.ts

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import type * as rpc from 'vscode-jsonrpc';
1919
import type * as lsp from 'vscode-languageserver-protocol';
2020
import type { MessageConnection } from 'vscode-ws-jsonrpc';
2121

22+
import { CompletionItemTag, DiagnosticTag } from './lsp';
2223
import { ILSPLogConsole } from './tokens';
2324
import { until_ready } from './utils';
2425

@@ -392,6 +393,79 @@ export class LSPConnection extends LspWsConnection {
392393
);
393394
}
394395

396+
/**
397+
* Initialization parameters to be sent to the language server.
398+
* Subclasses can overload this when adding more features.
399+
*/
400+
protected initializeParams(): lsp.InitializeParams {
401+
return {
402+
...super.initializeParams(),
403+
capabilities: {
404+
textDocument: {
405+
hover: {
406+
dynamicRegistration: true,
407+
contentFormat: ['markdown', 'plaintext']
408+
},
409+
synchronization: {
410+
dynamicRegistration: true,
411+
willSave: false,
412+
didSave: true,
413+
willSaveWaitUntil: false
414+
},
415+
completion: {
416+
dynamicRegistration: true,
417+
completionItem: {
418+
snippetSupport: false,
419+
commitCharactersSupport: true,
420+
documentationFormat: ['markdown', 'plaintext'],
421+
deprecatedSupport: true,
422+
preselectSupport: false,
423+
tagSupport: {
424+
valueSet: [CompletionItemTag.Deprecated]
425+
}
426+
},
427+
contextSupport: false
428+
},
429+
publishDiagnostics: {
430+
tagSupport: {
431+
valueSet: [DiagnosticTag.Deprecated, DiagnosticTag.Unnecessary]
432+
}
433+
},
434+
signatureHelp: {
435+
dynamicRegistration: true,
436+
signatureInformation: {
437+
documentationFormat: ['markdown', 'plaintext']
438+
}
439+
},
440+
declaration: {
441+
dynamicRegistration: true,
442+
linkSupport: true
443+
},
444+
definition: {
445+
dynamicRegistration: true,
446+
linkSupport: true
447+
},
448+
typeDefinition: {
449+
dynamicRegistration: true,
450+
linkSupport: true
451+
},
452+
implementation: {
453+
dynamicRegistration: true,
454+
linkSupport: true
455+
}
456+
} as lsp.TextDocumentClientCapabilities,
457+
workspace: {
458+
didChangeConfiguration: {
459+
dynamicRegistration: true
460+
}
461+
} as lsp.WorkspaceClientCapabilities
462+
} as lsp.ClientCapabilities,
463+
initializationOptions: null,
464+
processId: null,
465+
workspaceFolders: null
466+
};
467+
}
468+
395469
sendOpenWhenReady(documentInfo: IDocumentInfo) {
396470
if (this.isReady) {
397471
this.sendOpen(documentInfo);

packages/jupyterlab-lsp/src/features/diagnostics/diagnostics.ts

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { LSPConnection } from '../../connection';
1212
import { PositionConverter } from '../../converter';
1313
import { CodeMirrorIntegration } from '../../editor_integration/codemirror';
1414
import { FeatureSettings } from '../../feature';
15-
import { DiagnosticSeverity } from '../../lsp';
15+
import { DiagnosticSeverity, DiagnosticTag } from '../../lsp';
1616
import { IEditorPosition, IVirtualPosition } from '../../positioning';
1717
import { DefaultMap, uris_equal } from '../../utils';
1818
import { CodeMirrorVirtualEditor } from '../../virtual/codemirror_editor';
@@ -546,12 +546,6 @@ export class DiagnosticsCM extends CodeMirrorIntegration {
546546
return;
547547
}
548548

549-
let highest_severity_code = diagnostics
550-
.map(diagnostic => diagnostic.severity || this.defaultSeverity)
551-
.sort()[0];
552-
553-
const severity = DiagnosticSeverity[highest_severity_code];
554-
555549
let ce_editor = document.get_editor_at_virtual_line(start);
556550
let cm_editor =
557551
this.virtual_editor.ce_editor_to_cm_editor.get(ce_editor)!;
@@ -621,11 +615,31 @@ export class DiagnosticsCM extends CodeMirrorIntegration {
621615
markers_to_retain.add(diagnostic_hash);
622616

623617
if (!this.marked_diagnostics.has(diagnostic_hash)) {
618+
const highestSeverityCode = diagnostics
619+
.map(diagnostic => diagnostic.severity || this.defaultSeverity)
620+
.sort()[0];
621+
622+
const severity = DiagnosticSeverity[highestSeverityCode];
623+
624+
const classNames = [
625+
'cm-lsp-diagnostic',
626+
'cm-lsp-diagnostic-' + severity
627+
];
628+
629+
const tags: lsProtocol.DiagnosticTag[] = [];
630+
for (let diagnostic of diagnostics) {
631+
if (diagnostic.tags) {
632+
tags.push(...diagnostic.tags);
633+
}
634+
}
635+
for (const tag of new Set(tags)) {
636+
classNames.push('cm-lsp-diagnostic-tag-' + DiagnosticTag[tag]);
637+
}
624638
let options: CodeMirror.TextMarkerOptions = {
625639
title: diagnostics
626640
.map(d => d.message + (d.source ? ' (' + d.source + ')' : ''))
627641
.join('\n'),
628-
className: 'cm-lsp-diagnostic cm-lsp-diagnostic-' + severity
642+
className: classNames.join(' ')
629643
};
630644
let marker;
631645
try {

packages/jupyterlab-lsp/src/lsp.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,15 @@ export enum DiagnosticSeverity {
55
Hint = 4
66
}
77

8+
export enum DiagnosticTag {
9+
Unnecessary = 1,
10+
Deprecated = 2
11+
}
12+
13+
export enum CompletionItemTag {
14+
Deprecated = 1
15+
}
16+
817
export enum CompletionItemKind {
918
Text = 1,
1019
Method = 2,

packages/jupyterlab-lsp/style/highlight.css

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,21 @@
99
text-decoration-skip-ink: none;
1010
}
1111

12+
.cm-lsp-diagnostic-tag-Unused {
13+
/*
14+
* LSP: "Clients are allowed to render diagnostics with this tag faded out instead of having an error squiggle."
15+
*/
16+
opacity: 0.85;
17+
text-decoration: none !important;
18+
}
19+
20+
.cm-lsp-diagnostic-tag-Deprecated {
21+
/*
22+
* LSP: "Clients are allowed to rendered diagnostics with this tag strike through."
23+
*/
24+
text-decoration: line-through !important;
25+
}
26+
1227
.cm-lsp-diagnostic-Error {
1328
/*
1429
"wavy" would be ideal, but there seems to be a bug in Chrome which makes it

packages/lsp-ws-connection/src/ws-connection.ts

Lines changed: 3 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import * as events from 'events';
22

33
import type * as protocol from 'vscode-languageserver-protocol';
4-
import { CompletionItemTag, LocationLink } from 'vscode-languageserver-types';
4+
import type { LocationLink } from 'vscode-languageserver-types';
55
import { ConsoleLogger, MessageConnection, listen } from 'vscode-ws-jsonrpc';
66

77
import {
@@ -145,66 +145,11 @@ export class LspWsConnection
145145

146146
/**
147147
* Initialization parameters to be sent to the language server.
148-
* Subclasses can overload this when adding more features.
148+
* Subclasses should override this when adding more features.
149149
*/
150150
protected initializeParams(): protocol.InitializeParams {
151151
return {
152-
capabilities: {
153-
textDocument: {
154-
hover: {
155-
dynamicRegistration: true,
156-
contentFormat: ['markdown', 'plaintext']
157-
},
158-
synchronization: {
159-
dynamicRegistration: true,
160-
willSave: false,
161-
didSave: true,
162-
willSaveWaitUntil: false
163-
},
164-
completion: {
165-
dynamicRegistration: true,
166-
completionItem: {
167-
snippetSupport: false,
168-
commitCharactersSupport: true,
169-
documentationFormat: ['markdown', 'plaintext'],
170-
deprecatedSupport: true,
171-
preselectSupport: false,
172-
tagSupport: {
173-
valueSet: [CompletionItemTag.Deprecated]
174-
}
175-
},
176-
contextSupport: false
177-
},
178-
signatureHelp: {
179-
dynamicRegistration: true,
180-
signatureInformation: {
181-
documentationFormat: ['markdown', 'plaintext']
182-
}
183-
},
184-
declaration: {
185-
dynamicRegistration: true,
186-
linkSupport: true
187-
},
188-
definition: {
189-
dynamicRegistration: true,
190-
linkSupport: true
191-
},
192-
typeDefinition: {
193-
dynamicRegistration: true,
194-
linkSupport: true
195-
},
196-
implementation: {
197-
dynamicRegistration: true,
198-
linkSupport: true
199-
}
200-
} as protocol.ClientCapabilities,
201-
workspace: {
202-
didChangeConfiguration: {
203-
dynamicRegistration: true
204-
}
205-
} as protocol.WorkspaceClientCapabilities
206-
} as protocol.ClientCapabilities,
207-
initializationOptions: null,
152+
capabilities: {} as protocol.ClientCapabilities,
208153
processId: null,
209154
rootUri: this.rootUri,
210155
workspaceFolders: null

0 commit comments

Comments
 (0)