Skip to content

Commit

Permalink
Merge pull request #474 from krassowski/fix-status
Browse files Browse the repository at this point in the history
Fix connection manager loosing track of notebooks
  • Loading branch information
krassowski authored Jan 16, 2021
2 parents b161b27 + e736117 commit 379d033
Show file tree
Hide file tree
Showing 7 changed files with 49 additions and 26 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
## CHANGELOG

### `@krassowski/jupyterlab-lsp 3.0.1` (unreleased)
### `@krassowski/jupyterlab-lsp 3.1.0` (unreleased)

- features

Expand All @@ -10,9 +10,11 @@

- fix completions with R double and triple colon prefix ([#449])
- fix contrast on status icon when status item is active ([#465])
- fix connection manager loosing track of notebooks when multiple were open ([#474])

[#449]: https://github.com/krassowski/jupyterlab-lsp/pull/449
[#465]: https://github.com/krassowski/jupyterlab-lsp/pull/465
[#474]: https://github.com/krassowski/jupyterlab-lsp/pull/474

### `jupyter-lsp 1.0.1` (unreleased)

Expand Down
13 changes: 13 additions & 0 deletions atest/04_Interface/Statusbar.robot
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,19 @@ Statusbar Popup Opens
Element Should Contain ${POPOVER} initialized
[Teardown] Clean Up After Working With File Python.ipynb

Status Changes Between Notebooks
Setup Notebook Python Python.ipynb
Wait Until Fully Initialized
Lab Command New Notebook
Wait For Dialog
# Kernel selection dialog shows up, accept Python as default kernel
Accept Default Dialog Option
Element Should Contain ${STATUSBAR} Waiting...
Wait Until Fully Initialized
Switch To Tab Python.ipynb
Wait Until Fully Initialized
[Teardown] Clean Up After Working With File Python.ipynb

Status Changes Correctly Between Editors
Prepare File for Editing Python status example.py
Wait Until Fully Initialized
Expand Down
4 changes: 2 additions & 2 deletions packages/jupyterlab-lsp/src/adapters/adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -413,7 +413,7 @@ export abstract class WidgetAdapter<T extends IDocumentWidget> {

// TODO only send the difference, using connection.sendSelectiveChange()
let connection = this.connection_manager.connections.get(
virtual_document.id_path
virtual_document.uri
);
let adapter = this.adapters.get(virtual_document.id_path);

Expand Down Expand Up @@ -596,7 +596,7 @@ export abstract class WidgetAdapter<T extends IDocumentWidget> {
);
return {
document,
connection: this.connection_manager.connections.get(document.id_path),
connection: this.connection_manager.connections.get(document.uri),
virtual_position,
root_position,
features: this.get_features(document),
Expand Down
11 changes: 7 additions & 4 deletions packages/jupyterlab-lsp/src/components/statusbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ class LSPPopup extends VDomRenderer<LSPStatus.Model> {
// TODO: add a config buttons next to the language header
let list = documents.map((document, i) => {
let connection = this.model.connection_manager.connections.get(
document.id_path
document.uri
);

let status = '';
Expand Down Expand Up @@ -542,8 +542,8 @@ export namespace LSPStatus {
// detected documents with LSP servers available
let documents_with_servers = new Set<VirtualDocument>();

detected_documents.forEach((document, id_path) => {
let connection = this._connection_manager.connections.get(id_path);
detected_documents.forEach((document, uri) => {
let connection = this._connection_manager.connections.get(uri);
if (!connection) {
absent_documents.add(document);
return;
Expand Down Expand Up @@ -657,7 +657,7 @@ export namespace LSPStatus {

change_adapter(adapter: WidgetAdapter<IDocumentWidget> | null) {
if (this._adapter != null) {
this._adapter.status_message.changed.connect(this._onChange);
this._adapter.status_message.changed.disconnect(this._onChange);
}

if (adapter != null) {
Expand All @@ -671,6 +671,9 @@ export namespace LSPStatus {
return this._connection_manager;
}

/**
* Note: it is ever only set once, as connection_manager is a singleton.
*/
set connection_manager(connection_manager) {
if (this._connection_manager != null) {
this._connection_manager.connected.disconnect(this._onChange);
Expand Down
33 changes: 17 additions & 16 deletions packages/jupyterlab-lsp/src/connection_manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,13 @@ export interface ISocketConnectionOptions {
}

/**
* Each Widget with a document (whether file or a notebook) has its own DocumentConnectionManager
* (see JupyterLabWidgetAdapter), keeping the virtual document spaces separate if a file is opened twice.
* Each Widget with a document (whether file or a notebook) has the same DocumentConnectionManager
* (see JupyterLabWidgetAdapter). Using id_path instead of uri led to documents being overwritten
* as two identical id_paths could be created for two different notebooks.
*/
export class DocumentConnectionManager {
connections: Map<VirtualDocument.id_path, LSPConnection>;
documents: Map<VirtualDocument.id_path, VirtualDocument>;
connections: Map<VirtualDocument.uri, LSPConnection>;
documents: Map<VirtualDocument.uri, VirtualDocument>;
initialized: Signal<DocumentConnectionManager, IDocumentConnectionData>;
connected: Signal<DocumentConnectionManager, IDocumentConnectionData>;
/**
Expand All @@ -53,7 +54,7 @@ export class DocumentConnectionManager {
closed: Signal<DocumentConnectionManager, IDocumentConnectionData>;
documents_changed: Signal<
DocumentConnectionManager,
Map<VirtualDocument.id_path, VirtualDocument>
Map<VirtualDocument.uri, VirtualDocument>
>;
language_server_manager: ILanguageServerManager;
initial_configurations: TLanguageServerConfigurations;
Expand Down Expand Up @@ -83,7 +84,7 @@ export class DocumentConnectionManager {
this
);

this.documents.set(virtual_document.id_path, virtual_document);
this.documents.set(virtual_document.uri, virtual_document);
this.documents_changed.emit(this.documents);
}

Expand All @@ -98,7 +99,7 @@ export class DocumentConnectionManager {
this
);

this.documents.delete(virtual_document.id_path);
this.documents.delete(virtual_document.uri);
for (const foreign of virtual_document.foreign_documents.values()) {
this.disconnect_document_signals(foreign, false);
}
Expand All @@ -111,7 +112,7 @@ export class DocumentConnectionManager {
on_foreign_document_opened(_host: VirtualDocument, context: IForeignContext) {
console.log(
'LSP: ConnectionManager received foreign document: ',
context.foreign_document.id_path
context.foreign_document.uri
);
}

Expand Down Expand Up @@ -149,7 +150,7 @@ export class DocumentConnectionManager {

// if connecting for the first time, all documents subsequent documents will
// be re-opened and synced
this.connections.set(virtual_document.id_path, connection);
this.connections.set(virtual_document.uri, connection);

return connection;
}
Expand Down Expand Up @@ -188,12 +189,12 @@ export class DocumentConnectionManager {
if (error.message.indexOf('code = 1005') !== -1) {
console.warn(`LSP: Connection failed for ${connection}`);
this.forEachDocumentOfConnection(connection, virtual_document => {
console.warn('LSP: disconnecting ' + virtual_document.id_path);
console.warn('LSP: disconnecting ' + virtual_document.uri);
this.closed.emit({ connection, virtual_document });
this.ignored_languages.add(virtual_document.language);

console.warn(
`Cancelling further attempts to connect ${virtual_document.id_path} and other documents for this language (no support from the server)`
`Cancelling further attempts to connect ${virtual_document.uri} and other documents for this language (no support from the server)`
);
});
} else if (error.message.indexOf('code = 1006') !== -1) {
Expand Down Expand Up @@ -230,13 +231,13 @@ export class DocumentConnectionManager {
callback: (virtual_document: VirtualDocument) => void
) {
for (const [
virtual_document_id_path,
virtual_document_uri,
a_connection
] of this.connections.entries()) {
if (connection !== a_connection) {
continue;
}
callback(this.documents.get(virtual_document_id_path));
callback(this.documents.get(virtual_document_uri));
}
}

Expand Down Expand Up @@ -287,20 +288,20 @@ export class DocumentConnectionManager {
try {
await until_ready(() => connection.isReady, 200, 200);
} catch {
console.warn(`LSP: Connect timed out for ${virtual_document.id_path}`);
console.warn(`LSP: Connect timed out for ${virtual_document.uri}`);
return;
}
}

console.log('LSP:', document_path, virtual_document.id_path, 'connected.');
console.log('LSP:', document_path, virtual_document.uri, 'connected.');

this.connected.emit({ connection, virtual_document });

return connection;
}

public unregister_document(virtual_document: VirtualDocument) {
this.connections.delete(virtual_document.id_path);
this.connections.delete(virtual_document.uri);
this.documents_changed.emit(this.documents);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export class LSPConnector
implements CompletionHandler.ICompletionItemsConnector {
isDisposed = false;
private _editor: CodeEditor.IEditor;
private _connections: Map<VirtualDocument.id_path, LSPConnection>;
private _connections: Map<VirtualDocument.uri, LSPConnection>;
private _context_connector: ContextConnector;
private _kernel_connector: KernelConnector;
private _kernel_and_context_connector: CompletionConnector;
Expand Down Expand Up @@ -222,7 +222,7 @@ export class LSPConnector
document: VirtualDocument,
position_in_token: number
): Promise<CompletionHandler.ICompletionItemsReply> {
let connection = this._connections.get(document.id_path);
let connection = this._connections.get(document.uri);

console.log('[LSP][Completer] Fetching');
console.log('[LSP][Completer] Token:', token, start, end);
Expand Down
6 changes: 5 additions & 1 deletion packages/jupyterlab-lsp/src/virtual/document.ts
Original file line number Diff line number Diff line change
Expand Up @@ -734,7 +734,7 @@ export class VirtualDocument {
return this.parent.id_path + '-' + this.virtual_id;
}

get uri(): string {
get uri(): VirtualDocument.uri {
const encodedPath = encodeURI(this.path);
if (!this.parent) {
return encodedPath;
Expand Down Expand Up @@ -816,6 +816,10 @@ export namespace VirtualDocument {
* for documents which should be interpreted as one when stretched across cells.
*/
export type virtual_id = string;
/**
* Identifier composed of the file path and id_path.
*/
export type uri = string;
}

export function collect_documents(
Expand Down

0 comments on commit 379d033

Please sign in to comment.