Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

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 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.