diff --git a/lib/ace/undomanager.js b/lib/ace/undomanager.js index 304dac23..4d978d46 100644 --- a/lib/ace/undomanager.js +++ b/lib/ace/undomanager.js @@ -61,14 +61,19 @@ var UndoManager = function() { * **/ this.execute = function(options) { - var deltas = options.args[0]; + + // Normalize deltas for storage. + var deltaSets = this.$serializeDeltas(options.args[0]); + + // Add deltas to undo stack. this.$doc = options.args[1]; if (options.merge && this.hasUndo()){ - deltas = this.$undoStack.pop().concat(deltas); + deltaSets = this.$undoStack.pop().concat(deltaSets); } - this.$undoStack.push(deltas); + this.$undoStack.push(deltaSets); + + // Reset redo stack. this.$redoStack = []; - if (this.dirtyCounter < 0) { // The user has made a change after undoing past the last clean state. // We can never get back to a clean state now until markClean() is called. @@ -85,12 +90,11 @@ var UndoManager = function() { * @returns {Range} The range of the undo. **/ this.undo = function(dontSelect) { - var deltas = this.$undoStack.pop(); + var deltaSets = this.$undoStack.pop(); var undoSelectionRange = null; - if (deltas) { - undoSelectionRange = - this.$doc.undoChanges(deltas, dontSelect); - this.$redoStack.push(deltas); + if (deltaSets) { + undoSelectionRange = this.$doc.undoChanges(this.$deserializeDeltas(deltaSets), dontSelect); + this.$redoStack.push(deltaSets); this.dirtyCounter--; } @@ -104,15 +108,14 @@ var UndoManager = function() { * **/ this.redo = function(dontSelect) { - var deltas = this.$redoStack.pop(); + var deltaSets = this.$redoStack.pop(); var redoSelectionRange = null; - if (deltas) { + if (deltaSets) { redoSelectionRange = - this.$doc.redoChanges(deltas, dontSelect); - this.$undoStack.push(deltas); + this.$doc.redoChanges(this.$deserializeDeltas(deltaSets), dontSelect); + this.$undoStack.push(deltaSets); this.dirtyCounter++; } - return redoSelectionRange; }; @@ -160,7 +163,54 @@ var UndoManager = function() { this.isClean = function() { return this.dirtyCounter === 0; }; - + + // Serializes deltaSets to reduce memory usage. + this.$serializeDeltas = function(deltaSets) + { + return this.$cloneDeltaSetsObj(deltaSets, $serializeDelta); + } + function $serializeDelta(delta){ + return { + action: delta.action, + range: delta.range, + lines: (delta.lines.length == 1 ? null : delta.lines), + text: (delta.lines.length == 1 ? delta.lines[0] : null ), + }; + } + + // Deserializes deltaSets to allow application to the document. + this.$deserializeDeltas = function(deltaSets) + { + return this.$cloneDeltaSetsObj(deltaSets, $deserializeDelta); + } + function $deserializeDelta(delta){ + return { + action: delta.action, + range: delta.range, + lines: (delta.text === null ? delta.lines : [delta.text]) + }; + } + + // Helper for delta serialization and deserialization. + this.$cloneDeltaSetsObj = function(deltaSets_old, fnGetModifiedDelta) + { + var deltaSets_new = new Array(deltaSets_old.length); + for (var i in deltaSets_old) + { + var deltaSet_old = deltaSets_old[i]; + var deltaSet_new = { group: deltaSet_old.group, deltas: new Array(deltaSet_old.length)}; + + for (var i_ in deltaSet_old.deltas) + { + var delta_old = deltaSet_old.deltas[i_]; + deltaSet_new.deltas[i_] = fnGetModifiedDelta(delta_old); + } + + deltaSets_new[i] = deltaSet_new; + } + return deltaSets_new; + } + }).call(UndoManager.prototype); exports.UndoManager = UndoManager;