X-Git-Url: https://asedeno.scripts.mit.edu/gitweb/?a=blobdiff_plain;f=git-add--interactive.perl;h=f6e536ece314316ebb281721ed27d7519577202f;hb=8146f19762c8fd67f6df3da4ba87a4e5ea880909;hp=f7b0761732f4a752cc91fd7ca02e3a3e07dcfc17;hpb=2e2e91d6b27f522707322835a1f8c4a5e18a2419;p=git.git diff --git a/git-add--interactive.perl b/git-add--interactive.perl index f7b076173..f6e536ece 100755 --- a/git-add--interactive.perl +++ b/git-add--interactive.perl @@ -3,6 +3,8 @@ use strict; use Git; +binmode(STDOUT, ":raw"); + my $repo = Git->repository(); my $menu_use_color = $repo->get_colorbool('color.interactive'); @@ -91,6 +93,47 @@ if (!defined $GIT_DIR) { } chomp($GIT_DIR); +my %cquote_map = ( + "b" => chr(8), + "t" => chr(9), + "n" => chr(10), + "v" => chr(11), + "f" => chr(12), + "r" => chr(13), + "\\" => "\\", + "\042" => "\042", +); + +sub unquote_path { + local ($_) = @_; + my ($retval, $remainder); + if (!/^\042(.*)\042$/) { + return $_; + } + ($_, $retval) = ($1, ""); + while (/^([^\\]*)\\(.*)$/) { + $remainder = $2; + $retval .= $1; + for ($remainder) { + if (/^([0-3][0-7][0-7])(.*)$/) { + $retval .= chr(oct($1)); + $_ = $2; + last; + } + if (/^([\\\042btnvfr])(.*)$/) { + $retval .= $cquote_map{$1}; + $_ = $2; + last; + } + # This is malformed -- just return it as-is for now. + return $_[0]; + } + $_ = $remainder; + } + $retval .= $_; + return $retval; +} + sub refresh { my $fh; open $fh, 'git update-index --refresh |' @@ -104,7 +147,7 @@ sub refresh { sub list_untracked { map { chomp $_; - $_; + unquote_path($_); } run_cmd_pipe(qw(git ls-files --others --exclude-standard --), @ARGV); } @@ -141,7 +184,8 @@ sub list_modified { if (@ARGV) { @tracked = map { - chomp $_; $_; + chomp $_; + unquote_path($_); } run_cmd_pipe(qw(git ls-files --exclude-standard --), @ARGV); return if (!@tracked); } @@ -153,6 +197,7 @@ sub list_modified { if (($add, $del, $file) = /^([-\d]+) ([-\d]+) (.*)/) { my ($change, $bin); + $file = unquote_path($file); if ($add eq '-' && $del eq '-') { $change = 'binary'; $bin = 1; @@ -168,6 +213,7 @@ sub list_modified { } elsif (($adddel, $file) = /^ (create|delete) mode [0-7]+ (.*)$/) { + $file = unquote_path($file); $data{$file}{INDEX_ADDDEL} = $adddel; } } @@ -175,6 +221,7 @@ sub list_modified { for (run_cmd_pipe(qw(git diff-files --numstat --summary --), @tracked)) { if (($add, $del, $file) = /^([-\d]+) ([-\d]+) (.*)/) { + $file = unquote_path($file); if (!exists $data{$file}) { $data{$file} = +{ INDEX => 'unchanged', @@ -196,6 +243,7 @@ sub list_modified { } elsif (($adddel, $file) = /^ (create|delete) mode [0-7]+ (.*)$/) { + $file = unquote_path($file); $data{$file}{FILE_ADDDEL} = $adddel; } } @@ -302,7 +350,8 @@ sub find_unique_prefixes { } %search = %{$search{$letter}}; } - if ($soft_limit && $j + 1 > $soft_limit) { + if (ord($letters[0]) > 127 || + ($soft_limit && $j + 1 > $soft_limit)) { $prefix = undef; $remainder = $ret; } @@ -571,11 +620,12 @@ sub parse_diff { if ($diff_use_color) { @colored = run_cmd_pipe(qw(git diff-files -p --color --), $path); } - my (@hunk) = { TEXT => [], DISPLAY => [] }; + my (@hunk) = { TEXT => [], DISPLAY => [], TYPE => 'header' }; for (my $i = 0; $i < @diff; $i++) { if ($diff[$i] =~ /^@@ /) { - push @hunk, { TEXT => [], DISPLAY => [] }; + push @hunk, { TEXT => [], DISPLAY => [], + TYPE => 'hunk' }; } push @{$hunk[-1]{TEXT}}, $diff[$i]; push @{$hunk[-1]{DISPLAY}}, @@ -587,8 +637,8 @@ sub parse_diff { sub parse_diff_header { my $src = shift; - my $head = { TEXT => [], DISPLAY => [] }; - my $mode = { TEXT => [], DISPLAY => [] }; + my $head = { TEXT => [], DISPLAY => [], TYPE => 'header' }; + my $mode = { TEXT => [], DISPLAY => [], TYPE => 'mode' }; for (my $i = 0; $i < @{$src->{TEXT}}; $i++) { my $dest = $src->{TEXT}->[$i] =~ /^(old|new) mode (\d+)$/ ? @@ -635,6 +685,7 @@ sub split_hunk { my $this = +{ TEXT => [], DISPLAY => [], + TYPE => 'hunk', OLD => $o_ofs, NEW => $n_ofs, OCNT => 0, @@ -824,7 +875,11 @@ sub edit_hunk_loop { if (!defined $text) { return undef; } - my $newhunk = { TEXT => $text, USE => 1 }; + my $newhunk = { + TEXT => $text, + TYPE => $hunk->[$ix]->{TYPE}, + USE => 1 + }; if (diff_applies($head, @{$hunk}[0..$ix-1], $newhunk, @@ -845,6 +900,7 @@ sub help_patch_cmd { print colored $help_color, <<\EOF ; y - stage this hunk n - do not stage this hunk +q - quit, do not stage this hunk nor any of the remaining ones a - stage this and all the remaining hunks in the file d - do not stage this hunk nor any of the remaining hunks in the file g - select a hunk to go to @@ -881,7 +937,7 @@ sub patch_update_cmd { @mods); } for (@them) { - patch_update_file($_->{VALUE}); + return 0 if patch_update_file($_->{VALUE}); } } @@ -927,6 +983,7 @@ sub display_hunks { } sub patch_update_file { + my $quit = 0; my ($ix, $num); my $path = shift; my ($head, @hunk) = parse_diff($path); @@ -936,32 +993,7 @@ sub patch_update_file { } if (@{$mode->{TEXT}}) { - while (1) { - print @{$mode->{DISPLAY}}; - print colored $prompt_color, - "Stage mode change [y/n/a/d/?]? "; - my $line = prompt_single_character; - if ($line =~ /^y/i) { - $mode->{USE} = 1; - last; - } - elsif ($line =~ /^n/i) { - $mode->{USE} = 0; - last; - } - elsif ($line =~ /^a/i) { - $_->{USE} = 1 foreach ($mode, @hunk); - last; - } - elsif ($line =~ /^d/i) { - $_->{USE} = 0 foreach ($mode, @hunk); - last; - } - else { - help_patch_cmd(''); - next; - } - } + unshift @hunk, $mode; } $num = scalar @hunk; @@ -1005,14 +1037,19 @@ sub patch_update_file { } last if (!$undecided); - if (hunk_splittable($hunk[$ix]{TEXT})) { + if ($hunk[$ix]{TYPE} eq 'hunk' && + hunk_splittable($hunk[$ix]{TEXT})) { $other .= ',s'; } - $other .= ',e'; + if ($hunk[$ix]{TYPE} eq 'hunk') { + $other .= ',e'; + } for (@{$hunk[$ix]{DISPLAY}}) { print; } - print colored $prompt_color, "Stage this hunk [y,n,a,d,/$other,?]? "; + print colored $prompt_color, 'Stage ', + ($hunk[$ix]{TYPE} eq 'mode' ? 'mode change' : 'this hunk'), + " [y,n,q,a,d,/$other,?]? "; my $line = prompt_single_character; if ($line) { if ($line =~ /^y/i) { @@ -1064,6 +1101,16 @@ sub patch_update_file { } next; } + elsif ($line =~ /^q/i) { + while ($ix < $num) { + if (!defined $hunk[$ix]{USE}) { + $hunk[$ix]{USE} = 0; + } + $ix++; + } + $quit = 1; + next; + } elsif ($line =~ m|^/(.*)|) { my $regex = $1; if ($1 eq "") { @@ -1144,7 +1191,7 @@ sub patch_update_file { $num = scalar @hunk; next; } - elsif ($line =~ /^e/) { + elsif ($other =~ /e/ && $line =~ /^e/) { my $newhunk = edit_hunk_loop($head, \@hunk, $ix); if (defined $newhunk) { splice @hunk, $ix, 1, $newhunk; @@ -1165,9 +1212,6 @@ sub patch_update_file { my $n_lofs = 0; my @result = (); - if ($mode->{USE}) { - push @result, @{$mode->{TEXT}}; - } for (@hunk) { if ($_->{USE}) { push @result, @{$_->{TEXT}}; @@ -1190,6 +1234,7 @@ sub patch_update_file { } print "\n"; + return $quit; } sub diff_cmd {