diff --git a/src/vs/workbench/api/common/extHostNotebook.ts b/src/vs/workbench/api/common/extHostNotebook.ts index e6429ff35aef9a4a444c782770d2bbb799d1d482..9c639c41567968334565384d3a914e6ea04cc66e 100644 --- a/src/vs/workbench/api/common/extHostNotebook.ts +++ b/src/vs/workbench/api/common/extHostNotebook.ts @@ -428,9 +428,9 @@ export class ExtHostNotebookDocument extends Disposable { this._emitter.emitCellLanguageChange(event); } - private _changeCellMetadata(index: number, newMetadata: NotebookCellMetadata): void { + private _changeCellMetadata(index: number, newMetadata: NotebookCellMetadata | undefined): void { const cell = this._cells[index]; - cell.setMetadata(newMetadata); + cell.setMetadata(newMetadata || {}); const event: vscode.NotebookCellMetadataChangeEvent = { document: this.notebookDocument, cell: cell.cell }; this._emitter.emitCellMetadataChange(event); } diff --git a/src/vs/workbench/contrib/notebook/browser/diff/cellComponents.ts b/src/vs/workbench/contrib/notebook/browser/diff/cellComponents.ts index 2d5a9a1e84092cc6415d1436aec2618d1a17aed7..4bc5911f51b0623ef691c5faef5ef5d8a5d7130c 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/cellComponents.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/cellComponents.ts @@ -235,7 +235,7 @@ abstract class AbstractCellRenderer extends Disposable { { updateInfoRendering: this.updateMetadataRendering.bind(this), checkIfModified: (cell) => { - return cell.type === 'modified' && hash(cell.original?.metadata ?? {}) !== hash(cell.modified?.metadata ?? {}); + return cell.type === 'modified' && hash(this._getFormatedMetadataJSON(cell.original?.metadata || {})) !== hash(this._getFormatedMetadataJSON(cell.modified?.metadata ?? {})); }, getFoldingState: (cell) => { return cell.metadataFoldingState; @@ -321,10 +321,25 @@ abstract class AbstractCellRenderer extends Disposable { } } - private _getFormatedMetadataJSON(metadata: NotebookCellMetadata, language?: string) { + protected _getFormatedMetadataJSON(metadata: NotebookCellMetadata, language?: string) { + let filteredMetadata: { [key: string]: any } = {}; + if (this.notebookEditor.textModel) { + const transientMetadata = this.notebookEditor.textModel!.transientMetadata; + + const keys = new Set([...Object.keys(metadata)]); + for (let key of keys) { + if (!(transientMetadata[key as keyof NotebookCellMetadata]) + ) { + filteredMetadata[key] = metadata[key as keyof NotebookCellMetadata]; + } + } + } else { + filteredMetadata = metadata; + } + const content = JSON.stringify({ language, - ...metadata + ...filteredMetadata }); const edits = format(content, undefined, {}); diff --git a/src/vs/workbench/contrib/notebook/browser/diff/common.ts b/src/vs/workbench/contrib/notebook/browser/diff/common.ts index 7bc82bd4f9eccc4ec98edd44919e3b866c73e908..505718cea7ce018efc0d23a6f2d38761d779dd79 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/common.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/common.ts @@ -8,8 +8,10 @@ import { CellDiffViewModel } from 'vs/workbench/contrib/notebook/browser/diff/ce import { Event } from 'vs/base/common/event'; import { BareFontInfo } from 'vs/editor/common/config/fontInfo'; import { DisposableStore } from 'vs/base/common/lifecycle'; +import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel'; export interface INotebookTextDiffEditor { + readonly textModel?: NotebookTextModel; onMouseUp: Event<{ readonly event: MouseEvent; readonly target: CellDiffViewModel; }>; getOverflowContainerDomNode(): HTMLElement; getLayoutInfo(): NotebookLayoutInfo; diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts index 45413b3711b6578cefd4ac449c5528075b4a3c02..de6076b0ff3ef57fd4905838a6792bef279bb1b5 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts @@ -30,6 +30,7 @@ import { Emitter } from 'vs/base/common/event'; import { IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { NotebookDiffEditorEventDispatcher, NotebookLayoutChangedEvent } from 'vs/workbench/contrib/notebook/browser/viewModel/eventDispatcher'; import { EditorPane } from 'vs/workbench/browser/parts/editor/editorPane'; +import { INotebookDiffEditorModel } from 'vs/workbench/contrib/notebook/common/notebookCommon'; export const IN_NOTEBOOK_TEXT_DIFF_EDITOR = new RawContextKey('isInNotebookTextDiffEditor', false); @@ -46,6 +47,10 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD public readonly onMouseUp = this._onMouseUp.event; private _eventDispatcher: NotebookDiffEditorEventDispatcher | undefined; protected _scopeContextKeyService!: IContextKeyService; + private _model: INotebookDiffEditorModel | null = null; + get textModel() { + return this._model?.modified.notebook; + } constructor( @IInstantiationService readonly instantiationService: IInstantiationService, @@ -132,19 +137,19 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD async setInput(input: NotebookDiffEditorInput, options: EditorOptions | undefined, context: IEditorOpenContext, token: CancellationToken): Promise { await super.setInput(input, options, context, token); - const model = await input.resolve(); - if (model === null) { + this._model = await input.resolve(); + if (this._model === null) { return; } this._eventDispatcher = new NotebookDiffEditorEventDispatcher(); - const diffResult = await this.notebookEditorWorkerService.computeDiff(model.original.resource, model.modified.resource); + const diffResult = await this.notebookEditorWorkerService.computeDiff(this._model.original.resource, this._model.modified.resource); const cellChanges = diffResult.cellsDiff.changes; const cellDiffViewModels: CellDiffViewModel[] = []; - const originalModel = model.original.notebook; - const modifiedModel = model.modified.notebook; + const originalModel = this._model.original.notebook; + const modifiedModel = this._model.modified.notebook; let originalCellIndex = 0; let modifiedCellIndex = 0; diff --git a/src/vs/workbench/contrib/notebook/browser/notebookDiffEditorInput.ts b/src/vs/workbench/contrib/notebook/browser/notebookDiffEditorInput.ts index efb4c9a703fc1b2c05f48bbe178b6029381395d2..be382dcd70da308eacd47cc70312c03503714f5a 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookDiffEditorInput.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookDiffEditorInput.ts @@ -198,14 +198,6 @@ ${patterns} if (!this._textModel) { this._textModel = await this._notebookModelResolverService.resolve(this.resource, this.viewType!, editorId); this._originalTextModel = await this._notebookModelResolverService.resolve(this.originalResource, this.viewType!, editorId); - - // this._register(this._textModel.object.onDidChangeDirty(() => { - // this._onDidChangeDirty.fire(); - // })); - - // if (this._textModel.object.isDirty()) { - // this._onDidChangeDirty.fire(); - // } } return new NotebookDiffEditorModel(this._originalTextModel!.object as NotebookEditorModel, this._textModel.object as NotebookEditorModel); diff --git a/src/vs/workbench/contrib/notebook/common/model/cellEdit.ts b/src/vs/workbench/contrib/notebook/common/model/cellEdit.ts index abd87ce1d2c4047f54337157021962716c357712..5cde6b3bfaa5d24f522acd01eb61abea7f7aa27c 100644 --- a/src/vs/workbench/contrib/notebook/common/model/cellEdit.ts +++ b/src/vs/workbench/contrib/notebook/common/model/cellEdit.ts @@ -15,7 +15,7 @@ export interface ITextCellEditingDelegate { insertCell?(index: number, cell: NotebookCellTextModel): void; deleteCell?(index: number): void; moveCell?(fromIndex: number, length: number, toIndex: number, beforeSelections: number[] | undefined, endSelections: number[] | undefined): void; - updateCellMetadata?(index: number, newMetadata: NotebookCellMetadata | undefined): void; + updateCellMetadata?(index: number, newMetadata: NotebookCellMetadata): void; emitSelections(selections: number[]): void; } @@ -192,8 +192,8 @@ export class CellMetadataEdit implements IResourceUndoRedoElement { constructor( public resource: URI, readonly index: number, - readonly oldMetadata: NotebookCellMetadata | undefined, - readonly newMetadata: NotebookCellMetadata | undefined, + readonly oldMetadata: NotebookCellMetadata, + readonly newMetadata: NotebookCellMetadata, private editingDelegate: ITextCellEditingDelegate, ) { diff --git a/src/vs/workbench/contrib/notebook/common/model/notebookCellTextModel.ts b/src/vs/workbench/contrib/notebook/common/model/notebookCellTextModel.ts index 2e85398d330935adcba71d416398aabe46f01114..6d4b29511e210022dba7f24cf2d3c35f9e161c0c 100644 --- a/src/vs/workbench/contrib/notebook/common/model/notebookCellTextModel.ts +++ b/src/vs/workbench/contrib/notebook/common/model/notebookCellTextModel.ts @@ -32,13 +32,13 @@ export class NotebookCellTextModel extends Disposable implements ICell { return this._outputs; } - private _metadata: NotebookCellMetadata | undefined; + private _metadata: NotebookCellMetadata; get metadata() { return this._metadata; } - set metadata(newMetadata: NotebookCellMetadata | undefined) { + set metadata(newMetadata: NotebookCellMetadata) { this._metadata = newMetadata; this._hash = null; this._onDidChangeMetadata.fire(); @@ -89,7 +89,7 @@ export class NotebookCellTextModel extends Disposable implements ICell { ) { super(); this._outputs = outputs; - this._metadata = metadata; + this._metadata = metadata || {}; } getValue(): string { diff --git a/src/vs/workbench/contrib/notebook/common/model/notebookTextModel.ts b/src/vs/workbench/contrib/notebook/common/model/notebookTextModel.ts index 79903890afc38a78126da25974aaa5474f01dac0..3dc85af8047c4ca0b295cfba66b7b9cb9d58c7bc 100644 --- a/src/vs/workbench/contrib/notebook/common/model/notebookTextModel.ts +++ b/src/vs/workbench/contrib/notebook/common/model/notebookTextModel.ts @@ -187,7 +187,7 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel ) { const cellHandle = this._cellhandlePool++; const cellUri = CellUri.generate(this.uri, cellHandle); - return new NotebookCellTextModel(cellUri, cellHandle, source, language, cellKind, outputs || [], metadata, this._modelService); + return new NotebookCellTextModel(cellUri, cellHandle, source, language, cellKind, outputs || [], metadata || {}, this._modelService); } initialize(cells: ICellDto2[]) { @@ -497,59 +497,22 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel } } - private _compareCellMetadata(a: NotebookCellMetadata | undefined, b: NotebookCellMetadata | undefined) { - if (a?.editable !== b?.editable && !this.transientMetadata.editable) { - return true; - } - - if (a?.runnable !== b?.runnable && !this.transientMetadata.runnable) { - return true; - } - - if (a?.breakpointMargin !== b?.breakpointMargin && !this.transientMetadata.breakpointMargin) { - return true; - } - - if (a?.hasExecutionOrder !== b?.hasExecutionOrder && !this.transientMetadata.hasExecutionOrder) { - return true; - } - - if (a?.executionOrder !== b?.executionOrder && !this.transientMetadata.executionOrder) { - return true; - } - - if (a?.statusMessage !== b?.statusMessage && !this.transientMetadata.statusMessage) { - return true; - } - - if (a?.runState !== b?.runState && !this.transientMetadata.runState) { - return true; - } - - if (a?.runStartTime !== b?.runStartTime && !this.transientMetadata.runStartTime) { - return true; - } - - if (a?.lastRunDuration !== b?.lastRunDuration && !this.transientMetadata.lastRunDuration) { - return true; - } - - if (a?.inputCollapsed !== b?.inputCollapsed && !this.transientMetadata.inputCollapsed) { - return true; - } - - if (a?.outputCollapsed !== b?.outputCollapsed && !this.transientMetadata.outputCollapsed) { - return true; - } - - if (a?.custom !== b?.custom && !this.transientMetadata.custom) { - return true; + private _compareCellMetadata(a: NotebookCellMetadata, b: NotebookCellMetadata) { + const keys = new Set([...Object.keys(a || {}), ...Object.keys(b || {})]); + for (let key of keys) { + if ( + (a[key as keyof NotebookCellMetadata] !== b[key as keyof NotebookCellMetadata]) + && + !(this.transientMetadata[key as keyof NotebookCellMetadata]) + ) { + return true; + } } return false; } - changeCellMetadata(handle: number, metadata: NotebookCellMetadata | undefined, pushUndoStop: boolean) { + changeCellMetadata(handle: number, metadata: NotebookCellMetadata, pushUndoStop: boolean) { const cell = this.cells.find(cell => cell.handle === handle); if (!cell) { diff --git a/src/vs/workbench/contrib/notebook/common/notebookCommon.ts b/src/vs/workbench/contrib/notebook/common/notebookCommon.ts index f4327ddd295bc6b51f66520aa705326665192087..b634b6bd63e12878c02ed5bb6a001db09da19352 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookCommon.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookCommon.ts @@ -397,7 +397,7 @@ export interface NotebookCellsChangeMetadataEvent { readonly kind: NotebookCellsChangeType.ChangeMetadata; readonly versionId: number; readonly index: number; - readonly metadata: NotebookCellMetadata; + readonly metadata: NotebookCellMetadata | undefined; } export type NotebookCellsChangedEvent = NotebookCellsInitializeEvent | NotebookCellsModelChangedEvent | NotebookCellsModelMoveEvent | NotebookCellClearOutputEvent | NotebookCellsClearOutputEvent | NotebookCellsChangeLanguageEvent | NotebookCellsChangeMetadataEvent; diff --git a/src/vs/workbench/contrib/notebook/common/notebookEditorModelResolverService.ts b/src/vs/workbench/contrib/notebook/common/notebookEditorModelResolverService.ts index 139c02ae5b4eb0574096d1bc83977b27dc74e891..11587e612427a8317ce4dba0870c1616fe4259d9 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookEditorModelResolverService.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookEditorModelResolverService.ts @@ -76,3 +76,9 @@ export class NotebookModelResolverService implements INotebookEditorModelResolve }; } } + +// notebookService.onDidAddDocument + +// resolve() + +// notebookService.onDidRemoveDocument ...