Skip to content

Commit 4538c81

Browse files
committed
1 parent fdcc959 commit 4538c81

File tree

2 files changed

+90
-7
lines changed

2 files changed

+90
-7
lines changed

src/vs/base/common/arrays.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -666,6 +666,10 @@ export namespace CompareResult {
666666
return result < 0;
667667
}
668668

669+
export function isLessThanOrEqual(result: CompareResult): boolean {
670+
return result <= 0;
671+
}
672+
669673
export function isGreaterThan(result: CompareResult): boolean {
670674
return result > 0;
671675
}

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

Lines changed: 86 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@
33
* Licensed under the MIT License. See License.txt in the project root for license information.
44
*--------------------------------------------------------------------------------------------*/
55

6-
import { compareBy, equals, findLastIndex, numberComparator, reverseOrder } from 'vs/base/common/arrays';
6+
import { Comparator, CompareResult, compareBy, equals, findLastIndex, numberComparator, reverseOrder } from 'vs/base/common/arrays';
77
import { assertFn, checkAdjacentItems } from 'vs/base/common/assert';
88
import { CharCode } from 'vs/base/common/charCode';
99
import { SetMap } from 'vs/base/common/collections';
10+
import { BugIndicatingError } from 'vs/base/common/errors';
1011
import { LineRange } from 'vs/editor/common/core/lineRange';
1112
import { OffsetRange } from 'vs/editor/common/core/offsetRange';
1213
import { Position } from 'vs/editor/common/core/position';
@@ -302,7 +303,7 @@ export class AdvancedLinesDiffComputer implements ILinesDiffComputer {
302303
if (moves.length === 0) {
303304
return [];
304305
}
305-
const joinedMoves = [moves[0]];
306+
let joinedMoves = [moves[0]];
306307
for (let i = 1; i < moves.length; i++) {
307308
const last = joinedMoves[joinedMoves.length - 1];
308309
const current = moves[i];
@@ -324,6 +325,19 @@ export class AdvancedLinesDiffComputer implements ILinesDiffComputer {
324325
joinedMoves.push(current);
325326
}
326327

328+
// Ignore non moves
329+
const originalChanges = MonotonousFinder.createOfSorted(changes, c => c.originalRange.endLineNumberExclusive, numberComparator);
330+
joinedMoves = joinedMoves.filter(m => {
331+
const diffBeforeOriginalMove = originalChanges.findLastItemBeforeOrEqual(m.original.startLineNumber)
332+
|| new LineRangeMapping(new LineRange(1, 1), new LineRange(1, 1), []);
333+
334+
const modifiedDistToPrevDiff = m.modified.startLineNumber - diffBeforeOriginalMove.modifiedRange.endLineNumberExclusive;
335+
const originalDistToPrevDiff = m.original.startLineNumber - diffBeforeOriginalMove.originalRange.endLineNumberExclusive;
336+
337+
const differentDistances = modifiedDistToPrevDiff !== originalDistToPrevDiff;
338+
return differentDistances;
339+
});
340+
327341
const fullMoves = joinedMoves.map(m => {
328342
const moveChanges = this.refineDiff(originalLines, modifiedLines, new SequenceDiff(
329343
m.original.toOffsetRange(),
@@ -366,6 +380,60 @@ export class AdvancedLinesDiffComputer implements ILinesDiffComputer {
366380
}
367381
}
368382

383+
class MonotonousFinder<TItem, TDomain> {
384+
public static create<TItem, TDomain>(
385+
items: TItem[],
386+
itemToDomain: (item: TItem) => TDomain,
387+
domainComparator: Comparator<TDomain>,
388+
): MonotonousFinder<TItem, TDomain> {
389+
items.sort((a, b) => domainComparator(itemToDomain(a), itemToDomain(b)));
390+
return new MonotonousFinder(items, itemToDomain, domainComparator);
391+
}
392+
393+
public static createOfSorted<TItem, TDomain>(
394+
items: TItem[],
395+
itemToDomain: (item: TItem) => TDomain,
396+
domainComparator: Comparator<TDomain>,
397+
): MonotonousFinder<TItem, TDomain> {
398+
return new MonotonousFinder(items, itemToDomain, domainComparator);
399+
}
400+
401+
private _currentIdx = 0; // All values with index lower than this are smaller than or equal to _lastValue and vice versa.
402+
private _lastValue: TDomain | undefined = undefined; // Represents a smallest value.
403+
private _hasLastValue = false;
404+
405+
private constructor(
406+
private readonly _items: TItem[],
407+
private readonly _itemToDomain: (item: TItem) => TDomain,
408+
private readonly _domainComparator: Comparator<TDomain>,
409+
) {
410+
}
411+
412+
/**
413+
* Assumes the values are monotonously increasing.
414+
*/
415+
findLastItemBeforeOrEqual(value: TDomain): TItem | undefined {
416+
if (this._hasLastValue && CompareResult.isLessThan(this._domainComparator(value, this._lastValue!))) {
417+
// Values must be monotonously increasing
418+
throw new BugIndicatingError();
419+
}
420+
this._lastValue = value;
421+
this._hasLastValue = true;
422+
423+
while (
424+
this._currentIdx < this._items.length
425+
&& CompareResult.isLessThanOrEqual(this._domainComparator(
426+
this._itemToDomain(this._items[this._currentIdx]),
427+
value
428+
))
429+
) {
430+
this._currentIdx++;
431+
}
432+
433+
return this._currentIdx === 0 ? undefined : this._items[this._currentIdx - 1];
434+
}
435+
}
436+
369437
function intersectRanges(ranges1: LineRange[], ranges2: LineRange[]): LineRange[] {
370438
const result: LineRange[] = [];
371439

@@ -839,16 +907,15 @@ export class LinesSliceCharSequence implements ISequence {
839907
}
840908

841909
public extendToFullLines(range: OffsetRange): OffsetRange {
842-
const firstIdx = findLastIdxMonotonous(this.firstCharOffsetByLineMinusOne, x => x <= range.start);
843-
const lastIdx = findFirstIdxMonotonous(this.firstCharOffsetByLineMinusOne, x => range.endExclusive <= x);
844-
845-
const start = firstIdx === -1 ? 0 : this.firstCharOffsetByLineMinusOne[firstIdx];
846-
const end = lastIdx === this.firstCharOffsetByLineMinusOne.length ? this.elements.length : this.firstCharOffsetByLineMinusOne[lastIdx];
910+
const start = findLastMonotonous(this.firstCharOffsetByLineMinusOne, x => x <= range.start) ?? 0;
911+
const end = findFirstMonotonous(this.firstCharOffsetByLineMinusOne, x => range.endExclusive <= x) ?? this.elements.length;
847912
return new OffsetRange(start, end);
848913
}
849914
}
850915

851916
/**
917+
* `arr.map(predicate)` must be like `[true, ..., true, false, ..., false]`!
918+
*
852919
* @returns -1 if predicate is false for all items
853920
*/
854921
function findLastIdxMonotonous<T>(arr: T[], predicate: (item: T) => boolean): number {
@@ -865,7 +932,14 @@ function findLastIdxMonotonous<T>(arr: T[], predicate: (item: T) => boolean): nu
865932
return i - 1;
866933
}
867934

935+
export function findLastMonotonous<T>(arr: T[], predicate: (item: T) => boolean): T | undefined {
936+
const idx = findLastIdxMonotonous(arr, predicate);
937+
return idx === -1 ? undefined : arr[idx];
938+
}
939+
868940
/**
941+
* `arr.map(predicate)` must be like `[false, ..., false, true, ..., true]`!
942+
*
869943
* @returns arr.length if predicate is false for all items
870944
*/
871945
function findFirstIdxMonotonous<T>(arr: T[], predicate: (item: T) => boolean): number {
@@ -882,6 +956,11 @@ function findFirstIdxMonotonous<T>(arr: T[], predicate: (item: T) => boolean): n
882956
return i;
883957
}
884958

959+
export function findFirstMonotonous<T>(arr: T[], predicate: (item: T) => boolean): T | undefined {
960+
const idx = findFirstIdxMonotonous(arr, predicate);
961+
return idx === arr.length ? undefined : arr[idx];
962+
}
963+
885964
function isWordChar(charCode: number): boolean {
886965
return charCode >= CharCode.a && charCode <= CharCode.z
887966
|| charCode >= CharCode.A && charCode <= CharCode.Z

0 commit comments

Comments
 (0)