diff --git a/src/sql/workbench/contrib/notebook/browser/cellViews/textCell.component.ts b/src/sql/workbench/contrib/notebook/browser/cellViews/textCell.component.ts index 0a8a3a997d..e6204e2b05 100644 --- a/src/sql/workbench/contrib/notebook/browser/cellViews/textCell.component.ts +++ b/src/sql/workbench/contrib/notebook/browser/cellViews/textCell.component.ts @@ -104,8 +104,8 @@ export class TextCellComponent extends CellView implements OnInit, OnChanges { private _highlightRange: NotebookRange; private _isFindActive: boolean = false; - private readonly _undoStack = new RichTextEditStack(); - private readonly _redoStack = new RichTextEditStack(); + private readonly _undoStack: RichTextEditStack; + private readonly _redoStack: RichTextEditStack; constructor( @Inject(forwardRef(() => ChangeDetectorRef)) private _changeRef: ChangeDetectorRef, @@ -118,6 +118,10 @@ export class TextCellComponent extends CellView implements OnInit, OnChanges { this.markdownRenderer = this._instantiationService.createInstance(NotebookMarkdownRenderer); this.doubleClickEditEnabled = this._configurationService.getValue('notebook.enableDoubleClickEdit'); this.markdownPreviewLineHeight = this._configurationService.getValue('notebook.markdownPreviewLineHeight'); + let maxStackSize: number = this._configurationService.getValue('notebook.maxRichTextUndoHistory'); + this._undoStack = new RichTextEditStack(maxStackSize); + this._redoStack = new RichTextEditStack(maxStackSize); + this._register(toDisposable(() => { if (this.markdownResult) { this.markdownResult.dispose(); @@ -130,6 +134,11 @@ export class TextCellComponent extends CellView implements OnInit, OnChanges { this.markdownPreviewLineHeight = this._configurationService.getValue('notebook.markdownPreviewLineHeight'); this.updatePreview(); } + if (e.affectsConfiguration('notebook.maxRichTextUndoHistory')) { + let newStackSize: number = this._configurationService.getValue('notebook.maxRichTextUndoHistory'); + this._undoStack.maxStackSize = newStackSize; + this._redoStack.maxStackSize = newStackSize; + } })); } @@ -551,12 +560,24 @@ function preventDefaultAndExecCommand(e: KeyboardEvent, commandId: string) { export class RichTextEditStack { private _list: string[] = []; + constructor(private _maxStackSize: number) { + } + + public set maxStackSize(stackSize: number) { + this._maxStackSize = stackSize; + } + /** - * Adds an element to the top of the stack. + * Adds an element to the top of the stack. If the number of elements + * exceeds the max stack size, then the oldest elements are removed until + * the max size is reached. * @param element The string element to add to the stack. */ public push(element: string): void { this._list.push(element); + if (this._list.length > this._maxStackSize) { + this._list = this._list.slice(this._list.length - this._maxStackSize); + } } /** diff --git a/src/sql/workbench/contrib/notebook/browser/notebook.contribution.ts b/src/sql/workbench/contrib/notebook/browser/notebook.contribution.ts index 5dd7b8d4c9..0dd5e0eff5 100644 --- a/src/sql/workbench/contrib/notebook/browser/notebook.contribution.ts +++ b/src/sql/workbench/contrib/notebook/browser/notebook.contribution.ts @@ -325,6 +325,12 @@ configurationRegistry.registerConfiguration({ 'default': false, 'description': localize('notebook.showRenderedNotebookinDiffEditor', "(Preview) Show rendered notebook in diff editor.") }, + 'notebook.maxRichTextUndoHistory': { + 'type': 'number', + 'default': 200, + 'minimum': 10, + 'description': localize('notebook.maxRichTextUndoHistory', "The maximum number of changes stored in the undo history for the notebook Rich Text editor.") + } } }); diff --git a/src/sql/workbench/contrib/notebook/test/electron-browser/notebookUtils.test.ts b/src/sql/workbench/contrib/notebook/test/electron-browser/notebookUtils.test.ts index 1bf9c3da1a..f0c45c6955 100644 --- a/src/sql/workbench/contrib/notebook/test/electron-browser/notebookUtils.test.ts +++ b/src/sql/workbench/contrib/notebook/test/electron-browser/notebookUtils.test.ts @@ -264,7 +264,8 @@ suite('notebookUtils', function (): void { }); test('EditStack test', async function (): Promise { - let stack = new RichTextEditStack(); + let maxStackSize = 200; + let stack = new RichTextEditStack(maxStackSize); assert.strictEqual(stack.count, 0); stack.push('1'); @@ -290,5 +291,21 @@ suite('notebookUtils', function (): void { topElement = stack.pop(); assert.strictEqual(topElement, undefined); assert.strictEqual(stack.peek(), undefined); + + // Check max stack size + stack.clear(); + for (let i = 0; i < maxStackSize; i++) { + stack.push('a'); + } + stack.push('b'); + assert.strictEqual(stack.count, maxStackSize); + assert.strictEqual(stack.peek(), 'b'); + + // update max stack size and add new element + maxStackSize = 20; + stack.maxStackSize = maxStackSize; + stack.push('c'); + assert.strictEqual(stack.count, maxStackSize); + assert.strictEqual(stack.peek(), 'c'); }); });