diff --git a/extensions/vscode-notebook-tests/src/notebook.test.ts b/extensions/vscode-notebook-tests/src/notebook.test.ts index c34d11c4bafd0..d549dc8dc3f7d 100644 --- a/extensions/vscode-notebook-tests/src/notebook.test.ts +++ b/extensions/vscode-notebook-tests/src/notebook.test.ts @@ -418,9 +418,6 @@ suite('Notebook API tests', () => { }); test('edit API (replaceOutput)', async function () { - // no output events yet... - this.skip(); - assertInitalState(); const resource = await createRandomFile('', undefined, 'first', '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); @@ -430,7 +427,7 @@ suite('Notebook API tests', () => { }); const document = vscode.notebook.activeNotebookEditor?.document!; - assert.strictEqual(document.isDirty, false); + assert.strictEqual(document.isDirty, true); assert.strictEqual(document.cells.length, 1); assert.strictEqual(document.cells[0].outputs.length, 1); assert.strictEqual(document.cells[0].outputs[0].outputKind, vscode.CellOutputKind.Rich); @@ -439,9 +436,6 @@ suite('Notebook API tests', () => { }); test('edit API (replaceOutput, event)', async function () { - // no output events yet... - this.skip(); - assertInitalState(); const resource = await createRandomFile('', undefined, 'first', '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); @@ -453,6 +447,7 @@ suite('Notebook API tests', () => { const value = await outputChangeEvent; assert.strictEqual(value.document === vscode.notebook.activeNotebookEditor?.document, true); + assert.strictEqual(value.document.isDirty, true); assert.strictEqual(value.cells.length, 1); assert.strictEqual(value.cells[0].outputs.length, 1); assert.strictEqual(value.cells[0].outputs[0].outputKind, vscode.CellOutputKind.Rich); diff --git a/src/vs/workbench/api/common/extHostNotebook.ts b/src/vs/workbench/api/common/extHostNotebook.ts index f9ba5b1ef7570..379d6c285bd62 100644 --- a/src/vs/workbench/api/common/extHostNotebook.ts +++ b/src/vs/workbench/api/common/extHostNotebook.ts @@ -139,6 +139,10 @@ export class ExtHostCell extends Disposable { this._onDidDispose.fire(); } + setOutputs(newOutputs: vscode.CellOutput[]): void { + this._outputs = newOutputs; + } + private _updateOutputs(newOutputs: vscode.CellOutput[]) { const rawDiffs = diff(this._outputs || [], newOutputs || [], (a) => { return this._outputMapping.has(a); @@ -321,6 +325,8 @@ export class ExtHostNotebookDocument extends Disposable { this._spliceNotebookCells(event.changes, false); } else if (event.kind === NotebookCellsChangeType.Move) { this._moveCell(event.index, event.newIdx); + } else if (event.kind === NotebookCellsChangeType.Output) { + this._setCellOutputs(event.index, event.outputs); } else if (event.kind === NotebookCellsChangeType.CellClearOutput) { this._clearCellOutputs(event.index); } else if (event.kind === NotebookCellsChangeType.CellsClearOutput) { @@ -412,6 +418,12 @@ export class ExtHostNotebookDocument extends Disposable { }); } + private _setCellOutputs(index: number, outputs: IProcessedOutput[]): void { + const cell = this._cells[index]; + cell.setOutputs(outputs); + this._emitter.emitCellOutputsChange({ document: this.notebookDocument, cells: [cell.cell] }); + } + private _clearCellOutputs(index: number): void { const cell = this._cells[index].cell; cell.outputs = []; diff --git a/src/vs/workbench/contrib/notebook/common/model/notebookTextModel.ts b/src/vs/workbench/contrib/notebook/common/model/notebookTextModel.ts index 1f68435cbdce6..c1a7165beb825 100644 --- a/src/vs/workbench/contrib/notebook/common/model/notebookTextModel.ts +++ b/src/vs/workbench/contrib/notebook/common/model/notebookTextModel.ts @@ -505,13 +505,24 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel // TODO@rebornix should this trigger content change event? spliceNotebookCellOutputs(cellHandle: number, splices: NotebookCellOutputsSplice[]): void { const cell = this._mapping.get(cellHandle); - cell?.spliceNotebookCellOutputs(splices); + if (cell) { - if (!this.transientOptions.transientOutputs) { - this._increaseVersionId(); - this.setDirty(true); - this._onDidChangeContent.fire(); + cell.spliceNotebookCellOutputs(splices); + + if (!this.transientOptions.transientOutputs) { + this._increaseVersionId(); + this.setDirty(true); + this._onDidChangeContent.fire(); + } + + this._onDidModelChangeProxy.fire({ + kind: NotebookCellsChangeType.Output, + versionId: this.versionId, + index: this.cells.indexOf(cell), + outputs: cell.outputs ?? [] + }); } + } clearCellOutput(handle: number) { diff --git a/src/vs/workbench/contrib/notebook/common/notebookCommon.ts b/src/vs/workbench/contrib/notebook/common/notebookCommon.ts index 8f3e2d757d9f5..8300e9f395018 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookCommon.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookCommon.ts @@ -166,15 +166,15 @@ export interface IErrorOutput { /** * Exception Name */ - ename?: string; + ename: string; /** * Exception Value */ - evalue?: string; + evalue: string; /** * Exception call stacks */ - traceback?: string[]; + traceback: string[]; } export interface NotebookCellOutputMetadata { @@ -366,7 +366,8 @@ export enum NotebookCellsChangeType { CellsClearOutput = 4, ChangeLanguage = 5, Initialize = 6, - ChangeMetadata = 7 + ChangeMetadata = 7, + Output = 8, } export interface NotebookCellsInitializeEvent { @@ -388,6 +389,13 @@ export interface NotebookCellsModelMoveEvent { readonly versionId: number; } +export interface NotebookOutputChangedEvent { + readonly kind: NotebookCellsChangeType.Output; + readonly index: number; + readonly versionId: number; + readonly outputs: IProcessedOutput[]; +} + export interface NotebookCellClearOutputEvent { readonly kind: NotebookCellsChangeType.CellClearOutput; readonly index: number; @@ -413,7 +421,7 @@ export interface NotebookCellsChangeMetadataEvent { readonly metadata: NotebookCellMetadata | undefined; } -export type NotebookCellsChangedEvent = NotebookCellsInitializeEvent | NotebookCellsModelChangedEvent | NotebookCellsModelMoveEvent | NotebookCellClearOutputEvent | NotebookCellsClearOutputEvent | NotebookCellsChangeLanguageEvent | NotebookCellsChangeMetadataEvent; +export type NotebookCellsChangedEvent = NotebookCellsInitializeEvent | NotebookCellsModelChangedEvent | NotebookCellsModelMoveEvent | NotebookOutputChangedEvent | NotebookCellClearOutputEvent | NotebookCellsClearOutputEvent | NotebookCellsChangeLanguageEvent | NotebookCellsChangeMetadataEvent; export const enum CellEditType { Replace = 1, diff --git a/src/vs/workbench/test/browser/api/extHostNotebook.test.ts b/src/vs/workbench/test/browser/api/extHostNotebook.test.ts index 42ea107dbc777..2911cf0ab9093 100644 --- a/src/vs/workbench/test/browser/api/extHostNotebook.test.ts +++ b/src/vs/workbench/test/browser/api/extHostNotebook.test.ts @@ -178,7 +178,7 @@ suite('NotebookCell#Document', function () { cellKind: CellKind.Code, outputs: [], }]]] - }); + }, false); await p; @@ -234,7 +234,7 @@ suite('NotebookCell#Document', function () { kind: NotebookCellsChangeType.ModelChange, versionId: 2, changes: [[0, 1, []]] - }); + }, false); assert.equal(notebook.notebookDocument.cells.length, 1); assert.equal(cell1.document.isClosed, true); // ref still alive! diff --git a/src/vs/workbench/test/browser/api/extHostNotebookConcatDocument.test.ts b/src/vs/workbench/test/browser/api/extHostNotebookConcatDocument.test.ts index 764eee4540cf0..a25ee16c3f46f 100644 --- a/src/vs/workbench/test/browser/api/extHostNotebookConcatDocument.test.ts +++ b/src/vs/workbench/test/browser/api/extHostNotebookConcatDocument.test.ts @@ -143,7 +143,7 @@ suite('NotebookConcatDocument', function () { cellKind: CellKind.Code, outputs: [], }]]] - }); + }, false); assert.equal(notebook.notebookDocument.cells.length, 1 + 2); // markdown and code @@ -177,7 +177,7 @@ suite('NotebookConcatDocument', function () { cellKind: CellKind.Code, outputs: [], }]]] - }); + }, false); assert.equal(notebook.notebookDocument.cells.length, 1 + 2); // markdown and code @@ -210,7 +210,7 @@ suite('NotebookConcatDocument', function () { cellKind: CellKind.Code, outputs: [], }]]] - }); + }, false); assert.equal(notebook.notebookDocument.cells.length, 1 + 1); assert.equal(doc.version, 1); assertLines(doc, 'Hello', 'World', 'Hello World!'); @@ -233,7 +233,7 @@ suite('NotebookConcatDocument', function () { cellKind: CellKind.Code, outputs: [], }]]] - }); + }, false); assert.equal(notebook.notebookDocument.cells.length, 1 + 2); assert.equal(doc.version, 2); @@ -249,7 +249,7 @@ suite('NotebookConcatDocument', function () { kind: NotebookCellsChangeType.ModelChange, versionId: notebook.notebookDocument.version + 1, changes: [[1, 1, []]] - }); + }, false); assert.equal(notebook.notebookDocument.cells.length, 1 + 1); assert.equal(doc.version, 3); assertLines(doc, 'Hello', 'World', 'Hello World!'); @@ -283,7 +283,7 @@ suite('NotebookConcatDocument', function () { cellKind: CellKind.Code, outputs: [], }]]] - }); + }, false); assert.equal(notebook.notebookDocument.cells.length, 1 + 2); assert.equal(doc.version, 1); @@ -337,7 +337,7 @@ suite('NotebookConcatDocument', function () { cellKind: CellKind.Code, outputs: [], }]]] - }); + }, false); const mixedDoc = new ExtHostNotebookConcatDocument(extHostNotebooks, extHostDocuments, notebook.notebookDocument, undefined); const fooLangDoc = new ExtHostNotebookConcatDocument(extHostNotebooks, extHostDocuments, notebook.notebookDocument, 'fooLang'); @@ -359,7 +359,7 @@ suite('NotebookConcatDocument', function () { cellKind: CellKind.Code, outputs: [], }]]] - }); + }, false); assertLines(mixedDoc, 'fooLang-document', 'barLang-document', 'barLang-document2'); assertLines(fooLangDoc, 'fooLang-document'); @@ -401,7 +401,7 @@ suite('NotebookConcatDocument', function () { cellKind: CellKind.Code, outputs: [], }]]] - }); + }, false); assert.equal(notebook.notebookDocument.cells.length, 1 + 2); // markdown and code @@ -454,7 +454,7 @@ suite('NotebookConcatDocument', function () { cellKind: CellKind.Code, outputs: [], }]]] - }); + }, false); assert.equal(notebook.notebookDocument.cells.length, 1 + 2); // markdown and code @@ -491,7 +491,7 @@ suite('NotebookConcatDocument', function () { cellKind: CellKind.Code, outputs: [], }]]] - }); + }, false); assert.equal(notebook.notebookDocument.cells.length, 1 + 2); // markdown and code @@ -525,7 +525,7 @@ suite('NotebookConcatDocument', function () { cellKind: CellKind.Code, outputs: [], }]]] - }); + }, false); assert.equal(notebook.notebookDocument.cells.length, 1 + 2); // markdown and code