From 5a88598811e4d82fb15bc3aab52b6f3d2519750b Mon Sep 17 00:00:00 2001 From: Kevin Cunnane Date: Fri, 22 Feb 2019 16:22:40 -0800 Subject: [PATCH] Fix #3778 intellisense is delayed (#4134) - Jupyter completion item support was awaiting info before responding. Fix is to check if this is even a notebook cell first, then only await stuff if that's true --- .../intellisense/completionItemProvider.ts | 68 +++++++++---------- .../notebook/src/jupyter/jupyterController.ts | 1 - .../src/jupyter/jupyterNotebookProvider.ts | 6 +- 3 files changed, 36 insertions(+), 39 deletions(-) diff --git a/extensions/notebook/src/intellisense/completionItemProvider.ts b/extensions/notebook/src/intellisense/completionItemProvider.ts index 8ee6b70b56..5031ae5d33 100644 --- a/extensions/notebook/src/intellisense/completionItemProvider.ts +++ b/extensions/notebook/src/intellisense/completionItemProvider.ts @@ -11,22 +11,30 @@ import * as vscode from 'vscode'; import { charCountToJsCountDiff, jsIndexToCharIndex } from './text'; import { JupyterNotebookProvider } from '../jupyter/jupyterNotebookProvider'; import { JupyterSessionManager } from '../jupyter/jupyterSessionManager'; -import { Deferred } from '../common/promise'; -const timeoutMilliseconds = 4000; +const timeoutMilliseconds = 3000; export class NotebookCompletionItemProvider implements vscode.CompletionItemProvider { - private _allDocuments: nb.NotebookDocument[]; - private kernelDeferred = new Deferred(); constructor(private _notebookProvider: JupyterNotebookProvider) { } public provideCompletionItems(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken, context: vscode.CompletionContext) : vscode.ProviderResult { - this._allDocuments = nb.notebookDocuments; - let info = this.findMatchingCell(document); - this.isNotConnected(document, info); + let info = this.findMatchingCell(document, nb.notebookDocuments); + if (!info || !this._notebookProvider) { + // No matching document found + return Promise.resolve([]); + } + return this.getCompletionItemsForNotebookCell(document, position, token, info); + } + + private async getCompletionItemsForNotebookCell(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken, info: INewIntellisenseInfo + ): Promise { + info.kernel = await this.tryFindKernelForDocument(document, info); + if (!info.kernel) { + return []; + } // Get completions, with cancellation on timeout or if cancel is requested. // Note that it's important we always return some value, or intellisense will never complete let promises = [this.requestCompletions(info, position, document), this.onCanceled(token), this.onTimeout(timeoutMilliseconds)]; @@ -37,38 +45,29 @@ export class NotebookCompletionItemProvider implements vscode.CompletionItemProv return item; } - private isNotConnected(document: vscode.TextDocument, info: INewIntellisenseInfo): void { - if (!info || !this._notebookProvider) { - return; - } - let notebookManager: nb.NotebookManager = undefined; - - let kernel: nb.IKernel = undefined; + private async tryFindKernelForDocument(document: vscode.TextDocument, info: INewIntellisenseInfo): Promise { try { - this._notebookProvider.getNotebookManager(document.uri).then(manager => { - notebookManager = manager; - if (notebookManager) { - let sessionManager: JupyterSessionManager = (notebookManager.sessionManager); - let sessions = sessionManager.listRunning(); - if (sessions && sessions.length > 0) { - let session = sessions.find(session => session.path === info.notebook.uri.path); - if (!session) { - return; - } - kernel = session.kernel; + let notebookManager = await this._notebookProvider.getNotebookManager(document.uri); + if (notebookManager) { + let sessionManager: JupyterSessionManager = (notebookManager.sessionManager); + let sessions = sessionManager.listRunning(); + if (sessions && sessions.length > 0) { + let session = sessions.find(session => session.path === info.notebook.uri.path); + if (!session) { + return; } + return session.kernel; } - this.kernelDeferred.resolve(kernel); - }); + } } catch { // If an exception occurs, swallow it currently - return; + return undefined; } } - private findMatchingCell(document: vscode.TextDocument): INewIntellisenseInfo { - if (this._allDocuments && document) { - for (let doc of this._allDocuments) { + private findMatchingCell(document: vscode.TextDocument, allDocuments: nb.NotebookDocument[]): INewIntellisenseInfo { + if (allDocuments && document) { + for (let doc of allDocuments) { for (let cell of doc.cells) { if (cell && cell.uri && cell.uri.path === document.uri.path) { return { @@ -84,9 +83,7 @@ export class NotebookCompletionItemProvider implements vscode.CompletionItemProv } private async requestCompletions(info: INewIntellisenseInfo, position: vscode.Position, cellTextDocument: vscode.TextDocument): Promise { - let kernel = await this.kernelDeferred.promise; - this.kernelDeferred = new Deferred(); - if (!info || kernel === undefined || !kernel.supportsIntellisense || !kernel.isReady) { + if (!info || !info.kernel || !info.kernel.supportsIntellisense || !info.kernel.isReady) { return []; } let source = cellTextDocument.getText(); @@ -94,7 +91,7 @@ export class NotebookCompletionItemProvider implements vscode.CompletionItemProv return []; } let cursorPosition = this.toCursorPosition(position, source); - let result = await kernel.requestComplete({ + let result = await info.kernel.requestComplete({ code: source, cursor_pos: cursorPosition.adjustedPosition }); @@ -197,4 +194,5 @@ export interface INewIntellisenseInfo { editorUri: string; cell: nb.NotebookCell; notebook: nb.NotebookDocument; + kernel?: nb.IKernel; } \ No newline at end of file diff --git a/extensions/notebook/src/jupyter/jupyterController.ts b/extensions/notebook/src/jupyter/jupyterController.ts index c0795b0408..1cb46fef38 100644 --- a/extensions/notebook/src/jupyter/jupyterController.ts +++ b/extensions/notebook/src/jupyter/jupyterController.ts @@ -99,7 +99,6 @@ export class JupyterController implements vscode.Disposable { this.apiWrapper.registerCommand(constants.jupyterConfigurePython, () => { return this.doConfigurePython(jupyterInstaller); }); let supportedFileFilter: vscode.DocumentFilter[] = [ - { scheme: 'file', language: '*' }, { scheme: 'untitled', language: '*' } ]; this.extensionContext.subscriptions.push(this.apiWrapper.registerCompletionItemProvider(supportedFileFilter, new NotebookCompletionItemProvider(notebookProvider))); diff --git a/extensions/notebook/src/jupyter/jupyterNotebookProvider.ts b/extensions/notebook/src/jupyter/jupyterNotebookProvider.ts index b0d15c29dc..3d750bbe22 100644 --- a/extensions/notebook/src/jupyter/jupyterNotebookProvider.ts +++ b/extensions/notebook/src/jupyter/jupyterNotebookProvider.ts @@ -27,10 +27,10 @@ export class JupyterNotebookProvider implements nb.NotebookProvider { if (!notebookUri) { return Promise.reject(localize('errNotebookUriMissing', 'A notebook path is required')); } - return this.doGetNotebookManager(notebookUri); + return Promise.resolve(this.doGetNotebookManager(notebookUri)); } - private doGetNotebookManager(notebookUri: vscode.Uri): Promise { + private doGetNotebookManager(notebookUri: vscode.Uri): nb.NotebookManager { let uriString = notebookUri.toString(); let manager = this.managerTracker.get(uriString); if (!manager) { @@ -38,7 +38,7 @@ export class JupyterNotebookProvider implements nb.NotebookProvider { manager = new JupyterNotebookManager(serverManager); this.managerTracker.set(uriString, manager); } - return Promise.resolve(manager); + return manager; } handleNotebookClosed(notebookUri: vscode.Uri): void {