Fix bugs in undo/redo seleciton handling
This commit is contained in:
parent
86a0e98c36
commit
007125025f
1 changed files with 91 additions and 95 deletions
|
|
@ -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<deltas.length; i++) {
|
||||
var delta = deltas[i];
|
||||
var isInsert = delta.action == "insertText" || delta.action == "insertLines";
|
||||
var action = actions[actions.length-1];
|
||||
if (action.isInsert !== isInsert) {
|
||||
actions.push({
|
||||
isInsert: isInsert,
|
||||
start: isInsert ? delta.range.start : delta.range.end,
|
||||
end: isInsert ? delta.range.end : delta.range.start
|
||||
})
|
||||
}
|
||||
else {
|
||||
if (isInsert)
|
||||
action.end = delta.range.end;
|
||||
else
|
||||
action.start = delta.range.start;
|
||||
if (range.compare(delta.range.end) == 1) {
|
||||
range.setEnd(delta.range.end);
|
||||
}
|
||||
lastDeltaIsInsert = true;
|
||||
} else {
|
||||
if (range.compare(delta.range.start) == -1) {
|
||||
range =
|
||||
Range.fromPoints(delta.range.start, delta.range.start);
|
||||
}
|
||||
lastDeltaIsInsert = false;
|
||||
}
|
||||
}
|
||||
|
||||
// update selection based on last operation
|
||||
this.selection.clearSelection();
|
||||
var action = actions[actions.length-1];
|
||||
if (action.isInsert)
|
||||
this.selection.setSelectionRange(Range.fromPoints(action.start, action.end));
|
||||
else
|
||||
this.selection.moveCursorToPosition(action.end);
|
||||
// Check if this range and the last undo range has something in common.
|
||||
// If true, merge the ranges.
|
||||
if (lastUndoRange != null) {
|
||||
var cmp = lastUndoRange.compareRange(range);
|
||||
if (cmp == 1) {
|
||||
range.setStart(lastUndoRange.start);
|
||||
} else if (cmp == -1) {
|
||||
range.setEnd(lastUndoRange.end);
|
||||
}
|
||||
}
|
||||
|
||||
if (!range.isEmpty()) {
|
||||
this.selection.setSelectionRange(range);
|
||||
} else {
|
||||
this.selection.moveCursorToPosition(range.start);
|
||||
}
|
||||
return range;
|
||||
},
|
||||
|
||||
this.replace = function(range, text) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue