Skip to content

Commit 2f540c4

Browse files
committed
Manual edit: Simplify add/remove of full lines
Always choose the simplest diff.
1 parent fa32059 commit 2f540c4

File tree

2 files changed

+80
-9
lines changed

2 files changed

+80
-9
lines changed

nbdime-web/src/common/mergeview.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ import {
5050
} from './exceptions';
5151

5252
import {
53-
updateModel
53+
updateModel, shiftAddRemoveLines
5454
} from '../merge/manualedit';
5555

5656

@@ -375,12 +375,13 @@ class DiffView {
375375
debounceChange = window.setTimeout(
376376
update.bind(self, mode), fast === true ? 20 : 250);
377377
}
378-
function change(_cm: CodeMirror.Editor, change: CodeMirror.EditorChangeLinkedList) {
378+
function change(_cm: CodeMirror.Editor, change: CodeMirror.EditorChange) {
379379
let userEdit = !valueIn(change.origin, ['setValue', 'syncModel']);
380380
if (userEdit) {
381381
// Edited by hand!
382-
let baseLine = getMatchingBaseLine(change.from.line, self.lineChunks);
383382
let fullLines = splitLines(self.model.remote!);
383+
shiftAddRemoveLines(fullLines, change);
384+
let baseLine = getMatchingBaseLine(change.from.line, self.lineChunks);
384385
// Update lines with changes
385386
replaceCodeMirrorRange(fullLines, change.from, change.to, change.text);
386387
updateModel({

nbdime-web/src/merge/manualedit.ts

Lines changed: 76 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ function getPartials(diff: AddRem[], options: IUpdateModelOptions, startOffset:
214214
let line = options.baseLine;
215215
let ch = options.editCh;
216216
let {oldval, newval} = options;
217-
let lines: string[] | null = null;
217+
let lines: string[] = options.fullLines;
218218
let key = line;
219219
let linediff = 0;
220220

@@ -245,14 +245,12 @@ function getPartials(diff: AddRem[], options: IUpdateModelOptions, startOffset:
245245
} else if (partialStart) {
246246
// Addrange before current line (abutting)
247247
// and partial edit of current (unedited) line
248-
lines = options.fullLines;
249248
before.push(lines[options.editLine].slice(0, ch));
250249
// Indicate that one unedited line should be removed
251250
linediff = 1;
252251
}
253252
} else if (partialStart) {
254253
// Replace previously unedited line:
255-
lines = options.fullLines;
256254
before = [lines[options.editLine].slice(0, ch)];
257255
// Indicate that one unedited line should be removed
258256
linediff = 1;
@@ -279,9 +277,6 @@ function getPartials(diff: AddRem[], options: IUpdateModelOptions, startOffset:
279277
}
280278
if (!after && !fullDeleteEnd && !fullLineInsertions) {
281279
// Add remains of previously unedited line
282-
if (lines === null) {
283-
lines = options.fullLines;
284-
}
285280
let fullLine = lines[options.editLine + newval.length - 1];
286281
let cut = lastAddedLine.length;
287282
if (newval.length === 1) {
@@ -773,6 +768,81 @@ function patchPatchedModel(options: IUpdateModelOptions, diffs: 'all' | 'custom'
773768
// Add new decisions for changes that do no overlap
774769
}
775770

771+
772+
/**
773+
* Modify certain edits to use trailing newlines instead of leading
774+
*
775+
* Certain edits, e.g. adding a newline link this (bracketed part added):
776+
* line1[\n
777+
* line2]\n
778+
* can better be treated as:
779+
* line1\n
780+
* [line2\n]
781+
*
782+
* Similarly (bracketed part deleted):
783+
* line1[\n
784+
* line2]\n
785+
* can better be treated as:
786+
* line1\n
787+
* [line2\n]
788+
*
789+
* The end results are the same, but the diffs become simpler.
790+
*
791+
* Note that this needs to be called before base line is computed!
792+
*/
793+
export
794+
function shiftAddRemoveLines(base: string[], change: CodeMirror.EditorChange) {
795+
if (change.from.ch === 0) {
796+
// Nothing to do here
797+
return;
798+
}
799+
if (change.removed.length === 1 && change.removed[0] === '') {
800+
// Nothing removed
801+
// Check whether first inserted character is newline
802+
if (change.text.length > 1 && change.text[0] === '') {
803+
// and first subsequent character is newline
804+
let trailingLine = base[change.to.line];
805+
if (trailingLine.length > change.to.ch && trailingLine[change.to.ch] === '\n') {
806+
// Match, shift newline from head to tail
807+
change.from.line += 1;
808+
change.from.ch = 0;
809+
change.text.push(change.text.shift()!);
810+
}
811+
}
812+
} else if (change.text.length === 1 && change.text[0] === '') {
813+
// Nothing added
814+
// Check whether first removed character is newline
815+
if (change.removed.length > 1 && change.removed[0] === '') {
816+
// and first subsequent character is newline
817+
let trailingLine = base[change.to.line];
818+
if (trailingLine.length > change.to.ch && trailingLine[change.to.ch] === '\n') {
819+
// Match, shift newline from head to tail
820+
change.from.line += 1;
821+
change.from.ch = 0;
822+
change.to.line += 1;
823+
change.to.ch = 0;
824+
change.removed.push(change.removed.shift()!);
825+
}
826+
}
827+
} else {
828+
// Both added and removed
829+
// Check whether first removed character is newline
830+
if (change.removed.length > 1 && change.removed[0] === '') {
831+
// and first subsequent character is newline
832+
let trailingLine = base[change.to.line];
833+
if (trailingLine.length > change.to.ch && trailingLine[change.to.ch] === '\n') {
834+
// Match, shift newline from head to tail
835+
change.from.line += 1;
836+
change.from.ch = 0;
837+
change.to.line += 1;
838+
change.to.ch = 0;
839+
change.text.push(change.text.shift()!);
840+
change.removed.push(change.removed.shift()!);
841+
}
842+
}
843+
}
844+
}
845+
776846
export
777847
function updateModel(options: IUpdateModelOptions) {
778848
let model = options.model;

0 commit comments

Comments
 (0)