@@ -10,7 +10,7 @@ import { URI } from 'vs/base/common/uri';
1010import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel' ;
1111import { INotebookTextModel , NotebookCellOutputsSplice , NotebookCellTextModelSplice , NotebookDocumentMetadata , NotebookCellMetadata , ICellEditOperation , CellEditType , CellUri , ICellInsertEdit , NotebookCellsChangedEvent , CellKind , IProcessedOutput , notebookDocumentMetadataDefaults , diff , ICellDeleteEdit , NotebookCellsChangeType , ICellDto2 , IMainCellDto } from 'vs/workbench/contrib/notebook/common/notebookCommon' ;
1212import { ITextSnapshot } from 'vs/editor/common/model' ;
13- import { IUndoRedoService , UndoRedoElementType } from 'vs/platform/undoRedo/common/undoRedo' ;
13+ import { IUndoRedoService , UndoRedoElementType , IUndoRedoElement , IResourceUndoRedoElement } from 'vs/platform/undoRedo/common/undoRedo' ;
1414import { InsertCellEdit , DeleteCellEdit , MoveCellEdit , SpliceCellsEdit } from 'vs/workbench/contrib/notebook/common/model/cellEdit' ;
1515import { ITextModelService } from 'vs/editor/common/services/resolverService' ;
1616
@@ -66,6 +66,53 @@ export class NotebookTextModelSnapshot implements ITextSnapshot {
6666
6767}
6868
69+ class StackOperation implements IResourceUndoRedoElement {
70+ type : UndoRedoElementType . Resource ;
71+
72+ private _operations : IUndoRedoElement [ ] = [ ] ;
73+
74+ constructor ( readonly resource : URI , readonly label : string ) {
75+ this . type = UndoRedoElementType . Resource ;
76+ }
77+
78+ pushEditOperation ( element : IUndoRedoElement ) {
79+ this . _operations . push ( element ) ;
80+ }
81+
82+ undo ( ) : void {
83+ this . _operations . reverse ( ) . forEach ( o => o . undo ( ) ) ;
84+ }
85+ redo ( ) : void | Promise < void > {
86+ this . _operations . forEach ( o => o . redo ( ) ) ;
87+ }
88+ }
89+
90+ export class NotebookOperationManager {
91+ private _pendingStackOperation : StackOperation | null = null ;
92+ constructor ( private _undoService : IUndoRedoService , private _resource : URI ) {
93+
94+ }
95+
96+ pushStackElement ( label : string ) {
97+ if ( this . _pendingStackOperation ) {
98+ this . _undoService . pushElement ( this . _pendingStackOperation ) ;
99+ this . _pendingStackOperation = null ;
100+ return ;
101+ }
102+
103+ this . _pendingStackOperation = new StackOperation ( this . _resource , label ) ;
104+ }
105+
106+ pushEditOperation ( element : IUndoRedoElement ) {
107+ if ( this . _pendingStackOperation ) {
108+ this . _pendingStackOperation . pushEditOperation ( element ) ;
109+ return ;
110+ }
111+
112+ this . _undoService . pushElement ( element ) ;
113+ }
114+ }
115+
69116export class NotebookTextModel extends Disposable implements INotebookTextModel {
70117
71118 private _cellhandlePool : number = 0 ;
@@ -112,6 +159,8 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
112159 protected readonly _onDidChangeDirty = this . _register ( new Emitter < void > ( ) ) ;
113160 readonly onDidChangeDirty = this . _onDidChangeDirty . event ;
114161
162+ private _operationManager : NotebookOperationManager ;
163+
115164 constructor (
116165 public handle : number ,
117166 public viewType : string ,
@@ -122,6 +171,8 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
122171 ) {
123172 super ( ) ;
124173 this . cells = [ ] ;
174+
175+ this . _operationManager = new NotebookOperationManager ( this . _undoService , uri ) ;
125176 }
126177
127178 get isDirty ( ) {
@@ -173,6 +224,10 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
173224 this . _increaseVersionId ( ) ;
174225 }
175226
227+ pushStackElement ( label : string ) {
228+ this . _operationManager . pushStackElement ( label ) ;
229+ }
230+
176231 $applyEdit ( modelVersionId : number , rawEdits : ICellEditOperation [ ] , synchronous : boolean ) : boolean {
177232 if ( modelVersionId !== this . _versionId ) {
178233 return false ;
@@ -255,7 +310,7 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
255310 return [ diff [ 0 ] , deletedCells , diff [ 2 ] ] as [ number , NotebookCellTextModel [ ] , NotebookCellTextModel [ ] ] ;
256311 } ) ;
257312
258- this . _undoService . pushElement ( new SpliceCellsEdit ( this . uri , undoDiff , {
313+ this . _operationManager . pushEditOperation ( new SpliceCellsEdit ( this . uri , undoDiff , {
259314 insertCell : this . _insertCellDelegate . bind ( this ) ,
260315 deleteCell : this . _deleteCellDelegate . bind ( this ) ,
261316 emitSelections : this . _emitSelectionsDelegate . bind ( this )
@@ -266,7 +321,7 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
266321 }
267322
268323 $handleEdit ( label : string | undefined , undo : ( ) => void , redo : ( ) => void ) : void {
269- this . _undoService . pushElement ( {
324+ this . _operationManager . pushEditOperation ( {
270325 type : UndoRedoElementType . Resource ,
271326 resource : this . uri ,
272327 label : label ?? nls . localize ( 'defaultEditLabel' , "Edit" ) ,
@@ -502,7 +557,7 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
502557 const cell = this . createCellTextModel ( source , language , type , [ ] , metadata ) ;
503558
504559 if ( pushUndoStop ) {
505- this . _undoService . pushElement ( new InsertCellEdit ( this . uri , index , cell , {
560+ this . _operationManager . pushEditOperation ( new InsertCellEdit ( this . uri , index , cell , {
506561 insertCell : this . _insertCellDelegate . bind ( this ) ,
507562 deleteCell : this . _deleteCellDelegate . bind ( this ) ,
508563 emitSelections : this . _emitSelectionsDelegate . bind ( this )
@@ -522,7 +577,7 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
522577
523578 insertCell2 ( index : number , cell : NotebookCellTextModel , synchronous : boolean , pushUndoStop : boolean ) : void {
524579 if ( pushUndoStop ) {
525- this . _undoService . pushElement ( new InsertCellEdit ( this . uri , index , cell , {
580+ this . _operationManager . pushEditOperation ( new InsertCellEdit ( this . uri , index , cell , {
526581 insertCell : this . _insertCellDelegate . bind ( this ) ,
527582 deleteCell : this . _deleteCellDelegate . bind ( this ) ,
528583 emitSelections : this . _emitSelectionsDelegate . bind ( this )
@@ -536,7 +591,7 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
536591 deleteCell2 ( index : number , synchronous : boolean , pushUndoStop : boolean , beforeSelections : number [ ] | undefined , endSelections : number [ ] | undefined ) {
537592 const cell = this . cells [ index ] ;
538593 if ( pushUndoStop ) {
539- this . _undoService . pushElement ( new DeleteCellEdit ( this . uri , index , cell , {
594+ this . _operationManager . pushEditOperation ( new DeleteCellEdit ( this . uri , index , cell , {
540595 insertCell : this . _insertCellDelegate . bind ( this ) ,
541596 deleteCell : this . _deleteCellDelegate . bind ( this ) ,
542597 emitSelections : this . _emitSelectionsDelegate . bind ( this )
@@ -553,7 +608,7 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
553608 moveCellToIdx2 ( index : number , newIdx : number , synchronous : boolean , pushedToUndoStack : boolean , beforeSelections : number [ ] | undefined , endSelections : number [ ] | undefined ) : boolean {
554609 const cell = this . cells [ index ] ;
555610 if ( pushedToUndoStack ) {
556- this . _undoService . pushElement ( new MoveCellEdit ( this . uri , index , newIdx , {
611+ this . _operationManager . pushEditOperation ( new MoveCellEdit ( this . uri , index , newIdx , {
557612 moveCell : ( fromIndex : number , toIndex : number , beforeSelections : number [ ] | undefined , endSelections : number [ ] | undefined ) => {
558613 this . moveCellToIdx2 ( fromIndex , toIndex , true , false , beforeSelections , endSelections ) ;
559614 } ,
0 commit comments