diff --git a/extensions/vscode-notebook-tests/src/notebook.test.ts b/extensions/vscode-notebook-tests/src/notebook.test.ts index e3ea9eefece..238e7b2ecee 100644 --- a/extensions/vscode-notebook-tests/src/notebook.test.ts +++ b/extensions/vscode-notebook-tests/src/notebook.test.ts @@ -417,6 +417,37 @@ suite('Notebook API tests', () => { await saveAllFilesAndCloseAll(resource); }); + test('edit API (replaceOutput, USE NotebookCellOutput-type)', async function () { + assertInitalState(); + const resource = await createRandomFile('', undefined, 'first', '.vsctestnb'); + await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); + + await vscode.notebook.activeNotebookEditor!.edit(editBuilder => { + editBuilder.replaceCellOutput(0, [ + new vscode.NotebookCellOutput('application/foo', 'bar'), + new vscode.NotebookCellOutput('application/json', { data: true }, { metadata: true }), + ]); + }); + + const document = vscode.notebook.activeNotebookEditor?.document!; + assert.strictEqual(document.isDirty, true); + assert.strictEqual(document.cells.length, 1); + assert.strictEqual(document.cells[0].outputs.length, 2); + + // consuming is OLD api + const [one, two] = document.cells[0].outputs; + + assert.strictEqual(one.outputKind, vscode.CellOutputKind.Rich); + assert.strictEqual((one).data['application/foo'], 'bar'); + assert.strictEqual((one).metadata, undefined); + + assert.strictEqual(two.outputKind, vscode.CellOutputKind.Rich); + assert.deepStrictEqual((two).data['application/json'], { data: true }); + assert.deepStrictEqual((two).metadata, { custom: { metadata: true } }); + + await saveAllFilesAndCloseAll(undefined); + }); + test('edit API (replaceOutput)', async function () { assertInitalState(); const resource = await createRandomFile('', undefined, 'first', '.vsctestnb'); diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index ae1b9cd29ed..99d0458aacc 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -1237,6 +1237,15 @@ declare module 'vscode' { export type CellOutput = CellStreamOutput | CellErrorOutput | CellDisplayOutput; + export class NotebookCellOutput { + + readonly mime: string; + readonly value: unknown; + readonly metadata?: Record; + + constructor(mime: string, value: unknown, metadata?: Record); + } + export enum NotebookCellRunState { Running = 1, Idle = 2, @@ -1425,7 +1434,7 @@ declare module 'vscode' { export interface NotebookEditorEdit { replaceMetadata(value: NotebookDocumentMetadata): void; replaceCells(start: number, end: number, cells: NotebookCellData[]): void; - replaceCellOutput(index: number, outputs: CellOutput[]): void; + replaceCellOutput(index: number, outputs: (NotebookCellOutput | CellOutput)[]): void; replaceCellMetadata(index: number, metadata: NotebookCellMetadata): void; } diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts index 000b8a27af5..c23a0b17dd3 100644 --- a/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.ts @@ -1147,7 +1147,8 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I NotebookCellRunState: extHostTypes.NotebookCellRunState, NotebookRunState: extHostTypes.NotebookRunState, NotebookCellStatusBarAlignment: extHostTypes.NotebookCellStatusBarAlignment, - NotebookEditorRevealType: extHostTypes.NotebookEditorRevealType + NotebookEditorRevealType: extHostTypes.NotebookEditorRevealType, + NotebookCellOutput: extHostTypes.NotebookCellOutput, }; }; } diff --git a/src/vs/workbench/api/common/extHostNotebookEditor.ts b/src/vs/workbench/api/common/extHostNotebookEditor.ts index ea5ecb3512d..425a3e98602 100644 --- a/src/vs/workbench/api/common/extHostNotebookEditor.ts +++ b/src/vs/workbench/api/common/extHostNotebookEditor.ts @@ -7,6 +7,7 @@ import { readonly } from 'vs/base/common/errors'; import { Emitter, Event } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; import { MainThreadNotebookShape } from 'vs/workbench/api/common/extHost.protocol'; +import { NotebookCellOutput } from 'vs/workbench/api/common/extHostTypeConverters'; import * as extHostTypes from 'vs/workbench/api/common/extHostTypes'; import { addIdToOutput, CellEditType, ICellEditOperation, ICellReplaceEdit, INotebookEditData, notebookDocumentMetadataDefaults } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import * as vscode from 'vscode'; @@ -54,12 +55,18 @@ class NotebookEditorCellEditBuilder implements vscode.NotebookEditorEdit { }); } - replaceCellOutput(index: number, outputs: vscode.CellOutput[]): void { + replaceCellOutput(index: number, outputs: (vscode.NotebookCellOutput | vscode.CellOutput)[]): void { this._throwIfFinalized(); this._collectedEdits.push({ editType: CellEditType.Output, index, - outputs: outputs.map(output => addIdToOutput(output)) + outputs: outputs.map(output => { + if (extHostTypes.NotebookCellOutput.isNotebookCellOutput(output)) { + return addIdToOutput(NotebookCellOutput.from(output)); + } else { + return addIdToOutput(output); + } + }) }); } diff --git a/src/vs/workbench/api/common/extHostTypeConverters.ts b/src/vs/workbench/api/common/extHostTypeConverters.ts index f10f2fa7b89..9dab2c179b4 100644 --- a/src/vs/workbench/api/common/extHostTypeConverters.ts +++ b/src/vs/workbench/api/common/extHostTypeConverters.ts @@ -32,7 +32,7 @@ import { coalesce, isNonEmptyArray } from 'vs/base/common/arrays'; import { RenderLineNumbersType } from 'vs/editor/common/config/editorOptions'; import { CommandsConverter } from 'vs/workbench/api/common/extHostCommands'; import { ExtHostNotebookController } from 'vs/workbench/api/common/extHostNotebook'; -import { INotebookDecorationRenderOptions } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { CellOutputKind, IDisplayOutput, INotebookDecorationRenderOptions } from 'vs/workbench/contrib/notebook/common/notebookCommon'; export interface PositionLike { line: number; @@ -1295,6 +1295,16 @@ export namespace LogLevel { } } +export namespace NotebookCellOutput { + export function from(output: types.NotebookCellOutput): IDisplayOutput { + return { + outputKind: CellOutputKind.Rich, + data: { [output.mime]: output.value }, + metadata: output.metadata && { custom: output.metadata } + }; + } +} + export namespace NotebookExclusiveDocumentPattern { export function from(pattern: { include: vscode.GlobPattern | undefined, exclude: vscode.GlobPattern | undefined }): { include: string | types.RelativePattern | undefined, exclude: string | types.RelativePattern | undefined }; export function from(pattern: vscode.GlobPattern): string | types.RelativePattern; diff --git a/src/vs/workbench/api/common/extHostTypes.ts b/src/vs/workbench/api/common/extHostTypes.ts index 1497c19da9c..99ab95e9e81 100644 --- a/src/vs/workbench/api/common/extHostTypes.ts +++ b/src/vs/workbench/api/common/extHostTypes.ts @@ -2765,6 +2765,19 @@ export enum ColorThemeKind { //#region Notebook +export class NotebookCellOutput { + + static isNotebookCellOutput(obj: unknown): obj is vscode.NotebookCellOutput { + return obj instanceof NotebookCellOutput; + } + + constructor( + readonly mime: string, + readonly value: unknown, // JSON'able + readonly metadata?: Record + ) { } +} + export enum CellKind { Markdown = 1, Code = 2