On Mon, Jun 09, 2008 at 11:19:23PM +0200, Johan Herland wrote: > On Monday 09 June 2008, Jeff King wrote: > > But honestly, I don't really see a use case that isn't covered by > > "manually edit the diff and apply the hunk". And the rationale in your > > "side note" indicates that you think the same way. Below is a simple patch to build interactive edit support on top of Dscho's "git apply --recount" patch. Rather than create new hunks, the action is just "edit and apply": if the apply is successful, the hunk is removed from further consideration. This is just for playing with, and not for commit: - it's not very well tested :) - I think the recount stuff may have flaws; I didn't follow the thread too closely, but Junio seemed to have a lot of comments (I am working under the assumption that Dscho will get that part right, and we can just build on top of it) - I tried one or two simple tests where I edited and applied an early hunk, and then resumed the loop for later hunks. Everything seemed to work, but I am not convinced that it isn't possible to make the rest of the hunk selection loop useless by applying early and invalidating all of the other hunks. That might be a flaw with this approach. A more sane interface might be to simply jump from the hunk selection loop into manually editing _all_ hunks and then applying, ending the hunk selection loop. This should be applied on top of "allow git-apply to ignore the hunk headers" (v3) which can be found on the list. Obviously significant portions of the patch below are based on Thomas' version. -- >8 -- git-add--interactive: manual hunk editing mode Adds a new option 'e' to the 'add -p' command loop that lets you edit the current hunk in your favourite editor, applying the result. --- git-add--interactive.perl | 81 +++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 81 insertions(+), 0 deletions(-) diff --git a/git-add--interactive.perl b/git-add--interactive.perl index 903953e..62b5aed 100755 --- a/git-add--interactive.perl +++ b/git-add--interactive.perl @@ -2,6 +2,7 @@ use strict; use Git; +use File::Temp; my $repo = Git->repository(); @@ -770,6 +771,76 @@ sub coalesce_overlapping_hunks { return @out; } +sub edit_hunk_manually { + my ($oldtext) = @_; + + my $t = File::Temp->new( + TEMPLATE => $repo->repo_path . "/git-hunk-edit.XXXXXX", + SUFFIX => '.diff' + ); + print $t "# Manual hunk edit mode -- see bottom for a quick guide\n"; + print $t @$oldtext; + print $t <<EOF; +# --- +# To remove '-' lines, make them ' ' lines (context). +# To remove '+' lines, delete them. +# Empty lines and lines starting with # will be removed. +# +# Lines starting with @ start a new hunk. Line counts will be adjusted +# according to contents. If the line numbers are missing altogether, +# they will be inferred from the previous hunk. +# +# You can change the hunk to your heart's content, but it will be +# refused if the end result (the entire patch including your edited +# hunk) does not apply cleanly. +EOF + close $t; + + my $editor = $ENV{GIT_EDITOR} || $repo->config("core.editor") + || $ENV{VISUAL} || $ENV{EDITOR} || "vi"; + system('sh', '-c', $editor.' "$@"', $editor, $t); + + open my $fh, '<', $t + or die "failed to open hunk edit file for reading: " . $!; + my @newtext = grep { !/^#/ } <$fh>; + close $fh; + + # Reinsert the first hunk header if the user accidentally deleted it + if ($newtext[0] !~ /^@/) { + unshift @newtext, $oldtext->[0]; + } + return \@newtext; +} + +sub apply_diff { + open(my $fh, '|-', qw(git apply --cached --recount)); + print $fh map { @$_ } @_; + return close $fh; +} + +sub prompt_yesno { + my ($prompt) = @_; + while (1) { + print colored $prompt_color, $prompt; + my $line = <STDIN>; + return 0 if $line =~ /^n/i; + return 1 if $line =~ /^y/i; + } +} + +sub edit_hunk_loop { + my ($head, $text) = @_; + + while (1) { + $text = edit_hunk_manually($text); + apply_diff($head, $text) and return 1; + prompt_yesno( + 'Your edited hunk does not apply. Edit again ' + . '(saying "no" discards!) [y/n]? ' + ) or return 0; + } +} + sub help_patch_cmd { print colored $help_color, <<\EOF ; y - stage this hunk @@ -781,6 +852,7 @@ J - leave this hunk undecided, see next hunk k - leave this hunk undecided, see previous undecided hunk K - leave this hunk undecided, see previous hunk s - split the current hunk into smaller hunks +e - manually edit the current hunk ? - print help EOF } @@ -885,6 +957,7 @@ sub patch_update_file { if (hunk_splittable($hunk[$ix]{TEXT})) { $other .= '/s'; } + $other .= '/e'; for (@{$hunk[$ix]{DISPLAY}}) { print; } @@ -949,6 +1022,14 @@ sub patch_update_file { $num = scalar @hunk; next; } + elsif ($line =~ /^e/) { + if (edit_hunk_loop($head->{TEXT}, + $hunk[$ix]{TEXT})) { + splice @hunk, $ix, 1; + $num = @hunk; + } + next; + } else { help_patch_cmd($other); next; -- 1.5.6.rc2.26.gda075.dirty -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html