mirror of
https://github.com/ether/etherpad-lite.git
synced 2025-01-31 19:02:59 +01:00
Changeset: Turn mergingOpAssembler()
into a real class
This commit is contained in:
parent
9ea424c8f9
commit
cf82261d2b
1 changed files with 68 additions and 81 deletions
|
@ -319,13 +319,68 @@ class OpAssembler {
|
||||||
/**
|
/**
|
||||||
* Efficiently merges consecutive operations that are mergeable, ignores no-ops, and drops final
|
* Efficiently merges consecutive operations that are mergeable, ignores no-ops, and drops final
|
||||||
* pure "keeps". It does not re-order operations.
|
* 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.
|
* Generates operations from the given text and attributes.
|
||||||
|
@ -438,9 +493,9 @@ exports.checkRep = (cs) => {
|
||||||
* @returns {SmartOpAssembler}
|
* @returns {SmartOpAssembler}
|
||||||
*/
|
*/
|
||||||
exports.smartOpAssembler = () => {
|
exports.smartOpAssembler = () => {
|
||||||
const minusAssem = exports.mergingOpAssembler();
|
const minusAssem = new MergingOpAssembler();
|
||||||
const plusAssem = exports.mergingOpAssembler();
|
const plusAssem = new MergingOpAssembler();
|
||||||
const keepAssem = exports.mergingOpAssembler();
|
const keepAssem = new MergingOpAssembler();
|
||||||
const assem = exports.stringAssembler();
|
const assem = exports.stringAssembler();
|
||||||
let lastOpcode = '';
|
let lastOpcode = '';
|
||||||
let lengthChange = 0;
|
let lengthChange = 0;
|
||||||
|
@ -531,73 +586,7 @@ exports.smartOpAssembler = () => {
|
||||||
/**
|
/**
|
||||||
* @returns {MergingOpAssembler}
|
* @returns {MergingOpAssembler}
|
||||||
*/
|
*/
|
||||||
exports.mergingOpAssembler = () => {
|
exports.mergingOpAssembler = () => new 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,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns {OpAssembler}
|
* @returns {OpAssembler}
|
||||||
|
@ -1301,9 +1290,7 @@ exports.mutateAttributionLines = (cs, lines, pool) => {
|
||||||
let lineAssem = null;
|
let lineAssem = null;
|
||||||
|
|
||||||
const outputMutOp = (op) => {
|
const outputMutOp = (op) => {
|
||||||
if (!lineAssem) {
|
if (!lineAssem) lineAssem = new MergingOpAssembler();
|
||||||
lineAssem = exports.mergingOpAssembler();
|
|
||||||
}
|
|
||||||
lineAssem.append(op);
|
lineAssem.append(op);
|
||||||
if (op.lines <= 0) return;
|
if (op.lines <= 0) return;
|
||||||
assert(op.lines === 1, `Can't have op.lines of ${op.lines} in attribution lines`);
|
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
|
* @returns {string} joined Attribution lines
|
||||||
*/
|
*/
|
||||||
exports.joinAttributionLines = (theAlines) => {
|
exports.joinAttributionLines = (theAlines) => {
|
||||||
const assem = exports.mergingOpAssembler();
|
const assem = new MergingOpAssembler();
|
||||||
for (const aline of theAlines) {
|
for (const aline of theAlines) {
|
||||||
for (const op of exports.deserializeOps(aline)) assem.append(op);
|
for (const op of exports.deserializeOps(aline)) assem.append(op);
|
||||||
}
|
}
|
||||||
|
@ -1365,7 +1352,7 @@ exports.joinAttributionLines = (theAlines) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.splitAttributionLines = (attrOps, text) => {
|
exports.splitAttributionLines = (attrOps, text) => {
|
||||||
const assem = exports.mergingOpAssembler();
|
const assem = new MergingOpAssembler();
|
||||||
const lines = [];
|
const lines = [];
|
||||||
let pos = 0;
|
let pos = 0;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue