From df2934a80c6bb13202b46458aeaeb30ff3af06ab Mon Sep 17 00:00:00 2001 From: Cory Rivera Date: Tue, 11 Jan 2022 12:57:55 -0800 Subject: [PATCH] Enable VS Code extension APIs for getting opened notebook documents (#18043) --- .../api/common/vscodeNotebookEditor.ts | 45 +++++++++++++++++++ .../api/vscodeNotebookApi.test.ts | 38 ++++++++++++---- .../workbench/api/common/extHost.api.impl.ts | 13 +++--- 3 files changed, 81 insertions(+), 15 deletions(-) create mode 100644 src/sql/workbench/api/common/vscodeNotebookEditor.ts diff --git a/src/sql/workbench/api/common/vscodeNotebookEditor.ts b/src/sql/workbench/api/common/vscodeNotebookEditor.ts new file mode 100644 index 0000000000..c1c7837645 --- /dev/null +++ b/src/sql/workbench/api/common/vscodeNotebookEditor.ts @@ -0,0 +1,45 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import type * as vscode from 'vscode'; +import type * as azdata from 'azdata'; +import { VSCodeNotebookDocument } from 'sql/workbench/api/common/vscodeNotebookDocument'; +import { functionalityNotSupportedError } from 'sql/base/common/locConstants'; + +export class VSCodeNotebookEditor implements vscode.NotebookEditor { + private readonly _document: vscode.NotebookDocument; + + constructor(editor: azdata.nb.NotebookEditor) { + this._document = new VSCodeNotebookDocument(editor.document); + } + + public get document(): vscode.NotebookDocument { + return this._document; + } + + public get selections(): vscode.NotebookRange[] { + throw new Error(functionalityNotSupportedError); + } + + public get visibleRanges(): vscode.NotebookRange[] { + throw new Error(functionalityNotSupportedError); + } + + public get viewColumn(): vscode.ViewColumn | undefined { + throw new Error(functionalityNotSupportedError); + } + + public revealRange(range: vscode.NotebookRange, revealType?: vscode.NotebookEditorRevealType): void { + throw new Error(functionalityNotSupportedError); + } + + public edit(callback: (editBuilder: vscode.NotebookEditorEdit) => void): Promise { + return Promise.reject(functionalityNotSupportedError); + } + + public setDecorations(decorationType: vscode.NotebookEditorDecorationType, range: vscode.NotebookRange): void { + throw new Error(functionalityNotSupportedError); + } +} diff --git a/src/sql/workbench/test/electron-browser/api/vscodeNotebookApi.test.ts b/src/sql/workbench/test/electron-browser/api/vscodeNotebookApi.test.ts index e916336116..d703458124 100644 --- a/src/sql/workbench/test/electron-browser/api/vscodeNotebookApi.test.ts +++ b/src/sql/workbench/test/electron-browser/api/vscodeNotebookApi.test.ts @@ -15,6 +15,7 @@ import { NBFORMAT, NBFORMAT_MINOR } from 'sql/workbench/common/constants'; import { convertToVSCodeNotebookCell } from 'sql/workbench/api/common/vscodeExecuteProvider'; import { VSCodeNotebookDocument } from 'sql/workbench/api/common/vscodeNotebookDocument'; import { URI } from 'vs/base/common/uri'; +import { VSCodeNotebookEditor } from 'sql/workbench/api/common/vscodeNotebookEditor'; class MockNotebookSerializer implements vscode.NotebookSerializer { deserializeNotebook(content: Uint8Array, token: vscode.CancellationToken): vscode.NotebookData | Thenable { @@ -366,6 +367,17 @@ suite('Notebook Serializer', () => { validateCellRange: () => undefined }; + function validateDocsMatch(actualDoc: vscode.NotebookDocument, expectedDoc: vscode.NotebookDocument): void { + assert.deepStrictEqual(actualDoc.uri, expectedDoc.uri); + assert.strictEqual(actualDoc.notebookType, expectedDoc.notebookType); + assert.strictEqual(actualDoc.version, expectedDoc.version); + assert.strictEqual(actualDoc.isDirty, expectedDoc.isDirty); + assert.strictEqual(actualDoc.isUntitled, expectedDoc.isUntitled); + assert.strictEqual(actualDoc.isClosed, expectedDoc.isClosed); + assert.deepStrictEqual(actualDoc.metadata, expectedDoc.metadata); + assert.strictEqual(actualDoc.cellCount, expectedDoc.cellCount); + } + test('Convert ADS NotebookDocument into VS Code NotebookDocument', async () => { let expectedDoc: vscode.NotebookDocument = { get uri() { return testDoc.uri; }, @@ -382,14 +394,7 @@ suite('Notebook Serializer', () => { }; let actualDoc = new VSCodeNotebookDocument(testDoc); - assert.deepStrictEqual(actualDoc.uri, expectedDoc.uri); - assert.strictEqual(actualDoc.notebookType, expectedDoc.notebookType); - assert.strictEqual(actualDoc.version, expectedDoc.version); - assert.strictEqual(actualDoc.isDirty, expectedDoc.isDirty); - assert.strictEqual(actualDoc.isUntitled, expectedDoc.isUntitled); - assert.strictEqual(actualDoc.isClosed, expectedDoc.isClosed); - assert.deepStrictEqual(actualDoc.metadata, expectedDoc.metadata); - assert.strictEqual(actualDoc.cellCount, expectedDoc.cellCount); + validateDocsMatch(actualDoc, expectedDoc); }); // Have to validate cell fields manually since one of the NotebookCell fields is a function pointer, @@ -440,6 +445,23 @@ suite('Notebook Serializer', () => { secondCell = vsDoc.cellAt(10); validateCellMatches(secondCell, expectedCells[1]); }); + + test('VS Code NotebookEditor functionality', async () => { + let editor = { document: testDoc }; + let vscodeEditor = new VSCodeNotebookEditor(editor); + let expectedDoc = new VSCodeNotebookDocument(testDoc); + + validateDocsMatch(vscodeEditor.document, expectedDoc); + + // We only need the document field for VSCodeNotebookEditor, so the other + // fields should be non-functional + assert.throws(() => vscodeEditor.selections); + assert.throws(() => vscodeEditor.visibleRanges); + assert.throws(() => vscodeEditor.viewColumn); + assert.throws(() => vscodeEditor.revealRange(undefined)); + assert.throws(() => vscodeEditor.setDecorations(undefined, undefined)); + await assert.rejects(() => vscodeEditor.edit(() => undefined)); + }); }); suite('Notebook Controller', () => { diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts index 7bc16569a1..d1bed35dea 100644 --- a/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.ts @@ -94,6 +94,8 @@ import { matchesScheme } from 'vs/platform/opener/common/opener'; import { ExtHostNotebook } from 'sql/workbench/api/common/extHostNotebook'; import { functionalityNotSupportedError } from 'sql/base/common/locConstants'; import { ExtHostNotebookDocumentsAndEditors } from 'sql/workbench/api/common/extHostNotebookDocumentsAndEditors'; +import { VSCodeNotebookDocument } from 'sql/workbench/api/common/vscodeNotebookDocument'; +import { VSCodeNotebookEditor } from 'sql/workbench/api/common/vscodeNotebookEditor'; export interface IExtensionApiFactory { (extension: IExtensionDescription, registry: ExtensionDescriptionRegistry, configProvider: ExtHostConfigProvider): typeof vscode; @@ -716,10 +718,8 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor, ex return extHostWebviewViews.registerWebviewViewProvider(extension, viewId, provider, options?.webviewOptions); }, get activeNotebookEditor(): vscode.NotebookEditor | undefined { - // {{SQL CARBON EDIT}} Disable VS Code notebooks - throw new Error(functionalityNotSupportedError); - // checkProposedApiEnabled(extension); - // return extHostNotebook.activeNotebookEditor; + // {{SQL CARBON EDIT}} Use our own notebooks + return new VSCodeNotebookEditor(extHostNotebookDocumentsAndEditors.getActiveEditor()); }, onDidChangeActiveNotebookEditor(listener, thisArgs?, disposables?) { // {{SQL CARBON EDIT}} Disable VS Code notebooks @@ -884,9 +884,8 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor, ex return extHostDocumentSaveParticipant.getOnWillSaveTextDocumentEvent(extension)(listener, thisArgs, disposables); }, get notebookDocuments(): vscode.NotebookDocument[] { - // {{SQL CARBON EDIT}} Disable VS Code notebooks - throw new Error(functionalityNotSupportedError); - // return extHostNotebook.notebookDocuments.map(d => d.apiNotebook); + // {{SQL CARBON EDIT}} Use our own notebooks + return extHostNotebookDocumentsAndEditors.getAllDocuments().map(doc => new VSCodeNotebookDocument(doc.document)); }, async openNotebookDocument(uriOrType?: URI | string, content?: vscode.NotebookData) { // {{SQL CARBON EDIT}} Disable VS Code notebooks