@@ -767,6 +767,96 @@ sub split_hunk {
767
767
return @split ;
768
768
}
769
769
770
+ sub find_last_o_ctx {
771
+ my ($it ) = @_ ;
772
+ my $text = $it -> {TEXT };
773
+ my ($o_ofs , $o_cnt ) = parse_hunk_header($text -> [0]);
774
+ my $i = @{$text };
775
+ my $last_o_ctx = $o_ofs + $o_cnt ;
776
+ while (0 < --$i ) {
777
+ my $line = $text -> [$i ];
778
+ if ($line =~ / ^ / ) {
779
+ $last_o_ctx --;
780
+ next ;
781
+ }
782
+ last ;
783
+ }
784
+ return $last_o_ctx ;
785
+ }
786
+
787
+ sub merge_hunk {
788
+ my ($prev , $this ) = @_ ;
789
+ my ($o0_ofs , $o0_cnt , $n0_ofs , $n0_cnt ) =
790
+ parse_hunk_header($prev -> {TEXT }[0]);
791
+ my ($o1_ofs , $o1_cnt , $n1_ofs , $n1_cnt ) =
792
+ parse_hunk_header($this -> {TEXT }[0]);
793
+
794
+ my (@line , $i , $ofs , $o_cnt , $n_cnt );
795
+ $ofs = $o0_ofs ;
796
+ $o_cnt = $n_cnt = 0;
797
+ for ($i = 1; $i < @{$prev -> {TEXT }}; $i ++) {
798
+ my $line = $prev -> {TEXT }[$i ];
799
+ if ($line =~ / ^\+ / ) {
800
+ $n_cnt ++;
801
+ push @line , $line ;
802
+ next ;
803
+ }
804
+
805
+ last if ($o1_ofs <= $ofs );
806
+
807
+ $o_cnt ++;
808
+ $ofs ++;
809
+ if ($line =~ / ^ / ) {
810
+ $n_cnt ++;
811
+ }
812
+ push @line , $line ;
813
+ }
814
+
815
+ for ($i = 1; $i < @{$this -> {TEXT }}; $i ++) {
816
+ my $line = $this -> {TEXT }[$i ];
817
+ if ($line =~ / ^\+ / ) {
818
+ $n_cnt ++;
819
+ push @line , $line ;
820
+ next ;
821
+ }
822
+ $ofs ++;
823
+ $o_cnt ++;
824
+ if ($line =~ / ^ / ) {
825
+ $n_cnt ++;
826
+ }
827
+ push @line , $line ;
828
+ }
829
+ my $head = (" @@ -$o0_ofs " .
830
+ (($o_cnt != 1) ? " ,$o_cnt " : ' ' ) .
831
+ " +$n0_ofs " .
832
+ (($n_cnt != 1) ? " ,$n_cnt " : ' ' ) .
833
+ " @@\n " );
834
+ @{$prev -> {TEXT }} = ($head , @line );
835
+ }
836
+
837
+ sub coalesce_overlapping_hunks {
838
+ my (@in ) = @_ ;
839
+ my @out = ();
840
+
841
+ my ($last_o_ctx , $last_was_dirty );
842
+
843
+ for (grep { $_ -> {USE } } @in ) {
844
+ my $text = $_ -> {TEXT };
845
+ my ($o_ofs ) = parse_hunk_header($text -> [0]);
846
+ if (defined $last_o_ctx &&
847
+ $o_ofs <= $last_o_ctx &&
848
+ !$_ -> {DIRTY } &&
849
+ !$last_was_dirty ) {
850
+ merge_hunk($out [-1], $_ );
851
+ }
852
+ else {
853
+ push @out , $_ ;
854
+ }
855
+ $last_o_ctx = find_last_o_ctx($out [-1]);
856
+ $last_was_dirty = $_ -> {DIRTY };
857
+ }
858
+ return @out ;
859
+ }
770
860
771
861
sub color_diff {
772
862
return map {
@@ -878,7 +968,8 @@ sub edit_hunk_loop {
878
968
my $newhunk = {
879
969
TEXT => $text ,
880
970
TYPE => $hunk -> [$ix ]-> {TYPE },
881
- USE => 1
971
+ USE => 1,
972
+ DIRTY => 1,
882
973
};
883
974
if (diff_applies($head ,
884
975
@{$hunk }[0..$ix -1],
@@ -1210,6 +1301,8 @@ sub patch_update_file {
1210
1301
}
1211
1302
}
1212
1303
1304
+ @hunk = coalesce_overlapping_hunks(@hunk );
1305
+
1213
1306
my $n_lofs = 0;
1214
1307
my @result = ();
1215
1308
for (@hunk ) {
@@ -1224,6 +1317,7 @@ sub patch_update_file {
1224
1317
open $fh , ' | git apply --cached --recount' ;
1225
1318
for (@{$head -> {TEXT }}, @result ) {
1226
1319
print $fh $_ ;
1320
+ print STDERR $_ ;
1227
1321
}
1228
1322
if (!close $fh ) {
1229
1323
for (@{$head -> {TEXT }}, @result ) {
0 commit comments