Skip to content

Commit c85bf61

Browse files
authored
1 parent 5bd12ec commit c85bf61

File tree

17 files changed

+580
-165
lines changed

17 files changed

+580
-165
lines changed

src/vs/editor/common/diff/algorithms/joinSequenceDiffs.ts

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import { OffsetRange } from 'vs/editor/common/core/offsetRange';
77
import { ISequence, SequenceDiff } from 'vs/editor/common/diff/algorithms/diffAlgorithm';
8+
import { LinesSliceCharSequence } from 'vs/editor/common/diff/standardLinesDiffComputer';
89

910
export function optimizeSequenceDiffs(sequence1: ISequence, sequence2: ISequence, sequenceDiffs: SequenceDiff[]): SequenceDiff[] {
1011
let result = sequenceDiffs;
@@ -32,6 +33,74 @@ export function smoothenSequenceDiffs(sequence1: ISequence, sequence2: ISequence
3233
return result;
3334
}
3435

36+
export function randomRandomMatches(sequence1: LinesSliceCharSequence, sequence2: LinesSliceCharSequence, sequenceDiffs: SequenceDiff[]): SequenceDiff[] {
37+
let diffs = sequenceDiffs;
38+
39+
let counter = 0;
40+
let shouldRepeat: boolean;
41+
do {
42+
shouldRepeat = false;
43+
44+
const result: SequenceDiff[] = [
45+
diffs[0]
46+
];
47+
48+
for (let i = 1; i < diffs.length; i++) {
49+
const cur = diffs[i];
50+
const lastResult = result[result.length - 1];
51+
52+
function shouldJoinDiffs(before: SequenceDiff, after: SequenceDiff): boolean {
53+
const unchangedRange = new OffsetRange(lastResult.seq1Range.endExclusive, cur.seq1Range.start);
54+
55+
const unchangedLineCount = sequence1.countLinesIn(unchangedRange);
56+
if (unchangedLineCount > 5 || unchangedRange.length > 500) {
57+
return false;
58+
}
59+
60+
const unchangedText = sequence1.getText(unchangedRange).trim();
61+
if (unchangedText.length > 20 || unchangedText.split(/\r\n|\r|\n/).length > 1) {
62+
return false;
63+
}
64+
65+
const beforeLineCount1 = sequence1.countLinesIn(before.seq1Range);
66+
const beforeSeq1Length = before.seq1Range.length;
67+
const beforeLineCount2 = sequence2.countLinesIn(before.seq2Range);
68+
const beforeSeq2Length = before.seq2Range.length;
69+
70+
const afterLineCount1 = sequence1.countLinesIn(after.seq1Range);
71+
const afterSeq1Length = after.seq1Range.length;
72+
const afterLineCount2 = sequence2.countLinesIn(after.seq2Range);
73+
const afterSeq2Length = after.seq2Range.length;
74+
75+
// TODO: Maybe a neural net can be used to derive the result from these numbers
76+
77+
const max = 2 * 40 + 50;
78+
function cap(v: number): number {
79+
return Math.min(v, max);
80+
}
81+
82+
if (Math.pow(Math.pow(cap(beforeLineCount1 * 40 + beforeSeq1Length), 1.5) + Math.pow(cap(beforeLineCount2 * 40 + beforeSeq2Length), 1.5), 1.5)
83+
+ Math.pow(Math.pow(cap(afterLineCount1 * 40 + afterSeq1Length), 1.5) + Math.pow(cap(afterLineCount2 * 40 + afterSeq2Length), 1.5), 1.5) > ((max ** 1.5) ** 1.5) * 1.3) {
84+
return true;
85+
}
86+
return false;
87+
}
88+
89+
const shouldJoin = shouldJoinDiffs(lastResult, cur);
90+
if (shouldJoin) {
91+
shouldRepeat = true;
92+
result[result.length - 1] = result[result.length - 1].join(cur);
93+
} else {
94+
result.push(cur);
95+
}
96+
}
97+
98+
diffs = result;
99+
} while (counter++ < 10 && shouldRepeat);
100+
101+
return diffs;
102+
}
103+
35104
/**
36105
* This function fixes issues like this:
37106
* ```

src/vs/editor/common/diff/standardLinesDiffComputer.ts

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { Position } from 'vs/editor/common/core/position';
1111
import { Range } from 'vs/editor/common/core/range';
1212
import { DateTimeout, ISequence, ITimeout, InfiniteTimeout, SequenceDiff } from 'vs/editor/common/diff/algorithms/diffAlgorithm';
1313
import { DynamicProgrammingDiffing } from 'vs/editor/common/diff/algorithms/dynamicProgrammingDiffing';
14-
import { optimizeSequenceDiffs, smoothenSequenceDiffs } from 'vs/editor/common/diff/algorithms/joinSequenceDiffs';
14+
import { optimizeSequenceDiffs, randomRandomMatches, smoothenSequenceDiffs } from 'vs/editor/common/diff/algorithms/joinSequenceDiffs';
1515
import { MyersDiffAlgorithm } from 'vs/editor/common/diff/algorithms/myersDiffAlgorithm';
1616
import { ILinesDiffComputer, ILinesDiffComputerOptions, LineRangeMapping, LinesDiff, MovedText, RangeMapping, SimpleLineRangeMapping } from 'vs/editor/common/diff/linesDiffComputer';
1717

@@ -173,8 +173,8 @@ export class StandardLinesDiffComputer implements ILinesDiffComputer {
173173
}
174174

175175
private refineDiff(originalLines: string[], modifiedLines: string[], diff: SequenceDiff, timeout: ITimeout, considerWhitespaceChanges: boolean): { mappings: RangeMapping[]; hitTimeout: boolean } {
176-
const slice1 = new Slice(originalLines, diff.seq1Range, considerWhitespaceChanges);
177-
const slice2 = new Slice(modifiedLines, diff.seq2Range, considerWhitespaceChanges);
176+
const slice1 = new LinesSliceCharSequence(originalLines, diff.seq1Range, considerWhitespaceChanges);
177+
const slice2 = new LinesSliceCharSequence(modifiedLines, diff.seq2Range, considerWhitespaceChanges);
178178

179179
const diffResult = slice1.length + slice2.length < 500
180180
? this.dynamicProgrammingDiffing.compute(slice1, slice2, timeout)
@@ -184,6 +184,7 @@ export class StandardLinesDiffComputer implements ILinesDiffComputer {
184184
diffs = optimizeSequenceDiffs(slice1, slice2, diffs);
185185
diffs = coverFullWords(slice1, slice2, diffs);
186186
diffs = smoothenSequenceDiffs(slice1, slice2, diffs);
187+
diffs = randomRandomMatches(slice1, slice2, diffs);
187188

188189
const result = diffs.map(
189190
(d) =>
@@ -202,7 +203,7 @@ export class StandardLinesDiffComputer implements ILinesDiffComputer {
202203
}
203204
}
204205

205-
function coverFullWords(sequence1: Slice, sequence2: Slice, sequenceDiffs: SequenceDiff[]): SequenceDiff[] {
206+
function coverFullWords(sequence1: LinesSliceCharSequence, sequence2: LinesSliceCharSequence, sequenceDiffs: SequenceDiff[]): SequenceDiff[] {
206207
const additional: SequenceDiff[] = [];
207208

208209
let lastModifiedWord: { added: number; deleted: number; count: number; s1Range: OffsetRange; s2Range: OffsetRange } | undefined = undefined;
@@ -417,7 +418,7 @@ function getIndentation(str: string): number {
417418
return i;
418419
}
419420

420-
class Slice implements ISequence {
421+
export class LinesSliceCharSequence implements ISequence {
421422
private readonly elements: number[] = [];
422423
private readonly firstCharOffsetByLineMinusOne: number[] = [];
423424
public readonly lineRange: OffsetRange;
@@ -471,7 +472,11 @@ class Slice implements ISequence {
471472
}
472473

473474
get text(): string {
474-
return [...this.elements].map(e => String.fromCharCode(e)).join('');
475+
return this.getText(new OffsetRange(0, this.length));
476+
}
477+
478+
getText(range: OffsetRange): string {
479+
return this.elements.slice(range.start, range.endExclusive).map(e => String.fromCharCode(e)).join('');
475480
}
476481

477482
getElement(offset: number): number {
@@ -559,6 +564,10 @@ class Slice implements ISequence {
559564

560565
return new OffsetRange(start, end);
561566
}
567+
568+
public countLinesIn(range: OffsetRange): number {
569+
return this.translateOffset(range.endExclusive).lineNumber - this.translateOffset(range.start).lineNumber;
570+
}
562571
}
563572

564573
function isWordChar(charCode: number): boolean {

src/vs/editor/test/node/diffing/fixtures/class-replacement/advanced.expected.diff.json

Lines changed: 6 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,8 @@
1313
"modifiedRange": "[29,31)",
1414
"innerChanges": [
1515
{
16-
"originalRange": "[29,1 -> 33,1]",
17-
"modifiedRange": "[29,1 -> 29,1]"
18-
},
19-
{
20-
"originalRange": "[33,14 -> 33,41]",
21-
"modifiedRange": "[29,14 -> 30,54]"
16+
"originalRange": "[29,1 -> 33,41]",
17+
"modifiedRange": "[29,1 -> 30,54]"
2218
}
2319
]
2420
},
@@ -47,16 +43,8 @@
4743
"modifiedRange": "[36,37)",
4844
"innerChanges": [
4945
{
50-
"originalRange": "[41,9 -> 41,18]",
51-
"modifiedRange": "[36,9 -> 36,44]"
52-
},
53-
{
54-
"originalRange": "[41,26 -> 42,34]",
55-
"modifiedRange": "[36,52 -> 36,64]"
56-
},
57-
{
58-
"originalRange": "[43,1 -> 46,1]",
59-
"modifiedRange": "[37,1 -> 37,1]"
46+
"originalRange": "[41,9 -> 46,1]",
47+
"modifiedRange": "[36,9 -> 37,1]"
6048
}
6149
]
6250
},
@@ -65,12 +53,8 @@
6553
"modifiedRange": "[39,40)",
6654
"innerChanges": [
6755
{
68-
"originalRange": "[48,9 -> 63,48]",
69-
"modifiedRange": "[39,9 -> 39,43]"
70-
},
71-
{
72-
"originalRange": "[64,1 -> 72,1]",
73-
"modifiedRange": "[40,1 -> 40,1]"
56+
"originalRange": "[48,9 -> 72,1]",
57+
"modifiedRange": "[39,9 -> 40,1]"
7458
}
7559
]
7660
}

src/vs/editor/test/node/diffing/fixtures/difficult-move/advanced.expected.diff.json

Lines changed: 2 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -43,60 +43,8 @@
4343
"modifiedRange": "[226,234)",
4444
"innerChanges": [
4545
{
46-
"originalRange": "[222,17 -> 222,19]",
47-
"modifiedRange": "[226,17 -> 226,17]"
48-
},
49-
{
50-
"originalRange": "[223,4 -> 223,28]",
51-
"modifiedRange": "[227,4 -> 227,37]"
52-
},
53-
{
54-
"originalRange": "[223,32 -> 223,49]",
55-
"modifiedRange": "[227,41 -> 227,48]"
56-
},
57-
{
58-
"originalRange": "[223,54 -> 223,65]",
59-
"modifiedRange": "[227,53 -> 227,62]"
60-
},
61-
{
62-
"originalRange": "[224,4 -> 224,29]",
63-
"modifiedRange": "[228,4 -> 228,55]"
64-
},
65-
{
66-
"originalRange": "[224,43 -> 225,63]",
67-
"modifiedRange": "[228,69 -> 228,108]"
68-
},
69-
{
70-
"originalRange": "[225,78 -> 226,8]",
71-
"modifiedRange": "[228,123 -> 228,152]"
72-
},
73-
{
74-
"originalRange": "[226,22 -> 226,25]",
75-
"modifiedRange": "[228,166 -> 228,169]"
76-
},
77-
{
78-
"originalRange": "[227,5 -> 227,93]",
79-
"modifiedRange": "[229,5 -> 229,67]"
80-
},
81-
{
82-
"originalRange": "[228,5 -> 228,51]",
83-
"modifiedRange": "[230,5 -> 230,30]"
84-
},
85-
{
86-
"originalRange": "[229,6 -> 229,143]",
87-
"modifiedRange": "[231,6 -> 231,40]"
88-
},
89-
{
90-
"originalRange": "[230,5 -> 232,42]",
91-
"modifiedRange": "[232,5 -> 232,19]"
92-
},
93-
{
94-
"originalRange": "[232,48 -> 232,98]",
95-
"modifiedRange": "[232,25 -> 233,58]"
96-
},
97-
{
98-
"originalRange": "[233,1 -> 234,1]",
99-
"modifiedRange": "[234,1 -> 234,1]"
46+
"originalRange": "[222,17 -> 234,1]",
47+
"modifiedRange": "[226,17 -> 234,1]"
10048
}
10149
]
10250
}

src/vs/editor/test/node/diffing/fixtures/method-splitting/advanced.expected.diff.json

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -33,16 +33,8 @@
3333
"modifiedRange": "[7,9 -> 7,27]"
3434
},
3535
{
36-
"originalRange": "[7,61 -> 7,105]",
37-
"modifiedRange": "[7,50 -> 7,85]"
38-
},
39-
{
40-
"originalRange": "[7,112 -> 8,10]",
41-
"modifiedRange": "[7,92 -> 7,130]"
42-
},
43-
{
44-
"originalRange": "[8,15 -> 10,1]",
45-
"modifiedRange": "[7,135 -> 8,1]"
36+
"originalRange": "[7,61 -> 10,1]",
37+
"modifiedRange": "[7,50 -> 8,1]"
4638
}
4739
]
4840
},
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
this._sash = derivedWithStore('sash', (reader, store) => {
2+
const showSash = this._options.renderSideBySide.read(reader);
3+
this.elements.root.classList.toggle('side-by-side', showSash);
4+
if (!showSash) { return undefined; }
5+
const result = store.add(new DiffEditorSash(
6+
this._options,
7+
this.elements.root,
8+
{
9+
height: this._rootSizeObserver.height,
10+
width: this._rootSizeObserver.width.map((w, reader) => w - (this._options.renderOverviewRuler.read(reader) ? OverviewRulerPart.ENTIRE_DIFF_OVERVIEW_WIDTH : 0)),
11+
}
12+
));
13+
store.add(autorun('setBoundarySashes', reader => {
14+
const boundarySashes = this._boundarySashes.read(reader);
15+
if (boundarySashes) {
16+
result.setBoundarySashes(boundarySashes);
17+
}
18+
}));
19+
return result;
20+
});
21+
this._register(keepAlive(this._sash, true));
22+
23+
this._register(autorunWithStore2('UnchangedRangesFeature', (reader, store) => {
24+
this.unchangedRangesFeature = store.add(new (readHotReloadableExport(UnchangedRangesFeature, reader))(this._editors, this._diffModel, this._options));
25+
}));
26+
27+
this._register(autorunWithStore2('DiffEditorDecorations', (reader, store) => {
28+
store.add(new (readHotReloadableExport(DiffEditorDecorations, reader))(this._editors, this._diffModel, this._options));
29+
}));
30+
this._register(autorunWithStore2('ViewZoneManager', (reader, store) => {
31+
store.add(this._instantiationService.createInstance(
32+
readHotReloadableExport(ViewZoneManager, reader),
33+
this._editors,
34+
this._diffModel,
35+
this._options,
36+
this,
37+
() => this.unchangedRangesFeature.isUpdatingViewZones,
38+
));
39+
}));
40+
41+
this._register(autorunWithStore2('OverviewRulerPart', (reader, store) => {
42+
store.add(this._instantiationService.createInstance(readHotReloadableExport(OverviewRulerPart, reader), this._editors,
43+
this.elements.root,
44+
this._diffModel,
45+
this._rootSizeObserver.width,
46+
this._rootSizeObserver.height,
47+
this._layoutInfo.map(i => i.modifiedEditor),
48+
this._options,
49+
));
50+
}));
51+
52+
this._reviewPane = this._register(this._instantiationService.createInstance(DiffReview2, this));
53+
this.elements.root.appendChild(this._reviewPane.domNode.domNode);
54+
this.elements.root.appendChild(this._reviewPane.actionBarContainer.domNode);
55+
reviewPaneObservable.set(this._reviewPane, undefined);
56+
57+
this._createDiffEditorContributions();

0 commit comments

Comments
 (0)