Skip to content

Commit

Permalink
Remove unused methods insertRowColumn and removeRowColumn. Move metho…
Browse files Browse the repository at this point in the history
…ds only needed for editor support from `RGA` down to the subclass, `RGA.AceEditorRGA`.
  • Loading branch information
jorendorff committed Apr 10, 2016
1 parent 0cbd462 commit cb878d0
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 198 deletions.
122 changes: 50 additions & 72 deletions lib/rga.js
Original file line number Diff line number Diff line change
Expand Up @@ -179,78 +179,6 @@ RGA.prototype = {
return node;
},

getRowColumnBefore: function (t) {
if (t === this.left.timestamp)
throw new Error("no position before the left edge of the document");
var target = this._index.get(t);
if (target === undefined)
throw new Error("timestamp not present in document");
var r = 0, c = 0;
for (var node = this.left.next; node != target; node = node.next) {
if (!node.removed) {
if (node.atom === "\n") {
r++;
c = 0;
} else {
c++;
}
}
}
return {row: r, column: c};
},

getRowColumnAfter: function (t, wt) {
var target = this._index.get(t);
if (target === undefined)
throw new Error("timestamp not present in document");

var r = 0, c = -1; // c will be incremented to zero in the first pass through the loop
function advance(node) {
if (!node.removed) {
if (node.atom === "\n") {
r++;
c = 0;
} else {
c++;
}
}
}

for (var node = this.left; ; node = node.next) {
advance(node);
if (node === target)
break;
}
while (node.next && wt < node.next.timestamp) {
node = node.next;
advance(node);
}

return {row: r, column: c};
},

insertRowColumn: function (source, line, column, text) {
var r = 1;
var u = this.getNodeAt(line, column).timestamp;
for (var i = 0; i < text.length; i++) {
var node = {atom: text[i], timestamp: this._timestamp()};
this.downstream(source, {type: "addRight", t: u, w: node});
u = node.timestamp;
}
},

removeRowColumn: function (source, line, column, length) {
var node = this.getNodeAt(line, column);
for (var i = 0; i < length; i++) {
node = node.next;
while (node && node.removed)
node = node.next;
if (!node)
throw new Error("tried to remove more characters than exist in document");
this.downstream(source, {type: "remove", t: node.timestamp});
}
},

timestampToIndex: function (t) {
var offset = -1;
for (var node = this.left; node.timestamp !== t; node = node.next) {
Expand Down Expand Up @@ -413,6 +341,56 @@ RGA.AceEditorRGA = function AceEditorRGA(id, editor, history, queue) {

RGA.AceEditorRGA.prototype = Object.create(RGA.prototype);
Object.assign(RGA.AceEditorRGA.prototype, {
getRowColumnBefore: function (t) {
if (t === this.left.timestamp)
throw new Error("no position before the left edge of the document");
var target = this._index.get(t);
if (target === undefined)
throw new Error("timestamp not present in document");
var r = 0, c = 0;
for (var node = this.left.next; node != target; node = node.next) {
if (!node.removed) {
if (node.atom === "\n") {
r++;
c = 0;
} else {
c++;
}
}
}
return {row: r, column: c};
},

getRowColumnAfter: function (t, wt) {
var target = this._index.get(t);
if (target === undefined)
throw new Error("timestamp not present in document");

var r = 0, c = -1; // c will be incremented to zero in the first pass through the loop
function advance(node) {
if (!node.removed) {
if (node.atom === "\n") {
r++;
c = 0;
} else {
c++;
}
}
}

for (var node = this.left; ; node = node.next) {
advance(node);
if (node === target)
break;
}
while (node.next && wt < node.next.timestamp) {
node = node.next;
advance(node);
}

return {row: r, column: c};
},

_assertInSync: function () {
var erText = this.text();
if (this._lastText != erText) {
Expand Down
126 changes: 0 additions & 126 deletions test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -221,130 +221,4 @@ describe("RGA", () => {
assert.strictEqual(p._subscribers.length, 0);
});
});

describe("insertRowColumn", () => {
it("inserts text", () => {
var p = new RGA(0);
p.insertRowColumn(p, 0, 0, "hello world\n");
assert.strictEqual(p.text(), "hello world\n");
p.insertRowColumn(p, 0, 0, "## ");
assert.strictEqual(p.text(), "## hello world\n");
p.insertRowColumn(p, 1, 0, "\nThis program prints a greeting to stdout.\n\n" +
" print 'hello'\n");
assert.strictEqual(p.text(), "## hello world\n\n" +
"This program prints a greeting to stdout.\n\n" +
" print 'hello'\n");
p.insertRowColumn(p, 4, 16, " world");
assert.strictEqual(p.text(), "## hello world\n\n" +
"This program prints a greeting to stdout.\n\n" +
" print 'hello world'\n");
});

it("can get row and column numbers right even after deletions", () => {
var p = new RGA(0);
p.insertRowColumn(p, 0, 0, "ab1234ch");
p.removeRowColumn(p, 0, 2, 4);
p.insertRowColumn(p, 0, 3, "defg");
assert.strictEqual(p.text(), "abcdefgh");
p.insertRowColumn(p, 0, 8, "\n1234567\n89\nijkqrs");
p.removeRowColumn(p, 0, 8, 12);
p.insertRowColumn(p, 0, 11, "lmnop");
assert.strictEqual(p.text(), "abcdefghijklmnopqrs");
});

var arbitraryChar = jsc.elements(['a', 'b', 'c', 'X', 'Y', 'Z', '0', '\n', ' ', '\u1234']);
var arbitraryStr = jsc.elements(['', 'xyzzy', 'hello\nworld\n', '\n\n\n\n', '\nok',
Array(16).join("wat" - 1) + " Batman!"]);

var arbitraryRGA = jsc.bless({
generator: function () {
var len = jsc.random(0, 30), pRemove = jsc.random.number(0, 1);
var timestamps = [];
for (var i = 0; i < len; i++)
timestamps[i] = i;

var h = new RGA(0);
var prev = h.left.timestamp;
for (var i = 0; i < len; i++) {
var tIndex = jsc.random(0, timestamps.length - 1);
var t = timestamps[tIndex];
timestamps[tIndex] = timestamps[timestamps.length - 1];
timestamps.length--;

var w = {atom: arbitraryChar.generator(), timestamp: t};
h._downstream(h.downstream, {type: "addRight", t: prev, w: w});
if (jsc.random.number(0, 1) < pRemove)
h._downstream(h.downstream, {type: "remove", t: t});
prev = t;
}
return h;
}
});

function randomPositionIn(str) {
var offset = jsc.random(0, str.length); // note: inclusive of str.length
var lines = str.slice(0, offset).split("\n");
var row = lines.length - 1;
return {
offset: offset,
row: row,
column: lines[row].length
};
}

var arbitraryTestCase = jsc.bless({
generator: function () {
var a = arbitraryRGA.generator();
var text = a.text();
return {
history: a.history(),
text: text,
loc: randomPositionIn(text),
insert: arbitraryStr.generator()
};
}
});

jsc.property("inserts text (in random test cases)", arbitraryTestCase, testCase => {
var p = new RGA(0, testCase.history);
p.insertRowColumn(p, testCase.loc.row, testCase.loc.column, testCase.insert);
var text = testCase.text;
var offset = testCase.loc.offset;
return p.text() === text.slice(0, offset) + testCase.insert + text.slice(offset);
});
});

describe("removeRowColumn", () => {
it("can remove text at the beginning of the array", () => {
var p = new RGA(0);
type(p, p.left.timestamp, "abcdefg");
p.removeRowColumn(p, 0, 0, 3);
assert.strictEqual(p.text(), "defg");
});

it("can remove text at the end of the array", () => {
var p = new RGA(0);
type(p, p.left.timestamp, "hi\nthere\nyou kid");
p.removeRowColumn(p, 2, 3, 4);
assert.strictEqual(p.text(), "hi\nthere\nyou");
});

it("can remove everything from the array", () => {
var p = new RGA(0);
type(p, p.left.timestamp, "good morning, how are\nyou today?");
p.removeRowColumn(p, 0, 0, p.text().length);
assert.strictEqual(p.text(), "");
});

it("can remove characters when some characters have already been removed", () => {
var p = new RGA(0);
type(p, p.left.timestamp, "abcdefg");
p.removeRowColumn(p, 0, 3, 1);
assert.strictEqual(p.text(), "abcefg");
p.removeRowColumn(p, 0, 2, 2);
assert.strictEqual(p.text(), "abfg");
p.removeRowColumn(p, 0, 0, 4);
assert.strictEqual(p.text(), "");
});
});
});

0 comments on commit cb878d0

Please sign in to comment.