Skip to content

Commit

Permalink
Fix / complete validateDelta
Browse files Browse the repository at this point in the history
This uncovered the fact that until now delta.range had not always been a
Range object. This inconsistency has been resolved by my changes in
mirror.js.
  • Loading branch information
aldendaniels committed Jan 11, 2014
1 parent 08edcdf commit ef0e8da
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 47 deletions.
96 changes: 50 additions & 46 deletions lib/ace/apply_delta.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,59 +33,63 @@ define(function(require, exports, module) {

var Range = require("./range").Range;

function splitLine (lines, point) {
var text = lines[point.row];
lines[point.row] = text.slice(0, point.column);
lines.splice(point.row + 1, 0, text.slice(point.column));
function splitLine (docLines, position) {
var text = docLines[position.row];
docLines[position.row] = text.slice(0, position.column);
docLines.splice(position.row + 1, 0, text.slice(position.column));
}

function joinLineWithNext(lines, row) {
lines[row] += lines[row + 1];
lines.splice(row + 1, 1);
function joinLineWithNext(docLines, row) {
docLines[row] += docLines[row + 1];
docLines.splice(row + 1, 1);
}

function throwDeltaError(delta, errorText){
errorText = 'Invalid Delta: ' + errorText;
console.log(errorText, delta);
throw errorText;
console.log('Invalid Delta:', delta);
throw 'Invalid Delta: ' + errorText;
}

function validateDelta(lines, delta) {
function positionInDocument(docLines, position)
{
return position.row >= 0 && position.row < docLines.length &&
position.column >= 0 && position.column <= docLines[position.row].length;
}

function validateDelta(docLines, delta) {

// Validate action.
// Validate action string.
if (delta.action != 'insert' && delta.action != 'remove')
fnThrow('Delta action must be "insert" or "remove".');

// Validate lines.
if (!delta.lines instanceof Array)
fnThrow('Delta lines must be an array');
throwDeltaError(delta, 'delta.action must be "insert" or "remove"');

// Validate lines type.
if (!(delta.lines instanceof Array))
throwDeltaError(delta, 'delta.lines must be an Array');

// Validate range type.
if (!delta.range instanceof Range)
fnThrow('Range object is not an instance of the Range class');
// Validate start point.
if (!(delta.range instanceof Range))
throwDeltaError(delta, 'delta.range must be an instance of the Range class');

// Validate that the start point is contained in the document.
var start = delta.range.start;
if (Math.min(Math.max(start.row, 0), lines.length - 1 ) != start.row ||
Math.min(Math.max(start.column, 0), lines[start.row].length) != start.column)
{
fnThrow('Range start point not contained in document');
}
if (!positionInDocument(docLines, delta.range.start))
throwDeltaError(delta, 'delta.range.start must be contained in document');

// Validate ending row offset.
if (delta.lines.length - 1 != delta.range.end.row - delta.range.start.row)
fnThrow('Range row offsets does not match delta lines');
// Validate that the end point is contained in the document (remove deltas only).
var end = delta.range.end;
if (delta.action == 'remove' && !positionInDocument(docLines, end))
throwDeltaError(delta, 'delta.range.end must contained in document for "remove" actions');

// TODO:
// - Validate that the ending column offset matches the lines.
// - Validate the deleted lines match the lines in the document.
// - Vaiidate that an insert delta does not contain more than 65001 entries.
// Validate that the .range size matches the .lines size.
var numRangeRows = end.row - start.row;
var numRangeLastLineChars = (end.column - (numRangeRows == 0 ? start.column : 0));
if (numRangeRows != delta.lines.length - 1 || delta.lines[numRangeRows].length != numRangeLastLineChars)
throwDeltaError(delta, 'delta.range must match delta lines');
}

exports.applyDelta = function(lines, delta) {
exports.applyDelta = function(docLines, delta) {

// Validate delta.
validateDelta(lines, delta);
validateDelta(docLines, delta);

// Apply delta.
if (delta.range.start.row == delta.range.end.row)
Expand All @@ -96,15 +100,15 @@ exports.applyDelta = function(lines, delta) {
var row = delta.range.start.row;
var startColumn = delta.range.start.column;
var endColumn = delta.range.end.column;
var line = lines[row];
var line = docLines[row];
switch (delta.action) {

case 'insert':
lines[row] = line.substring(0, startColumn) + delta.lines[0] + line.substring(startColumn);
docLines[row] = line.substring(0, startColumn) + delta.lines[0] + line.substring(startColumn);
break;

case 'remove':
lines[row] = line.substring(0, startColumn) + line.substring(endColumn);
docLines[row] = line.substring(0, startColumn) + line.substring(endColumn);
break;
}
} else {
Expand All @@ -113,20 +117,20 @@ exports.applyDelta = function(lines, delta) {
switch (delta.action) {

case 'insert':
splitLine(lines, delta.range.start);
lines.splice.apply(lines, [delta.range.start.row + 1, 0].concat(delta.lines));
joinLineWithNext(lines, delta.range.start.row);
joinLineWithNext(lines, delta.range.end.row);
splitLine(docLines, delta.range.start);
docLines.splice.apply(docLines, [delta.range.start.row + 1, 0].concat(delta.lines));
joinLineWithNext(docLines, delta.range.start.row);
joinLineWithNext(docLines, delta.range.end.row);
break;

case 'remove':
splitLine(lines, delta.range.end);
splitLine(lines, delta.range.start);
lines.splice(
splitLine(docLines, delta.range.end);
splitLine(docLines, delta.range.start);
docLines.splice(
delta.range.start.row + 1, // Where to start deleting
delta.range.end.row - delta.range.start.row + 1 // Num lines to delete.
);
joinLineWithNext(lines, delta.range.start.row);
joinLineWithNext(docLines, delta.range.start.row);
break;
}
}
Expand Down
13 changes: 12 additions & 1 deletion lib/ace/worker/mirror.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
define(function(require, exports, module) {
"use strict";

var Range = require("../range").Range;
var Document = require("../document").Document;
var lang = require("../lib/lang");

Expand All @@ -12,7 +13,17 @@ var Mirror = exports.Mirror = function(sender) {

var _self = this;
sender.on("change", function(e) {
doc.applyDeltas(e.data);

// Convert delta.range back into a Range instance since
// window.onMessage loses non-primitive data. See http://jsfiddle.net/nqJfw/1/.
var deltas = e.data;
for (var i in deltas)
{
var delta = deltas[i];
delta.range = Range.fromPoints(delta.range.start, delta.range.end);
}

doc.applyDeltas(deltas);
if (_self.$timeout)
return deferredUpdate.schedule(_self.$timeout);
_self.onUpdate();
Expand Down

0 comments on commit ef0e8da

Please sign in to comment.