Skip to content

Commit 89fe40e

Browse files
committed
Changeset: Migrate from OpIter to deserializeOps()
1 parent 0eca025 commit 89fe40e

File tree

16 files changed

+147
-179
lines changed

16 files changed

+147
-179
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
* `eachAttribNumber()`
2222
* `makeAttribsString()`
2323
* `opAttributeValue()`
24+
* `opIterator()`: Deprecated in favor of the new `deserializeOps()` generator
25+
function.
2426
* `appendATextToAssembler()`: Deprecated in favor of the new `opsFromAText()`
2527
generator function.
2628
* `newOp()`: Deprecated in favor of the new `Op` class.

doc/api/hooks_server-side.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -670,9 +670,8 @@ const Changeset = require('ep_etherpad-lite/static/js/Changeset');
670670

671671
exports.getLineHTMLForExport = async (hookName, context) => {
672672
if (!context.attribLine) return;
673-
const opIter = Changeset.opIterator(context.attribLine);
674-
if (!opIter.hasNext()) return;
675-
const op = opIter.next();
673+
const [op] = Changeset.deserializeOps(context.attribLine);
674+
if (op == null) return;
676675
const heading = AttributeMap.fromString(op.attribs, context.apool).get('heading');
677676
if (!heading) return;
678677
context.lineContent = `<${heading}>${context.lineContent}</${heading}>`;

src/node/db/API.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -527,12 +527,10 @@ exports.restoreRevision = async (padID, rev) => {
527527
atext.text += '\n';
528528

529529
const eachAttribRun = (attribs, func) => {
530-
const attribsIter = Changeset.opIterator(attribs);
531530
let textIndex = 0;
532531
const newTextStart = 0;
533532
const newTextEnd = atext.text.length;
534-
while (attribsIter.hasNext()) {
535-
const op = attribsIter.next();
533+
for (const op of Changeset.deserializeOps(attribs)) {
536534
const nextIndex = textIndex + op.chars;
537535
if (!(nextIndex <= newTextStart || textIndex >= newTextEnd)) {
538536
func(Math.max(newTextStart, textIndex), Math.min(newTextEnd, nextIndex), op.attribs);

src/node/handler/PadMessageHandler.js

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -586,12 +586,7 @@ const handleUserChanges = async (socket, message) => {
586586
Changeset.checkRep(changeset);
587587

588588
// Validate all added 'author' attribs to be the same value as the current user
589-
const iterator = Changeset.opIterator(Changeset.unpack(changeset).ops);
590-
let op;
591-
592-
while (iterator.hasNext()) {
593-
op = iterator.next();
594-
589+
for (const op of Changeset.deserializeOps(Changeset.unpack(changeset).ops)) {
595590
// + can add text with attribs
596591
// = can change or add attribs
597592
// - can have attribs, but they are discarded and don't show up in the attribs -
@@ -741,10 +736,8 @@ const _correctMarkersInPad = (atext, apool) => {
741736
// collect char positions of line markers (e.g. bullets) in new atext
742737
// that aren't at the start of a line
743738
const badMarkers = [];
744-
const iter = Changeset.opIterator(atext.attribs);
745739
let offset = 0;
746-
while (iter.hasNext()) {
747-
const op = iter.next();
740+
for (const op of Changeset.deserializeOps(atext.attribs)) {
748741
const attribs = AttributeMap.fromString(op.attribs, apool);
749742
const hasMarker = AttributeManager.lineAttributes.some((a) => attribs.has(a));
750743
if (hasMarker) {

src/node/utils/ExportHelper.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,8 @@ exports._analyzeLine = (text, aline, apool) => {
5252
let lineMarker = 0;
5353
line.listLevel = 0;
5454
if (aline) {
55-
const opIter = Changeset.opIterator(aline);
56-
if (opIter.hasNext()) {
57-
const op = opIter.next();
55+
const [op] = Changeset.deserializeOps(aline);
56+
if (op != null) {
5857
const attribs = AttributeMap.fromString(op.attribs, apool);
5958
let listType = attribs.get('list');
6059
if (listType) {

src/node/utils/ExportHtml.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -197,13 +197,12 @@ const getHTMLFromAtext = async (pad, atext, authorColors) => {
197197
return;
198198
}
199199

200-
const iter = Changeset.opIterator(Changeset.subattribution(attribs, idx, idx + numChars));
200+
const ops = Changeset.deserializeOps(Changeset.subattribution(attribs, idx, idx + numChars));
201201
idx += numChars;
202202

203203
// this iterates over every op string and decides which tags to open or to close
204204
// based on the attribs used
205-
while (iter.hasNext()) {
206-
const o = iter.next();
205+
for (const o of ops) {
207206
const usedAttribs = [];
208207

209208
// mark all attribs as used

src/node/utils/ExportTxt.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,11 +76,10 @@ const getTXTFromAtext = (pad, atext, authorColors) => {
7676
return;
7777
}
7878

79-
const iter = Changeset.opIterator(Changeset.subattribution(attribs, idx, idx + numChars));
79+
const ops = Changeset.deserializeOps(Changeset.subattribution(attribs, idx, idx + numChars));
8080
idx += numChars;
8181

82-
while (iter.hasNext()) {
83-
const o = iter.next();
82+
for (const o of ops) {
8483
let propChanged = false;
8584

8685
for (const a of attributes.decodeAttribString(o.attribs)) {

src/node/utils/ImportHtml.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,12 +67,10 @@ exports.setPadHTML = async (pad, html) => {
6767
const builder = Changeset.builder(1);
6868

6969
// assemble each line into the builder
70-
const attribsIter = Changeset.opIterator(newAttribs);
7170
let textIndex = 0;
7271
const newTextStart = 0;
7372
const newTextEnd = newText.length;
74-
while (attribsIter.hasNext()) {
75-
const op = attribsIter.next();
73+
for (const op of Changeset.deserializeOps(newAttribs)) {
7674
const nextIndex = textIndex + op.chars;
7775
if (!(nextIndex <= newTextStart || textIndex >= newTextEnd)) {
7876
const start = Math.max(newTextStart, textIndex);

src/node/utils/padDiff.js

Lines changed: 26 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -35,16 +35,10 @@ PadDiff.prototype._isClearAuthorship = function (changeset) {
3535
return false;
3636
}
3737

38-
// lets iterator over the operators
39-
const iterator = Changeset.opIterator(unpacked.ops);
40-
41-
// get the first operator, this should be a clear operator
42-
const clearOperator = iterator.next();
38+
const [clearOperator, anotherOp] = Changeset.deserializeOps(unpacked.ops);
4339

4440
// check if there is only one operator
45-
if (iterator.hasNext() === true) {
46-
return false;
47-
}
41+
if (anotherOp != null) return false;
4842

4943
// check if this operator doesn't change text
5044
if (clearOperator.opcode !== '=') {
@@ -212,18 +206,14 @@ PadDiff.prototype._extendChangesetWithAuthor = (changeset, author, apool) => {
212206
// unpack
213207
const unpacked = Changeset.unpack(changeset);
214208

215-
const iterator = Changeset.opIterator(unpacked.ops);
216209
const assem = Changeset.opAssembler();
217210

218211
// create deleted attribs
219212
const authorAttrib = apool.putAttrib(['author', author || '']);
220213
const deletedAttrib = apool.putAttrib(['removed', true]);
221214
const attribs = `*${Changeset.numToString(authorAttrib)}*${Changeset.numToString(deletedAttrib)}`;
222215

223-
// iteratore over the operators of the changeset
224-
while (iterator.hasNext()) {
225-
const operator = iterator.next();
226-
216+
for (const operator of Changeset.deserializeOps(unpacked.ops)) {
227217
if (operator.opcode === '-') {
228218
// this is a delete operator, extend it with the author
229219
operator.attribs = attribs;
@@ -268,22 +258,23 @@ PadDiff.prototype._createDeletionChangeset = function (cs, startAText, apool) {
268258

269259
let curLine = 0;
270260
let curChar = 0;
271-
let curLineOpIter = null;
272-
let curLineOpIterLine;
261+
let curLineOps = null;
262+
let curLineOpsNext = null;
263+
let curLineOpsLine;
273264
let curLineNextOp = new Changeset.Op('+');
274265

275266
const unpacked = Changeset.unpack(cs);
276-
const csIter = Changeset.opIterator(unpacked.ops);
277267
const builder = Changeset.builder(unpacked.newLen);
278268

279269
const consumeAttribRuns = (numChars, func /* (len, attribs, endsLine)*/) => {
280-
if ((!curLineOpIter) || (curLineOpIterLine !== curLine)) {
281-
// create curLineOpIter and advance it to curChar
282-
curLineOpIter = Changeset.opIterator(aLinesGet(curLine));
283-
curLineOpIterLine = curLine;
270+
if (!curLineOps || curLineOpsLine !== curLine) {
271+
curLineOps = Changeset.deserializeOps(aLinesGet(curLine));
272+
curLineOpsNext = curLineOps.next();
273+
curLineOpsLine = curLine;
284274
let indexIntoLine = 0;
285-
while (curLineOpIter.hasNext()) {
286-
curLineNextOp = curLineOpIter.next();
275+
while (!curLineOpsNext.done) {
276+
curLineNextOp = curLineOpsNext.value;
277+
curLineOpsNext = curLineOps.next();
287278
if (indexIntoLine + curLineNextOp.chars >= curChar) {
288279
curLineNextOp.chars -= (curChar - indexIntoLine);
289280
break;
@@ -293,16 +284,22 @@ PadDiff.prototype._createDeletionChangeset = function (cs, startAText, apool) {
293284
}
294285

295286
while (numChars > 0) {
296-
if ((!curLineNextOp.chars) && (!curLineOpIter.hasNext())) {
287+
if (!curLineNextOp.chars && curLineOpsNext.done) {
297288
curLine++;
298289
curChar = 0;
299-
curLineOpIterLine = curLine;
290+
curLineOpsLine = curLine;
300291
curLineNextOp.chars = 0;
301-
curLineOpIter = Changeset.opIterator(aLinesGet(curLine));
292+
curLineOps = Changeset.deserializeOps(aLinesGet(curLine));
293+
curLineOpsNext = curLineOps.next();
302294
}
303295

304296
if (!curLineNextOp.chars) {
305-
curLineNextOp = curLineOpIter.hasNext() ? curLineOpIter.next() : new Changeset.Op();
297+
if (curLineOpsNext.done) {
298+
curLineNextOp = new Changeset.Op();
299+
} else {
300+
curLineNextOp = curLineOpsNext.value;
301+
curLineOpsNext = curLineOps.next();
302+
}
306303
}
307304

308305
const charsToUse = Math.min(numChars, curLineNextOp.chars);
@@ -314,7 +311,7 @@ PadDiff.prototype._createDeletionChangeset = function (cs, startAText, apool) {
314311
curChar += charsToUse;
315312
}
316313

317-
if ((!curLineNextOp.chars) && (!curLineOpIter.hasNext())) {
314+
if (!curLineNextOp.chars && curLineOpsNext.done) {
318315
curLine++;
319316
curChar = 0;
320317
}
@@ -324,7 +321,7 @@ PadDiff.prototype._createDeletionChangeset = function (cs, startAText, apool) {
324321
if (L) {
325322
curLine += L;
326323
curChar = 0;
327-
} else if (curLineOpIter && curLineOpIterLine === curLine) {
324+
} else if (curLineOps && curLineOpsLine === curLine) {
328325
consumeAttribRuns(N, () => {});
329326
} else {
330327
curChar += N;
@@ -361,10 +358,7 @@ PadDiff.prototype._createDeletionChangeset = function (cs, startAText, apool) {
361358
};
362359
};
363360

364-
// iterate over all operators of this changeset
365-
while (csIter.hasNext()) {
366-
const csOp = csIter.next();
367-
361+
for (const csOp of Changeset.deserializeOps(unpacked.ops)) {
368362
if (csOp.opcode === '=') {
369363
const textBank = nextText(csOp.chars);
370364

src/static/js/AttributeManager.js

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -150,9 +150,9 @@ AttributeManager.prototype = _(AttributeManager.prototype).extend({
150150
// get `attributeName` attribute of first char of line
151151
const aline = this.rep.alines[lineNum];
152152
if (!aline) return '';
153-
const opIter = Changeset.opIterator(aline);
154-
if (!opIter.hasNext()) return '';
155-
return AttributeMap.fromString(opIter.next().attribs, this.rep.apool).get(attributeName) || '';
153+
const [op] = Changeset.deserializeOps(aline);
154+
if (op == null) return '';
155+
return AttributeMap.fromString(op.attribs, this.rep.apool).get(attributeName) || '';
156156
},
157157

158158
/*
@@ -163,9 +163,8 @@ AttributeManager.prototype = _(AttributeManager.prototype).extend({
163163
// get attributes of first char of line
164164
const aline = this.rep.alines[lineNum];
165165
if (!aline) return [];
166-
const opIter = Changeset.opIterator(aline);
167-
if (!opIter.hasNext()) return [];
168-
const op = opIter.next();
166+
const [op] = Changeset.deserializeOps(aline);
167+
if (op == null) return [];
169168
return [...attributes.attribsFromString(op.attribs, this.rep.apool)];
170169
},
171170

@@ -221,13 +220,8 @@ AttributeManager.prototype = _(AttributeManager.prototype).extend({
221220
const end = selEnd[1];
222221
let hasAttrib = true;
223222

224-
// Iterate over attribs on this line
225-
226-
const opIter = Changeset.opIterator(rep.alines[lineNum]);
227223
let indexIntoLine = 0;
228-
229-
while (opIter.hasNext()) {
230-
const op = opIter.next();
224+
for (const op of Changeset.deserializeOps(rep.alines[lineNum])) {
231225
const opStartInLine = indexIntoLine;
232226
const opEndInLine = opStartInLine + op.chars;
233227
if (!hasIt(op.attribs)) {
@@ -260,15 +254,11 @@ AttributeManager.prototype = _(AttributeManager.prototype).extend({
260254
if (!aline) {
261255
return [];
262256
}
263-
// iterate through all operations of a line
264-
const opIter = Changeset.opIterator(aline);
265257

266258
// we need to sum up how much characters each operations take until the wanted position
267259
let currentPointer = 0;
268-
let currentOperation;
269260

270-
while (opIter.hasNext()) {
271-
currentOperation = opIter.next();
261+
for (const currentOperation of Changeset.deserializeOps(aline)) {
272262
currentPointer += currentOperation.chars;
273263
if (currentPointer <= column) continue;
274264
return [...attributes.attribsFromString(currentOperation.attribs, this.rep.apool)];

0 commit comments

Comments
 (0)