Skip to content

Commit

Permalink
new undo manager
Browse files Browse the repository at this point in the history
  • Loading branch information
nightwing committed Oct 28, 2017
1 parent bde5b19 commit 64d5077
Show file tree
Hide file tree
Showing 7 changed files with 658 additions and 246 deletions.
150 changes: 55 additions & 95 deletions lib/ace/edit_session.js
Original file line number Diff line number Diff line change
Expand Up @@ -259,15 +259,17 @@ EditSession.$uid = 0;
this.$resetRowCache(delta.start.row);

var removedFolds = this.$updateInternalDataOnChange(delta);
if (!this.$fromUndo && this.$undoManager && !delta.ignore) {
this.$deltasDoc.push(delta);
if (removedFolds && removedFolds.length != 0) {
this.$deltasFold.push({
if (!this.$fromUndo && this.$undoManager) {
if (removedFolds && removedFolds.length) {
this.$undoManager.add({
action: "removeFolds",
folds: removedFolds
});
}, this.mergeUndoDeltas);
this.mergeUndoDeltas = true;
}

this.$undoManager.add(delta, this.mergeUndoDeltas);
this.mergeUndoDeltas = true;

this.$informUndoManager.schedule();
}

Expand All @@ -285,9 +287,6 @@ EditSession.$uid = 0;
this.selection.moveTo(0, 0);

this.$resetRowCache(0);
this.$deltas = [];
this.$deltasDoc = [];
this.$deltasFold = [];
this.setUndoManager(this.$undoManager);
this.getUndoManager().reset();
};
Expand Down Expand Up @@ -375,46 +374,20 @@ EditSession.$uid = 0;
**/
this.setUndoManager = function(undoManager) {
this.$undoManager = undoManager;
this.$deltas = [];
this.$deltasDoc = [];
this.$deltasFold = [];


if (this.$informUndoManager)
this.$informUndoManager.cancel();

if (undoManager) {
var self = this;

undoManager.addSession(this);
this.$syncInformUndoManager = function() {
self.$informUndoManager.cancel();

if (self.$deltasFold.length) {
self.$deltas.push({
group: "fold",
deltas: self.$deltasFold
});
self.$deltasFold = [];
}

if (self.$deltasDoc.length) {
self.$deltas.push({
group: "doc",
deltas: self.$deltasDoc
});
self.$deltasDoc = [];
}

if (self.$deltas.length > 0) {
undoManager.execute({
action: "aceupdate",
args: [self.$deltas, self],
merge: self.mergeUndoDeltas
});
}
self.mergeUndoDeltas = false;
self.$deltas = [];
};
this.$informUndoManager = lang.delayedCall(this.$syncInformUndoManager);
} else {
this.$syncInformUndoManager = function() {};
}
};

Expand All @@ -429,7 +402,11 @@ EditSession.$uid = 0;
this.$defaultUndoManager = {
undo: function() {},
redo: function() {},
reset: function() {}
reset: function() {},
add: function() {},
addSelection: function() {},
startNewGroup: function() {},
addSession: function() {}
};

/**
Expand Down Expand Up @@ -1175,25 +1152,22 @@ EditSession.$uid = 0;
return;

this.$fromUndo = true;
var lastUndoRange = null;
for (var i = deltas.length - 1; i != -1; i--) {
var delta = deltas[i];
if (delta.group == "doc") {
this.doc.revertDeltas(delta.deltas);
lastUndoRange =
this.$getUndoSelection(delta.deltas, true, lastUndoRange);
} else {
delta.deltas.forEach(function(foldDelta) {
this.addFolds(foldDelta.folds);
}, this);
if (delta.action == "insert" || delta.action == "remove") {
this.doc.revertDelta(delta);
} else if (delta.folds) {
this.addFolds(delta.folds);
}
}
if (!dontSelect && this.$undoSelect) {
// console.log(deltas.selectionBefore + "uuu")
if (deltas.selectionBefore)
this.selection.fromJSON(deltas.selectionBefore);
else
this.selection.setRange(this.$getUndoSelection(deltas, true));
}
this.$fromUndo = false;
lastUndoRange &&
this.$undoSelect &&
!dontSelect &&
this.selection.setSelectionRange(lastUndoRange);
return lastUndoRange;
};

/**
Expand All @@ -1208,50 +1182,53 @@ EditSession.$uid = 0;
return;

this.$fromUndo = true;
var lastUndoRange = null;
for (var i = 0; i < deltas.length; i++) {
var delta = deltas[i];
if (delta.group == "doc") {
this.doc.applyDeltas(delta.deltas);
lastUndoRange =
this.$getUndoSelection(delta.deltas, false, lastUndoRange);
if (delta.action == "insert" || delta.action == "remove") {
this.doc.applyDelta(delta);
}
}

if (!dontSelect && this.$undoSelect) {
if (deltas.selectionAfter)
this.selection.fromJSON(deltas.selectionAfter);
else
this.selection.setRange(this.$getUndoSelection(deltas, false));
}
this.$fromUndo = false;
lastUndoRange &&
this.$undoSelect &&
!dontSelect &&
this.selection.setSelectionRange(lastUndoRange);
return lastUndoRange;
};

/**
* Enables or disables highlighting of the range where an undo occured.
* @param {Boolean} enable If `true`, selects the range of the reinserted change
*
*
**/
this.setUndoSelect = function(enable) {
this.$undoSelect = enable;
};

this.$getUndoSelection = function(deltas, isUndo, lastUndoRange) {
this.$getUndoSelection = function(deltas, isUndo) {
function isInsert(delta) {
return isUndo ? delta.action !== "insert" : delta.action === "insert";
}

var delta = deltas[0];
var range, point;
var lastDeltaIsInsert = false;
if (isInsert(delta)) {
range = Range.fromPoints(delta.start, delta.end);
lastDeltaIsInsert = true;
} else {
range = Range.fromPoints(delta.start, delta.start);
lastDeltaIsInsert = false;
}
var lastDeltaIsInsert;

for (var i = 1; i < deltas.length; i++) {
delta = deltas[i];
for (var i = 0; i < deltas.length; i++) {
var delta = deltas[i];
if (!delta.start) continue; // skip folds
if (!range) {
if (isInsert(delta)) {
range = Range.fromPoints(delta.start, delta.end);
lastDeltaIsInsert = true;
} else {
range = Range.fromPoints(delta.start, delta.start);
lastDeltaIsInsert = false;
}
continue;
}

if (isInsert(delta)) {
point = delta.start;
if (range.compare(point.row, point.column) == -1) {
Expand All @@ -1270,23 +1247,6 @@ EditSession.$uid = 0;
lastDeltaIsInsert = false;
}
}

// Check if this range and the last undo range has something in common.
// If true, merge the ranges.
if (lastUndoRange != null) {
if (Range.comparePoints(lastUndoRange.start, range.start) === 0) {
lastUndoRange.start.column += range.end.column - range.start.column;
lastUndoRange.end.column += range.end.column - range.start.column;
}

var cmp = lastUndoRange.compareRange(range);
if (cmp == 1) {
range.setStart(lastUndoRange.start);
} else if (cmp == -1) {
range.setEnd(lastUndoRange.end);
}
}

return range;
};

Expand Down
39 changes: 26 additions & 13 deletions lib/ace/editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -116,21 +116,25 @@ Editor.$uid = 0;
oop.implement(this, EventEmitter);

this.$initOperationListeners = function() {
function last(a) {return a[a.length - 1];}

this.selections = [];
this.commands.on("exec", this.startOperation.bind(this), true);
this.commands.on("afterExec", this.endOperation.bind(this), true);

this.$opResetTimer = lang.delayedCall(this.endOperation.bind(this));


// todo: add before change events?
this.on("change", function() {
this.curOp || this.startOperation();
if (!this.curOp) {
this.startOperation();
this.curOp.selectionBefore = this.$lastSel;
}
this.curOp.docChanged = true;
}.bind(this), true);

this.on("changeSelection", function() {
this.curOp || this.startOperation();
if (!this.curOp) {
this.startOperation();
this.curOp.selectionBefore = this.$lastSel;
}
this.curOp.selectionChanged = true;
}.bind(this), true);
};
Expand All @@ -149,17 +153,18 @@ Editor.$uid = 0;
}

this.$opResetTimer.schedule();
this.curOp = {
this.curOp = this.session.curOp = {
command: commadEvent.command || {},
args: commadEvent.args,
scrollTop: this.renderer.scrollTop
};
this.curOp.selectionBefore = this.selection.toJSON();
};

this.endOperation = function(e) {
if (this.curOp) {
if (e && e.returnValue === false)
return this.curOp = null;
return (this.curOp = null);
this._signal("beforeEndOperation");
var command = this.curOp.command;
var scrollIntoView = command && command.scrollIntoView;
Expand Down Expand Up @@ -188,7 +193,12 @@ Editor.$uid = 0;
if (scrollIntoView == "animate")
this.renderer.animateScrolling(this.curOp.scrollTop);
}
var sel = this.selection.toJSON();
this.curOp.selectionAfter = sel;
this.$lastSel = this.selection.toJSON();

// console.log(this.$lastSel+" endOP")
this.session.getUndoManager().addSelection(sel);
this.prevOp = this.curOp;
this.curOp = null;
}
Expand Down Expand Up @@ -957,8 +967,11 @@ Editor.$uid = 0;
var transform = mode.transformAction(session.getState(cursor.row), 'insertion', this, session, text);
if (transform) {
if (text !== transform.text) {
this.session.mergeUndoDeltas = false;
this.$mergeNextCommand = false;
// keep automatic insertion in a separate delta, unless it is in multiselect mode
if (!this.inVirtualSelectionMode) {
this.session.mergeUndoDeltas = false;
this.mergeNextCommand = false;
}
}
text = transform.text;

Expand Down Expand Up @@ -2491,7 +2504,7 @@ Editor.$uid = 0;
* @related UndoManager.undo
**/
this.undo = function() {
this.session.getUndoManager().undo();
this.session.getUndoManager().undo(this.session);
this.renderer.scrollCursorIntoView(null, 0.5);
};

Expand All @@ -2500,7 +2513,7 @@ Editor.$uid = 0;
* @related UndoManager.redo
**/
this.redo = function() {
this.session.getUndoManager().redo();
this.session.getUndoManager().redo(this.session);
this.renderer.scrollCursorIntoView(null, 0.5);
};

Expand Down
2 changes: 1 addition & 1 deletion lib/ace/placeholder.js
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ var PlaceHolder = function(session, length, pos, others, mainClass, othersClass)
var undoManager = this.session.getUndoManager();
var undosRequired = (undoManager.$undoStack || undoManager.$undostack).length - this.$undoStackDepth;
for (var i = 0; i < undosRequired; i++) {
undoManager.undo(true);
undoManager.undo(this.session, true);
}
if (this.selectionBefore)
this.session.selection.fromJSON(this.selectionBefore);
Expand Down
Loading

0 comments on commit 64d5077

Please sign in to comment.