Changeset: Turn `mergingOpAssembler()` into a real class
parent
9ea424c8f9
commit
cf82261d2b
|
@ -319,13 +319,68 @@ class OpAssembler {
|
|||
/**
|
||||
* Efficiently merges consecutive operations that are mergeable, ignores no-ops, and drops final
|
||||
* pure "keeps". It does not re-order operations.
|
||||
*
|
||||
* @typedef {object} MergingOpAssembler
|
||||
* @property {Function} append -
|
||||
* @property {Function} clear -
|
||||
* @property {Function} endDocument -
|
||||
* @property {Function} toString -
|
||||
*/
|
||||
class MergingOpAssembler {
|
||||
constructor() {
|
||||
this._assem = new OpAssembler();
|
||||
this._bufOp = new Op();
|
||||
// If we get, for example, insertions [xxx\n,yyy], those don't merge, but if we get
|
||||
// [xxx\n,yyy,zzz\n], that merges to [xxx\nyyyzzz\n]. This variable stores the length of yyy and
|
||||
// any other newline-less ops immediately after it.
|
||||
this._bufOpAdditionalCharsAfterNewline = 0;
|
||||
}
|
||||
|
||||
clear() {
|
||||
this._assem.clear();
|
||||
clearOp(this._bufOp);
|
||||
}
|
||||
|
||||
_flush(isEndDocument) {
|
||||
if (!this._bufOp.opcode) return;
|
||||
if (isEndDocument && this._bufOp.opcode === '=' && !this._bufOp.attribs) {
|
||||
// final merged keep, leave it implicit
|
||||
} else {
|
||||
this._assem.append(this._bufOp);
|
||||
if (this._bufOpAdditionalCharsAfterNewline) {
|
||||
this._bufOp.chars = this._bufOpAdditionalCharsAfterNewline;
|
||||
this._bufOp.lines = 0;
|
||||
this._assem.append(this._bufOp);
|
||||
this._bufOpAdditionalCharsAfterNewline = 0;
|
||||
}
|
||||
}
|
||||
this._bufOp.opcode = '';
|
||||
}
|
||||
|
||||
append(op) {
|
||||
if (op.chars <= 0) return;
|
||||
if (this._bufOp.opcode === op.opcode && this._bufOp.attribs === op.attribs) {
|
||||
if (op.lines > 0) {
|
||||
// this._bufOp and additional chars are all mergeable into a multi-line op
|
||||
this._bufOp.chars += this._bufOpAdditionalCharsAfterNewline + op.chars;
|
||||
this._bufOp.lines += op.lines;
|
||||
this._bufOpAdditionalCharsAfterNewline = 0;
|
||||
} else if (this._bufOp.lines === 0) {
|
||||
// both this._bufOp and op are in-line
|
||||
this._bufOp.chars += op.chars;
|
||||
} else {
|
||||
// append in-line text to multi-line this._bufOp
|
||||
this._bufOpAdditionalCharsAfterNewline += op.chars;
|
||||
}
|
||||
} else {
|
||||
this._flush();
|
||||
copyOp(op, this._bufOp);
|
||||
}
|
||||
}
|
||||
|
||||
endDocument() {
|
||||
this._flush(true);
|
||||
}
|
||||
|
||||
toString() {
|
||||
this._flush();
|
||||
return this._assem.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates operations from the given text and attributes.
|
||||
|
@ -438,9 +493,9 @@ exports.checkRep = (cs) => {
|
|||
* @returns {SmartOpAssembler}
|
||||
*/
|
||||
exports.smartOpAssembler = () => {
|
||||
const minusAssem = exports.mergingOpAssembler();
|
||||
const plusAssem = exports.mergingOpAssembler();
|
||||
const keepAssem = exports.mergingOpAssembler();
|
||||
const minusAssem = new MergingOpAssembler();
|
||||
const plusAssem = new MergingOpAssembler();
|
||||
const keepAssem = new MergingOpAssembler();
|
||||
const assem = exports.stringAssembler();
|
||||
let lastOpcode = '';
|
||||
let lengthChange = 0;
|
||||
|
@ -531,73 +586,7 @@ exports.smartOpAssembler = () => {
|
|||
/**
|
||||
* @returns {MergingOpAssembler}
|
||||
*/
|
||||
exports.mergingOpAssembler = () => {
|
||||
const assem = exports.opAssembler();
|
||||
const bufOp = new Op();
|
||||
|
||||
// If we get, for example, insertions [xxx\n,yyy], those don't merge,
|
||||
// but if we get [xxx\n,yyy,zzz\n], that merges to [xxx\nyyyzzz\n].
|
||||
// This variable stores the length of yyy and any other newline-less
|
||||
// ops immediately after it.
|
||||
let bufOpAdditionalCharsAfterNewline = 0;
|
||||
|
||||
const flush = (isEndDocument) => {
|
||||
if (!bufOp.opcode) return;
|
||||
if (isEndDocument && bufOp.opcode === '=' && !bufOp.attribs) {
|
||||
// final merged keep, leave it implicit
|
||||
} else {
|
||||
assem.append(bufOp);
|
||||
if (bufOpAdditionalCharsAfterNewline) {
|
||||
bufOp.chars = bufOpAdditionalCharsAfterNewline;
|
||||
bufOp.lines = 0;
|
||||
assem.append(bufOp);
|
||||
bufOpAdditionalCharsAfterNewline = 0;
|
||||
}
|
||||
}
|
||||
bufOp.opcode = '';
|
||||
};
|
||||
|
||||
const append = (op) => {
|
||||
if (op.chars <= 0) return;
|
||||
if (bufOp.opcode === op.opcode && bufOp.attribs === op.attribs) {
|
||||
if (op.lines > 0) {
|
||||
// bufOp and additional chars are all mergeable into a multi-line op
|
||||
bufOp.chars += bufOpAdditionalCharsAfterNewline + op.chars;
|
||||
bufOp.lines += op.lines;
|
||||
bufOpAdditionalCharsAfterNewline = 0;
|
||||
} else if (bufOp.lines === 0) {
|
||||
// both bufOp and op are in-line
|
||||
bufOp.chars += op.chars;
|
||||
} else {
|
||||
// append in-line text to multi-line bufOp
|
||||
bufOpAdditionalCharsAfterNewline += op.chars;
|
||||
}
|
||||
} else {
|
||||
flush();
|
||||
copyOp(op, bufOp);
|
||||
}
|
||||
};
|
||||
|
||||
const endDocument = () => {
|
||||
flush(true);
|
||||
};
|
||||
|
||||
const toString = () => {
|
||||
flush();
|
||||
return assem.toString();
|
||||
};
|
||||
|
||||
const clear = () => {
|
||||
assem.clear();
|
||||
clearOp(bufOp);
|
||||
};
|
||||
return {
|
||||
append,
|
||||
toString,
|
||||
clear,
|
||||
endDocument,
|
||||
};
|
||||
};
|
||||
exports.mergingOpAssembler = () => new MergingOpAssembler();
|
||||
|
||||
/**
|
||||
* @returns {OpAssembler}
|
||||
|
@ -1301,9 +1290,7 @@ exports.mutateAttributionLines = (cs, lines, pool) => {
|
|||
let lineAssem = null;
|
||||
|
||||
const outputMutOp = (op) => {
|
||||
if (!lineAssem) {
|
||||
lineAssem = exports.mergingOpAssembler();
|
||||
}
|
||||
if (!lineAssem) lineAssem = new MergingOpAssembler();
|
||||
lineAssem.append(op);
|
||||
if (op.lines <= 0) return;
|
||||
assert(op.lines === 1, `Can't have op.lines of ${op.lines} in attribution lines`);
|
||||
|
@ -1357,7 +1344,7 @@ exports.mutateAttributionLines = (cs, lines, pool) => {
|
|||
* @returns {string} joined Attribution lines
|
||||
*/
|
||||
exports.joinAttributionLines = (theAlines) => {
|
||||
const assem = exports.mergingOpAssembler();
|
||||
const assem = new MergingOpAssembler();
|
||||
for (const aline of theAlines) {
|
||||
for (const op of exports.deserializeOps(aline)) assem.append(op);
|
||||
}
|
||||
|
@ -1365,7 +1352,7 @@ exports.joinAttributionLines = (theAlines) => {
|
|||
};
|
||||
|
||||
exports.splitAttributionLines = (attrOps, text) => {
|
||||
const assem = exports.mergingOpAssembler();
|
||||
const assem = new MergingOpAssembler();
|
||||
const lines = [];
|
||||
let pos = 0;
|
||||
|
||||
|
|
Loading…
Reference in New Issue