From 007125025fb3d68ab7053a193fbe477505cafe72 Mon Sep 17 00:00:00 2001 From: Julian Viereck Date: Fri, 29 Apr 2011 12:16:55 +0200 Subject: [PATCH] Fix bugs in undo/redo seleciton handling --- lib/ace/edit_session.js | 186 ++++++++++++++++++++-------------------- 1 file changed, 91 insertions(+), 95 deletions(-) diff --git a/lib/ace/edit_session.js b/lib/ace/edit_session.js index 570e374b..f6f5c5c5 100644 --- a/lib/ace/edit_session.js +++ b/lib/ace/edit_session.js @@ -107,10 +107,22 @@ var EditSession = function(text, mode) { this.$docChangeCounter --; console.log("<<< onChangeEnd", this.$docChangeCounter); if (this.$docChangeCounter == 0 - && this.$deltaFolds && this.$deltaFolds.length) + && !this.$fromUndo && this.$undoManager) { - this.$deltas = this.$deltaFolds.concat(this.$deltas); - this.$deltaFolds = []; + if (this.$deltasFold.length) { + this.$deltas.push({ + group: "fold", + deltas: this.$deltasFold + }); + this.$deltasFold = []; + } + if (this.$deltasDoc) { + this.$deltas.push({ + group: "doc", + deltas: this.$deltasDoc + }); + this.$deltasDoc = []; + } this.$informUndoManager.schedule(); } }; @@ -122,24 +134,14 @@ var EditSession = function(text, mode) { var removedFolds = this.$updateInternalDataOnChange(e); if (!this.$fromUndo && this.$undoManager && !delta.ignore) { console.log("onChange", JSON.stringify(delta)); - this.$deltas.push(delta); + this.$deltasDoc.push(delta); if (removedFolds && removedFolds.length != 0) { - this.$deltaFolds.push({ + this.$deltasFold.push({ action: "removeFolds", folds: removedFolds }); console.log("onChangeFold", removedFolds[0].toString()); } - // Only inform the undoManager about new deltas if there - // are no deltaFolds. As there are some deltasFolds, the - // undoManager get notified by the onChangeEnd once the - // change stack is empty. Calling this.$informUndoManager here - // might cause the current deltas get flushed to the undoManager - // before the change stack is empty and as such the deltaFolds might - // get added at the wrong position. - else if (!this.$deltaFolds.length) { - this.$informUndoManager.schedule(); - } } @@ -150,7 +152,8 @@ var EditSession = function(text, mode) { this.setValue = function(text) { this.doc.setValue(text); this.$deltas = []; - this.$deltaFolds = []; + this.$deltasDoc = []; + this.$deltasFold = []; this.getUndoManager().reset(); }; @@ -174,7 +177,8 @@ var EditSession = function(text, mode) { this.setUndoManager = function(undoManager) { this.$undoManager = undoManager; this.$deltas = []; - this.$deltaFolds = []; + this.$deltasDoc = []; + this.$deltasFold = []; if (this.$informUndoManager) { this.$informUndoManager.cancel(); @@ -655,106 +659,98 @@ var EditSession = function(text, mode) { return this.doc.remove(range); }; - var docActions = [ - "insertLines", - "insertText", - "removeLines", - "removeText" - ]; - - function filterDocActions(deltas) { - return deltas.filter(function(delta) { - return docActions.indexOf(delta.action) != -1; - }); - } - this.undoChanges = function(deltas) { if (!deltas.length) return; this.$fromUndo = true; - var docDeltas = filterDocActions(deltas); - if (docDeltas.length == deltas.length) { - this.doc.revertDeltas(deltas); - } else { - var groupDocDeltas = []; - for (var i = deltas.length - 1; i != -1; i--) { - delta = deltas[i]; - if (docActions.indexOf(delta.action) != -1) { - groupDocDeltas.push(delta); - } else { - groupDocDeltas.reverse() - this.doc.revertDeltas(groupDocDeltas); - this.$setUndoSelection(groupDocDeltas, true); - groupDocDeltas = []; - this.addFolds(delta.folds); - } + var lastUndoRange = null; + for (var i = deltas.length - 1; i != -1; i--) { + delta = deltas[i]; + if (delta.group == "doc") { + this.doc.revertDeltas(delta.deltas); + lastUndoRange = + this.$setUndoSelection(delta.deltas, true, lastUndoRange); + } else { + delta.deltas.forEach(function(foldDelta) { + this.addFolds(foldDelta.folds); + }, this); } - this.doc.revertDeltas(groupDocDeltas); } this.$fromUndo = false; - - if (docDeltas.length == deltas.length) { - this.$setUndoSelection(docDeltas, true); - } }, this.redoChanges = function(deltas) { if (!deltas.length) return; - var docDeltas = filterDocActions(deltas); this.$fromUndo = true; - this.doc.applyDeltas(docDeltas); + var lastUndoRange = null; + for (var i = 0; i < deltas.length; i++) { + delta = deltas[i]; + if (delta.group == "doc") { + this.doc.applyDeltas(delta.deltas); + lastUndoRange = + this.$setUndoSelection(delta.deltas, false, lastUndoRange); + } + } this.$fromUndo = false; - - this.$setUndoSelection(docDeltas, false); }, - this.$setUndoSelection = function(deltas, isUndo) { - // invert deltas is they are an undo - if (isUndo) - deltas = deltas.map(function(delta) { - var d = { - range: delta.range + this.$setUndoSelection = function(deltas, isUndo, lastUndoRange) { + function isInsert(delta) { + var insert = + delta.action == "insertText" || delta.action == "insertLines"; + return isUndo ? !insert : insert; + } + + var delta = deltas[0]; + var range; + var lastDeltaIsInsert = false; + if (isInsert(delta)) { + range = delta.range.clone(); + lastDeltaIsInsert = true; + } else { + range = Range.fromPoints(delta.range.start, delta.range.start); + lastDeltaIsInsert = false; + } + + for (var i = 1; i < deltas.length; i++) { + delta = deltas[i]; + if (isInsert(delta)) { + if (range.compare(delta.range.start) == -1) { + range.setStart(delta.range.start); } - if (delta.action == "insertText" || delta.action == "insertLines") - d.action = "removeText" - else - d.action = "insertText" - return d; - }).reverse(); - - - var actions = [{}]; - - // collapse insert and remove operations - for (var i=0; i