Skip to content

Commit 3220691

Browse files
committed
Changeset.js: fix handling of line mutations when dealing with the last characters of text
1 parent c828c8e commit 3220691

File tree

2 files changed

+80
-13
lines changed

2 files changed

+80
-13
lines changed

src/static/js/Changeset.js

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -766,7 +766,6 @@ exports.textLinesMutator = (lines) => {
766766
// TODO(doc) should this count the number of characters that are skipped to check?
767767
for (let i = 0; i < L; i++) {
768768
curCol = 0;
769-
putCurLineInSplice();
770769
curLine++;
771770
}
772771
} else {
@@ -844,9 +843,10 @@ exports.textLinesMutator = (lines) => {
844843
curSplice[1] += L - 1;
845844
const sline = curSplice.length - 1;
846845
removed = curSplice[sline].substring(curCol) + removed;
846+
const remaining = linesGet(curSplice[0] + curSplice[1]) || '';
847847
curSplice[sline] = curSplice[sline].substring(0, curCol) +
848-
linesGet(curSplice[0] + curSplice[1]);
849-
curSplice[1] += 1;
848+
remaining;
849+
curSplice[1] += remaining ? 1 : 0;
850850
}
851851
} else {
852852
removed = nextKLinesText(L);
@@ -908,9 +908,12 @@ exports.textLinesMutator = (lines) => {
908908
// insert the remaining new lines
909909
Array.prototype.push.apply(curSplice, newLines);
910910
curLine += newLines.length;
911-
// insert the remaining chars from the "old" line (e.g. the line we were in
912-
// when we started to insert new lines)
913-
curSplice.push(theLine.substring(lineCol));
911+
const remaining = theLine.substring(lineCol);
912+
if (remaining !== '') {
913+
// insert the remaining chars from the "old" line (e.g. the line we were in
914+
// when we started to insert new lines)
915+
curSplice.push(theLine.substring(lineCol));
916+
}
914917
curCol = 0; // TODO(doc) why is this not set to the length of last line?
915918
} else {
916919
Array.prototype.push.apply(curSplice, newLines);
@@ -920,13 +923,20 @@ exports.textLinesMutator = (lines) => {
920923
// there are no additional lines
921924
// although the line is put into splice, curLine is not increased, because
922925
// there may be more chars in the line (newline is not reached)
923-
const sline = putCurLineInSplice();
924-
if (!curSplice[sline]) {
925-
console.error('curSplice[sline] not populated, actual curSplice contents is ', curSplice, '. Possibly related to https://github.com/ether/etherpad-lite/issues/2802');
926+
if (!hasMore()) {
927+
// we are inserting at the end of lines. curCol is 0 or else curLine would be in splice
928+
curSplice.push(text);
929+
curCol += text.length;
930+
} else {
931+
const sline = putCurLineInSplice();
932+
if (!curSplice[sline]) {
933+
// TODO should never happen now
934+
console.error('curSplice[sline] not populated, actual curSplice contents is ', curSplice, '. Possibly related to https://github.com/ether/etherpad-lite/issues/2802');
935+
}
936+
curSplice[sline] = curSplice[sline].substring(0, curCol) + text +
937+
curSplice[sline].substring(curCol);
938+
curCol += text.length;
926939
}
927-
curSplice[sline] = curSplice[sline].substring(0, curCol) + text +
928-
curSplice[sline].substring(curCol);
929-
curCol += text.length;
930940
}
931941
}
932942
};

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

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,54 @@ describe('easysync', function () {
138138
['skip', 1, 1, true],
139139
], ['banana\n', 'cabbage\n', 'duffle\n']);
140140

141+
// #2836 regressions
142+
runMutationTest(8, ['\n'], [
143+
['remove', 1, 1, '\n'],
144+
['insert', 'c', 0],
145+
], ['c']);
146+
147+
runMutationTest(9, ['\n'], [
148+
['remove', 1, 1, '\n'],
149+
['insert', 'a'],
150+
['insert', 'c\n', 1],
151+
], ['ac\n']);
152+
153+
runMutationTest(10, ['\n'], [
154+
['remove', 1, 1, '\n'],
155+
['insert', 'a\n', 1],
156+
['insert', 'c'],
157+
], ['a\n', 'c']);
158+
159+
runMutationTest(11, ['\n', 'fun\n', '\n'], [
160+
['remove', 1, 1, '\n'],
161+
['skip', 4, 1, false],
162+
['remove', 1, 1, '\n'],
163+
['insert', 'c'],
164+
], ['fun\n', 'c']);
165+
166+
runMutationTest(12, ['\n', 'fun\n', '\n'], [
167+
['remove', 1, 1, '\n'],
168+
['skip', 3, 0, false],
169+
['remove', 2, 2, '\n\n'],
170+
['insert', 'c'],
171+
], ['func']);
172+
173+
runMutationTest(13, ['\n', 'fun\n', '\n'], [
174+
['remove', 1, 1, '\n'],
175+
['skip', 3, 0, false],
176+
['remove', 2, 2, '\n\n'],
177+
['insert', 'c'],
178+
['insert', 'a\n', 1],
179+
['insert', 'c'],
180+
], ['funca\n', 'c']);
181+
182+
runMutationTest(14, ['\n', 'fun\n', '\n'], [
183+
['remove', 1, 1, '\n'],
184+
['skip', 2, 0, false],
185+
['remove', 3, 2, 'n\n\n'],
186+
['insert', 'z'],
187+
], ['fuz']);
188+
141189
it('mutatorHasMore', async function () {
142190
const lines = ['1\n', '2\n', '3\n', '4\n'];
143191
let mu;
@@ -178,6 +226,7 @@ describe('easysync', function () {
178226
expect(mu.hasMore()).to.be(false);
179227
});
180228

229+
181230
describe('mutateTextLines', function () {
182231
const testMutateTextLines = (testId, cs, lines, correctLines) => {
183232
it(`testMutateTextLines#${testId}`, async function () {
@@ -189,8 +238,16 @@ describe('easysync', function () {
189238

190239
testMutateTextLines(1, 'Z:4<1|1-2-1|1+1+1$\nc', ['a\n', 'b\n'], ['\n', 'c\n']);
191240
testMutateTextLines(2, 'Z:4>0|1-2-1|2+3$\nc\n', ['a\n', 'b\n'], ['\n', 'c\n', '\n']);
192-
});
193241

242+
it('mutate keep only lines', async function () {
243+
const lines = ['1\n', '2\n', '3\n', '4\n'];
244+
const result = lines.slice();
245+
const cs = 'Z:8>0*0|1=2|2=2';
246+
247+
Changeset.mutateTextLines(cs, lines);
248+
expect(result).to.eql(lines);
249+
});
250+
});
194251

195252
describe('mutate attributions', function () {
196253
const testPoolWithChars = (() => {

0 commit comments

Comments
 (0)