@@ -799,7 +799,7 @@ export class LcsDiff {
799799 do {
800800 mergedDiffs = false ;
801801
802- // Shift all the changes first
802+ // Shift all the changes down first
803803 for ( let i = 0 ; i < changes . length ; i ++ ) {
804804 const change = changes [ i ] ;
805805 const originalStop = ( i < changes . length - 1 ) ? changes [ i + 1 ] . originalStart : this . OriginalSequence . getLength ( ) ;
@@ -834,9 +834,105 @@ export class LcsDiff {
834834 changes = result ;
835835 } while ( mergedDiffs ) ;
836836
837+ // Shift changes back up until we hit empty or whitespace-only lines
838+ for ( let i = changes . length - 1 ; i >= 0 ; i -- ) {
839+ const change = changes [ i ] ;
840+
841+ let originalStop = 0 ;
842+ let modifiedStop = 0 ;
843+ if ( i > 0 ) {
844+ const prevChange = changes [ i - 1 ] ;
845+ if ( prevChange . originalLength > 0 ) {
846+ originalStop = prevChange . originalStart + prevChange . originalLength ;
847+ }
848+ if ( prevChange . modifiedLength > 0 ) {
849+ modifiedStop = prevChange . modifiedStart + prevChange . modifiedLength ;
850+ }
851+ }
852+
853+ const checkOriginal = change . originalLength > 0 ;
854+ const checkModified = change . modifiedLength > 0 ;
855+
856+ let bestDelta = 0 ;
857+ let bestScore = this . _boundaryScore ( change . originalStart , change . originalLength , change . modifiedStart , change . modifiedLength ) ;
858+
859+ for ( let delta = 1 ; ; delta ++ ) {
860+ let originalStart = change . originalStart - delta ;
861+ let modifiedStart = change . modifiedStart - delta ;
862+
863+ if ( originalStart < originalStop || modifiedStart < modifiedStart ) {
864+ break ;
865+ }
866+
867+ if ( checkOriginal && ! this . OriginalElementsAreEqual ( originalStart , originalStart + change . originalLength ) ) {
868+ break ;
869+ }
870+
871+ if ( checkModified && ! this . ModifiedElementsAreEqual ( modifiedStart , modifiedStart + change . modifiedLength ) ) {
872+ break ;
873+ }
874+
875+ let score = this . _boundaryScore ( originalStart , change . originalLength , modifiedStart , change . modifiedLength ) ;
876+
877+ if ( score > bestScore ) {
878+ bestScore = score ;
879+ bestDelta = delta ;
880+ }
881+ }
882+
883+ change . originalStart -= bestDelta ;
884+ change . modifiedStart -= bestDelta ;
885+ }
886+
837887 return changes ;
838888 }
839889
890+ private _OriginalIsBoundary ( index : number ) : boolean {
891+ if ( index <= 0 || index >= this . OriginalSequence . getLength ( ) - 1 ) {
892+ return true ;
893+ }
894+ return / ^ \s * $ / . test ( this . OriginalSequence . getElementHash ( index ) ) ;
895+ }
896+
897+ private _OriginalRegionIsBoundary ( originalStart : number , originalLength : number ) : boolean {
898+ if ( this . _OriginalIsBoundary ( originalStart ) || this . _OriginalIsBoundary ( originalStart - 1 ) ) {
899+ return true ;
900+ }
901+ if ( originalLength > 0 ) {
902+ let originalEnd = originalStart + originalLength ;
903+ if ( this . _OriginalIsBoundary ( originalEnd - 1 ) || this . _OriginalIsBoundary ( originalEnd ) ) {
904+ return true ;
905+ }
906+ }
907+ return false ;
908+ }
909+
910+ private _ModifiedIsBoundary ( index : number ) : boolean {
911+ if ( index <= 0 || index >= this . ModifiedSequence . getLength ( ) - 1 ) {
912+ return true ;
913+ }
914+ return / ^ \s * $ / . test ( this . ModifiedSequence . getElementHash ( index ) ) ;
915+ }
916+
917+ private _ModifiedRegionIsBoundary ( modifiedStart : number , modifiedLength : number ) : boolean {
918+ if ( this . _ModifiedIsBoundary ( modifiedStart ) || this . _ModifiedIsBoundary ( modifiedStart - 1 ) ) {
919+ return true ;
920+ }
921+ if ( modifiedLength > 0 ) {
922+ let modifiedEnd = modifiedStart + modifiedLength ;
923+ if ( this . _ModifiedIsBoundary ( modifiedEnd - 1 ) || this . _ModifiedIsBoundary ( modifiedEnd ) ) {
924+ return true ;
925+ }
926+ }
927+ return false ;
928+ }
929+
930+ private _boundaryScore ( originalStart : number , originalLength : number , modifiedStart : number , modifiedLength : number ) : number {
931+ let originalScore = ( this . _OriginalRegionIsBoundary ( originalStart , originalLength ) ? 1 : 0 ) ;
932+ let modifiedScore = ( this . _ModifiedRegionIsBoundary ( modifiedStart , modifiedLength ) ? 1 : 0 ) ;
933+ return ( originalScore + modifiedScore ) ;
934+ }
935+
840936 /**
841937 * Concatenates the two input DiffChange lists and returns the resulting
842938 * list.
0 commit comments