Skip to content

Commit 2a2f15b

Browse files
committed
Changeset: Migrate from mergingOpAssembler() to squashOps()
1 parent 4f94319 commit 2a2f15b

File tree

4 files changed

+63
-58
lines changed

4 files changed

+63
-58
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
* `opIterator()`: Deprecated in favor of the new `deserializeOps()` generator
2727
function.
2828
* `opAssembler()`: Deprecated in favor of the new `serializeOps()` function.
29+
* `mergingOpAssembler()`: Deprecated in favor of the new `squashOps()`
30+
generator function (combined with `serializeOps()`).
2931
* `appendATextToAssembler()`: Deprecated in favor of the new `opsFromAText()`
3032
generator function.
3133
* `newOp()`: Deprecated in favor of the new `Op` class.

src/static/js/Changeset.js

Lines changed: 37 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,7 @@ class OpAssembler {
338338
* @yields {Op} The squashed operations.
339339
* @returns {Generator<Op>}
340340
*/
341-
const squashOps = function* (ops, finalize) {
341+
exports.squashOps = function* (ops, finalize) {
342342
let prevOp = new Op();
343343
// If we get, for example, insertions [xxx\n,yyy], those don't merge, but if we get
344344
// [xxx\n,yyy,zzz\n], that merges to [xxx\nyyyzzz\n]. This variable stores the length of yyy and
@@ -402,7 +402,7 @@ class MergingOpAssembler {
402402
}
403403

404404
_serialize(finalize) {
405-
this._serialized = exports.serializeOps(squashOps(this._ops, finalize));
405+
this._serialized = exports.serializeOps(exports.squashOps(this._ops, finalize));
406406
}
407407

408408
append(op) {
@@ -465,32 +465,29 @@ const opsFromText = function* (opcode, text, attribs = '', pool = null) {
465465
*/
466466
class SmartOpAssembler {
467467
constructor() {
468-
this._minusAssem = new MergingOpAssembler();
469-
this._plusAssem = new MergingOpAssembler();
470-
this._keepAssem = new MergingOpAssembler();
471468
this._assem = exports.stringAssembler();
472469
this.clear();
473470
}
474471

475472
clear() {
476-
this._minusAssem.clear();
477-
this._plusAssem.clear();
478-
this._keepAssem.clear();
473+
this._minusAssem = [];
474+
this._plusAssem = [];
475+
this._keepAssem = [];
479476
this._assem.clear();
480477
this._lastOpcode = '';
481478
this._lengthChange = 0;
482479
}
483480

484-
_flushKeeps() {
485-
this._assem.append(this._keepAssem.toString());
486-
this._keepAssem.clear();
481+
_flushKeeps(finalize) {
482+
this._assem.append(exports.serializeOps(exports.squashOps(this._keepAssem, finalize)));
483+
this._keepAssem = [];
487484
}
488485

489486
_flushPlusMinus() {
490-
this._assem.append(this._minusAssem.toString());
491-
this._minusAssem.clear();
492-
this._assem.append(this._plusAssem.toString());
493-
this._plusAssem.clear();
487+
this._assem.append(exports.serializeOps(exports.squashOps(this._minusAssem, false)));
488+
this._minusAssem = [];
489+
this._assem.append(exports.serializeOps(exports.squashOps(this._plusAssem, false)));
490+
this._plusAssem = [];
494491
}
495492

496493
append(op) {
@@ -499,21 +496,21 @@ class SmartOpAssembler {
499496

500497
if (op.opcode === '-') {
501498
if (this._lastOpcode === '=') {
502-
this._flushKeeps();
499+
this._flushKeeps(false);
503500
}
504-
this._minusAssem.append(op);
501+
this._minusAssem.push(copyOp(op));
505502
this._lengthChange -= op.chars;
506503
} else if (op.opcode === '+') {
507504
if (this._lastOpcode === '=') {
508-
this._flushKeeps();
505+
this._flushKeeps(false);
509506
}
510-
this._plusAssem.append(op);
507+
this._plusAssem.push(copyOp(op));
511508
this._lengthChange += op.chars;
512509
} else if (op.opcode === '=') {
513510
if (this._lastOpcode !== '=') {
514511
this._flushPlusMinus();
515512
}
516-
this._keepAssem.append(op);
513+
this._keepAssem.push(copyOp(op));
517514
}
518515
this._lastOpcode = op.opcode;
519516
}
@@ -537,12 +534,13 @@ class SmartOpAssembler {
537534

538535
toString() {
539536
this._flushPlusMinus();
540-
this._flushKeeps();
537+
this._flushKeeps(false);
541538
return this._assem.toString();
542539
}
543540

544541
endDocument() {
545-
this._keepAssem.endDocument();
542+
this._flushPlusMinus();
543+
this._flushKeeps(true);
546544
}
547545

548546
getLengthChange() {
@@ -611,9 +609,14 @@ exports.checkRep = (cs) => {
611609
exports.smartOpAssembler = () => new SmartOpAssembler();
612610

613611
/**
612+
* @deprecated Use `squashOps` with `serializeOps` instead.
614613
* @returns {MergingOpAssembler}
615614
*/
616-
exports.mergingOpAssembler = () => new MergingOpAssembler();
615+
exports.mergingOpAssembler = () => {
616+
padutils.warnWithStack(
617+
'Changeset.mergingOpAssembler() is deprecated; use Changeset.squashOps() instead');
618+
return new MergingOpAssembler();
619+
};
617620

618621
/**
619622
* @deprecated Use `serializeOps` instead.
@@ -1323,12 +1326,12 @@ exports.mutateAttributionLines = (cs, lines, pool) => {
13231326
let lineAssem = null;
13241327

13251328
const outputMutOp = (op) => {
1326-
if (!lineAssem) lineAssem = new MergingOpAssembler();
1327-
lineAssem.append(op);
1329+
if (!lineAssem) lineAssem = [];
1330+
lineAssem.push(op);
13281331
if (op.lines <= 0) return;
13291332
assert(op.lines === 1, `Can't have op.lines of ${op.lines} in attribution lines`);
13301333
// ship it to the mut
1331-
mut.insert(lineAssem.toString(), 1);
1334+
mut.insert(exports.serializeOps(exports.squashOps(lineAssem, false)), 1);
13321335
lineAssem = null;
13331336
};
13341337

@@ -1377,23 +1380,22 @@ exports.mutateAttributionLines = (cs, lines, pool) => {
13771380
* @returns {string} joined Attribution lines
13781381
*/
13791382
exports.joinAttributionLines = (theAlines) => {
1380-
const assem = new MergingOpAssembler();
1381-
for (const aline of theAlines) {
1382-
for (const op of exports.deserializeOps(aline)) assem.append(op);
1383-
}
1384-
return assem.toString();
1383+
const ops = (function* () {
1384+
for (const aline of theAlines) yield* exports.deserializeOps(aline);
1385+
})();
1386+
return exports.serializeOps(exports.squashOps(ops, false));
13851387
};
13861388

13871389
exports.splitAttributionLines = (attrOps, text) => {
1388-
const assem = new MergingOpAssembler();
1390+
let ops = [];
13891391
const lines = [];
13901392
let pos = 0;
13911393

13921394
const appendOp = (op) => {
1393-
assem.append(op);
1395+
ops.push(op);
13941396
if (op.lines > 0) {
1395-
lines.push(assem.toString());
1396-
assem.clear();
1397+
lines.push(exports.serializeOps(exports.squashOps(ops, false)));
1398+
ops = [];
13971399
}
13981400
pos += op.chars;
13991401
};

src/static/js/changesettracker.js

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -143,21 +143,21 @@ const makeChangesetTracker = (scheduler, apool, aceCallbacksProvider) => {
143143
// Sanitize authorship: Replace all author attributes with this user's author ID in case the
144144
// text was copied from another author.
145145
const cs = Changeset.unpack(userChangeset);
146-
const assem = Changeset.mergingOpAssembler();
147-
148-
for (const op of Changeset.deserializeOps(cs.ops)) {
149-
if (op.opcode === '+') {
150-
const attribs = AttributeMap.fromString(op.attribs, apool);
151-
const oldAuthorId = attribs.get('author');
152-
if (oldAuthorId != null && oldAuthorId !== authorId) {
153-
attribs.set('author', authorId);
154-
op.attribs = attribs.toString();
146+
const ops = (function* () {
147+
for (const op of Changeset.deserializeOps(cs.ops)) {
148+
if (op.opcode === '+') {
149+
const attribs = AttributeMap.fromString(op.attribs, apool);
150+
const oldAuthorId = attribs.get('author');
151+
if (oldAuthorId != null && oldAuthorId !== authorId) {
152+
attribs.set('author', authorId);
153+
op.attribs = attribs.toString();
154+
}
155155
}
156+
yield op;
156157
}
157-
assem.append(op);
158-
}
159-
assem.endDocument();
160-
userChangeset = Changeset.pack(cs.oldLen, cs.newLen, assem.toString(), cs.charBank);
158+
})();
159+
const serializedOps = Changeset.serializeOps(Changeset.squashOps(ops, true));
160+
userChangeset = Changeset.pack(cs.oldLen, cs.newLen, serializedOps, cs.charBank);
161161
Changeset.checkRep(userChangeset);
162162

163163
if (Changeset.isIdentity(userChangeset)) toSubmit = null;

src/tests/frontend/specs/easysync-other.js

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -112,16 +112,17 @@ describe('easysync-other', function () {
112112
describe('split/join attribution lines', function () {
113113
const testSplitJoinAttributionLines = (randomSeed) => {
114114
const stringToOps = (str) => {
115-
const assem = Changeset.mergingOpAssembler();
116-
const o = new Changeset.Op('+');
117-
o.chars = 1;
118-
for (let i = 0; i < str.length; i++) {
119-
const c = str.charAt(i);
120-
o.lines = (c === '\n' ? 1 : 0);
121-
o.attribs = (c === 'a' || c === 'b' ? `*${c}` : '');
122-
assem.append(o);
123-
}
124-
return assem.toString();
115+
const ops = (function* () {
116+
for (let i = 0; i < str.length; i++) {
117+
const c = str.charAt(i);
118+
const o = new Changeset.Op('+');
119+
o.chars = 1;
120+
o.lines = (c === '\n' ? 1 : 0);
121+
o.attribs = (c === 'a' || c === 'b' ? `*${c}` : '');
122+
yield o;
123+
}
124+
})();
125+
return Changeset.serializeOps(Changeset.squashOps(ops, false));
125126
};
126127

127128
it(`testSplitJoinAttributionLines#${randomSeed}`, async function () {

0 commit comments

Comments
 (0)