diff --git a/news/3 Code Health/12025.md b/news/3 Code Health/12025.md new file mode 100644 index 000000000000..e051a1a0a85a --- /dev/null +++ b/news/3 Code Health/12025.md @@ -0,0 +1 @@ +Ensure we can use proposed VS Code API with `ts-node`. diff --git a/src/client/common/application/notebook.ts b/src/client/common/application/notebook.ts index 34ba9c06df11..8985581cf6fc 100644 --- a/src/client/common/application/notebook.ts +++ b/src/client/common/application/notebook.ts @@ -2,21 +2,16 @@ // Licensed under the MIT License. import { inject, injectable } from 'inversify'; -import { - Disposable, - Event, - EventEmitter, - GlobPattern, +import { Disposable, Event, EventEmitter, GlobPattern, TextDocument, window } from 'vscode'; +import type { notebook, NotebookContentProvider, NotebookDocument, NotebookEditor, NotebookKernel, NotebookOutputRenderer, - NotebookOutputSelector, - TextDocument, - window -} from 'vscode'; + NotebookOutputSelector +} from 'vscode-proposed'; import { UseProposedApi } from '../constants'; import { IDisposableRegistry } from '../types'; import { @@ -36,13 +31,13 @@ export class VSCodeNotebook implements IVSCodeNotebook { | NotebookCellLanguageChangeEvent >(); public get onDidOpenNotebookDocument(): Event { - return notebook.onDidOpenNotebookDocument; + return this.notebook.onDidOpenNotebookDocument; } public get onDidCloseNotebookDocument(): Event { - return notebook.onDidCloseNotebookDocument; + return this.notebook.onDidCloseNotebookDocument; } public get notebookEditors() { - return notebook.visibleNotebookEditors; + return this.notebook.visibleNotebookEditors; } public get onDidChangeNotebookDocument(): Event< | NotebookCellsChangeEvent @@ -64,7 +59,7 @@ export class VSCodeNotebook implements IVSCodeNotebook { } // Temporary, currently VSC API doesn't work well. // `notebook.activeNotebookEditor` is not reset when opening another file. - if (!notebook.activeNotebookEditor) { + if (!this.notebook.activeNotebookEditor) { return; } // If we have a text editor opened and it is not a cell, then we know for certain a notebook is not open. @@ -72,28 +67,36 @@ export class VSCodeNotebook implements IVSCodeNotebook { return; } // Temporary until VSC API stabilizes. - if (Array.isArray(notebook.visibleNotebookEditors)) { - return notebook.visibleNotebookEditors.find((item) => item.active && item.visible); + if (Array.isArray(this.notebook.visibleNotebookEditors)) { + return this.notebook.visibleNotebookEditors.find((item) => item.active && item.visible); } - return notebook.activeNotebookEditor; + return this.notebook.activeNotebookEditor; } private addedEventHandlers?: boolean; + private _notebook?: typeof notebook; + private get notebook() { + if (!this._notebook) { + // tslint:disable-next-line: no-require-imports + this._notebook = require('vscode').notebook; + } + return this._notebook!; + } constructor( @inject(UseProposedApi) private readonly useProposedApi: boolean, @inject(IDisposableRegistry) private readonly disposables: IDisposableRegistry ) {} public registerNotebookContentProvider(notebookType: string, provider: NotebookContentProvider): Disposable { - return notebook.registerNotebookContentProvider(notebookType, provider); + return this.notebook.registerNotebookContentProvider(notebookType, provider); } public registerNotebookKernel(id: string, selectors: GlobPattern[], kernel: NotebookKernel): Disposable { - return notebook.registerNotebookKernel(id, selectors, kernel); + return this.notebook.registerNotebookKernel(id, selectors, kernel); } public registerNotebookOutputRenderer( id: string, outputSelector: NotebookOutputSelector, renderer: NotebookOutputRenderer ): Disposable { - return notebook.registerNotebookOutputRenderer(id, outputSelector, renderer); + return this.notebook.registerNotebookOutputRenderer(id, outputSelector, renderer); } public isCell(textDocument: TextDocument) { return ( @@ -109,16 +112,16 @@ export class VSCodeNotebook implements IVSCodeNotebook { } this.disposables.push( ...[ - notebook.onDidChangeCellLanguage((e) => + this.notebook.onDidChangeCellLanguage((e) => this._onDidChangeNotebookDocument.fire({ ...e, type: 'changeCellLanguage' }) ), - notebook.onDidChangeCellOutputs((e) => + this.notebook.onDidChangeCellOutputs((e) => this._onDidChangeNotebookDocument.fire({ ...e, type: 'changeCellOutputs' }) ), - notebook.onDidChangeNotebookCells((e) => + this.notebook.onDidChangeNotebookCells((e) => this._onDidChangeNotebookDocument.fire({ ...e, type: 'changeCells' }) ), - notebook.onDidMoveNotebookCell((e) => + this.notebook.onDidMoveNotebookCell((e) => this._onDidChangeNotebookDocument.fire({ ...e, type: 'moveCell' }) ) ] diff --git a/src/client/common/application/types.ts b/src/client/common/application/types.ts index b7ea624119f3..deb0f3eaf269 100644 --- a/src/client/common/application/types.ts +++ b/src/client/common/application/types.ts @@ -24,16 +24,6 @@ import { InputBoxOptions, MessageItem, MessageOptions, - NotebookCellLanguageChangeEvent as VSCNotebookCellLanguageChangeEvent, - NotebookCellMoveEvent as VSCNotebookCellMoveEvent, - NotebookCellOutputsChangeEvent as VSCNotebookCellOutputsChangeEvent, - NotebookCellsChangeEvent as VSCNotebookCellsChangeEvent, - NotebookContentProvider, - NotebookDocument, - NotebookEditor, - NotebookKernel, - NotebookOutputRenderer, - NotebookOutputSelector, OpenDialogOptions, OutputChannel, Progress, @@ -68,6 +58,18 @@ import { WorkspaceFolderPickOptions, WorkspaceFoldersChangeEvent } from 'vscode'; +import type { + NotebookCellLanguageChangeEvent as VSCNotebookCellLanguageChangeEvent, + NotebookCellMoveEvent as VSCNotebookCellMoveEvent, + NotebookCellOutputsChangeEvent as VSCNotebookCellOutputsChangeEvent, + NotebookCellsChangeEvent as VSCNotebookCellsChangeEvent, + NotebookContentProvider, + NotebookDocument, + NotebookEditor, + NotebookKernel, + NotebookOutputRenderer, + NotebookOutputSelector +} from 'vscode-proposed'; import * as vsls from 'vsls/vscode'; import { IAsyncDisposable, Resource } from '../types'; diff --git a/src/client/datascience/notebook/cellUpdateHelpers.ts b/src/client/datascience/notebook/cellUpdateHelpers.ts index 3fa52c7f23b7..69eab964390a 100644 --- a/src/client/datascience/notebook/cellUpdateHelpers.ts +++ b/src/client/datascience/notebook/cellUpdateHelpers.ts @@ -3,7 +3,7 @@ 'use strict'; -import { NotebookCell, NotebookDocument } from 'vscode'; +import type { NotebookCell, NotebookDocument } from 'vscode-proposed'; import { IDisposable } from '../../common/types'; import { traceError } from '../../logging'; import { ICell, INotebookModel } from '../types'; diff --git a/src/client/datascience/notebook/contentProvider.ts b/src/client/datascience/notebook/contentProvider.ts index 5110bc11e39d..90f8fde16fd6 100644 --- a/src/client/datascience/notebook/contentProvider.ts +++ b/src/client/datascience/notebook/contentProvider.ts @@ -4,15 +4,13 @@ 'use strict'; import { inject, injectable } from 'inversify'; -import { - CancellationToken, - EventEmitter, +import { CancellationToken, EventEmitter, Uri } from 'vscode'; +import type { NotebookContentProvider as VSCodeNotebookContentProvider, NotebookData, NotebookDocument, - NotebookDocumentEditEvent, - Uri -} from 'vscode'; + NotebookDocumentEditEvent +} from 'vscode-proposed'; import { INotebookStorageProvider } from '../interactive-ipynb/notebookStorageProvider'; import { notebookModelToVSCNotebookData } from './helpers'; diff --git a/src/client/datascience/notebook/executionService.ts b/src/client/datascience/notebook/executionService.ts index 7205019668ac..03a357812eb2 100644 --- a/src/client/datascience/notebook/executionService.ts +++ b/src/client/datascience/notebook/executionService.ts @@ -6,8 +6,8 @@ import { nbformat } from '@jupyterlab/coreutils'; import { inject, injectable } from 'inversify'; import { Subscription } from 'rxjs'; -import { CancellationToken, NotebookCell, NotebookCellRunState, NotebookDocument } from 'vscode'; -import { CancellationTokenSource } from 'vscode-jsonrpc'; +import { CancellationToken, CancellationTokenSource } from 'vscode'; +import type { NotebookCell, NotebookDocument } from 'vscode-proposed'; import { ICommandManager } from '../../common/application/types'; import { wrapCancellationTokens } from '../../common/cancellation'; import '../../common/extensions'; @@ -26,6 +26,8 @@ import { updateCellWithErrorStatus } from './executionHelpers'; import { INotebookExecutionService } from './types'; +// tslint:disable-next-line: no-var-requires no-require-imports +const vscodeNotebookEnums = require('vscode') as typeof import('vscode-proposed'); /** * VSC will use this class to execute cells in a notebook. @@ -138,7 +140,7 @@ export class NotebookExecutionService implements INotebookExecutionService { return; } deferred.resolve(); - cell.metadata.runState = NotebookCellRunState.Idle; + cell.metadata.runState = vscodeNotebookEnums.NotebookCellRunState.Idle; // Interrupt kernel only if original cancellation was cancelled. if (token.isCancellationRequested) { @@ -147,7 +149,7 @@ export class NotebookExecutionService implements INotebookExecutionService { }); cell.metadata.runStartTime = new Date().getTime(); - cell.metadata.runState = NotebookCellRunState.Running; + cell.metadata.runState = vscodeNotebookEnums.NotebookCellRunState.Running; if (!findMappedNotebookCellModel(cell, model.cells)) { // tslint:disable-next-line: no-suspicious-comment @@ -181,8 +183,8 @@ export class NotebookExecutionService implements INotebookExecutionService { }, () => { cell.metadata.runState = wrappedToken.isCancellationRequested - ? NotebookCellRunState.Idle - : NotebookCellRunState.Success; + ? vscodeNotebookEnums.NotebookCellRunState.Idle + : vscodeNotebookEnums.NotebookCellRunState.Success; cell.metadata.lastRunDuration = stopWatch.elapsedTime; cell.metadata.statusMessage = ''; deferred.resolve(); diff --git a/src/client/datascience/notebook/helpers.ts b/src/client/datascience/notebook/helpers.ts index 2376b61e5ea6..a9a5d158f778 100644 --- a/src/client/datascience/notebook/helpers.ts +++ b/src/client/datascience/notebook/helpers.ts @@ -4,17 +4,16 @@ 'use strict'; import { nbformat } from '@jupyterlab/coreutils'; -import { +import type { CellDisplayOutput, CellErrorOutput, - CellKind, CellOutput, - CellOutputKind, CellStreamOutput, NotebookCellData, - NotebookCellRunState, NotebookData -} from 'vscode'; +} from 'vscode-proposed'; +// tslint:disable-next-line: no-var-requires no-require-imports +const vscodeNotebookEnums = require('vscode') as typeof import('vscode-proposed'); import { concatMultilineStringInput, concatMultilineStringOutput } from '../../../datascience-ui/common'; import { MARKDOWN_LANGUAGE, PYTHON_LANGUAGE } from '../../common/constants'; import { traceError, traceWarning } from '../../logging'; @@ -67,12 +66,13 @@ export function cellToVSCNotebookCellData(cell: ICell): NotebookCellData | undef } return { - cellKind: cell.data.cell_type === 'code' ? CellKind.Code : CellKind.Markdown, + cellKind: + cell.data.cell_type === 'code' ? vscodeNotebookEnums.CellKind.Code : vscodeNotebookEnums.CellKind.Markdown, language: cell.data.cell_type === 'code' ? PYTHON_LANGUAGE : MARKDOWN_LANGUAGE, metadata: { editable: true, executionOrder: typeof cell.data.execution_count === 'number' ? cell.data.execution_count : undefined, - runState: NotebookCellRunState.Idle, + runState: vscodeNotebookEnums.NotebookCellRunState.Idle, runnable: cell.data.cell_type === 'code', custom: { cellId: cell.id @@ -157,7 +157,7 @@ function translateDisplayDataOutput(output: nbformat.IDisplayData): CellDisplayO ] = `
`; } return { - outputKind: CellOutputKind.Rich, + outputKind: vscodeNotebookEnums.CellOutputKind.Rich, data }; } @@ -177,14 +177,14 @@ function translateStreamOutput(output: nbformat.IStream): CellStreamOutput | Cel if (!hasAngleBrackets && !hasAnsiChars) { // Plain text output. return { - outputKind: CellOutputKind.Text, + outputKind: vscodeNotebookEnums.CellOutputKind.Text, text }; } // Format the output, but ensure we have the plain text output as well. const richOutput: CellDisplayOutput = { - outputKind: CellOutputKind.Rich, + outputKind: vscodeNotebookEnums.CellOutputKind.Rich, data: { ['text/plain']: text } @@ -212,7 +212,7 @@ export function translateErrorOutput(output: nbformat.IError): CellErrorOutput { return { ename: output.ename, evalue: output.evalue, - outputKind: CellOutputKind.Error, + outputKind: vscodeNotebookEnums.CellOutputKind.Error, traceback: output.traceback }; } diff --git a/src/client/datascience/notebook/notebookEditor.ts b/src/client/datascience/notebook/notebookEditor.ts index cf8439f26e99..3fdffce23472 100644 --- a/src/client/datascience/notebook/notebookEditor.ts +++ b/src/client/datascience/notebook/notebookEditor.ts @@ -3,7 +3,8 @@ 'use strict'; -import { CellKind, ConfigurationTarget, Event, EventEmitter, NotebookDocument, Uri, WebviewPanel } from 'vscode'; +import { CellKind, ConfigurationTarget, Event, EventEmitter, Uri, WebviewPanel } from 'vscode'; +import type { NotebookDocument } from 'vscode-proposed'; import { IApplicationShell, ICommandManager, IVSCodeNotebook } from '../../common/application/types'; import { PYTHON_LANGUAGE } from '../../common/constants'; import { IConfigurationService } from '../../common/types'; diff --git a/src/client/datascience/notebook/notebookEditorProvider.ts b/src/client/datascience/notebook/notebookEditorProvider.ts index 44683139dd5c..40e8d977731b 100644 --- a/src/client/datascience/notebook/notebookEditorProvider.ts +++ b/src/client/datascience/notebook/notebookEditorProvider.ts @@ -4,7 +4,8 @@ 'use strict'; import { inject, injectable } from 'inversify'; -import { Event, EventEmitter, NotebookDocument, Uri } from 'vscode'; +import { Event, EventEmitter, Uri } from 'vscode'; +import type { NotebookDocument } from 'vscode-proposed'; import { IExtensionSingleActivationService } from '../../activation/types'; import { IApplicationShell, ICommandManager, IVSCodeNotebook, IWorkspaceService } from '../../common/application/types'; import '../../common/extensions'; diff --git a/src/client/datascience/notebook/notebookKernel.ts b/src/client/datascience/notebook/notebookKernel.ts index f744495badef..b2ec0a7cc9f5 100644 --- a/src/client/datascience/notebook/notebookKernel.ts +++ b/src/client/datascience/notebook/notebookKernel.ts @@ -4,7 +4,8 @@ 'use strict'; import { inject, injectable } from 'inversify'; -import { CancellationToken, NotebookCell, NotebookDocument, NotebookKernel as VSCNotebookKernel, Uri } from 'vscode'; +import { CancellationToken, Uri } from 'vscode'; +import type { NotebookCell, NotebookDocument, NotebookKernel as VSCNotebookKernel } from 'vscode-proposed'; import { INotebookExecutionService } from './types'; /** diff --git a/src/client/datascience/notebook/types.ts b/src/client/datascience/notebook/types.ts index 5f30a99a4de1..daec77e8122e 100644 --- a/src/client/datascience/notebook/types.ts +++ b/src/client/datascience/notebook/types.ts @@ -3,7 +3,8 @@ 'use strict'; -import { CancellationToken, NotebookCell, NotebookDocument } from 'vscode'; +import type { CancellationToken } from 'vscode'; +import type { NotebookCell, NotebookDocument } from 'vscode-proposed'; export const INotebookExecutionService = Symbol('INotebookExecutionService'); export interface INotebookExecutionService { diff --git a/src/test/datascience/notebook/contentProvider.unit.test.ts b/src/test/datascience/notebook/contentProvider.unit.test.ts index 55a836d62d8f..f3d308ef6f86 100644 --- a/src/test/datascience/notebook/contentProvider.unit.test.ts +++ b/src/test/datascience/notebook/contentProvider.unit.test.ts @@ -5,12 +5,15 @@ import { assert } from 'chai'; import { anything, instance, mock, when } from 'ts-mockito'; -import { CellKind, NotebookCellRunState, NotebookContentProvider as VSCodeNotebookContentProvider, Uri } from 'vscode'; +import { Uri } from 'vscode'; +// tslint:disable-next-line: no-var-requires no-require-imports +const vscodeNotebookEnums = require('vscode') as typeof import('vscode-proposed'); +import type { NotebookContentProvider as VSCodeNotebookContentProvider } from 'vscode-proposed'; import { MARKDOWN_LANGUAGE, PYTHON_LANGUAGE } from '../../../client/common/constants'; import { INotebookStorageProvider } from '../../../client/datascience/interactive-ipynb/notebookStorageProvider'; import { NotebookContentProvider } from '../../../client/datascience/notebook/contentProvider'; import { CellState, INotebookModel } from '../../../client/datascience/types'; - +// tslint:disable: no-any suite('Data Science - NativeNotebook ContentProvider', () => { let storageProvider: INotebookStorageProvider; let contentProvider: VSCodeNotebookContentProvider; @@ -57,14 +60,14 @@ suite('Data Science - NativeNotebook ContentProvider', () => { assert.deepEqual(notebook.languages, [PYTHON_LANGUAGE, MARKDOWN_LANGUAGE]); assert.deepEqual(notebook.cells, [ { - cellKind: CellKind.Code, + cellKind: (vscodeNotebookEnums as any).CellKind.Code, language: PYTHON_LANGUAGE, outputs: [], source: 'print(1)', metadata: { editable: true, executionOrder: 10, - runState: NotebookCellRunState.Idle, + runState: (vscodeNotebookEnums as any).NotebookCellRunState.Idle, runnable: true, custom: { cellId: 'MyCellId1' @@ -72,14 +75,14 @@ suite('Data Science - NativeNotebook ContentProvider', () => { } }, { - cellKind: CellKind.Markdown, + cellKind: (vscodeNotebookEnums as any).CellKind.Markdown, language: MARKDOWN_LANGUAGE, outputs: [], source: '# HEAD', metadata: { editable: true, executionOrder: undefined, - runState: NotebookCellRunState.Idle, + runState: (vscodeNotebookEnums as any).NotebookCellRunState.Idle, runnable: false, custom: { cellId: 'MyCellId2' diff --git a/src/test/datascience/notebook/executionService.ds.test.ts b/src/test/datascience/notebook/executionService.ds.test.ts index f8fed609ba89..4f7e7a9980f8 100644 --- a/src/test/datascience/notebook/executionService.ds.test.ts +++ b/src/test/datascience/notebook/executionService.ds.test.ts @@ -9,13 +9,10 @@ import cloneDeep = require('lodash/cloneDeep'); import { Subject } from 'rxjs'; import * as sinon from 'sinon'; import { anything, instance, mock, when } from 'ts-mockito'; -import { - CancellationToken, - CancellationTokenSource, - NotebookCell, - NotebookCellRunState, - NotebookDocument -} from 'vscode'; +import { CancellationToken, CancellationTokenSource } from 'vscode'; +import type { NotebookCell, NotebookDocument } from 'vscode-proposed'; +// tslint:disable-next-line: no-var-requires no-require-imports +const vscodeNotebookEnums = require('vscode') as typeof import('vscode-proposed'); import { IApplicationEnvironment, ICommandManager } from '../../../client/common/application/types'; import { IConfigurationService, IDisposable } from '../../../client/common/types'; import { createDeferredFromPromise, sleep } from '../../../client/common/utils/async'; @@ -146,7 +143,7 @@ suite('DataScience - VSCode Notebook - Execution', function () { // Wait for 5s, and verify cell is still running. await sleep(5_000); assert.isFalse(deferred.completed); - assert.equal(cell.metadata.runState, NotebookCellRunState.Running); + assert.equal(cell.metadata.runState, vscodeNotebookEnums.NotebookCellRunState.Running); // Interrupt the kernel. fakeTimer.install(); @@ -154,7 +151,7 @@ suite('DataScience - VSCode Notebook - Execution', function () { await fakeTimer.wait(); assert.isTrue(deferred.completed); - assert.equal(cell.metadata.runState, NotebookCellRunState.Idle); + assert.equal(cell.metadata.runState, vscodeNotebookEnums.NotebookCellRunState.Idle); }); test('Cancelling token will interrupt kernel', async () => { // Open the notebook @@ -179,7 +176,7 @@ suite('DataScience - VSCode Notebook - Execution', function () { // Wait for 5s, and verify cell is still running. await sleep(5_000); assert.isFalse(deferred.completed); - assert.equal(cell.metadata.runState, NotebookCellRunState.Running); + assert.equal(cell.metadata.runState, vscodeNotebookEnums.NotebookCellRunState.Running); // Interrupt the kernel. fakeTimer.install(); @@ -207,12 +204,12 @@ suite('DataScience - VSCode Notebook - Execution', function () { // Wait for 5s, and verify cell is still running. await sleep(5_000); assert.isFalse(deferred.completed); - assert.equal(cell.metadata.runState, NotebookCellRunState.Running); + assert.equal(cell.metadata.runState, vscodeNotebookEnums.NotebookCellRunState.Running); // Interrupt the kernel. await editor.interruptKernel(); assert.isTrue(deferred.completed); - assert.equal(cell.metadata.runState, NotebookCellRunState.Idle); + assert.equal(cell.metadata.runState, vscodeNotebookEnums.NotebookCellRunState.Idle); }); test('Restarting kernel will cancel cell execution', async () => { // Open the notebook @@ -233,11 +230,11 @@ suite('DataScience - VSCode Notebook - Execution', function () { // Wait for 5s, and verify cell is still running. await sleep(5_000); assert.isFalse(deferred.completed); - assert.equal(cell.metadata.runState, NotebookCellRunState.Running); + assert.equal(cell.metadata.runState, vscodeNotebookEnums.NotebookCellRunState.Running); await editor.restartKernel(); assert.isTrue(deferred.completed); - assert.equal(cell.metadata.runState, NotebookCellRunState.Idle); + assert.equal(cell.metadata.runState, vscodeNotebookEnums.NotebookCellRunState.Idle); }); test('Interrupting kernel will cancel all pending cells', async () => { // Open the notebook @@ -262,15 +259,15 @@ suite('DataScience - VSCode Notebook - Execution', function () { await sleep(5_000); assert.isFalse(deferred1.completed); assert.isFalse(deferred2.completed); - assert.equal(cell1.metadata.runState, NotebookCellRunState.Running); - assert.equal(cell2.metadata.runState, NotebookCellRunState.Running); + assert.equal(cell1.metadata.runState, vscodeNotebookEnums.NotebookCellRunState.Running); + assert.equal(cell2.metadata.runState, vscodeNotebookEnums.NotebookCellRunState.Running); // Interrupt the kernel. await editor.interruptKernel(); assert.isTrue(deferred1.completed); assert.isTrue(deferred2.completed); - assert.equal(cell1.metadata.runState, NotebookCellRunState.Idle); - assert.equal(cell2.metadata.runState, NotebookCellRunState.Idle); + assert.equal(cell1.metadata.runState, vscodeNotebookEnums.NotebookCellRunState.Idle); + assert.equal(cell2.metadata.runState, vscodeNotebookEnums.NotebookCellRunState.Idle); }); test('Interrupting kernel will cancel cell execution in notebook', async () => { // Open the notebook @@ -291,14 +288,14 @@ suite('DataScience - VSCode Notebook - Execution', function () { // Wait for 5s, and verify cell is still running. await sleep(5_000); assert.isFalse(deferred.completed); - assert.equal(cell.metadata.runState, NotebookCellRunState.Running); + assert.equal(cell.metadata.runState, vscodeNotebookEnums.NotebookCellRunState.Running); // Interrupt the kernel. fakeTimer.install(); await editor.interruptKernel(); await fakeTimer.wait(); assert.isTrue(deferred.completed); - assert.equal(cell.metadata.runState, NotebookCellRunState.Idle); + assert.equal(cell.metadata.runState, vscodeNotebookEnums.NotebookCellRunState.Idle); }); test('Errors thrown while starting a cell execution are handled by error handler', async () => { // Open the notebook diff --git a/src/test/datascience/notebook/helpers.unit.test.ts b/src/test/datascience/notebook/helpers.unit.test.ts index 4a7283e65202..ed492f9cbb50 100644 --- a/src/test/datascience/notebook/helpers.unit.test.ts +++ b/src/test/datascience/notebook/helpers.unit.test.ts @@ -5,7 +5,9 @@ import { nbformat } from '@jupyterlab/coreutils'; import { assert } from 'chai'; -import { CellKind, CellOutput, CellOutputKind, NotebookCellRunState } from 'vscode'; +import type { CellOutput } from 'vscode-proposed'; +// tslint:disable-next-line: no-var-requires no-require-imports +const vscodeNotebookEnums = require('vscode') as typeof import('vscode-proposed'); import { MARKDOWN_LANGUAGE, PYTHON_LANGUAGE } from '../../../client/common/constants'; import { notebookModelToVSCNotebookData } from '../../../client/datascience/notebook/helpers'; import { CellState, INotebookModel } from '../../../client/datascience/types'; @@ -47,14 +49,14 @@ suite('Data Science - NativeNotebook helpers', () => { assert.deepEqual(notebook.languages, [PYTHON_LANGUAGE, MARKDOWN_LANGUAGE]); assert.deepEqual(notebook.cells, [ { - cellKind: CellKind.Code, + cellKind: vscodeNotebookEnums.CellKind.Code, language: PYTHON_LANGUAGE, outputs: [], source: 'print(1)', metadata: { editable: true, executionOrder: 10, - runState: NotebookCellRunState.Idle, + runState: vscodeNotebookEnums.NotebookCellRunState.Idle, runnable: true, custom: { cellId: 'MyCellId1' @@ -62,14 +64,14 @@ suite('Data Science - NativeNotebook helpers', () => { } }, { - cellKind: CellKind.Markdown, + cellKind: vscodeNotebookEnums.CellKind.Markdown, language: MARKDOWN_LANGUAGE, outputs: [], source: '# HEAD', metadata: { editable: true, executionOrder: undefined, - runState: NotebookCellRunState.Idle, + runState: vscodeNotebookEnums.NotebookCellRunState.Idle, runnable: false, custom: { cellId: 'MyCellId2' @@ -120,11 +122,11 @@ suite('Data Science - NativeNotebook helpers', () => { ], [ { - outputKind: CellOutputKind.Text, + outputKind: vscodeNotebookEnums.CellOutputKind.Text, text: 'Error' }, { - outputKind: CellOutputKind.Text, + outputKind: vscodeNotebookEnums.CellOutputKind.Text, text: 'NoError' } ] @@ -141,7 +143,7 @@ suite('Data Science - NativeNotebook helpers', () => { ], [ { - outputKind: CellOutputKind.Rich, + outputKind: vscodeNotebookEnums.CellOutputKind.Rich, data: { 'text/html': '✅ Loading\n', 'text/plain': '\u001b[K\u001b[33m✅ \u001b[0m Loading\n' @@ -161,7 +163,7 @@ suite('Data Science - NativeNotebook helpers', () => { ], [ { - outputKind: CellOutputKind.Rich, + outputKind: vscodeNotebookEnums.CellOutputKind.Rich, data: { 'text/html': '1 is < 2', 'text/plain': '1 is < 2' @@ -181,7 +183,7 @@ suite('Data Science - NativeNotebook helpers', () => { ], [ { - outputKind: CellOutputKind.Rich, + outputKind: vscodeNotebookEnums.CellOutputKind.Rich, data: { 'text/html': '1 is < 2✅ Loading\n', @@ -203,7 +205,7 @@ suite('Data Science - NativeNotebook helpers', () => { ], [ { - outputKind: CellOutputKind.Error, + outputKind: vscodeNotebookEnums.CellOutputKind.Error, ename: 'Error Name', evalue: 'Error Value', traceback: ['stack1', 'stack2', 'stack3'] @@ -226,7 +228,7 @@ suite('Data Science - NativeNotebook helpers', () => { ], [ { - outputKind: CellOutputKind.Rich, + outputKind: vscodeNotebookEnums.CellOutputKind.Rich, data: { 'text/plain': 'Hello World!' } @@ -248,7 +250,7 @@ suite('Data Science - NativeNotebook helpers', () => { ], [ { - outputKind: CellOutputKind.Rich, + outputKind: vscodeNotebookEnums.CellOutputKind.Rich, data: { 'image/png': 'base64PNG', 'image/jpeg': 'base64JPEG' @@ -272,7 +274,7 @@ suite('Data Science - NativeNotebook helpers', () => { ], [ { - outputKind: CellOutputKind.Rich, + outputKind: vscodeNotebookEnums.CellOutputKind.Rich, data: { 'text/html': '
', @@ -297,7 +299,7 @@ suite('Data Science - NativeNotebook helpers', () => { ], [ { - outputKind: CellOutputKind.Rich, + outputKind: vscodeNotebookEnums.CellOutputKind.Rich, data: { 'text/html': '
', @@ -322,7 +324,7 @@ suite('Data Science - NativeNotebook helpers', () => { ], [ { - outputKind: CellOutputKind.Rich, + outputKind: vscodeNotebookEnums.CellOutputKind.Rich, data: { 'text/html': '
', @@ -348,7 +350,7 @@ suite('Data Science - NativeNotebook helpers', () => { ], [ { - outputKind: CellOutputKind.Rich, + outputKind: vscodeNotebookEnums.CellOutputKind.Rich, data: { 'text/html': '
', diff --git a/types/vscode-proposed/index.d.ts b/types/vscode-proposed/index.d.ts new file mode 100644 index 000000000000..845ad603c1a3 --- /dev/null +++ b/types/vscode-proposed/index.d.ts @@ -0,0 +1,394 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import { + Event, + GlobPattern, + Uri, + TextDocument, + ViewColumn, + CancellationToken, + Disposable, + DocumentSelector +} from 'vscode'; + +// Copy nb section from https://github.com/microsoft/vscode/blob/master/src/vs/vscode.proposed.d.ts. +export enum CellKind { + Markdown = 1, + Code = 2 +} + +export enum CellOutputKind { + Text = 1, + Error = 2, + Rich = 3 +} + +export interface CellStreamOutput { + outputKind: CellOutputKind.Text; + text: string; +} + +export interface CellErrorOutput { + outputKind: CellOutputKind.Error; + /** + * Exception Name + */ + ename: string; + /** + * Exception Value + */ + evalue: string; + /** + * Exception call stack + */ + traceback: string[]; +} + +export interface CellDisplayOutput { + outputKind: CellOutputKind.Rich; + /** + * { mime_type: value } + * + * Example: + * ```json + * { + * "outputKind": vscode.CellOutputKind.Rich, + * "data": { + * "text/html": [ + * "

Hello

" + * ], + * "text/plain": [ + * "" + * ] + * } + * } + */ + data: { [key: string]: any }; +} + +export type CellOutput = CellStreamOutput | CellErrorOutput | CellDisplayOutput; + +export enum NotebookCellRunState { + Running = 1, + Idle = 2, + Success = 3, + Error = 4 +} + +export interface NotebookCellMetadata { + /** + * Controls if the content of a cell is editable or not. + */ + editable?: boolean; + + /** + * Controls if the cell is executable. + * This metadata is ignored for markdown cell. + */ + runnable?: boolean; + + /** + * Controls if the cell has a margin to support the breakpoint UI. + * This metadata is ignored for markdown cell. + */ + breakpointMargin?: boolean; + + /** + * The order in which this cell was executed. + */ + executionOrder?: number; + + /** + * A status message to be shown in the cell's status bar + */ + statusMessage?: string; + + /** + * The cell's current run state + */ + runState?: NotebookCellRunState; + + /** + * If the cell is running, the time at which the cell started running + */ + runStartTime?: number; + + /** + * The total duration of the cell's last run + */ + lastRunDuration?: number; + + /** + * Additional attributes of a cell metadata. + */ + custom?: { [key: string]: any }; +} + +export interface NotebookCell { + readonly uri: Uri; + readonly cellKind: CellKind; + readonly document: TextDocument; + // API remove `source` or doc it as shorthand for document.getText() + readonly source: string; + language: string; + outputs: CellOutput[]; + metadata: NotebookCellMetadata; +} + +export interface NotebookDocumentMetadata { + /** + * Controls if users can add or delete cells + * Defaults to true + */ + editable?: boolean; + + /** + * Controls whether the full notebook can be run at once. + * Defaults to true + */ + runnable?: boolean; + + /** + * Default value for [cell editable metadata](#NotebookCellMetadata.editable). + * Defaults to true. + */ + cellEditable?: boolean; + + /** + * Default value for [cell runnable metadata](#NotebookCellMetadata.runnable). + * Defaults to true. + */ + cellRunnable?: boolean; + + /** + * Whether the [execution order](#NotebookCellMetadata.executionOrder) indicator will be displayed. + * Defaults to true. + */ + hasExecutionOrder?: boolean; + + displayOrder?: GlobPattern[]; + + /** + * Additional attributes of the document metadata. + */ + custom?: { [key: string]: any }; +} + +export interface NotebookDocument { + readonly uri: Uri; + readonly fileName: string; + readonly isDirty: boolean; + readonly cells: NotebookCell[]; + languages: string[]; + displayOrder?: GlobPattern[]; + metadata: NotebookDocumentMetadata; +} + +export interface NotebookConcatTextDocument { + isClosed: boolean; + dispose(): void; + onDidChange: Event; + version: number; + getText(): string; + getText(range: Range): string; + offsetAt(position: Position): number; + positionAt(offset: number): Position; + locationAt(positionOrRange: Position | Range): Location; + positionAt(location: Location): Position; +} + +export interface NotebookEditorCellEdit { + insert( + index: number, + content: string | string[], + language: string, + type: CellKind, + outputs: CellOutput[], + metadata: NotebookCellMetadata | undefined + ): void; + delete(index: number): void; +} + +export interface NotebookEditor { + /** + * The document associated with this notebook editor. + */ + readonly document: NotebookDocument; + + /** + * The primary selected cell on this notebook editor. + */ + readonly selection?: NotebookCell; + + /** + * The column in which this editor shows. + */ + viewColumn?: ViewColumn; + + /** + * Whether the panel is active (focused by the user). + */ + readonly active: boolean; + + /** + * Whether the panel is visible. + */ + readonly visible: boolean; + + /** + * Fired when the output hosting webview posts a message. + */ + readonly onDidReceiveMessage: Event; + /** + * Post a message to the output hosting webview. + * + * Messages are only delivered if the editor is live. + * + * @param message Body of the message. This must be a string or other json serilizable object. + */ + postMessage(message: any): Thenable; + + /** + * Convert a uri for the local file system to one that can be used inside outputs webview. + */ + asWebviewUri(localResource: Uri): Uri; + + edit(callback: (editBuilder: NotebookEditorCellEdit) => void): Thenable; +} + +export interface NotebookOutputSelector { + type: string; + subTypes?: string[]; +} + +export interface NotebookOutputRenderer { + /** + * + * @returns HTML fragment. We can probably return `CellOutput` instead of string ? + * + */ + render(document: NotebookDocument, output: CellDisplayOutput, mimeType: string): string; + preloads?: Uri[]; +} + +export interface NotebookCellsChangeData { + readonly start: number; + readonly deletedCount: number; + readonly items: NotebookCell[]; +} + +export interface NotebookCellsChangeEvent { + /** + * The affected document. + */ + readonly document: NotebookDocument; + readonly changes: ReadonlyArray; +} + +export interface NotebookCellMoveEvent { + /** + * The affected document. + */ + readonly document: NotebookDocument; + readonly index: number; + readonly newIndex: number; +} + +export interface NotebookCellOutputsChangeEvent { + /** + * The affected document. + */ + readonly document: NotebookDocument; + readonly cells: NotebookCell[]; +} + +export interface NotebookCellLanguageChangeEvent { + /** + * The affected document. + */ + readonly document: NotebookDocument; + readonly cell: NotebookCell; + readonly language: string; +} + +export interface NotebookCellData { + readonly cellKind: CellKind; + readonly source: string; + language: string; + outputs: CellOutput[]; + metadata: NotebookCellMetadata; +} + +export interface NotebookData { + readonly cells: NotebookCellData[]; + readonly languages: string[]; + readonly metadata: NotebookDocumentMetadata; +} + +interface NotebookDocumentEditEvent { + /** + * The document that the edit is for. + */ + readonly document: NotebookDocument; +} + +export interface NotebookContentProvider { + openNotebook(uri: Uri): NotebookData | Promise; + saveNotebook(document: NotebookDocument, cancellation: CancellationToken): Promise; + saveNotebookAs(targetResource: Uri, document: NotebookDocument, cancellation: CancellationToken): Promise; + readonly onDidChangeNotebook: Event; + + // revert?(document: NotebookDocument, cancellation: CancellationToken): Thenable; + // backup?(document: NotebookDocument, cancellation: CancellationToken): Thenable; + + kernel?: NotebookKernel; +} + +export interface NotebookKernel { + label: string; + preloads?: Uri[]; + executeCell(document: NotebookDocument, cell: NotebookCell, token: CancellationToken): Promise; + executeAllCells(document: NotebookDocument, token: CancellationToken): Promise; +} + +export namespace notebook { + export function registerNotebookContentProvider( + notebookType: string, + provider: NotebookContentProvider + ): Disposable; + + export function registerNotebookKernel(id: string, selectors: GlobPattern[], kernel: NotebookKernel): Disposable; + + export function registerNotebookOutputRenderer( + id: string, + outputSelector: NotebookOutputSelector, + renderer: NotebookOutputRenderer + ): Disposable; + + export const onDidOpenNotebookDocument: Event; + export const onDidCloseNotebookDocument: Event; + export let visibleNotebookEditors: NotebookEditor[]; + export const onDidChangeVisibleNotebookEditors: Event; + + // remove activeNotebookDocument, now that there is activeNotebookEditor.document + export let activeNotebookDocument: NotebookDocument | undefined; + + export let activeNotebookEditor: NotebookEditor | undefined; + + export const onDidChangeNotebookCells: Event; + export const onDidMoveNotebookCell: Event; + export const onDidChangeCellOutputs: Event; + export const onDidChangeCellLanguage: Event; + /** + * Create a document that is the concatenation of all notebook cells. By default all code-cells are included + * but a selector can be provided to narrow to down the set of cells. + * + * @param notebook + * @param selector + */ + export function createConcatTextDocument( + notebook: NotebookDocument, + selector?: DocumentSelector + ): NotebookConcatTextDocument; +} diff --git a/typings/vscode-proposed/index.d.ts b/typings/vscode-proposed/index.d.ts new file mode 100644 index 000000000000..845ad603c1a3 --- /dev/null +++ b/typings/vscode-proposed/index.d.ts @@ -0,0 +1,394 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import { + Event, + GlobPattern, + Uri, + TextDocument, + ViewColumn, + CancellationToken, + Disposable, + DocumentSelector +} from 'vscode'; + +// Copy nb section from https://github.com/microsoft/vscode/blob/master/src/vs/vscode.proposed.d.ts. +export enum CellKind { + Markdown = 1, + Code = 2 +} + +export enum CellOutputKind { + Text = 1, + Error = 2, + Rich = 3 +} + +export interface CellStreamOutput { + outputKind: CellOutputKind.Text; + text: string; +} + +export interface CellErrorOutput { + outputKind: CellOutputKind.Error; + /** + * Exception Name + */ + ename: string; + /** + * Exception Value + */ + evalue: string; + /** + * Exception call stack + */ + traceback: string[]; +} + +export interface CellDisplayOutput { + outputKind: CellOutputKind.Rich; + /** + * { mime_type: value } + * + * Example: + * ```json + * { + * "outputKind": vscode.CellOutputKind.Rich, + * "data": { + * "text/html": [ + * "

Hello

" + * ], + * "text/plain": [ + * "" + * ] + * } + * } + */ + data: { [key: string]: any }; +} + +export type CellOutput = CellStreamOutput | CellErrorOutput | CellDisplayOutput; + +export enum NotebookCellRunState { + Running = 1, + Idle = 2, + Success = 3, + Error = 4 +} + +export interface NotebookCellMetadata { + /** + * Controls if the content of a cell is editable or not. + */ + editable?: boolean; + + /** + * Controls if the cell is executable. + * This metadata is ignored for markdown cell. + */ + runnable?: boolean; + + /** + * Controls if the cell has a margin to support the breakpoint UI. + * This metadata is ignored for markdown cell. + */ + breakpointMargin?: boolean; + + /** + * The order in which this cell was executed. + */ + executionOrder?: number; + + /** + * A status message to be shown in the cell's status bar + */ + statusMessage?: string; + + /** + * The cell's current run state + */ + runState?: NotebookCellRunState; + + /** + * If the cell is running, the time at which the cell started running + */ + runStartTime?: number; + + /** + * The total duration of the cell's last run + */ + lastRunDuration?: number; + + /** + * Additional attributes of a cell metadata. + */ + custom?: { [key: string]: any }; +} + +export interface NotebookCell { + readonly uri: Uri; + readonly cellKind: CellKind; + readonly document: TextDocument; + // API remove `source` or doc it as shorthand for document.getText() + readonly source: string; + language: string; + outputs: CellOutput[]; + metadata: NotebookCellMetadata; +} + +export interface NotebookDocumentMetadata { + /** + * Controls if users can add or delete cells + * Defaults to true + */ + editable?: boolean; + + /** + * Controls whether the full notebook can be run at once. + * Defaults to true + */ + runnable?: boolean; + + /** + * Default value for [cell editable metadata](#NotebookCellMetadata.editable). + * Defaults to true. + */ + cellEditable?: boolean; + + /** + * Default value for [cell runnable metadata](#NotebookCellMetadata.runnable). + * Defaults to true. + */ + cellRunnable?: boolean; + + /** + * Whether the [execution order](#NotebookCellMetadata.executionOrder) indicator will be displayed. + * Defaults to true. + */ + hasExecutionOrder?: boolean; + + displayOrder?: GlobPattern[]; + + /** + * Additional attributes of the document metadata. + */ + custom?: { [key: string]: any }; +} + +export interface NotebookDocument { + readonly uri: Uri; + readonly fileName: string; + readonly isDirty: boolean; + readonly cells: NotebookCell[]; + languages: string[]; + displayOrder?: GlobPattern[]; + metadata: NotebookDocumentMetadata; +} + +export interface NotebookConcatTextDocument { + isClosed: boolean; + dispose(): void; + onDidChange: Event; + version: number; + getText(): string; + getText(range: Range): string; + offsetAt(position: Position): number; + positionAt(offset: number): Position; + locationAt(positionOrRange: Position | Range): Location; + positionAt(location: Location): Position; +} + +export interface NotebookEditorCellEdit { + insert( + index: number, + content: string | string[], + language: string, + type: CellKind, + outputs: CellOutput[], + metadata: NotebookCellMetadata | undefined + ): void; + delete(index: number): void; +} + +export interface NotebookEditor { + /** + * The document associated with this notebook editor. + */ + readonly document: NotebookDocument; + + /** + * The primary selected cell on this notebook editor. + */ + readonly selection?: NotebookCell; + + /** + * The column in which this editor shows. + */ + viewColumn?: ViewColumn; + + /** + * Whether the panel is active (focused by the user). + */ + readonly active: boolean; + + /** + * Whether the panel is visible. + */ + readonly visible: boolean; + + /** + * Fired when the output hosting webview posts a message. + */ + readonly onDidReceiveMessage: Event; + /** + * Post a message to the output hosting webview. + * + * Messages are only delivered if the editor is live. + * + * @param message Body of the message. This must be a string or other json serilizable object. + */ + postMessage(message: any): Thenable; + + /** + * Convert a uri for the local file system to one that can be used inside outputs webview. + */ + asWebviewUri(localResource: Uri): Uri; + + edit(callback: (editBuilder: NotebookEditorCellEdit) => void): Thenable; +} + +export interface NotebookOutputSelector { + type: string; + subTypes?: string[]; +} + +export interface NotebookOutputRenderer { + /** + * + * @returns HTML fragment. We can probably return `CellOutput` instead of string ? + * + */ + render(document: NotebookDocument, output: CellDisplayOutput, mimeType: string): string; + preloads?: Uri[]; +} + +export interface NotebookCellsChangeData { + readonly start: number; + readonly deletedCount: number; + readonly items: NotebookCell[]; +} + +export interface NotebookCellsChangeEvent { + /** + * The affected document. + */ + readonly document: NotebookDocument; + readonly changes: ReadonlyArray; +} + +export interface NotebookCellMoveEvent { + /** + * The affected document. + */ + readonly document: NotebookDocument; + readonly index: number; + readonly newIndex: number; +} + +export interface NotebookCellOutputsChangeEvent { + /** + * The affected document. + */ + readonly document: NotebookDocument; + readonly cells: NotebookCell[]; +} + +export interface NotebookCellLanguageChangeEvent { + /** + * The affected document. + */ + readonly document: NotebookDocument; + readonly cell: NotebookCell; + readonly language: string; +} + +export interface NotebookCellData { + readonly cellKind: CellKind; + readonly source: string; + language: string; + outputs: CellOutput[]; + metadata: NotebookCellMetadata; +} + +export interface NotebookData { + readonly cells: NotebookCellData[]; + readonly languages: string[]; + readonly metadata: NotebookDocumentMetadata; +} + +interface NotebookDocumentEditEvent { + /** + * The document that the edit is for. + */ + readonly document: NotebookDocument; +} + +export interface NotebookContentProvider { + openNotebook(uri: Uri): NotebookData | Promise; + saveNotebook(document: NotebookDocument, cancellation: CancellationToken): Promise; + saveNotebookAs(targetResource: Uri, document: NotebookDocument, cancellation: CancellationToken): Promise; + readonly onDidChangeNotebook: Event; + + // revert?(document: NotebookDocument, cancellation: CancellationToken): Thenable; + // backup?(document: NotebookDocument, cancellation: CancellationToken): Thenable; + + kernel?: NotebookKernel; +} + +export interface NotebookKernel { + label: string; + preloads?: Uri[]; + executeCell(document: NotebookDocument, cell: NotebookCell, token: CancellationToken): Promise; + executeAllCells(document: NotebookDocument, token: CancellationToken): Promise; +} + +export namespace notebook { + export function registerNotebookContentProvider( + notebookType: string, + provider: NotebookContentProvider + ): Disposable; + + export function registerNotebookKernel(id: string, selectors: GlobPattern[], kernel: NotebookKernel): Disposable; + + export function registerNotebookOutputRenderer( + id: string, + outputSelector: NotebookOutputSelector, + renderer: NotebookOutputRenderer + ): Disposable; + + export const onDidOpenNotebookDocument: Event; + export const onDidCloseNotebookDocument: Event; + export let visibleNotebookEditors: NotebookEditor[]; + export const onDidChangeVisibleNotebookEditors: Event; + + // remove activeNotebookDocument, now that there is activeNotebookEditor.document + export let activeNotebookDocument: NotebookDocument | undefined; + + export let activeNotebookEditor: NotebookEditor | undefined; + + export const onDidChangeNotebookCells: Event; + export const onDidMoveNotebookCell: Event; + export const onDidChangeCellOutputs: Event; + export const onDidChangeCellLanguage: Event; + /** + * Create a document that is the concatenation of all notebook cells. By default all code-cells are included + * but a selector can be provided to narrow to down the set of cells. + * + * @param notebook + * @param selector + */ + export function createConcatTextDocument( + notebook: NotebookDocument, + selector?: DocumentSelector + ): NotebookConcatTextDocument; +}