diff --git a/src/vs/workbench/api/browser/mainThreadNotebookDocuments.ts b/src/vs/workbench/api/browser/mainThreadNotebookDocuments.ts index d2bf4a13f27..3d2785cd483 100644 --- a/src/vs/workbench/api/browser/mainThreadNotebookDocuments.ts +++ b/src/vs/workbench/api/browser/mainThreadNotebookDocuments.ts @@ -114,7 +114,8 @@ export class MainThreadNotebookDocuments implements MainThreadNotebookDocumentsS language: cell.language, cellKind: cell.cellKind, outputs: cell.outputs, - metadata: cell.metadata + metadata: cell.metadata, + internalMetadata: cell.internalMetadata, }; } diff --git a/src/vs/workbench/api/browser/mainThreadNotebookDocumentsAndEditors.ts b/src/vs/workbench/api/browser/mainThreadNotebookDocumentsAndEditors.ts index d7415d36864..be97d15f096 100644 --- a/src/vs/workbench/api/browser/mainThreadNotebookDocumentsAndEditors.ts +++ b/src/vs/workbench/api/browser/mainThreadNotebookDocumentsAndEditors.ts @@ -234,7 +234,8 @@ export class MainThreadNotebooksAndEditors { language: cell.language, cellKind: cell.cellKind, outputs: cell.outputs, - metadata: cell.metadata + metadata: cell.metadata, + internalMetadata: cell.internalMetadata, })) }; } diff --git a/src/vs/workbench/api/common/extHostNotebookDocument.ts b/src/vs/workbench/api/common/extHostNotebookDocument.ts index 78d10165bb5..131569c1f74 100644 --- a/src/vs/workbench/api/common/extHostNotebookDocument.ts +++ b/src/vs/workbench/api/common/extHostNotebookDocument.ts @@ -11,7 +11,7 @@ import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments'; import { ExtHostDocumentsAndEditors, IExtHostModelAddedData } from 'vs/workbench/api/common/extHostDocumentsAndEditors'; import * as extHostTypeConverters from 'vs/workbench/api/common/extHostTypeConverters'; import * as extHostTypes from 'vs/workbench/api/common/extHostTypes'; -import { CellKind, IMainCellDto, IOutputDto, IOutputItemDto, NotebookCellMetadata, NotebookCellsChangedEventDto, NotebookCellsChangeType, NotebookCellsSplice2 } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { CellKind, IMainCellDto, IOutputDto, IOutputItemDto, NotebookCellInternalMetadata, NotebookCellMetadata, NotebookCellsChangedEventDto, NotebookCellsChangeType, NotebookCellsSplice2 } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import * as vscode from 'vscode'; class RawContentChangeEvent { @@ -48,7 +48,7 @@ export class ExtHostCell { private _metadata: extHostTypes.NotebookCellMetadata; private _previousResult: vscode.NotebookCellExecutionSummary | undefined; - private _internalMetadata: NotebookCellMetadata; + private _internalMetadata: NotebookCellInternalMetadata; readonly handle: number; readonly uri: URI; readonly cellKind: CellKind; @@ -64,12 +64,12 @@ export class ExtHostCell { this.uri = URI.revive(_cellData.uri); this.cellKind = _cellData.cellKind; this._outputs = _cellData.outputs.map(extHostTypeConverters.NotebookCellOutput.to); - this._internalMetadata = _cellData.metadata ?? {}; - this._metadata = extHostTypeConverters.NotebookCellMetadata.to(this._internalMetadata); - this._previousResult = extHostTypeConverters.NotebookCellPreviousExecutionResult.to(this._internalMetadata); + this._internalMetadata = _cellData.internalMetadata ?? {}; + this._metadata = extHostTypeConverters.NotebookCellMetadata.to(_cellData.metadata ?? {}); + this._previousResult = extHostTypeConverters.NotebookCellExecutionSummary.to(_cellData.internalMetadata ?? {}); } - get internalMetadata(): NotebookCellMetadata { + get internalMetadata(): NotebookCellInternalMetadata { return this._internalMetadata; } @@ -109,9 +109,12 @@ export class ExtHostCell { } setMetadata(newMetadata: NotebookCellMetadata): void { - this._internalMetadata = newMetadata; this._metadata = extHostTypeConverters.NotebookCellMetadata.to(newMetadata); - this._previousResult = extHostTypeConverters.NotebookCellPreviousExecutionResult.to(newMetadata); + } + + setInternalMetadata(newInternalMetadata: NotebookCellInternalMetadata): void { + this._internalMetadata = newInternalMetadata; + this._previousResult = extHostTypeConverters.NotebookCellExecutionSummary.to(newInternalMetadata); } } @@ -213,6 +216,8 @@ export class ExtHostNotebookDocument { this._changeCellLanguage(rawEvent.index, rawEvent.language); } else if (rawEvent.kind === NotebookCellsChangeType.ChangeCellMetadata) { this._changeCellMetadata(rawEvent.index, rawEvent.metadata); + } else if (rawEvent.kind === NotebookCellsChangeType.ChangeCellInternalMetadata) { + this._changeCellInternalMetadata(rawEvent.index, rawEvent.internalMetadata); } } } @@ -334,7 +339,6 @@ export class ExtHostNotebookDocument { private _changeCellMetadata(index: number, newMetadata: NotebookCellMetadata): void { const cell = this._cells[index]; - const originalInternalMetadata = cell.internalMetadata; const originalExtMetadata = cell.apiCell.metadata; cell.setMetadata(newMetadata); const newExtMetadata = cell.apiCell.metadata; @@ -342,9 +346,16 @@ export class ExtHostNotebookDocument { if (!equals(originalExtMetadata, newExtMetadata)) { this._emitter.emitCellMetadataChange(deepFreeze({ document: this.apiNotebook, cell: cell.apiCell })); } + } - if (originalInternalMetadata.runState !== newMetadata.runState) { - const executionState = newMetadata.runState ?? extHostTypes.NotebookCellExecutionState.Idle; + private _changeCellInternalMetadata(index: number, newInternalMetadata: NotebookCellInternalMetadata): void { + const cell = this._cells[index]; + + const originalInternalMetadata = cell.internalMetadata; + cell.setInternalMetadata(newInternalMetadata); + + if (originalInternalMetadata.runState !== newInternalMetadata.runState) { + const executionState = newInternalMetadata.runState ?? extHostTypes.NotebookCellExecutionState.Idle; this._emitter.emitCellExecutionStateChange(deepFreeze({ document: this.apiNotebook, cell: cell.apiCell, executionState })); } } diff --git a/src/vs/workbench/api/common/extHostNotebookKernels.ts b/src/vs/workbench/api/common/extHostNotebookKernels.ts index 91007850945..f654250d323 100644 --- a/src/vs/workbench/api/common/extHostNotebookKernels.ts +++ b/src/vs/workbench/api/common/extHostNotebookKernels.ts @@ -16,7 +16,7 @@ import { asWebviewUri } from 'vs/workbench/api/common/shared/webview'; import { ResourceMap } from 'vs/base/common/map'; import { timeout } from 'vs/base/common/async'; import { ExtHostCell, ExtHostNotebookDocument } from 'vs/workbench/api/common/extHostNotebookDocument'; -import { CellEditType, IImmediateCellEditOperation, NullablePartialNotebookCellMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { CellEditType, IImmediateCellEditOperation, NullablePartialNotebookCellInternalMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { CancellationTokenSource } from 'vs/base/common/cancellation'; import { NotebookCellExecutionState } from 'vs/workbench/api/common/extHostTypes'; import { asArray } from 'vs/base/common/arrays'; @@ -373,8 +373,8 @@ class NotebookCellExecutionTask extends Disposable { } } - private mixinMetadata(mixinMetadata: NullablePartialNotebookCellMetadata) { - const edit: IImmediateCellEditOperation = { editType: CellEditType.PartialMetadata, handle: this._cell.handle, metadata: mixinMetadata }; + private mixinMetadata(mixinMetadata: NullablePartialNotebookCellInternalMetadata) { + const edit: IImmediateCellEditOperation = { editType: CellEditType.PartialInternalMetadata, handle: this._cell.handle, internalMetadata: mixinMetadata }; this.applyEdits([edit]); } diff --git a/src/vs/workbench/api/common/extHostTypeConverters.ts b/src/vs/workbench/api/common/extHostTypeConverters.ts index 505ad95ddbe..72eccc15c02 100644 --- a/src/vs/workbench/api/common/extHostTypeConverters.ts +++ b/src/vs/workbench/api/common/extHostTypeConverters.ts @@ -1443,8 +1443,8 @@ export namespace NotebookDocumentMetadata { } } -export namespace NotebookCellPreviousExecutionResult { - export function to(data: notebooks.NotebookCellMetadata): vscode.NotebookCellExecutionSummary { +export namespace NotebookCellExecutionSummary { + export function to(data: notebooks.NotebookCellInternalMetadata): vscode.NotebookCellExecutionSummary { return { startTime: data.runStartTime, endTime: data.runEndTime, @@ -1453,7 +1453,7 @@ export namespace NotebookCellPreviousExecutionResult { }; } - export function from(data: vscode.NotebookCellExecutionSummary): Partial { + export function from(data: vscode.NotebookCellExecutionSummary): Partial { return { lastRunSuccess: data.success, runStartTime: data.startTime, @@ -1492,10 +1492,8 @@ export namespace NotebookCellData { cellKind: NotebookCellKind.from(data.kind), language: data.languageId, source: data.value, - metadata: { - ...data.metadata, - ...NotebookCellPreviousExecutionResult.from(data.executionSummary ?? {}) - }, + metadata: data.metadata, + internalMetadata: NotebookCellExecutionSummary.from(data.executionSummary ?? {}), outputs: data.outputs ? data.outputs.map(NotebookCellOutput.from) : [] }; } @@ -1642,15 +1640,7 @@ export namespace NotebookDocumentContentOptions { export function from(options: vscode.NotebookDocumentContentOptions | undefined): notebooks.TransientOptions { return { transientOutputs: options?.transientOutputs ?? false, - transientCellMetadata: { - ...options?.transientCellMetadata, - executionOrder: true, - runState: true, - runStartTime: true, - runStartTimeAdjustment: true, - runEndTime: true, - lastRunSuccess: true - }, + transientCellMetadata: options?.transientCellMetadata ?? {}, transientDocumentMetadata: options?.transientDocumentMetadata ?? {} }; } diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/coreActions.ts b/src/vs/workbench/contrib/notebook/browser/contrib/coreActions.ts index 0ff295fff63..692c8d40f76 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/coreActions.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/coreActions.ts @@ -803,7 +803,7 @@ async function runCell(accessor: ServicesAccessor, context: INotebookActionConte } if (context.ui && context.cell) { - if (context.cell.metadata?.runState === NotebookCellExecutionState.Executing) { + if (context.cell.internalMetadata?.runState === NotebookCellExecutionState.Executing) { return; } return context.notebookEditor.executeNotebookCells(Iterable.single(context.cell)); @@ -1251,10 +1251,9 @@ registerAction2(class ClearCellOutputsAction extends NotebookCellAction { editor.viewModel.notebookDocument.applyEdits([{ editType: CellEditType.Output, index, outputs: [] }], true, undefined, () => undefined, undefined); - if (context.cell.metadata && context.cell.metadata?.runState !== NotebookCellExecutionState.Executing) { + if (context.cell.internalMetadata?.runState !== NotebookCellExecutionState.Executing) { context.notebookEditor.viewModel.notebookDocument.applyEdits([{ - editType: CellEditType.Metadata, index, metadata: { - ...context.cell.metadata, + editType: CellEditType.PartialInternalMetadata, index, internalMetadata: { runState: NotebookCellExecutionState.Idle, runStartTime: undefined, runStartTimeAdjustment: undefined, @@ -1465,10 +1464,9 @@ registerAction2(class ClearAllCellOutputsAction extends NotebookAction { })), true, undefined, () => undefined, undefined); const clearExecutionMetadataEdits = editor.viewModel.notebookDocument.cells.map((cell, index) => { - if (cell.metadata && cell.metadata?.runState !== NotebookCellExecutionState.Executing) { + if (cell.internalMetadata?.runState !== NotebookCellExecutionState.Executing) { return { - editType: CellEditType.Metadata, index, metadata: { - ...cell.metadata, + editType: CellEditType.PartialInternalMetadata, index, internalMetadata: { runState: NotebookCellExecutionState.Idle, runStartTime: undefined, runStartTimeAdjustment: undefined, diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/statusBar/contributedStatusBarItemController.ts b/src/vs/workbench/contrib/notebook/browser/contrib/statusBar/contributedStatusBarItemController.ts index a8bc2832cf4..7d855e950d0 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/statusBar/contributedStatusBarItemController.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/statusBar/contributedStatusBarItemController.ts @@ -87,6 +87,7 @@ class CellStatusBarHelper extends Disposable { this._register(this._cell.model.onDidChangeContent(() => this._updateSoon())); this._register(this._cell.model.onDidChangeLanguage(() => this._updateSoon())); this._register(this._cell.model.onDidChangeMetadata(() => this._updateSoon())); + this._register(this._cell.model.onDidChangeInternalMetadata(() => this._updateSoon())); this._register(this._cell.model.onDidChangeOutputs(() => this._updateSoon())); } diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/statusBar/executionStatusBarItemController.ts b/src/vs/workbench/contrib/notebook/browser/contrib/statusBar/executionStatusBarItemController.ts index 5644ce6cb79..b34c318e9ab 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/statusBar/executionStatusBarItemController.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/statusBar/executionStatusBarItemController.ts @@ -89,7 +89,7 @@ class ExecutionStateCellStatusBarHelper extends Disposable { super(); this._update(); - this._register(this._cell.model.onDidChangeMetadata(() => this._update())); + this._register(this._cell.model.onDidChangeInternalMetadata(() => this._update())); } private async _update() { @@ -107,13 +107,13 @@ class ExecutionStateCellStatusBarHelper extends Disposable { return; } - const item = this._getItemForState(cell.metadata?.runState, cell.metadata?.lastRunSuccess); + const item = this._getItemForState(cell.internalMetadata?.runState ?? NotebookCellExecutionState.Idle, cell.internalMetadata?.lastRunSuccess); // Show the execution spinner for a minimum time - if (cell.metadata?.runState === NotebookCellExecutionState.Executing) { + if (cell.internalMetadata?.runState === NotebookCellExecutionState.Executing) { this._currentExecutingStateTimer = setTimeout(() => { this._currentExecutingStateTimer = undefined; - if (cell.metadata?.runState !== NotebookCellExecutionState.Executing) { + if (cell.internalMetadata?.runState !== NotebookCellExecutionState.Executing) { this._update(); } }, ExecutionStateCellStatusBarHelper.MIN_SPINNER_TIME); @@ -179,21 +179,22 @@ class TimerCellStatusBarHelper extends Disposable { this._scheduler = this._register(new RunOnceScheduler(() => this._update(), TimerCellStatusBarHelper.UPDATE_INTERVAL)); this._update(); - this._register(this._cell.model.onDidChangeMetadata(() => this._update())); + this._register(this._cell.model.onDidChangeInternalMetadata(() => this._update())); } private async _update() { let item: INotebookCellStatusBarItem | undefined; - if (this._cell.metadata?.runState === NotebookCellExecutionState.Executing) { - const startTime = this._cell.metadata.runStartTime; - const adjustment = this._cell.metadata.runStartTimeAdjustment; + const state = this._cell.internalMetadata?.runState ?? NotebookCellExecutionState.Idle; + if (state === NotebookCellExecutionState.Executing) { + const startTime = this._cell.internalMetadata?.runStartTime; + const adjustment = this._cell.internalMetadata?.runStartTimeAdjustment; if (typeof startTime === 'number') { item = this._getTimeItem(startTime, Date.now(), adjustment); this._scheduler.schedule(); } - } else if (this._cell.metadata?.runState === NotebookCellExecutionState.Idle) { - const startTime = this._cell.metadata.runStartTime; - const endTime = this._cell.metadata.runEndTime; + } else if (state === NotebookCellExecutionState.Idle) { + const startTime = this._cell.internalMetadata?.runStartTime; + const endTime = this._cell.internalMetadata?.runEndTime; if (typeof startTime === 'number' && typeof endTime === 'number') { item = this._getTimeItem(startTime, endTime); } @@ -250,7 +251,7 @@ class KeybindingPlaceholderStatusBarHelper extends Disposable { NOTEBOOK_CELL_EXECUTION_STATE.bindTo(this._contextKeyService).set('idle'); this._update(); - this._register(this._cell.model.onDidChangeMetadata(() => this._update())); + this._register(this._cell.model.onDidChangeInternalMetadata(() => this._update())); } private async _update() { @@ -261,7 +262,7 @@ class KeybindingPlaceholderStatusBarHelper extends Disposable { } private _getItemsForCell(cell: ICellViewModel): INotebookCellStatusBarItem[] { - if (typeof cell.metadata?.runState !== 'undefined' || typeof cell.metadata?.lastRunSuccess !== 'undefined') { + if (typeof cell.internalMetadata?.runState !== 'undefined' || typeof cell.internalMetadata?.lastRunSuccess !== 'undefined') { return []; } diff --git a/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts index 18f142fe53f..7ca3b25b9da 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts @@ -490,22 +490,6 @@ abstract class AbstractElementRenderer extends Disposable { } break; - case 'executionOrder': - // number - if (typeof newMetadataObj[key] === 'number') { - result[key] = newMetadataObj[key]; - } else { - result[key] = currentMetadata[key as keyof NotebookCellMetadata]; - } - break; - case 'runState': - // enum - if (typeof newMetadataObj[key] === 'number' && [1, 2, 3, 4].indexOf(newMetadataObj[key]) >= 0) { - result[key] = newMetadataObj[key]; - } else { - result[key] = currentMetadata[key as keyof NotebookCellMetadata]; - } - break; default: result[key] = newMetadataObj[key]; break; diff --git a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts index fd69c02aa50..f7aea5b4270 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts @@ -21,7 +21,7 @@ import { ContextKeyExpr, RawContextKey, IContextKeyService } from 'vs/platform/c import { OutputRenderer } from 'vs/workbench/contrib/notebook/browser/view/output/outputRenderer'; import { CellViewModel, IModelDecorationsChangeAccessor, NotebookViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel'; import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel'; -import { CellKind, NotebookCellMetadata, INotebookKernel, IOrderedMimeType, INotebookRendererInfo, ICellOutput, IOutputItemDto, INotebookCellStatusBarItem } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { CellKind, NotebookCellMetadata, INotebookKernel, IOrderedMimeType, INotebookRendererInfo, ICellOutput, IOutputItemDto, INotebookCellStatusBarItem, NotebookCellInternalMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { ICellRange, cellRangesToIndexes, reduceRanges } from 'vs/workbench/contrib/notebook/common/notebookRange'; import { Webview } from 'vs/workbench/contrib/webview/browser/webview'; import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel'; @@ -263,6 +263,7 @@ export interface ICellViewModel extends IGenericCellViewModel { getTextLength(): number; getHeight(lineHeight: number): number; metadata: NotebookCellMetadata | undefined; + internalMetadata: NotebookCellInternalMetadata | undefined; textModel: ITextModel | undefined; hasModel(): this is IEditableCellViewModel; resolveTextModel(): Promise; @@ -822,6 +823,7 @@ export enum CursorAtBoundary { export interface CellViewModelStateChangeEvent { readonly metadataChanged?: boolean; + readonly internalMetadataChanged?: boolean; readonly runStateChanged?: boolean; readonly selectionChanged?: boolean; readonly focusModeChanged?: boolean; diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditorKernelManager.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditorKernelManager.ts index 033e28d165f..a272c05fce7 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditorKernelManager.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditorKernelManager.ts @@ -47,7 +47,7 @@ export class NotebookEditorKernelManager extends Disposable { const cellHandles: number[] = []; for (const cell of cells) { - if (cell.cellKind !== CellKind.Code || cell.metadata?.runState === NotebookCellExecutionState.Pending || cell.metadata?.runState === NotebookCellExecutionState.Executing) { + if (cell.cellKind !== CellKind.Code || cell.internalMetadata?.runState === NotebookCellExecutionState.Pending || cell.internalMetadata?.runState === NotebookCellExecutionState.Executing) { continue; } if (!kernel.supportedLanguages.includes(cell.language)) { diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidgetContextKeys.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidgetContextKeys.ts index 01117f9e17c..5ec47907d10 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidgetContextKeys.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidgetContextKeys.ts @@ -69,9 +69,9 @@ export class NotebookEditorContextKeys { if (!e.runStateChanged) { return; } - if (c.metadata?.runState === NotebookCellExecutionState.Pending) { + if (c.internalMetadata?.runState === NotebookCellExecutionState.Pending) { executionCount++; - } else if (c.metadata?.runState === NotebookCellExecutionState.Idle) { + } else if (c.internalMetadata?.runState === NotebookCellExecutionState.Idle) { executionCount--; } this._someCellRunning.set(executionCount > 0); diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/cellContextKeys.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/cellContextKeys.ts index 689dbf809e6..43ea4f9d594 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/cellContextKeys.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/cellContextKeys.ts @@ -69,7 +69,7 @@ export class CellContextKeyManager extends Disposable { this.contextKeyService.bufferChangeEvents(() => { this.updateForFocusState(); - this.updateForMetadata(); + this.updateForInternalMetadata(); this.updateForEditState(); this.updateForCollapseState(); this.updateForOutputs(); @@ -80,8 +80,8 @@ export class CellContextKeyManager extends Disposable { private onDidChangeState(e: CellViewModelStateChangeEvent) { this.contextKeyService.bufferChangeEvents(() => { - if (e.metadataChanged) { - this.updateForMetadata(); + if (e.internalMetadataChanged) { + this.updateForInternalMetadata(); } if (e.editStateChanged) { @@ -114,17 +114,17 @@ export class CellContextKeyManager extends Disposable { } - private updateForMetadata() { - const metadata = this.element.metadata; + private updateForInternalMetadata() { + const internalMetadata = this.element.internalMetadata; this.cellEditable.set(!this.notebookEditor.viewModel?.options.isReadOnly); - const runState = metadata.runState ?? NotebookCellExecutionState.Idle; + const runState = internalMetadata.runState ?? NotebookCellExecutionState.Idle; if (this.element instanceof MarkdownCellViewModel) { this.cellRunState.reset(); } else if (runState === NotebookCellExecutionState.Idle) { - if (metadata.lastRunSuccess === true) { + if (internalMetadata.lastRunSuccess === true) { this.cellRunState.set('succeeded'); - } else if (metadata.lastRunSuccess === false) { + } else if (internalMetadata.lastRunSuccess === false) { this.cellRunState.set('failed'); } else { this.cellRunState.set('idle'); diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts index 9ebb664546d..d22419f52cf 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts @@ -46,7 +46,7 @@ import { StatefulMarkdownCell } from 'vs/workbench/contrib/notebook/browser/view import { CodeCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel'; import { MarkdownCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/markdownCellViewModel'; import { CellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel'; -import { CellEditType, CellKind, NotebookCellMetadata, NotebookCellExecutionState, NotebookCellsChangeType } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { CellEditType, CellKind, NotebookCellMetadata, NotebookCellExecutionState, NotebookCellInternalMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { CodiconActionViewItem } from 'vs/workbench/contrib/notebook/browser/view/renderers/cellActionView'; import { ThemeIcon } from 'vs/platform/theme/common/themeService'; import { errorStateIcon, successStateIcon, unfoldIcon } from 'vs/workbench/contrib/notebook/browser/notebookIcons'; @@ -843,25 +843,25 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende } } - private updateForMetadata(element: CodeCellViewModel, templateData: CodeCellRenderTemplate, editorOptions: CellEditorOptions): void { + private updateForInternalMetadata(element: CodeCellViewModel, templateData: CodeCellRenderTemplate, editorOptions: CellEditorOptions): void { if (!this.notebookEditor.hasModel()) { return; } - const metadata = element.metadata; - this.updateExecutionOrder(metadata, templateData); + const internalMetadata = element.internalMetadata; + this.updateExecutionOrder(internalMetadata, templateData); - if (metadata.runState === NotebookCellExecutionState.Executing) { + if (internalMetadata.runState === NotebookCellExecutionState.Executing) { templateData.progressBar.infinite().show(500); } else { templateData.progressBar.hide(); } } - private updateExecutionOrder(metadata: NotebookCellMetadata, templateData: CodeCellRenderTemplate): void { + private updateExecutionOrder(internalMetadata: NotebookCellInternalMetadata, templateData: CodeCellRenderTemplate): void { if (this.notebookEditor.activeKernel?.implementsExecutionOrder) { - const executionOrderLabel = typeof metadata.executionOrder === 'number' ? - `[${metadata.executionOrder}]` : + const executionOrderLabel = typeof internalMetadata.executionOrder === 'number' ? + `[${internalMetadata.executionOrder}]` : '[ ]'; templateData.executionOrderLabel.innerText = executionOrderLabel; } else { @@ -950,13 +950,13 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende this.updateForLayout(element, templateData); })); - this.updateForMetadata(element, templateData, cellEditorOptions); + this.updateForInternalMetadata(element, templateData, cellEditorOptions); this.updateForHover(element, templateData); this.updateForFocus(element, templateData); cellEditorOptions.setLineNumbers(element.lineNumbers); elementDisposables.add(element.onDidChangeState((e) => { - if (e.metadataChanged) { - this.updateForMetadata(element, templateData, cellEditorOptions); + if (e.internalMetadataChanged) { + this.updateForInternalMetadata(element, templateData, cellEditorOptions); } if (e.outputIsHoveredChanged) { @@ -971,11 +971,6 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende cellEditorOptions.setLineNumbers(element.lineNumbers); } })); - elementDisposables.add(this.notebookEditor.viewModel.notebookDocument.onDidChangeContent(e => { - if (e.rawEvents.find(event => event.kind === NotebookCellsChangeType.ChangeDocumentMetadata)) { - this.updateForMetadata(element, templateData, cellEditorOptions); - } - })); this.updateForOutputs(element, templateData); elementDisposables.add(element.onDidChangeOutputs(_e => this.updateForOutputs(element, templateData))); diff --git a/src/vs/workbench/contrib/notebook/browser/viewModel/baseCellViewModel.ts b/src/vs/workbench/contrib/notebook/browser/viewModel/baseCellViewModel.ts index 8ed3cb6b951..57ed3710937 100644 --- a/src/vs/workbench/contrib/notebook/browser/viewModel/baseCellViewModel.ts +++ b/src/vs/workbench/contrib/notebook/browser/viewModel/baseCellViewModel.ts @@ -39,6 +39,9 @@ export abstract class BaseCellViewModel extends Disposable { get metadata() { return this.model.metadata; } + get internalMetadata() { + return this.model.internalMetadata; + } get language() { return this.model.language; } @@ -135,8 +138,12 @@ export abstract class BaseCellViewModel extends Disposable { ) { super(); - this._register(model.onDidChangeMetadata(e => { - this._onDidChangeState.fire({ metadataChanged: true, runStateChanged: e.runStateChanged }); + this._register(model.onDidChangeMetadata(() => { + this._onDidChangeState.fire({ metadataChanged: true }); + })); + + this._register(model.onDidChangeInternalMetadata(e => { + this._onDidChangeState.fire({ internalMetadataChanged: true, runStateChanged: e.runStateChanged }); })); this._register(this._viewContext.notebookOptions.onDidChangeOptions(e => { diff --git a/src/vs/workbench/contrib/notebook/common/model/notebookCellTextModel.ts b/src/vs/workbench/contrib/notebook/common/model/notebookCellTextModel.ts index c6471f1c6fd..5123621f35b 100644 --- a/src/vs/workbench/contrib/notebook/common/model/notebookCellTextModel.ts +++ b/src/vs/workbench/contrib/notebook/common/model/notebookCellTextModel.ts @@ -4,18 +4,18 @@ *--------------------------------------------------------------------------------------------*/ import { Emitter, Event } from 'vs/base/common/event'; -import { ICell, NotebookCellOutputsSplice, CellKind, NotebookCellMetadata, TransientOptions, IOutputDto, ICellOutput, CellMetadataChangedEvent } from 'vs/workbench/contrib/notebook/common/notebookCommon'; -import { PieceTreeTextBufferBuilder } from 'vs/editor/common/model/pieceTreeTextBuffer/pieceTreeTextBufferBuilder'; +import { hash } from 'vs/base/common/hash'; +import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; import * as UUID from 'vs/base/common/uuid'; -import * as model from 'vs/editor/common/model'; import { Range } from 'vs/editor/common/core/range'; -import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; -import { hash } from 'vs/base/common/hash'; +import * as model from 'vs/editor/common/model'; import { PieceTreeTextBuffer } from 'vs/editor/common/model/pieceTreeTextBuffer/pieceTreeTextBuffer'; -import { NotebookCellOutputTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellOutputTextModel'; -import { IModeService } from 'vs/editor/common/services/modeService'; +import { PieceTreeTextBufferBuilder } from 'vs/editor/common/model/pieceTreeTextBuffer/pieceTreeTextBufferBuilder'; import { TextModel } from 'vs/editor/common/model/textModel'; +import { IModeService } from 'vs/editor/common/services/modeService'; +import { NotebookCellOutputTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellOutputTextModel'; +import { CellInternalMetadataChangedEvent, CellKind, ICell, ICellOutput, IOutputDto, NotebookCellInternalMetadata, NotebookCellMetadata, NotebookCellOutputsSplice, TransientOptions } from 'vs/workbench/contrib/notebook/common/notebookCommon'; export class NotebookCellTextModel extends Disposable implements ICell { private _onDidChangeOutputs = new Emitter(); @@ -24,8 +24,11 @@ export class NotebookCellTextModel extends Disposable implements ICell { private _onDidChangeContent = new Emitter<'content' | 'language'>(); onDidChangeContent: Event<'content' | 'language'> = this._onDidChangeContent.event; - private _onDidChangeMetadata = new Emitter(); - onDidChangeMetadata: Event = this._onDidChangeMetadata.event; + private _onDidChangeMetadata = new Emitter(); + onDidChangeMetadata: Event = this._onDidChangeMetadata.event; + + private _onDidChangeInternalMetadata = new Emitter(); + onDidChangeInternalMetadata: Event = this._onDidChangeInternalMetadata.event; private _onDidChangeLanguage = new Emitter(); onDidChangeLanguage: Event = this._onDidChangeLanguage.event; @@ -43,14 +46,26 @@ export class NotebookCellTextModel extends Disposable implements ICell { } set metadata(newMetadata: NotebookCellMetadata) { - const runStateChanged = this._metadata.runState !== newMetadata.runState; - newMetadata = { - ...newMetadata, - ...{ runStartTimeAdjustment: computeRunStartTimeAdjustment(this._metadata, newMetadata) } - }; this._metadata = newMetadata; this._hash = null; - this._onDidChangeMetadata.fire({ runStateChanged }); + this._onDidChangeMetadata.fire(); + } + + private _internalMetadata: NotebookCellInternalMetadata; + + get internalMetadata() { + return this._internalMetadata; + } + + set internalMetadata(newInternalMetadata: NotebookCellInternalMetadata) { + const runStateChanged = this._internalMetadata.runState !== newInternalMetadata.runState; + newInternalMetadata = { + ...newInternalMetadata, + ...{ runStartTimeAdjustment: computeRunStartTimeAdjustment(this._internalMetadata, newInternalMetadata) } + }; + this._internalMetadata = newInternalMetadata; + this._hash = null; + this._onDidChangeInternalMetadata.fire({ runStateChanged }); } get language() { @@ -148,12 +163,14 @@ export class NotebookCellTextModel extends Disposable implements ICell { public cellKind: CellKind, outputs: IOutputDto[], metadata: NotebookCellMetadata | undefined, + internalMetadata: NotebookCellInternalMetadata | undefined, public readonly transientOptions: TransientOptions, private readonly _modeService: IModeService ) { super(); this._outputs = outputs.map(op => new NotebookCellOutputTextModel(op)); this._metadata = metadata || {}; + this._internalMetadata = internalMetadata || {}; } getValue(): string { @@ -220,12 +237,6 @@ export class NotebookCellTextModel extends Disposable implements ICell { } } -export function cloneMetadata(cell: NotebookCellTextModel) { - return { - ...cell.metadata - }; -} - export function cloneNotebookCellTextModel(cell: NotebookCellTextModel) { return { source: cell.getValue(), @@ -235,11 +246,12 @@ export function cloneNotebookCellTextModel(cell: NotebookCellTextModel) { outputs: output.outputs, /* paste should generate new outputId */ outputId: UUID.generateUuid() })), - metadata: cloneMetadata(cell) + metadata: { ...cell.metadata }, + internalMetadata: { ...cell.internalMetadata }, }; } -function computeRunStartTimeAdjustment(oldMetadata: NotebookCellMetadata, newMetadata: NotebookCellMetadata): number | undefined { +function computeRunStartTimeAdjustment(oldMetadata: NotebookCellInternalMetadata, newMetadata: NotebookCellInternalMetadata): number | undefined { if (oldMetadata.runStartTime !== newMetadata.runStartTime && typeof newMetadata.runStartTime === 'number') { const offset = Date.now() - newMetadata.runStartTime; return offset < 0 ? Math.abs(offset) : 0; diff --git a/src/vs/workbench/contrib/notebook/common/model/notebookTextModel.ts b/src/vs/workbench/contrib/notebook/common/model/notebookTextModel.ts index d349301b4ae..74115aeef94 100644 --- a/src/vs/workbench/contrib/notebook/common/model/notebookTextModel.ts +++ b/src/vs/workbench/contrib/notebook/common/model/notebookTextModel.ts @@ -8,7 +8,7 @@ import { Emitter, Event } from 'vs/base/common/event'; import { Disposable, dispose, IDisposable } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel'; -import { INotebookTextModel, NotebookCellOutputsSplice, NotebookDocumentMetadata, NotebookCellMetadata, ICellEditOperation, CellEditType, CellUri, notebookDocumentMetadataDefaults, diff, NotebookCellsChangeType, ICellDto2, TransientOptions, NotebookTextModelChangedEvent, NotebookRawContentEvent, IOutputDto, ICellOutput, IOutputItemDto, ISelectionState, NullablePartialNotebookCellMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { INotebookTextModel, NotebookCellOutputsSplice, NotebookDocumentMetadata, NotebookCellMetadata, ICellEditOperation, CellEditType, CellUri, notebookDocumentMetadataDefaults, diff, NotebookCellsChangeType, ICellDto2, TransientOptions, NotebookTextModelChangedEvent, NotebookRawContentEvent, IOutputDto, ICellOutput, IOutputItemDto, ISelectionState, NullablePartialNotebookCellMetadata, NotebookCellInternalMetadata, NullablePartialNotebookCellInternalMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { IUndoRedoService, UndoRedoElementType, IUndoRedoElement, IResourceUndoRedoElement, UndoRedoGroup, IWorkspaceUndoRedoElement } from 'vs/platform/undoRedo/common/undoRedo'; import { MoveCellEdit, SpliceCellsEdit, CellMetadataEdit } from 'vs/workbench/contrib/notebook/common/model/cellEdit'; import { ISequence, LcsDiff } from 'vs/base/common/diff/diff'; @@ -284,7 +284,7 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel const mainCells = cells.map(cell => { const cellHandle = this._cellhandlePool++; const cellUri = CellUri.generate(this.uri, cellHandle); - return new NotebookCellTextModel(cellUri, cellHandle, cell.source, cell.language, cell.cellKind, cell.outputs || [], cell.metadata, this.transientOptions, this._modeService); + return new NotebookCellTextModel(cellUri, cellHandle, cell.source, cell.language, cell.cellKind, cell.outputs || [], cell.metadata, cell.internalMetadata, this.transientOptions, this._modeService); }); for (let i = 0; i < mainCells.length; i++) { @@ -475,6 +475,10 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel this._assertIndex(cellIndex); this._changeCellMetadataPartial(this._cells[cellIndex], edit.metadata, computeUndoRedo); break; + case CellEditType.PartialInternalMetadata: + this._assertIndex(cellIndex); + this._changeCellInternalMetadataPartial(this._cells[cellIndex], edit.internalMetadata); + break; case CellEditType.CellLanguage: this._assertIndex(edit.index); this._changeCellLanguage(this._cells[edit.index], edit.language, computeUndoRedo); @@ -514,7 +518,7 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel const cellUri = CellUri.generate(this.uri, cellHandle); const cell = new NotebookCellTextModel( cellUri, cellHandle, - cellDto.source, cellDto.language, cellDto.cellKind, cellDto.outputs || [], cellDto.metadata, this.transientOptions, + cellDto.source, cellDto.language, cellDto.cellKind, cellDto.outputs || [], cellDto.metadata, cellDto.internalMetadata, this.transientOptions, this._modeService ); const textModel = this._modelService.getModel(cellUri); @@ -692,14 +696,7 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel private _isCellMetadataChanged(a: NotebookCellMetadata, b: NotebookCellMetadata) { const keys = new Set([...Object.keys(a || {}), ...Object.keys(b || {})]); for (let key of keys) { - if (key === 'custom') { - if (!this._customMetadataEqual(a[key], b[key]) - && - !(this.transientOptions.transientCellMetadata[key as keyof NotebookCellMetadata]) - ) { - return true; - } - } else if ( + if ( (a[key as keyof NotebookCellMetadata] !== b[key as keyof NotebookCellMetadata]) && !(this.transientOptions.transientCellMetadata[key as keyof NotebookCellMetadata]) @@ -745,7 +742,7 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel let k: keyof NullablePartialNotebookCellMetadata; for (k in metadata) { const value = metadata[k] ?? undefined; - newMetadata[k] = value as any; // TS... + newMetadata[k] = value as any; } return this._changeCellMetadata(cell, newMetadata, computeUndoRedo); @@ -763,10 +760,7 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel if (!cell) { return; } - this._changeCellMetadata(cell, { - ...newMetadata, - runState: cell.metadata.runState - }, false); + this._changeCellMetadata(cell, newMetadata, false); } }), undefined, undefined); } @@ -778,6 +772,20 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel this._eventEmitter.emit({ kind: NotebookCellsChangeType.ChangeCellMetadata, index: this._cells.indexOf(cell), metadata: cell.metadata, transient: !triggerDirtyChange }, true); } + private _changeCellInternalMetadataPartial(cell: NotebookCellTextModel, internalMetadata: NullablePartialNotebookCellInternalMetadata) { + const newInternalMetadata: NotebookCellInternalMetadata = { + ...cell.internalMetadata + }; + let k: keyof NotebookCellInternalMetadata; + for (k in internalMetadata) { + const value = internalMetadata[k] ?? undefined; + newInternalMetadata[k] = value as any; + } + + cell.internalMetadata = newInternalMetadata; + this._eventEmitter.emit({ kind: NotebookCellsChangeType.ChangeCellInternalMetadata, index: this._cells.indexOf(cell), internalMetadata: cell.internalMetadata, transient: true }, true); + } + private _changeCellLanguage(cell: NotebookCellTextModel, languageId: string, computeUndoRedo: boolean) { if (cell.language === languageId) { return; diff --git a/src/vs/workbench/contrib/notebook/common/notebookCommon.ts b/src/vs/workbench/contrib/notebook/common/notebookCommon.ts index 98e6211c2e3..482129fac5a 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookCommon.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookCommon.ts @@ -80,12 +80,6 @@ export interface INotebookCellPreviousExecutionResult { } export interface NotebookCellMetadata { - executionOrder?: number; - lastRunSuccess?: boolean; - runState?: NotebookCellExecutionState; - runStartTime?: number; - runStartTimeAdjustment?: number; - runEndTime?: number; inputCollapsed?: boolean; outputCollapsed?: boolean; @@ -95,6 +89,15 @@ export interface NotebookCellMetadata { [key: string]: unknown; } +export interface NotebookCellInternalMetadata { + executionOrder?: number; + lastRunSuccess?: boolean; + runState?: NotebookCellExecutionState; + runStartTime?: number; + runStartTimeAdjustment?: number; + runEndTime?: number; +} + export type TransientCellMetadata = { [K in keyof NotebookCellMetadata]?: boolean }; export type TransientDocumentMetadata = { [K in keyof NotebookDocumentMetadata]?: boolean }; @@ -182,7 +185,7 @@ export interface ICellOutput { appendData(items: IOutputItemDto[]): void; } -export interface CellMetadataChangedEvent { +export interface CellInternalMetadataChangedEvent { readonly runStateChanged?: boolean; } @@ -195,7 +198,8 @@ export interface ICell { metadata?: NotebookCellMetadata; onDidChangeOutputs?: Event; onDidChangeLanguage: Event; - onDidChangeMetadata: Event; + onDidChangeMetadata: Event; + onDidChangeInternalMetadata: Event; } export interface INotebookTextModel { @@ -229,6 +233,7 @@ export interface IMainCellDto { cellKind: CellKind; outputs: IOutputDto[]; metadata?: NotebookCellMetadata; + internalMetadata?: NotebookCellInternalMetadata; } export type NotebookCellsSplice2 = [ @@ -249,7 +254,8 @@ export enum NotebookCellsChangeType { OutputItem = 9, ChangeCellContent = 10, ChangeDocumentMetadata = 11, - Unknown = 12 + ChangeCellInternalMetadata = 12, + Unknown = 100 } export interface NotebookCellsInitializeEvent { @@ -300,6 +306,12 @@ export interface NotebookCellsChangeMetadataEvent { readonly metadata: NotebookCellMetadata; } +export interface NotebookCellsChangeInternalMetadataEvent { + readonly kind: NotebookCellsChangeType.ChangeCellInternalMetadata; + readonly index: number; + readonly internalMetadata: NotebookCellInternalMetadata; +} + export interface NotebookDocumentChangeMetadataEvent { readonly kind: NotebookCellsChangeType.ChangeDocumentMetadata; readonly metadata: NotebookDocumentMetadata; @@ -309,14 +321,14 @@ export interface NotebookDocumentUnknownChangeEvent { readonly kind: NotebookCellsChangeType.Unknown; } -export type NotebookRawContentEventDto = NotebookCellsInitializeEvent | NotebookDocumentChangeMetadataEvent | NotebookCellContentChangeEvent | NotebookCellsModelChangedEvent | NotebookCellsModelMoveEvent | NotebookOutputChangedEvent | NotebookOutputItemChangedEvent | NotebookCellsChangeLanguageEvent | NotebookCellsChangeMetadataEvent | NotebookDocumentUnknownChangeEvent; +export type NotebookRawContentEventDto = NotebookCellsInitializeEvent | NotebookDocumentChangeMetadataEvent | NotebookCellContentChangeEvent | NotebookCellsModelChangedEvent | NotebookCellsModelMoveEvent | NotebookOutputChangedEvent | NotebookOutputItemChangedEvent | NotebookCellsChangeLanguageEvent | NotebookCellsChangeMetadataEvent | NotebookCellsChangeInternalMetadataEvent | NotebookDocumentUnknownChangeEvent; export type NotebookCellsChangedEventDto = { readonly rawEvents: NotebookRawContentEventDto[]; readonly versionId: number; }; -export type NotebookRawContentEvent = (NotebookCellsInitializeEvent | NotebookDocumentChangeMetadataEvent | NotebookCellContentChangeEvent | NotebookCellsModelChangedEvent | NotebookCellsModelMoveEvent | NotebookOutputChangedEvent | NotebookOutputItemChangedEvent | NotebookCellsChangeLanguageEvent | NotebookCellsChangeMetadataEvent | NotebookDocumentUnknownChangeEvent) & { transient: boolean; }; +export type NotebookRawContentEvent = (NotebookCellsInitializeEvent | NotebookDocumentChangeMetadataEvent | NotebookCellContentChangeEvent | NotebookCellsModelChangedEvent | NotebookCellsModelMoveEvent | NotebookOutputChangedEvent | NotebookOutputItemChangedEvent | NotebookCellsChangeLanguageEvent | NotebookCellsChangeMetadataEvent | NotebookCellsChangeInternalMetadataEvent | NotebookDocumentUnknownChangeEvent) & { transient: boolean; }; export enum SelectionStateType { Handle = 0, @@ -352,7 +364,8 @@ export const enum CellEditType { DocumentMetadata = 5, Move = 6, OutputItems = 7, - PartialMetadata = 8 + PartialMetadata = 8, + PartialInternalMetadata = 9, } export interface ICellDto2 { @@ -361,6 +374,7 @@ export interface ICellDto2 { cellKind: CellKind; outputs: IOutputDto[]; metadata?: NotebookCellMetadata; + internalMetadata?: NotebookCellInternalMetadata; } export interface ICellReplaceEdit { @@ -404,7 +418,7 @@ export type NullablePartialNotebookCellMetadata = { export interface ICellPartialMetadataEdit { editType: CellEditType.PartialMetadata; index: number; - metadata: Partial; + metadata: NullablePartialNotebookCellMetadata; } export interface ICellPartialMetadataEditByHandle { @@ -413,6 +427,21 @@ export interface ICellPartialMetadataEditByHandle { metadata: Partial; } +export type NullablePartialNotebookCellInternalMetadata = { + [Key in keyof Partial]: NotebookCellInternalMetadata[Key] | null +}; +export interface ICellPartialInternalMetadataEdit { + editType: CellEditType.PartialInternalMetadata; + index: number; + internalMetadata: NullablePartialNotebookCellInternalMetadata; +} + +export interface ICellPartialInternalMetadataEditByHandle { + editType: CellEditType.PartialInternalMetadata; + handle: number; + internalMetadata: Partial; +} + export interface ICellLanguageEdit { editType: CellEditType.CellLanguage; index: number; @@ -431,8 +460,8 @@ export interface ICellMoveEdit { newIdx: number; } -export type IImmediateCellEditOperation = ICellOutputEditByHandle | ICellPartialMetadataEditByHandle | ICellOutputItemEdit; -export type ICellEditOperation = IImmediateCellEditOperation | ICellReplaceEdit | ICellOutputEdit | ICellMetadataEdit | ICellPartialMetadataEdit | IDocumentMetadataEdit | ICellMoveEdit | ICellOutputItemEdit | ICellLanguageEdit; +export type IImmediateCellEditOperation = ICellOutputEditByHandle | ICellPartialMetadataEditByHandle | ICellOutputItemEdit | ICellPartialInternalMetadataEdit | ICellPartialInternalMetadataEditByHandle | ICellPartialMetadataEdit; +export type ICellEditOperation = IImmediateCellEditOperation | ICellReplaceEdit | ICellOutputEdit | ICellMetadataEdit | ICellPartialMetadataEdit | ICellPartialInternalMetadataEdit | IDocumentMetadataEdit | ICellMoveEdit | ICellOutputItemEdit | ICellLanguageEdit; export interface NotebookDataDto { readonly cells: ICellDto2[]; diff --git a/src/vs/workbench/contrib/notebook/common/notebookEditorModel.ts b/src/vs/workbench/contrib/notebook/common/notebookEditorModel.ts index 47a80fc8aef..0d8d088512e 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookEditorModel.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookEditorModel.ts @@ -552,7 +552,8 @@ export class NotebookFileWorkingCopyModel implements IFileWorkingCopyModel { cellKind: cell.cellKind, language: cell.language, source: cell.getValue(), - outputs: [] + outputs: [], + internalMetadata: cell.internalMetadata }; cellData.outputs = !this._notebookSerializer.options.transientOutputs ? cell.outputs : []; diff --git a/src/vs/workbench/contrib/notebook/common/services/notebookSimpleWorker.ts b/src/vs/workbench/contrib/notebook/common/services/notebookSimpleWorker.ts index 27c516baaf2..01f1b0a09b5 100644 --- a/src/vs/workbench/contrib/notebook/common/services/notebookSimpleWorker.ts +++ b/src/vs/workbench/contrib/notebook/common/services/notebookSimpleWorker.ts @@ -9,7 +9,7 @@ import { URI } from 'vs/base/common/uri'; import { IRequestHandler } from 'vs/base/common/worker/simpleWorker'; import * as model from 'vs/editor/common/model'; import { PieceTreeTextBufferBuilder } from 'vs/editor/common/model/pieceTreeTextBuffer/pieceTreeTextBufferBuilder'; -import { CellKind, ICellDto2, IMainCellDto, INotebookDiffResult, IOutputDto, NotebookCellMetadata, NotebookCellsChangedEventDto, NotebookCellsChangeType, NotebookCellsSplice2, NotebookDataDto, NotebookDocumentMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { CellKind, ICellDto2, IMainCellDto, INotebookDiffResult, IOutputDto, NotebookCellInternalMetadata, NotebookCellMetadata, NotebookCellsChangedEventDto, NotebookCellsChangeType, NotebookCellsSplice2, NotebookDataDto, NotebookDocumentMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { Range } from 'vs/editor/common/core/range'; import { EditorWorkerHost } from 'vs/workbench/contrib/notebook/common/services/notebookWorkerServiceImpl'; @@ -46,7 +46,8 @@ class MirrorCell { public language: string, public cellKind: CellKind, public outputs: IOutputDto[], - public metadata?: NotebookCellMetadata + public metadata?: NotebookCellMetadata, + public internalMetadata?: NotebookCellInternalMetadata, ) { } @@ -70,7 +71,7 @@ class MirrorCell { return this._primaryKey!; } - this._hash = hash([hash(this.language), hash(this.getValue()), this.metadata, this.outputs.map(op => ({ + this._hash = hash([hash(this.language), hash(this.getValue()), this.metadata, this.internalMetadata, this.outputs.map(op => ({ outputs: op.outputs, metadata: op.metadata }))]); @@ -82,7 +83,7 @@ class MirrorCell { return this._hash; } - this._hash = hash([hash(this.getValue()), this.language, this.metadata]); + this._hash = hash([hash(this.getValue()), this.language, this.metadata, this.internalMetadata]); return this._hash; } } @@ -114,6 +115,9 @@ class MirrorNotebookDocument { } else if (e.kind === NotebookCellsChangeType.ChangeCellMetadata) { const cell = this.cells[e.index]; cell.metadata = e.metadata; + } else if (e.kind === NotebookCellsChangeType.ChangeCellInternalMetadata) { + const cell = this.cells[e.index]; + cell.internalMetadata = e.internalMetadata; } }); } diff --git a/src/vs/workbench/contrib/notebook/common/services/notebookWorkerServiceImpl.ts b/src/vs/workbench/contrib/notebook/common/services/notebookWorkerServiceImpl.ts index 395bf87c2ec..c5845369422 100644 --- a/src/vs/workbench/contrib/notebook/common/services/notebookWorkerServiceImpl.ts +++ b/src/vs/workbench/contrib/notebook/common/services/notebookWorkerServiceImpl.ts @@ -105,7 +105,8 @@ export class NotebookEditorModelManager extends Disposable { language: cell.language, cellKind: cell.cellKind, outputs: cell.outputs.map(op => ({ outputId: op.outputId, outputs: op.outputs })), - metadata: cell.metadata + metadata: cell.metadata, + internalMetadata: cell.internalMetadata, })), metadata: model.metadata } @@ -122,7 +123,8 @@ export class NotebookEditorModelManager extends Disposable { language: cell.language, cellKind: cell.cellKind, outputs: cell.outputs, - metadata: cell.metadata + metadata: cell.metadata, + internalMetadata: cell.internalMetadata, }; }; diff --git a/src/vs/workbench/contrib/notebook/test/notebookTextModel.test.ts b/src/vs/workbench/contrib/notebook/test/notebookTextModel.test.ts index a0aa9c41836..5a3969a77f4 100644 --- a/src/vs/workbench/contrib/notebook/test/notebookTextModel.test.ts +++ b/src/vs/workbench/contrib/notebook/test/notebookTextModel.test.ts @@ -294,7 +294,7 @@ suite('NotebookTextModel', () => { textModel.applyEdits([{ index: 0, editType: CellEditType.Metadata, - metadata: { executionOrder: 15 }, + metadata: { customProperty: 15 }, }], true, undefined, () => undefined, undefined); textModel.applyEdits([{ @@ -304,7 +304,7 @@ suite('NotebookTextModel', () => { }], true, undefined, () => undefined, undefined); assert.strictEqual(textModel.cells.length, 1); - assert.strictEqual(textModel.cells[0].metadata?.executionOrder, undefined); + assert.strictEqual(textModel.cells[0].metadata?.customProperty, undefined); } ); }); @@ -320,7 +320,7 @@ suite('NotebookTextModel', () => { textModel.applyEdits([{ index: 0, editType: CellEditType.PartialMetadata, - metadata: { executionOrder: 15 }, + metadata: { customProperty: 15 }, }], true, undefined, () => undefined, undefined); textModel.applyEdits([{ @@ -330,7 +330,7 @@ suite('NotebookTextModel', () => { }], true, undefined, () => undefined, undefined); assert.strictEqual(textModel.cells.length, 1); - assert.strictEqual(textModel.cells[0].metadata?.executionOrder, 15); + assert.strictEqual(textModel.cells[0].metadata?.customProperty, 15); } ); }); diff --git a/src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts b/src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts index 7ec10b0a28e..b36dc8d6b8a 100644 --- a/src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts +++ b/src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts @@ -55,7 +55,7 @@ export class TestCell extends NotebookCellTextModel { outputs: IOutputDto[], modeService: IModeService, ) { - super(CellUri.generate(URI.parse('test:///fake/notebook'), handle), handle, source, language, cellKind, outputs, undefined, { transientCellMetadata: {}, transientDocumentMetadata: {}, transientOutputs: false }, modeService); + super(CellUri.generate(URI.parse('test:///fake/notebook'), handle), handle, source, language, cellKind, outputs, undefined, undefined, { transientCellMetadata: {}, transientDocumentMetadata: {}, transientOutputs: false }, modeService); } } diff --git a/src/vs/workbench/test/browser/api/extHostNotebook.test.ts b/src/vs/workbench/test/browser/api/extHostNotebook.test.ts index 682b3e7d658..edc23df29ae 100644 --- a/src/vs/workbench/test/browser/api/extHostNotebook.test.ts +++ b/src/vs/workbench/test/browser/api/extHostNotebook.test.ts @@ -13,7 +13,7 @@ import { mock } from 'vs/base/test/common/mock'; import { IModelAddedData, MainContext, MainThreadCommandsShape, MainThreadNotebookShape } from 'vs/workbench/api/common/extHost.protocol'; import { ExtHostNotebookController } from 'vs/workbench/api/common/extHostNotebook'; import { ExtHostNotebookDocument } from 'vs/workbench/api/common/extHostNotebookDocument'; -import { CellKind, CellUri, NotebookCellExecutionState, NotebookCellsChangeType } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { CellKind, CellUri, NotebookCellsChangeType } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { URI } from 'vs/base/common/uri'; import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments'; import { ExtHostCommands } from 'vs/workbench/api/common/extHostCommands'; @@ -412,30 +412,4 @@ suite('NotebookCell#Document', function () { assert.strictEqual(first.document.languageId, 'fooLang'); assert.ok(removedDoc === addedDoc); }); - - test('change cell execution state does not trigger onDidChangeMetadata event', async function () { - let didFireOnDidChangeMetadata = false; - let e = extHostNotebooks.onDidChangeCellMetadata(() => { - didFireOnDidChangeMetadata = true; - }); - - const changeExeState = Event.toPromise(extHostNotebooks.onDidChangeNotebookCellExecutionState); - - extHostNotebooks.$acceptModelChanged(notebook.uri, { - versionId: 12, rawEvents: [{ - kind: NotebookCellsChangeType.ChangeCellMetadata, - index: 0, - metadata: { - ...notebook.getCellFromIndex(0)?.internalMetadata, - ...{ - runState: NotebookCellExecutionState.Executing - } - } - }] - }, false); - - await changeExeState; - assert.strictEqual(didFireOnDidChangeMetadata, false); - e.dispose(); - }); });