Skip to content

Commit 7c986e9

Browse files
committed
transient metadata
1 parent 1fe5613 commit 7c986e9

File tree

10 files changed

+152
-33
lines changed

10 files changed

+152
-33
lines changed

src/vs/workbench/api/browser/mainThreadNotebook.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { MainContext, MainThreadNotebookShape, NotebookExtensionDescription, IEx
99
import { Disposable, IDisposable, combinedDisposable, DisposableStore } from 'vs/base/common/lifecycle';
1010
import { URI, UriComponents } from 'vs/base/common/uri';
1111
import { INotebookService, IMainNotebookController } from 'vs/workbench/contrib/notebook/common/notebookService';
12-
import { NOTEBOOK_DISPLAY_ORDER, NotebookCellOutputsSplice, NotebookDocumentMetadata, NotebookCellMetadata, ICellEditOperation, ACCESSIBLE_NOTEBOOK_DISPLAY_ORDER, CellEditType, CellKind, INotebookKernelInfo, INotebookKernelInfoDto, IEditor, INotebookDocumentFilter, DisplayOrderKey } from 'vs/workbench/contrib/notebook/common/notebookCommon';
12+
import { NOTEBOOK_DISPLAY_ORDER, NotebookCellOutputsSplice, NotebookDocumentMetadata, NotebookCellMetadata, ICellEditOperation, ACCESSIBLE_NOTEBOOK_DISPLAY_ORDER, CellEditType, CellKind, INotebookKernelInfo, INotebookKernelInfoDto, IEditor, INotebookDocumentFilter, DisplayOrderKey, TransientMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon';
1313
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
1414
import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel';
1515
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
@@ -375,10 +375,11 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
375375
// }
376376
}
377377

378-
async $registerNotebookProvider(_extension: NotebookExtensionDescription, _viewType: string, _supportBackup: boolean, _kernel: INotebookKernelInfoDto | undefined): Promise<void> {
378+
async $registerNotebookProvider(_extension: NotebookExtensionDescription, _viewType: string, _supportBackup: boolean, _kernel: INotebookKernelInfoDto | undefined, options: { transientMetadata: TransientMetadata }): Promise<void> {
379379
const controller: IMainNotebookController = {
380380
kernel: _kernel,
381381
supportBackup: _supportBackup,
382+
options: options,
382383
reloadNotebook: async (mainthreadTextModel: NotebookTextModel) => {
383384
const data = await this._proxy.$resolveNotebookData(_viewType, mainthreadTextModel.uri);
384385
if (!data) {
@@ -387,6 +388,7 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
387388

388389
mainthreadTextModel.languages = data.languages;
389390
mainthreadTextModel.metadata = data.metadata;
391+
mainthreadTextModel.transientMetadata = options.transientMetadata;
390392

391393
const edits: ICellEditOperation[] = [
392394
{ editType: CellEditType.Delete, count: mainthreadTextModel.cells.length, index: 0 },
@@ -410,6 +412,7 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
410412

411413
textModel.languages = data.languages;
412414
textModel.metadata = data.metadata;
415+
textModel.transientMetadata = options.transientMetadata;
413416

414417
if (data.cells.length) {
415418
textModel.initialize(data!.cells);
@@ -551,7 +554,7 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
551554
async $updateNotebookCellMetadata(viewType: string, resource: UriComponents, handle: number, metadata: NotebookCellMetadata): Promise<void> {
552555
this.logService.debug('MainThreadNotebooks#updateNotebookCellMetadata', resource.path, handle, metadata);
553556
const textModel = this._notebookService.getNotebookTextModel(URI.from(resource));
554-
textModel?.updateNotebookCellMetadata(handle, metadata);
557+
textModel?.changeCellMetadata(handle, metadata, true);
555558
}
556559

557560
async $spliceNotebookCellOutputs(viewType: string, resource: UriComponents, cellHandle: number, splices: NotebookCellOutputsSplice[]): Promise<void> {

src/vs/workbench/api/common/extHost.api.impl.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -950,9 +950,11 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
950950
checkProposedApiEnabled(extension);
951951
return extHostNotebook.onDidChangeActiveNotebookKernel;
952952
},
953-
registerNotebookContentProvider: (viewType: string, provider: vscode.NotebookContentProvider) => {
953+
registerNotebookContentProvider: (viewType: string, provider: vscode.NotebookContentProvider, options?: {
954+
transientMetadata?: { [K in keyof vscode.NotebookCellMetadata]?: boolean }
955+
}) => {
954956
checkProposedApiEnabled(extension);
955-
return extHostNotebook.registerNotebookContentProvider(extension, viewType, provider);
957+
return extHostNotebook.registerNotebookContentProvider(extension, viewType, provider, options);
956958
},
957959
registerNotebookKernel: (id: string, selector: vscode.GlobPattern[], kernel: vscode.NotebookKernel) => {
958960
checkProposedApiEnabled(extension);

src/vs/workbench/api/common/extHost.protocol.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ import { TunnelDto } from 'vs/workbench/api/common/extHostTunnelService';
5151
import { TunnelOptions } from 'vs/platform/remote/common/tunnel';
5252
import { Timeline, TimelineChangeEvent, TimelineOptions, TimelineProviderDescriptor, InternalTimelineOptions } from 'vs/workbench/contrib/timeline/common/timeline';
5353
import { revive } from 'vs/base/common/marshalling';
54-
import { IProcessedOutput, INotebookDisplayOrder, NotebookCellMetadata, NotebookDocumentMetadata, ICellEditOperation, NotebookCellsChangedEvent, NotebookDataDto, INotebookKernelInfoDto, IMainCellDto, INotebookDocumentFilter, INotebookKernelInfoDto2 } from 'vs/workbench/contrib/notebook/common/notebookCommon';
54+
import { IProcessedOutput, INotebookDisplayOrder, NotebookCellMetadata, NotebookDocumentMetadata, ICellEditOperation, NotebookCellsChangedEvent, NotebookDataDto, INotebookKernelInfoDto, IMainCellDto, INotebookDocumentFilter, INotebookKernelInfoDto2, TransientMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon';
5555
import { CallHierarchyItem } from 'vs/workbench/contrib/callHierarchy/common/callHierarchy';
5656
import { Dto } from 'vs/base/common/types';
5757
import { ISerializableEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariable';
@@ -715,7 +715,7 @@ export type NotebookCellOutputsSplice = [
715715
];
716716

717717
export interface MainThreadNotebookShape extends IDisposable {
718-
$registerNotebookProvider(extension: NotebookExtensionDescription, viewType: string, supportBackup: boolean, kernelInfoDto: INotebookKernelInfoDto | undefined): Promise<void>;
718+
$registerNotebookProvider(extension: NotebookExtensionDescription, viewType: string, supportBackup: boolean, kernelInfoDto: INotebookKernelInfoDto | undefined, options: { transientMetadata: TransientMetadata }): Promise<void>;
719719
$onNotebookChange(viewType: string, resource: UriComponents): Promise<void>;
720720
$unregisterNotebookProvider(viewType: string): Promise<void>;
721721
$registerNotebookKernel(extension: NotebookExtensionDescription, id: string, label: string, selectors: (string | IRelativePattern)[], preloads: UriComponents[]): Promise<void>;

src/vs/workbench/api/common/extHostNotebook.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -954,6 +954,9 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
954954
extension: IExtensionDescription,
955955
viewType: string,
956956
provider: vscode.NotebookContentProvider & { kernel?: vscode.NotebookKernel },
957+
options?: {
958+
transientMetadata?: { [K in keyof NotebookCellMetadata]?: boolean }
959+
}
957960
): vscode.Disposable {
958961

959962
if (this._notebookContentProviders.has(viewType)) {
@@ -985,7 +988,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
985988

986989
const supportBackup = !!provider.backupNotebook;
987990

988-
this._proxy.$registerNotebookProvider({ id: extension.identifier, location: extension.extensionLocation, description: extension.description }, viewType, supportBackup, provider.kernel ? { id: viewType, label: provider.kernel.label, extensionLocation: extension.extensionLocation, preloads: provider.kernel.preloads } : undefined);
991+
this._proxy.$registerNotebookProvider({ id: extension.identifier, location: extension.extensionLocation, description: extension.description }, viewType, supportBackup, provider.kernel ? { id: viewType, label: provider.kernel.label, extensionLocation: extension.extensionLocation, preloads: provider.kernel.preloads } : undefined, { transientMetadata: options?.transientMetadata || {} });
989992

990993
return new extHostTypes.Disposable(() => {
991994
listener.dispose();

src/vs/workbench/contrib/notebook/browser/contrib/coreActions.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1292,7 +1292,7 @@ registerAction2(class extends NotebookCellAction {
12921292

12931293
editor.viewModel.notebookDocument.clearCellOutput(context.cell.handle);
12941294
if (context.cell.metadata && context.cell.metadata?.runState !== NotebookCellRunState.Running) {
1295-
context.notebookEditor.viewModel!.notebookDocument.changeCellMetadata(context.cell.handle, {
1295+
context.notebookEditor.viewModel!.notebookDocument.deltaCellMetadata(context.cell.handle, {
12961296
runState: NotebookCellRunState.Idle,
12971297
runStartTime: undefined,
12981298
lastRunDuration: undefined,
@@ -1562,7 +1562,7 @@ registerAction2(class extends NotebookCellAction {
15621562
}
15631563

15641564
async runWithContext(accessor: ServicesAccessor, context: INotebookCellActionContext): Promise<void> {
1565-
context.notebookEditor.viewModel!.notebookDocument.changeCellMetadata(context.cell.handle, { inputCollapsed: true });
1565+
context.notebookEditor.viewModel!.notebookDocument.deltaCellMetadata(context.cell.handle, { inputCollapsed: true });
15661566
}
15671567
});
15681568

@@ -1585,7 +1585,7 @@ registerAction2(class extends NotebookCellAction {
15851585
}
15861586

15871587
async runWithContext(accessor: ServicesAccessor, context: INotebookCellActionContext): Promise<void> {
1588-
context.notebookEditor.viewModel!.notebookDocument.changeCellMetadata(context.cell.handle, { inputCollapsed: false });
1588+
context.notebookEditor.viewModel!.notebookDocument.deltaCellMetadata(context.cell.handle, { inputCollapsed: false });
15891589
}
15901590
});
15911591

@@ -1608,7 +1608,7 @@ registerAction2(class extends NotebookCellAction {
16081608
}
16091609

16101610
async runWithContext(accessor: ServicesAccessor, context: INotebookCellActionContext): Promise<void> {
1611-
context.notebookEditor.viewModel!.notebookDocument.changeCellMetadata(context.cell.handle, { outputCollapsed: true });
1611+
context.notebookEditor.viewModel!.notebookDocument.deltaCellMetadata(context.cell.handle, { outputCollapsed: true });
16121612
}
16131613
});
16141614

@@ -1631,7 +1631,7 @@ registerAction2(class extends NotebookCellAction {
16311631
}
16321632

16331633
async runWithContext(accessor: ServicesAccessor, context: INotebookCellActionContext): Promise<void> {
1634-
context.notebookEditor.viewModel!.notebookDocument.changeCellMetadata(context.cell.handle, { outputCollapsed: false });
1634+
context.notebookEditor.viewModel!.notebookDocument.deltaCellMetadata(context.cell.handle, { outputCollapsed: false });
16351635
}
16361636
});
16371637

src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -329,9 +329,9 @@ abstract class AbstractCellRenderer {
329329
}
330330

331331
if (templateData.currentRenderedCell.metadata?.inputCollapsed) {
332-
this.notebookEditor.viewModel!.notebookDocument.changeCellMetadata(templateData.currentRenderedCell.handle, { inputCollapsed: false });
332+
this.notebookEditor.viewModel!.notebookDocument.deltaCellMetadata(templateData.currentRenderedCell.handle, { inputCollapsed: false });
333333
} else if (templateData.currentRenderedCell.metadata?.outputCollapsed) {
334-
this.notebookEditor.viewModel!.notebookDocument.changeCellMetadata(templateData.currentRenderedCell.handle, { outputCollapsed: false });
334+
this.notebookEditor.viewModel!.notebookDocument.deltaCellMetadata(templateData.currentRenderedCell.handle, { outputCollapsed: false });
335335
}
336336
}));
337337
}

src/vs/workbench/contrib/notebook/common/model/cellEdit.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import { IResourceUndoRedoElement, UndoRedoElementType } from 'vs/platform/undoRedo/common/undoRedo';
77
import { URI } from 'vs/base/common/uri';
88
import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel';
9+
import { NotebookCellMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon';
910

1011
/**
1112
* It should not modify Undo/Redo stack
@@ -14,6 +15,7 @@ export interface ITextCellEditingDelegate {
1415
insertCell?(index: number, cell: NotebookCellTextModel): void;
1516
deleteCell?(index: number): void;
1617
moveCell?(fromIndex: number, length: number, toIndex: number, beforeSelections: number[] | undefined, endSelections: number[] | undefined): void;
18+
updateCellMetadata?(index: number, newMetadata: NotebookCellMetadata | undefined): void;
1719
emitSelections(selections: number[]): void;
1820
}
1921

@@ -183,3 +185,33 @@ export class SpliceCellsEdit implements IResourceUndoRedoElement {
183185
}
184186
}
185187
}
188+
189+
export class CellMetadataEdit implements IResourceUndoRedoElement {
190+
type: UndoRedoElementType.Resource = UndoRedoElementType.Resource;
191+
label: string = 'Update Cell Metadata';
192+
constructor(
193+
public resource: URI,
194+
readonly index: number,
195+
readonly oldMetadata: NotebookCellMetadata | undefined,
196+
readonly newMetadata: NotebookCellMetadata | undefined,
197+
private editingDelegate: ITextCellEditingDelegate,
198+
) {
199+
200+
}
201+
202+
undo(): void {
203+
if (!this.editingDelegate.updateCellMetadata) {
204+
return;
205+
}
206+
207+
this.editingDelegate.updateCellMetadata(this.index, this.oldMetadata);
208+
}
209+
210+
redo(): void | Promise<void> {
211+
if (!this.editingDelegate.updateCellMetadata) {
212+
return;
213+
}
214+
215+
this.editingDelegate.updateCellMetadata(this.index, this.newMetadata);
216+
}
217+
}

src/vs/workbench/contrib/notebook/common/model/notebookTextModel.ts

Lines changed: 93 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@ import { Emitter, Event } from 'vs/base/common/event';
88
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
99
import { URI } from 'vs/base/common/uri';
1010
import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel';
11-
import { INotebookTextModel, NotebookCellOutputsSplice, NotebookCellTextModelSplice, NotebookDocumentMetadata, NotebookCellMetadata, ICellEditOperation, CellEditType, CellUri, NotebookCellsChangedEvent, CellKind, IProcessedOutput, notebookDocumentMetadataDefaults, diff, NotebookCellsChangeType, ICellDto2, IMainCellDto } from 'vs/workbench/contrib/notebook/common/notebookCommon';
11+
import { INotebookTextModel, NotebookCellOutputsSplice, NotebookCellTextModelSplice, NotebookDocumentMetadata, NotebookCellMetadata, ICellEditOperation, CellEditType, CellUri, NotebookCellsChangedEvent, CellKind, IProcessedOutput, notebookDocumentMetadataDefaults, diff, NotebookCellsChangeType, ICellDto2, IMainCellDto, TransientMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon';
1212
import { ITextSnapshot } from 'vs/editor/common/model';
1313
import { IUndoRedoService, UndoRedoElementType, IUndoRedoElement, IResourceUndoRedoElement } from 'vs/platform/undoRedo/common/undoRedo';
14-
import { InsertCellEdit, DeleteCellEdit, MoveCellEdit, SpliceCellsEdit } from 'vs/workbench/contrib/notebook/common/model/cellEdit';
14+
import { InsertCellEdit, DeleteCellEdit, MoveCellEdit, SpliceCellsEdit, CellMetadataEdit } from 'vs/workbench/contrib/notebook/common/model/cellEdit';
1515
import { ITextModelService } from 'vs/editor/common/services/resolverService';
1616

1717
export class NotebookTextModelSnapshot implements ITextSnapshot {
@@ -128,6 +128,7 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
128128
cells: NotebookCellTextModel[];
129129
languages: string[] = [];
130130
metadata: NotebookDocumentMetadata = notebookDocumentMetadataDefaults;
131+
transientMetadata: TransientMetadata = {};
131132
private _isUntitled: boolean | undefined = undefined;
132133
private _versionId = 0;
133134

@@ -259,7 +260,7 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
259260
break;
260261
case CellEditType.Metadata:
261262
this.assertIndex(edit.index);
262-
this.changeCellMetadata(this.cells[edit.index].handle, edit.metadata);
263+
this.deltaCellMetadata(this.cells[edit.index].handle, edit.metadata);
263264
break;
264265
}
265266
}
@@ -342,14 +343,6 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
342343
this._onDidChangeMetadata.fire(this.metadata);
343344
}
344345

345-
updateNotebookCellMetadata(handle: number, metadata: NotebookCellMetadata) {
346-
const cell = this.cells.find(cell => cell.handle === handle);
347-
348-
if (cell) {
349-
cell.metadata = metadata;
350-
}
351-
}
352-
353346
insertTemplateCell(cell: NotebookCellTextModel) {
354347
if (this.cells.length > 0 || this._isUntitled !== undefined) {
355348
return;
@@ -504,16 +497,99 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
504497
}
505498
}
506499

507-
changeCellMetadata(handle: number, newMetadata: NotebookCellMetadata) {
500+
private _compareCellMetadata(a: NotebookCellMetadata | undefined, b: NotebookCellMetadata | undefined) {
501+
if (a?.editable !== b?.editable && !this.transientMetadata.editable) {
502+
return true;
503+
}
504+
505+
if (a?.runnable !== b?.runnable && !this.transientMetadata.runnable) {
506+
return true;
507+
}
508+
509+
if (a?.breakpointMargin !== b?.breakpointMargin && !this.transientMetadata.breakpointMargin) {
510+
return true;
511+
}
512+
513+
if (a?.hasExecutionOrder !== b?.hasExecutionOrder && !this.transientMetadata.hasExecutionOrder) {
514+
return true;
515+
}
516+
517+
if (a?.executionOrder !== b?.executionOrder && !this.transientMetadata.executionOrder) {
518+
return true;
519+
}
520+
521+
if (a?.statusMessage !== b?.statusMessage && !this.transientMetadata.statusMessage) {
522+
return true;
523+
}
524+
525+
if (a?.runState !== b?.runState && !this.transientMetadata.runState) {
526+
return true;
527+
}
528+
529+
if (a?.runStartTime !== b?.runStartTime && !this.transientMetadata.runStartTime) {
530+
return true;
531+
}
532+
533+
if (a?.lastRunDuration !== b?.lastRunDuration && !this.transientMetadata.lastRunDuration) {
534+
return true;
535+
}
536+
537+
if (a?.inputCollapsed !== b?.inputCollapsed && !this.transientMetadata.inputCollapsed) {
538+
return true;
539+
}
540+
541+
if (a?.outputCollapsed !== b?.outputCollapsed && !this.transientMetadata.outputCollapsed) {
542+
return true;
543+
}
544+
545+
if (a?.custom !== b?.custom && !this.transientMetadata.custom) {
546+
return true;
547+
}
548+
549+
return false;
550+
}
551+
552+
changeCellMetadata(handle: number, metadata: NotebookCellMetadata | undefined, pushUndoStop: boolean) {
553+
const cell = this.cells.find(cell => cell.handle === handle);
554+
555+
if (!cell) {
556+
return;
557+
}
558+
559+
const triggerDirtyChange = this._compareCellMetadata(cell.metadata, metadata);
560+
561+
if (triggerDirtyChange) {
562+
if (pushUndoStop) {
563+
const index = this.cells.indexOf(cell);
564+
this._operationManager.pushEditOperation(new CellMetadataEdit(this.uri, index, Object.freeze(cell.metadata), Object.freeze(metadata), {
565+
updateCellMetadata: (index, newMetadata) => {
566+
const cell = this.cells[index];
567+
if (!cell) {
568+
return;
569+
}
570+
this.changeCellMetadata(cell.handle, newMetadata, false);
571+
},
572+
emitSelections: this._emitSelectionsDelegate.bind(this)
573+
}));
574+
}
575+
cell.metadata = metadata;
576+
this.setDirty(true);
577+
this._onDidChangeContent.fire();
578+
} else {
579+
cell.metadata = metadata;
580+
}
581+
582+
this._increaseVersionId();
583+
this._onDidModelChangeProxy.fire({ kind: NotebookCellsChangeType.ChangeMetadata, versionId: this._versionId, index: this.cells.indexOf(cell), metadata: cell.metadata });
584+
}
585+
586+
deltaCellMetadata(handle: number, newMetadata: NotebookCellMetadata) {
508587
const cell = this._mapping.get(handle);
509588
if (cell) {
510-
cell.metadata = {
589+
this.changeCellMetadata(handle, {
511590
...cell.metadata,
512591
...newMetadata
513-
};
514-
515-
this._increaseVersionId();
516-
this._onDidModelChangeProxy.fire({ kind: NotebookCellsChangeType.ChangeMetadata, versionId: this._versionId, index: this.cells.indexOf(cell), metadata: cell.metadata });
592+
}, true);
517593
}
518594
}
519595

src/vs/workbench/contrib/notebook/common/notebookCommon.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,8 @@ export interface NotebookCellMetadata {
103103
custom?: { [key: string]: unknown };
104104
}
105105

106+
export type TransientMetadata = { [K in keyof NotebookCellMetadata]?: boolean };
107+
106108
export interface INotebookDisplayOrder {
107109
defaultOrder: string[];
108110
userOrder?: string[];

0 commit comments

Comments
 (0)