Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Updating terminology in function names and comments so that operation…

…s are streams of changes, not streams of (levenshtein distance) operations which was confusing
  • Loading branch information...
commit 051354c2dcec721d552eee0c6329ae259f60214f 1 parent 35643e5
@fitzgen authored
Showing with 109 additions and 107 deletions.
  1. +11 −11 apply.js
  2. +6 −6 client.js
  3. +1 −1  messages.js
  4. +39 −37 operations.js
  5. +4 −4 ot.js
  6. +48 −48 xform.js
View
22 apply.js
@@ -9,34 +9,34 @@
/*global define */
define(["./operations"], function (operations) {
- return function (ops, doc) {
+ return function (op, doc) {
var i,
len,
index = 0,
newDoc = "";
- for ( i = 0, len = ops.length; i < len; i += 1 ) {
- switch ( operations.type(ops[i]) ) {
+ for ( i = 0, len = op.length; i < len; i += 1 ) {
+ switch ( operations.type(op[i]) ) {
case "retain":
- newDoc += doc.slice(0, operations.val(ops[i]));
- doc = doc.slice(operations.val(ops[i]));
+ newDoc += doc.slice(0, operations.val(op[i]));
+ doc = doc.slice(operations.val(op[i]));
break;
case "insert":
- newDoc += operations.val(ops[i]);
+ newDoc += operations.val(op[i]);
break;
case "delete":
- if ( doc.indexOf(operations.val(ops[i])) !== 0 ) {
- throw new TypeError("Expected '" + operations.val(ops[i])
+ if ( doc.indexOf(operations.val(op[i])) !== 0 ) {
+ throw new TypeError("Expected '" + operations.val(op[i])
+ "' to delete, found '" + doc.slice(0, 10)
+ "...'");
} else {
- doc = doc.slice(operations.val(ops[i]).length);
+ doc = doc.slice(operations.val(op[i]).length);
break;
}
default:
throw new TypeError("Unknown operation: "
- + operations.type(ops[i]));
+ + operations.type(op[i]));
}
}
return newDoc;
- }
+ };
});
View
12 client.js
@@ -27,8 +27,8 @@ define([
var i, len, msg;
for ( i = 0, len = outgoing.length; i < len; i++ ) {
msg = outgoing[i];
- xform(messages.operations(msg), ops, function (aPrime, bPrime) {
- messages.operations(msg, aPrime);
+ xform(messages.operation(msg), ops, function (aPrime, bPrime) {
+ messages.operation(msg, aPrime);
messages.document(msg, apply(messages.document(msg), aPrime));
messages.revision(msg, messages.revision(msg)+1);
ops = bPrime;
@@ -62,7 +62,7 @@ define([
uiDoc = ui.getDocument();
if ( uiDoc !== previousDoc ) {
msg = {};
- messages.operations(msg, operations.getOperations(previousDoc, uiDoc));
+ messages.operation(msg, operations.operation(previousDoc, uiDoc));
messages.document(msg, uiDoc);
messages.revision(msg, ++previousRevision);
messages.id(msg, id);
@@ -87,8 +87,8 @@ define([
// to have to do a deep equality test on every check here.
function isOurOutgoing (msg, outgoing) {
var top = outgoing[0],
- topOps = messages.operations(top),
- msgOps = messages.operations(msg),
+ topOps = messages.operation(top),
+ msgOps = messages.operation(msg),
i = 0,
len = msgOps.length;
if ( messages.id(msg) !== messages.id(top) ) {
@@ -144,7 +144,7 @@ define([
outgoing.shift();
} else {
// TODO: need to handle cursor selection and index
- xformEach(outgoing, messages.operations(msg));
+ xformEach(outgoing, messages.operation(msg));
// TODO: cursor position
if ( outgoing.length ) {
View
2  messages.js
@@ -25,7 +25,7 @@ define(function () {
// client connect.
document: defineGetSet("doc"),
revision: defineGetSet("rev"),
- operations: defineGetSet("ops"),
+ operation: defineGetSet("op"),
id: defineGetSet("id")
};
View
76 operations.js
@@ -1,6 +1,6 @@
-// This module defines the implementation of our operations. How they are
-// represented, their construction, and how to calculate the set of operations
-// to change some document A in to document B.
+// Operations are a stream of individual changes which span the whole document
+// from start to finish. Changes have a type which is one of retain, insert, or
+// delete, and have associated data based on their type.
/*jslint onevar: true, undef: true, eqeqeq: true, bitwise: true,
@@ -11,7 +11,7 @@
define(function () {
- // Simple operation constructors.
+ // Simple change constructors.
function insert (chars) {
return ["insert", chars];
@@ -25,12 +25,12 @@ define(function () {
return ["retain", n];
}
- function type (operation) {
- return operation[0];
+ function type (change) {
+ return change[0];
}
- function val (operation) {
- return operation[1];
+ function val (change) {
+ return change[1];
}
// We don't want to copy arrays all the time, aren't mutating lists, and
@@ -69,20 +69,20 @@ define(function () {
// Abstract out the table in case I want to change the implementation to
// arrays of arrays or something.
- function put (table, x, y, ops) {
- return (table[String(x) + "," + String(y)] = ops);
+ function put (table, x, y, changes) {
+ return (table[String(x) + "," + String(y)] = changes);
}
function get (table, x, y) {
- var ops = table[String(x) + "," + String(y)];
- if ( ops ) {
- return ops;
+ var changes = table[String(x) + "," + String(y)];
+ if ( changes ) {
+ return changes;
} else {
throw new TypeError("No operations at " + String(x) + "," + String(y));
}
}
- function makeOperationsTable (s, t) {
+ function makeChangesTable (s, t) {
var table = {},
n = s.length,
m = t.length,
@@ -101,50 +101,52 @@ define(function () {
}
function chooseCell (table, x, y, k) {
- var prevOps = get(table, x, y-1),
- min = prevOps.length,
+ var prevChanges = get(table, x, y-1),
+ min = prevChanges.length,
direction = "up";
if ( get(table, x-1, y).length < min ) {
- prevOps = get(table, x-1, y);
- min = prevOps.length;
+ prevChanges = get(table, x-1, y);
+ min = prevChanges.length;
direction = "left";
}
if ( get(table, x-1, y-1).length < min ) {
- prevOps = get(table, x-1, y-1);
- min = prevOps.length;
+ prevChanges = get(table, x-1, y-1);
+ min = prevChanges.length;
direction = "diagonal";
}
- return k(direction, prevOps);
+ return k(direction, prevChanges);
}
return {
- getOperations: function (s, t) {
+ // Constructor for operations (which are a stream of changes). Uses
+ // variation of Levenshtein Distance.
+ operation: function (s, t) {
var n = s.length,
m = t.length,
i,
j,
- ops = makeOperationsTable(s, t);
+ changes = makeChangesTable(s, t);
for ( i = 1; i <= m; i += 1 ) {
for ( j = 1; j <= n; j += 1 ) {
- chooseCell(ops, i, j, function (direction, prevOps) {
+ chooseCell(changes, i, j, function (direction, prevChanges) {
switch ( direction ) {
case "left":
- put(ops, i, j, cons(insert(t.charAt(i-1)), prevOps));
+ put(changes, i, j, cons(insert(t.charAt(i-1)), prevChanges));
break;
case "up":
- put(ops, i, j, cons(del(s.charAt(j-1)), prevOps));
+ put(changes, i, j, cons(del(s.charAt(j-1)), prevChanges));
break;
case "diagonal":
if ( s.charAt(j-1) === t.charAt(i-1) ) {
- put(ops, i, j, cons(retain(1), prevOps));
+ put(changes, i, j, cons(retain(1), prevChanges));
} else {
- put(ops, i, j, cons(insert(t.charAt(i-1)),
- cons(del(s.charAt(j-1)),
- prevOps)));
+ put(changes, i, j, cons(insert(t.charAt(i-1)),
+ cons(del(s.charAt(j-1)),
+ prevChanges)));
}
break;
default:
@@ -153,7 +155,7 @@ define(function () {
});
}
}
- return get(ops, i-1, j-1).toArray().reverse();
+ return get(changes, i-1, j-1).toArray().reverse();
},
insert: insert,
@@ -162,16 +164,16 @@ define(function () {
type: type,
val: val,
- isDelete: function (op) {
- return typeof op === "object" && type(op) === "delete";
+ isDelete: function (change) {
+ return typeof change === "object" && type(change) === "delete";
},
- isRetain: function (op) {
- return typeof op === "object" && type(op) === "retain";
+ isRetain: function (change) {
+ return typeof change === "object" && type(change) === "retain";
},
- isInsert: function (op) {
- return typeof op === "object" && type(op) === "insert";
+ isInsert: function (change) {
+ return typeof change === "object" && type(change) === "insert";
}
};
View
8 ot.js
@@ -43,10 +43,10 @@ define([
}.bind(this));
};
- manager.applyOperations = function (message) {
+ manager.applyOperation = function (message) {
var id = messages.id(message),
newRev = messages.revision(message),
- ops = messages.operations(message),
+ op = messages.operation(message),
emit = this.emit.bind(this);
store.getDocument(id, function (err, doc) {
@@ -55,7 +55,7 @@ define([
} else {
if ( newRev === doc.rev+1 ) {
try {
- doc.doc = apply(ops, doc.doc);
+ doc.doc = apply(op, doc.doc);
} catch (e) {
emit("error", e);
return;
@@ -74,7 +74,7 @@ define([
msg = {};
messages.revision(msg, doc.rev);
messages.id(msg, doc.id);
- messages.operations(msg, ops);
+ messages.operation(msg, op);
messages.document(msg, doc.doc);
emit("update", msg);
}
View
96 xform.js
@@ -9,15 +9,15 @@
define(["./operations"], function (ops) {
- // Pattern match on two operations by looking up their transforming function
- // in the `xformTable`. Each function in the table should take arguments
- // like the following:
+ // Pattern match on two changes by looking up their transforming function in
+ // the `xformTable`. Each function in the table should take arguments like
+ // the following:
//
- // xformer(operationA, operationB, indexA, indexB, continuation)
+ // xformer(changeA, changeB, indexA, indexB, continuation)
//
// and should return the results by calling the continuation
//
- // return continuation(aPrime || null, bPrime || null, newIndexA, newIndexB);
+ // return continuation(changeAPrime || null, changeBPrime || null, newIndexA, newIndexB);
var xformTable = {};
@@ -25,69 +25,69 @@ define(["./operations"], function (ops) {
return a + "," + b;
}
- // Define a transformation function for when we are comparing two operations
- // of typeA and typeB.
+ // Define a transformation function for when we are comparing two changes of
+ // typeA and typeB.
function defXformer (typeA, typeB, xformer) {
xformTable[join(typeA, typeB)] = xformer;
}
// Assumptions currently made by all of the xformer functions: that all of
- // the individual operations only deal with one character at a time.
+ // the individual changes only deal with one character at a time.
- defXformer("retain", "retain", function (opA, opB, indexA, indexB, k) {
- k(opA, opB, indexA+1, indexB+1);
+ defXformer("retain", "retain", function (changeA, changeB, indexA, indexB, k) {
+ k(changeA, changeB, indexA+1, indexB+1);
});
- defXformer("delete", "delete", function (opA, opB, indexA, indexB, k) {
- if ( ops.val(opA) === ops.val(opB) ) {
+ defXformer("delete", "delete", function (changeA, changeB, indexA, indexB, k) {
+ if ( ops.val(changeA) === ops.val(changeB) ) {
k(null, null, indexA+1, indexB+1);
} else {
throw new TypeError("Document state mismatch: delete("
- + ops.val(opA) + ") !== delete(" + ops.val(opB) + ")");
+ + ops.val(changeA) + ") !== delete(" + ops.val(changeB) + ")");
}
});
- defXformer("insert", "insert", function (opA, opB, indexA, indexB, k) {
- if ( ops.val(opA) === ops.val(opB) ) {
+ defXformer("insert", "insert", function (changeA, changeB, indexA, indexB, k) {
+ if ( ops.val(changeA) === ops.val(changeB) ) {
k(ops.retain(1), ops.retain(1), indexA+1, indexB+1);
} else {
- k(opA, ops.retain(1), indexA+1, indexB);
+ k(changeA, ops.retain(1), indexA+1, indexB);
}
});
- defXformer("retain", "delete", function (opA, opB, indexA, indexB, k) {
- k(null, opB, indexA+1, indexB+1);
+ defXformer("retain", "delete", function (changeA, changeB, indexA, indexB, k) {
+ k(null, changeB, indexA+1, indexB+1);
});
- defXformer("delete", "retain", function (opA, opB, indexA, indexB, k) {
- k(opA, null, indexA+1, indexB+1);
+ defXformer("delete", "retain", function (changeA, changeB, indexA, indexB, k) {
+ k(changeA, null, indexA+1, indexB+1);
});
- defXformer("insert", "retain", function (opA, opB, indexA, indexB, k) {
- k(opA, opB, indexA+1, indexB);
+ defXformer("insert", "retain", function (changeA, changeB, indexA, indexB, k) {
+ k(changeA, changeB, indexA+1, indexB);
});
- defXformer("retain", "insert", function (opA, opB, indexA, indexB, k) {
- k(opA, opB, indexA, indexB+1);
+ defXformer("retain", "insert", function (changeA, changeB, indexA, indexB, k) {
+ k(changeA, changeB, indexA, indexB+1);
});
- defXformer("insert", "delete", function (opA, opB, indexA, indexB, k) {
- k(opA, ops.retain(1), indexA+1, indexB);
+ defXformer("insert", "delete", function (changeA, changeB, indexA, indexB, k) {
+ k(changeA, ops.retain(1), indexA+1, indexB);
});
- defXformer("delete", "insert", function (opA, opB, indexA, indexB, k) {
- k(ops.retain(1), opB, indexA, indexB+1);
+ defXformer("delete", "insert", function (changeA, changeB, indexA, indexB, k) {
+ k(ops.retain(1), changeB, indexA, indexB+1);
});
- return function (operationsA, operationsB, k) {
- var operationsAPrime = [],
- operationsBPrime = [],
- lenA = operationsA.length,
- lenB = operationsB.length,
+ return function (operationA, operationB, k) {
+ var operationAPrime = [],
+ operationBPrime = [],
+ lenA = operationA.length,
+ lenB = operationB.length,
indexA = 0,
indexB = 0,
- opA,
- opB,
+ changeA,
+ changeB,
xformer;
// Continuation for the xformer.
@@ -95,39 +95,39 @@ define(["./operations"], function (ops) {
indexA = newIndexA;
indexB = newIndexB;
if ( aPrime ) {
- operationsAPrime.push(aPrime);
+ operationAPrime.push(aPrime);
}
if ( bPrime ) {
- operationsBPrime.push(bPrime);
+ operationBPrime.push(bPrime);
}
}
while ( indexA < lenA && indexB < lenB ) {
- opA = operationsA[indexA];
- opB = operationsB[indexB];
- xformer = xformTable[join(ops.type(opA), ops.type(opB))];
+ changeA = operationA[indexA];
+ changeB = operationB[indexB];
+ xformer = xformTable[join(ops.type(changeA), ops.type(changeB))];
if ( xformer ) {
- xformer(opA, opB, indexA, indexB, kk);
+ xformer(changeA, changeB, indexA, indexB, kk);
} else {
throw new TypeError("Unknown combination to transform: "
- + join(ops.type(opA), ops.type(opB)));
+ + join(ops.type(changeA), ops.type(changeB)));
}
}
- // If either set of operations was longer than the other, we can just
+ // If either operation contains more changes than the other, we just
// pass them on to the prime version.
for ( ; indexA < lenA; indexA++ ) {
- operationsAPrime.push(operationsA[indexA]);
- operationsBPrime.push(ops.retain(1));
+ operationAPrime.push(operationA[indexA]);
+ operationBPrime.push(ops.retain(1));
}
for ( ; indexB < lenB; indexB++ ) {
- operationsBPrime.push(operationsB[indexB]);
- operationsAPrime.push(ops.retain(1));
+ operationBPrime.push(operationB[indexB]);
+ operationAPrime.push(ops.retain(1));
}
- return k(operationsAPrime, operationsBPrime);
+ return k(operationAPrime, operationBPrime);
};
});
Please sign in to comment.
Something went wrong with that request. Please try again.