@@ -525,6 +525,9 @@ exports.mergingOpAssembler = () => {
525
525
// ops immediately after it.
526
526
let bufOpAdditionalCharsAfterNewline = 0 ;
527
527
528
+ /**
529
+ * @param {boolean } [isEndDocument]
530
+ */
528
531
const flush = ( isEndDocument ) => {
529
532
if ( ! bufOp . opcode ) return ;
530
533
if ( isEndDocument && bufOp . opcode === '=' && ! bufOp . attribs ) {
@@ -803,7 +806,7 @@ class TextLinesMutator {
803
806
804
807
/**
805
808
* Indicates if curLine is already in the splice. This is necessary because the last element in
806
- * curSplice is curLine when this line is currently worked on (e.g. when skipping are inserting).
809
+ * curSplice is curLine when this line is currently worked on (e.g. when skipping or inserting).
807
810
*
808
811
* TODO(doc) why aren't removals considered?
809
812
*
@@ -831,7 +834,7 @@ class TextLinesMutator {
831
834
* It will skip some newlines by putting them into the splice.
832
835
*
833
836
* @param {number } L -
834
- * @param {boolean } includeInSplice - indicates if attributes are present
837
+ * @param {boolean } includeInSplice - Indicates that attributes are present.
835
838
*/
836
839
skipLines ( L , includeInSplice ) {
837
840
if ( ! L ) return ;
@@ -960,7 +963,7 @@ class TextLinesMutator {
960
963
/** @type {string } */
961
964
const theLine = this . _curSplice [ sline ] ;
962
965
const lineCol = this . _curCol ;
963
- // insert the first new line
966
+ // Insert the chars up to `curCol` and the first new line.
964
967
this . _curSplice [ sline ] = theLine . substring ( 0 , lineCol ) + newLines [ 0 ] ;
965
968
this . _curLine ++ ;
966
969
newLines . splice ( 0 , 1 ) ;
@@ -976,9 +979,8 @@ class TextLinesMutator {
976
979
this . _curLine += newLines . length ;
977
980
}
978
981
} else {
979
- // there are no additional lines
980
- // although the line is put into splice, curLine is not increased, because
981
- // there may be more chars in the line (newline is not reached)
982
+ // There are no additional lines. Although the line is put into splice, curLine is not
983
+ // increased because there may be more chars in the line (newline is not reached).
982
984
const sline = this . _putCurLineInSplice ( ) ;
983
985
if ( ! this . _curSplice [ sline ] ) {
984
986
const err = new Error (
@@ -1277,6 +1279,13 @@ exports.applyToAttribution = (cs, astr, pool) => {
1277
1279
return applyZip ( astr , unpacked . ops , ( op1 , op2 ) => slicerZipperFunc ( op1 , op2 , pool ) ) ;
1278
1280
} ;
1279
1281
1282
+ /**
1283
+ * Applies a changeset to an array of attribute lines.
1284
+ *
1285
+ * @param {string } cs - The encoded changeset.
1286
+ * @param {Array<string> } lines - Attribute lines. Modified in place.
1287
+ * @param {AttributePool } pool - Attribute pool.
1288
+ */
1280
1289
exports . mutateAttributionLines = ( cs , lines , pool ) => {
1281
1290
const unpacked = exports . unpack ( cs ) ;
1282
1291
const csOps = exports . deserializeOps ( unpacked . ops ) ;
@@ -1286,26 +1295,47 @@ exports.mutateAttributionLines = (cs, lines, pool) => {
1286
1295
// treat the attribution lines as text lines, mutating a line at a time
1287
1296
const mut = new TextLinesMutator ( lines ) ;
1288
1297
1289
- /** @type {?Generator<Op> } */
1298
+ /**
1299
+ * The Ops in the current line from `lines`.
1300
+ *
1301
+ * @type {?Generator<Op> }
1302
+ */
1290
1303
let lineOps = null ;
1291
1304
let lineOpsNext = null ;
1292
1305
1293
1306
const lineOpsHasNext = ( ) => lineOpsNext && ! lineOpsNext . done ;
1307
+ /**
1308
+ * Returns false if we are on the last attribute line in `lines` and there is no additional op in
1309
+ * that line.
1310
+ *
1311
+ * @returns {boolean } True if there are more ops to go through.
1312
+ */
1294
1313
const isNextMutOp = ( ) => lineOpsHasNext ( ) || mut . hasMore ( ) ;
1295
1314
1315
+ /**
1316
+ * @returns {Op } The next Op from `lineIter`. If there are no more Ops, `lineIter` is reset to
1317
+ * iterate over the next line, which is consumed from `mut`. If there are no more lines,
1318
+ * returns a null Op.
1319
+ */
1296
1320
const nextMutOp = ( ) => {
1297
1321
if ( ! lineOpsHasNext ( ) && mut . hasMore ( ) ) {
1322
+ // There are more attribute lines in `lines` to do AND either we just started so `lineIter` is
1323
+ // still null or there are no more ops in current `lineIter`.
1298
1324
const line = mut . removeLines ( 1 ) ;
1299
1325
lineOps = exports . deserializeOps ( line ) ;
1300
1326
lineOpsNext = lineOps . next ( ) ;
1301
1327
}
1302
- if ( ! lineOpsHasNext ( ) ) return new Op ( ) ;
1328
+ if ( ! lineOpsHasNext ( ) ) return new Op ( ) ; // No more ops and no more lines.
1303
1329
const op = lineOpsNext . value ;
1304
1330
lineOpsNext = lineOps . next ( ) ;
1305
1331
return op ;
1306
1332
} ;
1307
1333
let lineAssem = null ;
1308
1334
1335
+ /**
1336
+ * Appends an op to `lineAssem`. In case `lineAssem` includes one single newline, adds it to the
1337
+ * `lines` mutator.
1338
+ */
1309
1339
const outputMutOp = ( op ) => {
1310
1340
if ( ! lineAssem ) {
1311
1341
lineAssem = exports . mergingOpAssembler ( ) ;
@@ -1322,25 +1352,29 @@ exports.mutateAttributionLines = (cs, lines, pool) => {
1322
1352
let attOp = new Op ( ) ;
1323
1353
while ( csOp . opcode || ! csOpsNext . done || attOp . opcode || isNextMutOp ( ) ) {
1324
1354
if ( ! csOp . opcode && ! csOpsNext . done ) {
1355
+ // coOp done, but more ops in cs.
1325
1356
csOp = csOpsNext . value ;
1326
1357
csOpsNext = csOps . next ( ) ;
1327
1358
}
1328
1359
if ( ! csOp . opcode && ! attOp . opcode && ! lineAssem && ! lineOpsHasNext ( ) ) {
1329
1360
break ; // done
1330
1361
} else if ( csOp . opcode === '=' && csOp . lines > 0 && ! csOp . attribs && ! attOp . opcode &&
1331
1362
! lineAssem && ! lineOpsHasNext ( ) ) {
1332
- // skip multiple lines; this is what makes small changes not order of the document size
1363
+ // Skip multiple lines without attributes; this is what makes small changes not order of the
1364
+ // document size.
1333
1365
mut . skipLines ( csOp . lines ) ;
1334
1366
csOp . opcode = '' ;
1335
1367
} else if ( csOp . opcode === '+' ) {
1336
1368
const opOut = copyOp ( csOp ) ;
1337
1369
if ( csOp . lines > 1 ) {
1370
+ // Copy the first line from `csOp` to `opOut`.
1338
1371
const firstLineLen = csBank . indexOf ( '\n' , csBankIndex ) + 1 - csBankIndex ;
1339
1372
csOp . chars -= firstLineLen ;
1340
1373
csOp . lines -- ;
1341
1374
opOut . lines = 1 ;
1342
1375
opOut . chars = firstLineLen ;
1343
1376
} else {
1377
+ // Either one or no newlines in '+' `csOp`, copy to `opOut` and reset `csOp`.
1344
1378
csOp . opcode = '' ;
1345
1379
}
1346
1380
outputMutOp ( opOut ) ;
@@ -1758,7 +1792,7 @@ exports.copyAText = (atext1, atext2) => {
1758
1792
} ;
1759
1793
1760
1794
/**
1761
- * Convert AText to a series of operations.
1795
+ * Convert AText to a series of operations. Strips final newline.
1762
1796
*
1763
1797
* @param {AText } atext - The AText to convert.
1764
1798
* @yields {Op}
0 commit comments