Skip to content

Commit 5d33fd2

Browse files
authored
Merge pull request #738 from jupyter-lsp/client-capability-to-features
Move client capabilities to features
2 parents f08e1dc + 2802387 commit 5d33fd2

File tree

15 files changed

+139
-77
lines changed

15 files changed

+139
-77
lines changed

atest/05_Features/Completion.robot

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ Filters Completions In Case Sensitive Mode
3636
Completer Should Suggest test
3737
Completer Should Not Suggest TabError
3838

39-
4039
Can Prioritize Kernel Completions
4140
# note: disabling pre-filtering to get ranking without match scoring
4241
Configure JupyterLab Plugin {"kernelCompletionsFirst": true, "kernelResponseTimeout": -1, "preFilterMatches": false} plugin id=${COMPLETION PLUGIN ID}

atest/05_Features/Diagnostics.robot

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ Force Tags feature:diagnostics
44
Test Setup Setup Notebook Python Diagnostic.ipynb
55
Test Teardown Clean Up After Working With File Diagnostic.ipynb
66
Resource ../Keywords.robot
7-
87
# note: diagnostics are also tested in 01_Editor and 04_Interface/DiagnosticsPanel.robot
98

109
*** Test Cases ***

atest/05_Features/Signature.robot

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,18 +62,16 @@ Details Should Expand On Click
6262
Wait Until Keyword Succeeds 20x 0.5s Page Should Contain Element ${SIGNATURE_BOX}
6363
Wait Until Keyword Succeeds 10x 0.5s Element Should Contain ${SIGNATURE_BOX} Short description.
6464
Page Should Contain Element ${SIGNATURE_DETAILS}
65-
Details Should Be Collapsed ${SIGNATURE_DETAILS_CSS}
65+
Details Should Be Collapsed ${SIGNATURE_DETAILS_CSS}
6666
Click Element ${SIGNATURE_DETAILS}
6767
Details Should Be Expanded ${SIGNATURE_DETAILS_CSS}
6868

6969
*** Keywords ***
70-
7170
Details Should Be Expanded
7271
[Arguments] ${css_locator}
7372
${is_open} Execute JavaScript return document.querySelector('${css_locator}').open
7473
Should Be True ${is_open} == True
7574

76-
7775
Details Should Be Collapsed
7876
[Arguments] ${css_locator}
7977
${is_open} Execute JavaScript return document.querySelector('${css_locator}').open

docs/Extending.ipynb

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@
3434
" `CodeMirrorIntegration` class.\n",
3535
"- `labIntegration`: an optional object integrating feature with the JupyterLab\n",
3636
" interface\n",
37+
"- `capabilities`: an optional object defining the [client\n",
38+
" capabilities][clientcapabilities] implemented by your feature,\n",
3739
"- optional fields for easy integration of some of the common JupyterLab systems,\n",
3840
" such as:\n",
3941
" - settings system\n",
@@ -46,7 +48,10 @@
4648
"#### How to override the default implementation of a feature?\n",
4749
"\n",
4850
"You can specify a list of extensions to be disabled the the feature manager\n",
49-
"passing their plugin identifiers in `supersedes` field of `IFeatureOptions`."
51+
"passing their plugin identifiers in `supersedes` field of `IFeatureOptions`.\n",
52+
"\n",
53+
"[clientCapabilities]:\n",
54+
"https://microsoft.github.io/language-server-protocol/specifications/specification-3-17/#clientCapabilities]"
5055
]
5156
},
5257
{

packages/jupyterlab-lsp/src/adapters/adapter.ts

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { ILogPayload } from '@jupyterlab/logconsole';
66
import { nullTranslator, TranslationBundle } from '@jupyterlab/translation';
77
import { JSONObject } from '@lumino/coreutils';
88
import { Signal } from '@lumino/signaling';
9+
import mergeWith from 'lodash.mergewith';
910

1011
import { ICommandContext } from '../command_manager';
1112
import { LSPConnection } from '../connection';
@@ -17,7 +18,7 @@ import {
1718
import { EditorAdapter } from '../editor_integration/editor_adapter';
1819
import { IFeature, IFeatureEditorIntegration } from '../feature';
1920
import { ILSPExtension, ILSPLogConsole } from '../index';
20-
import { LanguageIdentifier } from '../lsp';
21+
import { ClientCapabilities, LanguageIdentifier } from '../lsp';
2122
import { IRootPosition, IVirtualPosition } from '../positioning';
2223
import { IForeignContext, VirtualDocument } from '../virtual/document';
2324
import { IVirtualEditor } from '../virtual/editor';
@@ -632,7 +633,31 @@ export abstract class WidgetAdapter<T extends IDocumentWidget> {
632633

633634
this.console.log(`will connect using language: ${language}`);
634635

636+
let capabilities: ClientCapabilities = {
637+
textDocument: {
638+
synchronization: {
639+
dynamicRegistration: true,
640+
willSave: false,
641+
didSave: true,
642+
willSaveWaitUntil: false
643+
}
644+
},
645+
workspace: {
646+
didChangeConfiguration: {
647+
dynamicRegistration: true
648+
}
649+
}
650+
};
651+
652+
for (const feature of this.extension.feature_manager.features) {
653+
if (!feature.capabilities) {
654+
continue;
655+
}
656+
capabilities = mergeWith(capabilities, feature.capabilities);
657+
}
658+
635659
let options: ISocketConnectionOptions = {
660+
capabilities,
636661
virtual_document,
637662
language,
638663
document_path: this.document_path

packages/jupyterlab-lsp/src/connection.ts

Lines changed: 8 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,12 @@ 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';
22+
import { ClientCapabilities } from './lsp';
2323
import { ILSPLogConsole } from './tokens';
2424
import { until_ready } from './utils';
2525

2626
interface ILSPOptions extends ILspOptions {
27+
capabilities: ClientCapabilities;
2728
serverIdentifier?: string;
2829
console: ILSPLogConsole;
2930
}
@@ -336,6 +337,7 @@ export class LSPConnection extends LspWsConnection {
336337
public clientRequests: ClientRequests;
337338
public serverRequests: ServerRequests;
338339
protected console: ILSPLogConsole;
340+
private _options: ILSPOptions;
339341
public logAllCommunication: boolean;
340342

341343
public log(kind: MessageKind, message: IMessageLog) {
@@ -379,6 +381,7 @@ export class LSPConnection extends LspWsConnection {
379381

380382
constructor(options: ILSPOptions) {
381383
super(options);
384+
this._options = options;
382385
this.logAllCommunication = false;
383386
this.serverIdentifier = options.serverIdentifier;
384387
this.console = options.console.scope(this.serverIdentifier + ' connection');
@@ -400,66 +403,10 @@ export class LSPConnection extends LspWsConnection {
400403
protected initializeParams(): lsp.InitializeParams {
401404
return {
402405
...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,
406+
// TODO: remove as `lsp.ClientCapabilities` after upgrading to 3.17
407+
// which should finally include a fix for moniker issue:
408+
// https://github.com/microsoft/vscode-languageserver-node/pull/720
409+
capabilities: this._options.capabilities as lsp.ClientCapabilities,
463410
initializationOptions: null,
464411
processId: null,
465412
workspaceFolders: null

packages/jupyterlab-lsp/src/connection_manager.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import type * as protocol from 'vscode-languageserver-protocol';
44

55
import { AskServersToSendTraceNotifications } from './_plugin';
66
import type * as ConnectionModuleType from './connection';
7+
import { ClientCapabilities } from './lsp';
78
import {
89
ILSPLogConsole,
910
ILanguageServerManager,
@@ -29,6 +30,10 @@ export interface ISocketConnectionOptions {
2930
* Path to the document in the JupyterLab space
3031
*/
3132
document_path: string;
33+
/**
34+
* LSP capabilities describing currently supported features
35+
*/
36+
capabilities: ClientCapabilities;
3237
}
3338

3439
/**
@@ -127,7 +132,7 @@ export class DocumentConnectionManager {
127132
options: ISocketConnectionOptions
128133
): Promise<ConnectionModuleType.LSPConnection> {
129134
this.console.log('Connection Socket', options);
130-
let { virtual_document, language } = options;
135+
let { virtual_document, language, capabilities } = options;
131136

132137
this.connect_document_signals(virtual_document);
133138

@@ -153,7 +158,8 @@ export class DocumentConnectionManager {
153158
language_server_id!,
154159
uris,
155160
this.on_new_connection,
156-
this.console
161+
this.console,
162+
capabilities
157163
);
158164

159165
// if connecting for the first time, all documents subsequent documents will
@@ -469,7 +475,8 @@ namespace Private {
469475
language_server_id: TLanguageServerId,
470476
uris: DocumentConnectionManager.IURIs,
471477
onCreate: (connection: ConnectionModuleType.LSPConnection) => void,
472-
console: ILSPLogConsole
478+
console: ILSPLogConsole,
479+
capabilities: ClientCapabilities
473480
): Promise<ConnectionModuleType.LSPConnection> {
474481
if (_promise == null) {
475482
// TODO: consider lazy-loading _only_ the modules that _must_ be webpacked
@@ -489,7 +496,8 @@ namespace Private {
489496
serverUri: uris.server,
490497
rootUri: uris.base,
491498
serverIdentifier: language_server_id,
492-
console: console
499+
console: console,
500+
capabilities: capabilities
493501
});
494502
// TODO: remove remaining unbounded users of connection.on
495503
connection.setMaxListeners(999);

packages/jupyterlab-lsp/src/editor_integration/testutils.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,8 @@ function FeatureSupport<TBase extends TestEnvironmentConstructor>(Base: TBase) {
258258
serverUri: 'ws://localhost:8080',
259259
rootUri: 'file:///unit-test',
260260
serverIdentifier: DEFAULT_SERVER_ID,
261-
console: new BrowserConsole()
261+
console: new BrowserConsole(),
262+
capabilities: {}
262263
});
263264
}
264265

packages/jupyterlab-lsp/src/feature.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { Signal } from '@lumino/signaling';
88
import { StatusMessage, WidgetAdapter } from './adapters/adapter';
99
import { CommandEntryPoint, ICommandContext } from './command_manager';
1010
import { LSPConnection } from './connection';
11+
import { ClientCapabilities } from './lsp';
1112
import { IRootPosition } from './positioning';
1213
import { VirtualDocument } from './virtual/document';
1314
import { IEditorChange, IVirtualEditor } from './virtual/editor';
@@ -123,6 +124,10 @@ export interface IFeature {
123124
IEditorName,
124125
IFeatureEditorIntegrationConstructor<IVirtualEditor<IEditor>>
125126
>;
127+
/**
128+
* LSP capabilities implemented by the feature.
129+
*/
130+
capabilities?: ClientCapabilities;
126131
/**
127132
* Command specification, including context menu placement options.
128133
*/

packages/jupyterlab-lsp/src/features/completion/index.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { ILSPCompletionThemeManager } from '@krassowski/completion-theme/lib/typ
1111
import completionSvg from '../../../style/icons/completion.svg';
1212
import { CodeCompletion as LSPCompletionSettings } from '../../_completion';
1313
import { FeatureSettings } from '../../feature';
14+
import { CompletionItemTag } from '../../lsp';
1415
import {
1516
ILSPAdapterManager,
1617
ILSPFeatureManager,
@@ -66,7 +67,25 @@ export const COMPLETION_PLUGIN: JupyterFrontEndPlugin<void> = {
6667
id: FEATURE_ID,
6768
name: 'LSP Completion',
6869
labIntegration: labIntegration,
69-
settings: settings
70+
settings: settings,
71+
capabilities: {
72+
textDocument: {
73+
completion: {
74+
dynamicRegistration: true,
75+
completionItem: {
76+
snippetSupport: false,
77+
commitCharactersSupport: true,
78+
documentationFormat: ['markdown', 'plaintext'],
79+
deprecatedSupport: true,
80+
preselectSupport: false,
81+
tagSupport: {
82+
valueSet: [CompletionItemTag.Deprecated]
83+
}
84+
},
85+
contextSupport: false
86+
}
87+
}
88+
}
7089
}
7190
});
7291
}

0 commit comments

Comments
 (0)