continue refactoring
This commit is contained in:
parent
46f3d77068
commit
6b60bcbbd6
7 changed files with 135 additions and 134 deletions
|
|
@ -42,7 +42,6 @@ function positionInDocument(docLines, position) {
|
|||
}
|
||||
|
||||
function validateDelta(docLines, delta) {
|
||||
|
||||
// Validate action string.
|
||||
if (delta.action != "insert" && delta.action != "remove")
|
||||
throwDeltaError(delta, "delta.action must be 'insert' or 'remove'");
|
||||
|
|
@ -73,47 +72,37 @@ function validateDelta(docLines, delta) {
|
|||
}
|
||||
|
||||
exports.applyDelta = function(docLines, delta, doNotValidate) {
|
||||
|
||||
// Validate delta.
|
||||
if (!doNotValidate)
|
||||
validateDelta(docLines, delta);
|
||||
|
||||
var row = delta.start.row;
|
||||
var startColumn = delta.start.column;
|
||||
var line = docLines[row];
|
||||
// Apply delta.
|
||||
if (row == delta.end.row) {
|
||||
// Apply single-line delta.
|
||||
// Note: The multi-line code below correctly handle single-line
|
||||
// deltas too, but we need to short-circuit for speed.
|
||||
var endColumn = delta.end.column;
|
||||
switch (delta.action) {
|
||||
case "insert":
|
||||
switch (delta.action) {
|
||||
case "insert":
|
||||
var lines = delta.lines;
|
||||
if (lines.length === 1) {
|
||||
docLines[row] = line.substring(0, startColumn) + delta.lines[0] + line.substring(startColumn);
|
||||
break;
|
||||
case "remove":
|
||||
docLines[row] = line.substring(0, startColumn) + line.substring(endColumn);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// Apply multi-line delta.
|
||||
switch (delta.action) {
|
||||
case "insert":
|
||||
} else {
|
||||
var line = docLines[row];
|
||||
var args = [row, 1].concat(delta.lines);
|
||||
docLines.splice.apply(docLines, args);
|
||||
docLines[row] = line.substring(0, startColumn) + docLines[row];
|
||||
docLines[row + delta.lines.length - 1] += line.substring(startColumn);
|
||||
break;
|
||||
case "remove":
|
||||
var endRow
|
||||
}
|
||||
break;
|
||||
case "remove":
|
||||
var endColumn = delta.end.column;
|
||||
var endRow = delta.end.row;
|
||||
if (row === endRow) {
|
||||
docLines[row] = line.substring(0, startColumn) + line.substring(endColumn);
|
||||
} else {
|
||||
docLines.splice(
|
||||
row, // Where to start deleting
|
||||
delta.end.row - delta.start.row + 1, // Num lines to delete.
|
||||
line.substring(0, startColumn) + docLines[delta.end.row].substring(delta.end.column)
|
||||
row, endRow - row + 1,
|
||||
line.substring(0, startColumn) + docLines[endRow].substring(endColumn)
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -39,13 +39,12 @@ var Anchor = require("./anchor").Anchor;
|
|||
|
||||
/**
|
||||
* Contains the text of the document. Document can be attached to several [[EditSession `EditSession`]]s.
|
||||
*
|
||||
* At its core, `Document`s are just an array of strings, with each row in the document matching up to the array index.
|
||||
*
|
||||
* @class Document
|
||||
**/
|
||||
|
||||
/**
|
||||
/**
|
||||
*
|
||||
* Creates a new `Document`. If `text` is included, the `Document` contains those strings; otherwise, it's empty.
|
||||
* @param {String | Array} text The starting text
|
||||
|
|
@ -76,9 +75,9 @@ var Document = function(textOrLines) {
|
|||
* @param {String} text The text to use
|
||||
**/
|
||||
this.setValue = function(text) {
|
||||
var len = this.getLength();
|
||||
this.remove(new Range(0, 0, len, this.getLine(len-1).length));
|
||||
this.insert({row: 0, column:0}, text);
|
||||
var len = this.getLength() - 1;
|
||||
this.remove(new Range(0, 0, len, this.getLine(len).length));
|
||||
this.insert({row: 0, column: 0}, text);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -224,7 +223,7 @@ var Document = function(textOrLines) {
|
|||
**/
|
||||
this.getLinesForRange = function(range) {
|
||||
var lines;
|
||||
if (range.start.row == range.end.row) {
|
||||
if (range.start.row === range.end.row) {
|
||||
// Handle a single-line range.
|
||||
lines = [this.getLine(range.start.row).substring(range.start.column, range.end.column)];
|
||||
} else {
|
||||
|
|
@ -238,29 +237,6 @@ var Document = function(textOrLines) {
|
|||
return lines;
|
||||
};
|
||||
|
||||
this.$clipPosition = function(position) {
|
||||
var length = this.getLength();
|
||||
if (position.row >= length) {
|
||||
position.row = Math.max(0, length - 1);
|
||||
position.column = this.getLine(length - 1).length;
|
||||
} else {
|
||||
position.row = Math.max(0, position.row);
|
||||
position.column = Math.min(Math.max(position.column, 0), this.getLine(position.row).length);
|
||||
}
|
||||
return position;
|
||||
};
|
||||
|
||||
this.$getClippedRange = function(range) {
|
||||
// Get Range object.
|
||||
if (!range instanceof Range)
|
||||
range = Range.fromPoints(range.start, range.end);
|
||||
|
||||
// Return clipped range.
|
||||
this.$clipPosition(range.start);
|
||||
this.$clipPosition(range.end);
|
||||
return range;
|
||||
};
|
||||
|
||||
// Deprecated methods retained for backwards compatibility.
|
||||
this.insertLines = function(row, lines) {
|
||||
console.warn("Use of document.insertLines is deprecated. Use the insertFullLines method instead.");
|
||||
|
|
@ -305,25 +281,54 @@ var Document = function(textOrLines) {
|
|||
* ```
|
||||
**/
|
||||
this.insertInLine = function(position, text) {
|
||||
// Calculate insertion range end point.
|
||||
this.$clipPosition(position);
|
||||
var endPoint = {
|
||||
row : position.row,
|
||||
column : position.column + text.length
|
||||
};
|
||||
var start = this.clippedPos(position.row, position.column);
|
||||
var end = this.pos(position.row, position.column + text.length);
|
||||
|
||||
var range = Range.fromPoints(position, endPoint);
|
||||
// Apply delta (emits change).
|
||||
this.applyDelta({
|
||||
action: "insert",
|
||||
start: range.start,
|
||||
end: range.end,
|
||||
start: start,
|
||||
end: end,
|
||||
lines: [text]
|
||||
}, true /*doNotValidate*/);
|
||||
}, true);
|
||||
|
||||
return endPoint;
|
||||
return this.clonePos(end);
|
||||
};
|
||||
|
||||
this.clippedPos = function(row, column) {
|
||||
var length = this.getLength();
|
||||
if (row === undefined) {
|
||||
row = length;
|
||||
} else if (row < 0) {
|
||||
row = 0;
|
||||
} else if (row >= length) {
|
||||
row = length - 1;
|
||||
column = undefined
|
||||
}
|
||||
var line = this.getLine(row);
|
||||
column = Math.min(Math.max(column, 0), line.length);
|
||||
return {row: row, column: column};
|
||||
};
|
||||
|
||||
this.clonePos = function(pos) {
|
||||
return {row: pos.row, column: pos.column};
|
||||
};
|
||||
|
||||
this.pos = function(row, column) {
|
||||
return {row: row, column: column};
|
||||
};
|
||||
|
||||
this.$clipPosition = function(position) {
|
||||
var length = this.getLength();
|
||||
if (position.row >= length) {
|
||||
position.row = Math.max(0, length - 1);
|
||||
position.column = this.getLine(length - 1).length;
|
||||
} else {
|
||||
position.row = Math.max(0, position.row);
|
||||
position.column = Math.min(Math.max(position.column, 0), this.getLine(position.row).length);
|
||||
}
|
||||
return position;
|
||||
};
|
||||
|
||||
/**
|
||||
* Fires whenever the document changes.
|
||||
*
|
||||
|
|
@ -392,14 +397,12 @@ var Document = function(textOrLines) {
|
|||
*
|
||||
**/
|
||||
this.insertMergedLines = function(position, lines) {
|
||||
// Calculate insertion range end point.
|
||||
this.$clipPosition(position);
|
||||
var endPoint = {
|
||||
row : position.row + lines.length - 1,
|
||||
column : (lines.length == 1 ? position.column : 0) + lines[lines.length - 1].length
|
||||
};
|
||||
|
||||
// Apply delta (emits change).
|
||||
this.applyDelta({
|
||||
action: "insert",
|
||||
start: position,
|
||||
|
|
@ -417,15 +420,14 @@ var Document = function(textOrLines) {
|
|||
*
|
||||
**/
|
||||
this.remove = function(range) {
|
||||
// Apply delta (emits change).
|
||||
range = this.$getClippedRange(range);
|
||||
var start = this.clippedPos(range.start.row, range.start.column);
|
||||
this.applyDelta({
|
||||
action: "remove",
|
||||
start: range.start,
|
||||
end: range.end,
|
||||
start: start,
|
||||
end: this.clippedPos(range.end.row, range.end.column),
|
||||
lines: this.getLinesForRange(range),
|
||||
});
|
||||
return range.start;
|
||||
return this.clonePos(start);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -437,19 +439,16 @@ var Document = function(textOrLines) {
|
|||
*
|
||||
**/
|
||||
this.removeInLine = function(row, startColumn, endColumn) {
|
||||
// Calculate deleteion range.
|
||||
var range = new Range(row, startColumn, row, endColumn);
|
||||
range = this.$getClippedRange(range);
|
||||
var start = this.clippedPos(row, startColumn);
|
||||
|
||||
// Apply delta (emits change).
|
||||
this.applyDelta({
|
||||
action: "remove",
|
||||
start: range.start,
|
||||
end: range.end,
|
||||
start: start,
|
||||
end: this.clippedPos(row, endColumn),
|
||||
lines: this.getLinesForRange(range),
|
||||
}, true /*doNotValidate*/);
|
||||
}, true);
|
||||
|
||||
return range.start;
|
||||
return this.clonePos(start);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -478,7 +477,6 @@ var Document = function(textOrLines) {
|
|||
// Store delelted lines with bounding newlines ommitted (maintains previous behavior).
|
||||
var deletedLines = this.$lines.slice(firstRow, lastRow + 1);
|
||||
|
||||
// Apply delta (emits change).
|
||||
this.applyDelta({
|
||||
action: "remove",
|
||||
start: range.start,
|
||||
|
|
@ -496,13 +494,11 @@ var Document = function(textOrLines) {
|
|||
*
|
||||
**/
|
||||
this.removeNewLine = function(row) {
|
||||
if (row < this.getLength() - 1 && row >= 0) {
|
||||
var range = new Range(row, this.getLine(row).length, row + 1, 0);
|
||||
// Apply delta (emits change).
|
||||
if (row < this.getLength() - 1 && row >= 0) {
|
||||
this.applyDelta({
|
||||
action: "remove",
|
||||
start: range.start,
|
||||
end: range.end,
|
||||
start: this.pos(row, this.getLine(row).length),
|
||||
end: this.pos(row + 1, 0),
|
||||
lines: ["", ""]
|
||||
});
|
||||
}
|
||||
|
|
@ -566,10 +562,21 @@ var Document = function(textOrLines) {
|
|||
* @param {Object} delta A delta object (can include "insert" and "remove" actions)
|
||||
**/
|
||||
this.applyDelta = function(delta, doNotValidate) {
|
||||
var isInsert = delta.action == "insert";
|
||||
// An empty range is a NOOP.
|
||||
if (!Range.comparePoints(delta.start, delta.end))
|
||||
if (isInsert ? !delta.lines.length
|
||||
: !Range.comparePoints(delta.start, delta.end))
|
||||
return;
|
||||
|
||||
if (isInsert && delta.lines.length > 0xFFFF)
|
||||
this.$splitAndapplyLargeDelta(delta);
|
||||
|
||||
// Apply.
|
||||
applyDelta(this.$lines, delta, doNotValidate);
|
||||
this._signal("change", {data: delta});
|
||||
};
|
||||
|
||||
this.$splitAndapplyLargeDelta = function(delta) {
|
||||
// Split large insert deltas. This is necessary because:
|
||||
// 1. We need to support splicing delta lines into the document via $lines.splice.apply(...)
|
||||
// 2. fn.apply() doesn't work for a large number of params. The mallest threshold is on safari 0xFFFF.
|
||||
|
|
@ -578,28 +585,18 @@ var Document = function(textOrLines) {
|
|||
// delta handling is too slow. If we make delete delta handling faster we can split all large deltas
|
||||
// as shown in https://gist.github.com/aldendaniels/8367109#file-document-snippet-js
|
||||
// If we do this, update validateDelta() to limit the number of lines in a delete delta.
|
||||
var bIsInsert = delta.action == "insert";
|
||||
while (bIsInsert && delta.lines.length > 65001) {
|
||||
while (delta.lines.length > 0xFFFF) {
|
||||
// Get split deltas.
|
||||
var lines = delta.lines.splice(0, 65000);
|
||||
var lines = delta.lines.splice(0, 0xFFFF);
|
||||
lines.push("");
|
||||
var range = new Range(delta.start.row, delta.start.column,
|
||||
delta.start.row + 65000, 0)
|
||||
var start = delta.start;
|
||||
this.applyDelta({
|
||||
action: delta.action,
|
||||
lines: lines,
|
||||
start: range.start,
|
||||
end: range.end,
|
||||
});
|
||||
|
||||
// Update remaining delta.
|
||||
delta.start.row += 65000;
|
||||
delta.start.column = 0;
|
||||
start: this.pos(start.row, start.column),
|
||||
end: this.pos(start.row += 0xFFFF, start.column = 0) // Updates remaining delta.
|
||||
}, true);
|
||||
}
|
||||
|
||||
// Apply.
|
||||
applyDelta(this.$lines, delta, doNotValidate);
|
||||
this._emit("change", { data: delta });
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1394,25 +1394,25 @@ var EditSession = function(text, mode) {
|
|||
**/
|
||||
this.outdentRows = function (range) {
|
||||
var rowRange = range.collapseRows();
|
||||
var deleteRange = new Range(0, 0, 0, 0);
|
||||
var size = this.getTabSize();
|
||||
|
||||
|
||||
for (var i = rowRange.start.row; i <= rowRange.end.row; ++i) {
|
||||
var line = this.getLine(i);
|
||||
var row = i;
|
||||
var startCol = 0;
|
||||
var endCol = 0;
|
||||
|
||||
|
||||
deleteRange.start.row = i;
|
||||
deleteRange.end.row = i;
|
||||
for (var j = 0; j < size; ++j)
|
||||
if (line.charAt(j) != ' ')
|
||||
break;
|
||||
if (j < size && line.charAt(j) == '\t') {
|
||||
startCol = j;
|
||||
endCol = j + 1;
|
||||
deleteRange.start.column = j;
|
||||
deleteRange.end.column = j + 1;
|
||||
} else {
|
||||
startCol = 0;
|
||||
endCol = j;
|
||||
deleteRange.start.column = 0;
|
||||
deleteRange.end.column = j;
|
||||
}
|
||||
this.doc.removeInLine(row, startCol, endCol);
|
||||
this.remove(deleteRange);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -1684,7 +1684,7 @@ var EditSession = function(text, mode) {
|
|||
|
||||
this.$updating = true;
|
||||
if (len != 0) {
|
||||
if (action == "remove") {
|
||||
if (action === "remove") {
|
||||
this[useWrapMode ? "$wrapData" : "$rowLengthCache"].splice(firstRow, len);
|
||||
|
||||
var foldLines = this.$foldData;
|
||||
|
|
@ -1759,7 +1759,7 @@ var EditSession = function(text, mode) {
|
|||
// Realign folds. E.g. if you add some new chars before a fold, the
|
||||
// fold should "move" to the right.
|
||||
len = Math.abs(e.data.start.column - e.data.end.column);
|
||||
if (action == "remove") {
|
||||
if (action === "remove") {
|
||||
// Get all the folds in the change range and remove them.
|
||||
removedFolds = this.getFoldsInRange(e.data);
|
||||
this.removeFolds(removedFolds);
|
||||
|
|
|
|||
|
|
@ -181,13 +181,13 @@ var RangeList = function() {
|
|||
};
|
||||
|
||||
this.$onChange = function(e) {
|
||||
var changeRange = e.data.range;
|
||||
if (e.data.action[0] == "i"){
|
||||
var start = changeRange.start;
|
||||
var end = changeRange.end;
|
||||
var delta = e.data;
|
||||
if (delta.action == "insert"){
|
||||
var start = delta.start;
|
||||
var end = delta.end;
|
||||
} else {
|
||||
var end = changeRange.start;
|
||||
var start = changeRange.end;
|
||||
var end = delta.start;
|
||||
var start = delta.end;
|
||||
}
|
||||
var startRow = start.row;
|
||||
var endRow = end.row;
|
||||
|
|
|
|||
|
|
@ -61,10 +61,9 @@ var UndoManager = function() {
|
|||
*
|
||||
**/
|
||||
this.execute = function(options) {
|
||||
|
||||
// Normalize deltas for storage.
|
||||
var deltaSets = this.$serializeDeltas(options.args[0]);
|
||||
|
||||
// var deltaSets = this.$serializeDeltas(options.args[0]);
|
||||
var deltaSets = options.args[0];
|
||||
// Add deltas to undo stack.
|
||||
this.$doc = options.args[1];
|
||||
if (options.merge && this.hasUndo()){
|
||||
|
|
@ -207,7 +206,7 @@ var UndoManager = function() {
|
|||
|
||||
deltaSets_new[i] = deltaSet_new;
|
||||
}
|
||||
return deltaSets_new;
|
||||
return deltaSets_new;
|
||||
}
|
||||
|
||||
}).call(UndoManager.prototype);
|
||||
|
|
|
|||
|
|
@ -13,7 +13,19 @@ var Mirror = exports.Mirror = function(sender) {
|
|||
|
||||
var _self = this;
|
||||
sender.on("change", function(e) {
|
||||
doc.applyDeltas(e.data);
|
||||
var data = e.data;
|
||||
if (data[0].start) {
|
||||
doc.applyDeltas(data);
|
||||
} else {
|
||||
for (var i = 0; i < data.length; i += 2) {
|
||||
if (Array.isArray(data[i+1]))
|
||||
var d = {action: "insert", start: data[i], lines: data[i+1]};
|
||||
else
|
||||
var d = {action: "remove", start: data[i],end: data[i+1]};
|
||||
|
||||
doc.applyDelta(d, true);
|
||||
}
|
||||
}
|
||||
if (_self.$timeout)
|
||||
return deferredUpdate.schedule(_self.$timeout);
|
||||
_self.onUpdate();
|
||||
|
|
|
|||
|
|
@ -162,17 +162,21 @@ var WorkerClient = function(topLevelNamespaces, mod, classname, workerUrl) {
|
|||
|
||||
this.changeListener = function(e) {
|
||||
if (!this.deltaQueue) {
|
||||
this.deltaQueue = [e.data];
|
||||
this.deltaQueue = [];
|
||||
setTimeout(this.$sendDeltaQueue, 0);
|
||||
} else
|
||||
this.deltaQueue.push(e.data);
|
||||
}
|
||||
var delta = e.data;
|
||||
if (delta.action == "insert")
|
||||
this.deltaQueue.push(delta.start, delta.lines);
|
||||
else
|
||||
this.deltaQueue.push(delta.start, delta.end);
|
||||
};
|
||||
|
||||
this.$sendDeltaQueue = function() {
|
||||
var q = this.deltaQueue;
|
||||
if (!q) return;
|
||||
this.deltaQueue = null;
|
||||
if (q.length > 20 && q.length > this.$doc.getLength() >> 1) {
|
||||
if (q.length > 50 && q.length > this.$doc.getLength() >> 1) {
|
||||
this.call("setValue", [this.$doc.getValue()]);
|
||||
} else
|
||||
this.emit("change", {data: q});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue