3
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
4
*--------------------------------------------------------------------------------------------*/
5
5
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' ;
7
7
import { assertFn , checkAdjacentItems } from 'vs/base/common/assert' ;
8
8
import { CharCode } from 'vs/base/common/charCode' ;
9
9
import { SetMap } from 'vs/base/common/collections' ;
10
+ import { BugIndicatingError } from 'vs/base/common/errors' ;
10
11
import { LineRange } from 'vs/editor/common/core/lineRange' ;
11
12
import { OffsetRange } from 'vs/editor/common/core/offsetRange' ;
12
13
import { Position } from 'vs/editor/common/core/position' ;
@@ -302,7 +303,7 @@ export class AdvancedLinesDiffComputer implements ILinesDiffComputer {
302
303
if ( moves . length === 0 ) {
303
304
return [ ] ;
304
305
}
305
- const joinedMoves = [ moves [ 0 ] ] ;
306
+ let joinedMoves = [ moves [ 0 ] ] ;
306
307
for ( let i = 1 ; i < moves . length ; i ++ ) {
307
308
const last = joinedMoves [ joinedMoves . length - 1 ] ;
308
309
const current = moves [ i ] ;
@@ -324,6 +325,19 @@ export class AdvancedLinesDiffComputer implements ILinesDiffComputer {
324
325
joinedMoves . push ( current ) ;
325
326
}
326
327
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
+
327
341
const fullMoves = joinedMoves . map ( m => {
328
342
const moveChanges = this . refineDiff ( originalLines , modifiedLines , new SequenceDiff (
329
343
m . original . toOffsetRange ( ) ,
@@ -366,6 +380,60 @@ export class AdvancedLinesDiffComputer implements ILinesDiffComputer {
366
380
}
367
381
}
368
382
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
+
369
437
function intersectRanges ( ranges1 : LineRange [ ] , ranges2 : LineRange [ ] ) : LineRange [ ] {
370
438
const result : LineRange [ ] = [ ] ;
371
439
@@ -839,16 +907,15 @@ export class LinesSliceCharSequence implements ISequence {
839
907
}
840
908
841
909
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 ;
847
912
return new OffsetRange ( start , end ) ;
848
913
}
849
914
}
850
915
851
916
/**
917
+ * `arr.map(predicate)` must be like `[true, ..., true, false, ..., false]`!
918
+ *
852
919
* @returns -1 if predicate is false for all items
853
920
*/
854
921
function findLastIdxMonotonous < T > ( arr : T [ ] , predicate : ( item : T ) => boolean ) : number {
@@ -865,7 +932,14 @@ function findLastIdxMonotonous<T>(arr: T[], predicate: (item: T) => boolean): nu
865
932
return i - 1 ;
866
933
}
867
934
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
+
868
940
/**
941
+ * `arr.map(predicate)` must be like `[false, ..., false, true, ..., true]`!
942
+ *
869
943
* @returns arr.length if predicate is false for all items
870
944
*/
871
945
function findFirstIdxMonotonous < T > ( arr : T [ ] , predicate : ( item : T ) => boolean ) : number {
@@ -882,6 +956,11 @@ function findFirstIdxMonotonous<T>(arr: T[], predicate: (item: T) => boolean): n
882
956
return i ;
883
957
}
884
958
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
+
885
964
function isWordChar ( charCode : number ) : boolean {
886
965
return charCode >= CharCode . a && charCode <= CharCode . z
887
966
|| charCode >= CharCode . A && charCode <= CharCode . Z
0 commit comments