]> git.ipfire.org Git - thirdparty/git.git/blobdiff - git-add--interactive.perl
add -p: calculate offset delta for edited patches
[thirdparty/git.git] / git-add--interactive.perl
index 28b325d75481b74e8f7b16485e1fc18ad854161c..b5f01160c5c6d8abb9bea65d1efb85bf62bd0d73 100755 (executable)
@@ -751,6 +751,15 @@ sub parse_hunk_header {
        return ($o_ofs, $o_cnt, $n_ofs, $n_cnt);
 }
 
+sub format_hunk_header {
+       my ($o_ofs, $o_cnt, $n_ofs, $n_cnt) = @_;
+       return ("@@ -$o_ofs" .
+               (($o_cnt != 1) ? ",$o_cnt" : '') .
+               " +$n_ofs" .
+               (($n_cnt != 1) ? ",$n_cnt" : '') .
+               " @@\n");
+}
+
 sub split_hunk {
        my ($text, $display) = @_;
        my @split = ();
@@ -838,11 +847,7 @@ sub split_hunk {
                my $o_cnt = $hunk->{OCNT};
                my $n_cnt = $hunk->{NCNT};
 
-               my $head = ("@@ -$o_ofs" .
-                           (($o_cnt != 1) ? ",$o_cnt" : '') .
-                           " +$n_ofs" .
-                           (($n_cnt != 1) ? ",$n_cnt" : '') .
-                           " @@\n");
+               my $head = format_hunk_header($o_ofs, $o_cnt, $n_ofs, $n_cnt);
                my $display_head = $head;
                unshift @{$hunk->{TEXT}}, $head;
                if ($diff_use_color) {
@@ -912,11 +917,7 @@ sub merge_hunk {
                }
                push @line, $line;
        }
-       my $head = ("@@ -$o0_ofs" .
-                   (($o_cnt != 1) ? ",$o_cnt" : '') .
-                   " +$n0_ofs" .
-                   (($n_cnt != 1) ? ",$n_cnt" : '') .
-                   " @@\n");
+       my $head = format_hunk_header($o0_ofs, $o_cnt, $n0_ofs, $n_cnt);
        @{$prev->{TEXT}} = ($head, @line);
 }
 
@@ -925,14 +926,35 @@ sub coalesce_overlapping_hunks {
        my @out = ();
 
        my ($last_o_ctx, $last_was_dirty);
+       my $ofs_delta = 0;
 
-       for (grep { $_->{USE} } @in) {
+       for (@in) {
                if ($_->{TYPE} ne 'hunk') {
                        push @out, $_;
                        next;
                }
                my $text = $_->{TEXT};
-               my ($o_ofs) = parse_hunk_header($text->[0]);
+               my ($o_ofs, $o_cnt, $n_ofs, $n_cnt) =
+                                               parse_hunk_header($text->[0]);
+               unless ($_->{USE}) {
+                       $ofs_delta += $o_cnt - $n_cnt;
+                       # If this hunk has been edited then subtract
+                       # the delta that is due to the edit.
+                       if ($_->{OFS_DELTA}) {
+                               $ofs_delta -= $_->{OFS_DELTA};
+                       }
+                       next;
+               }
+               if ($ofs_delta) {
+                       $n_ofs += $ofs_delta;
+                       $_->{TEXT}->[0] = format_hunk_header($o_ofs, $o_cnt,
+                                                            $n_ofs, $n_cnt);
+               }
+               # If this hunk was edited then adjust the offset delta
+               # to reflect the edit.
+               if ($_->{OFS_DELTA}) {
+                       $ofs_delta += $_->{OFS_DELTA};
+               }
                if (defined $last_o_ctx &&
                    $o_ofs <= $last_o_ctx &&
                    !$_->{DIRTY} &&
@@ -1004,6 +1026,30 @@ marked for discarding."),
 marked for applying."),
 );
 
+sub recount_edited_hunk {
+       local $_;
+       my ($oldtext, $newtext) = @_;
+       my ($o_cnt, $n_cnt) = (0, 0);
+       for (@{$newtext}[1..$#{$newtext}]) {
+               my $mode = substr($_, 0, 1);
+               if ($mode eq '-') {
+                       $o_cnt++;
+               } elsif ($mode eq '+') {
+                       $n_cnt++;
+               } elsif ($mode eq ' ') {
+                       $o_cnt++;
+                       $n_cnt++;
+               }
+       }
+       my ($o_ofs, undef, $n_ofs, undef) =
+                                       parse_hunk_header($newtext->[0]);
+       $newtext->[0] = format_hunk_header($o_ofs, $o_cnt, $n_ofs, $n_cnt);
+       my (undef, $orig_o_cnt, undef, $orig_n_cnt) =
+                                       parse_hunk_header($oldtext->[0]);
+       # Return the change in the number of lines inserted by this hunk
+       return $orig_o_cnt - $orig_n_cnt - $o_cnt + $n_cnt;
+}
+
 sub edit_hunk_manually {
        my ($oldtext) = @_;
 
@@ -1102,25 +1148,32 @@ sub prompt_yesno {
 }
 
 sub edit_hunk_loop {
-       my ($head, $hunk, $ix) = @_;
-       my $text = $hunk->[$ix]->{TEXT};
+       my ($head, $hunks, $ix) = @_;
+       my $hunk = $hunks->[$ix];
+       my $text = $hunk->{TEXT};
 
        while (1) {
-               $text = edit_hunk_manually($text);
-               if (!defined $text) {
+               my $newtext = edit_hunk_manually($text);
+               if (!defined $newtext) {
                        return undef;
                }
                my $newhunk = {
-                       TEXT => $text,
-                       TYPE => $hunk->[$ix]->{TYPE},
+                       TEXT => $newtext,
+                       TYPE => $hunk->{TYPE},
                        USE => 1,
                        DIRTY => 1,
                };
+               $newhunk->{OFS_DELTA} = recount_edited_hunk($text, $newtext);
+               # If this hunk has already been edited then add the
+               # offset delta of the previous edit to get the real
+               # delta from the original unedited hunk.
+               $hunk->{OFS_DELTA} and
+                               $newhunk->{OFS_DELTA} += $hunk->{OFS_DELTA};
                if (diff_applies($head,
-                                @{$hunk}[0..$ix-1],
+                                @{$hunks}[0..$ix-1],
                                 $newhunk,
-                                @{$hunk}[$ix+1..$#{$hunk}])) {
-                       $newhunk->{DISPLAY} = [color_diff(@{$text})];
+                                @{$hunks}[$ix+1..$#{$hunks}])) {
+                       $newhunk->{DISPLAY} = [color_diff(@{$newtext})];
                        return $newhunk;
                }
                else {