git_config_rename_section_in_file(): avoid resource leak
[gitweb.git] / git-add--interactive.perl
index a4b29840a9806fb563fc38565bd40cbe79dcb52b..709a5f6ce6fbdb2da14084e94ae9df1db1c3d0a6 100755 (executable)
@@ -46,7 +46,7 @@
 my $normal_color = $repo->get_color("", "reset");
 
 my $diff_algorithm = $repo->config('diff.algorithm');
-my $diff_compaction_heuristic = $repo->config_bool('diff.compactionheuristic');
+my $diff_indent_heuristic = $repo->config_bool('diff.indentheuristic');
 my $diff_filter = $repo->config('interactive.difffilter');
 
 my $use_readkey = 0;
@@ -92,6 +92,7 @@ sub colored {
 }
 
 # command line options
+my $patch_mode_only;
 my $patch_mode;
 my $patch_mode_revision;
 
@@ -104,9 +105,6 @@ sub colored {
                DIFF => 'diff-files -p',
                APPLY => sub { apply_patch 'apply --cached', @_; },
                APPLY_CHECK => 'apply --cached',
-               VERB => 'Stage',
-               TARGET => '',
-               PARTICIPLE => 'staging',
                FILTER => 'file-only',
                IS_REVERSE => 0,
        },
@@ -114,9 +112,6 @@ sub colored {
                DIFF => 'diff-index -p HEAD',
                APPLY => sub { apply_patch 'apply --cached', @_; },
                APPLY_CHECK => 'apply --cached',
-               VERB => 'Stash',
-               TARGET => '',
-               PARTICIPLE => 'stashing',
                FILTER => undef,
                IS_REVERSE => 0,
        },
@@ -124,9 +119,6 @@ sub colored {
                DIFF => 'diff-index -p --cached',
                APPLY => sub { apply_patch 'apply -R --cached', @_; },
                APPLY_CHECK => 'apply -R --cached',
-               VERB => 'Unstage',
-               TARGET => '',
-               PARTICIPLE => 'unstaging',
                FILTER => 'index-only',
                IS_REVERSE => 1,
        },
@@ -134,9 +126,6 @@ sub colored {
                DIFF => 'diff-index -R -p --cached',
                APPLY => sub { apply_patch 'apply --cached', @_; },
                APPLY_CHECK => 'apply --cached',
-               VERB => 'Apply',
-               TARGET => ' to index',
-               PARTICIPLE => 'applying',
                FILTER => 'index-only',
                IS_REVERSE => 0,
        },
@@ -144,9 +133,6 @@ sub colored {
                DIFF => 'diff-files -p',
                APPLY => sub { apply_patch 'apply -R', @_; },
                APPLY_CHECK => 'apply -R',
-               VERB => 'Discard',
-               TARGET => ' from worktree',
-               PARTICIPLE => 'discarding',
                FILTER => 'file-only',
                IS_REVERSE => 1,
        },
@@ -154,9 +140,6 @@ sub colored {
                DIFF => 'diff-index -p',
                APPLY => sub { apply_patch_for_checkout_commit '-R', @_ },
                APPLY_CHECK => 'apply -R',
-               VERB => 'Discard',
-               TARGET => ' from index and worktree',
-               PARTICIPLE => 'discarding',
                FILTER => undef,
                IS_REVERSE => 1,
        },
@@ -164,15 +147,13 @@ sub colored {
                DIFF => 'diff-index -R -p',
                APPLY => sub { apply_patch_for_checkout_commit '', @_ },
                APPLY_CHECK => 'apply',
-               VERB => 'Apply',
-               TARGET => ' to index and worktree',
-               PARTICIPLE => 'applying',
                FILTER => undef,
                IS_REVERSE => 0,
        },
 );
 
-my %patch_mode_flavour = %{$patch_modes{stage}};
+$patch_mode = 'stage';
+my %patch_mode_flavour = %{$patch_modes{$patch_mode}};
 
 sub run_cmd_pipe {
        if ($^O eq 'MSWin32') {
@@ -294,26 +275,17 @@ sub list_modified {
        my ($only) = @_;
        my (%data, @return);
        my ($add, $del, $adddel, $file);
-       my @tracked = ();
-
-       if (@ARGV) {
-               @tracked = map {
-                       chomp $_;
-                       unquote_path($_);
-               } run_cmd_pipe(qw(git ls-files --), @ARGV);
-               return if (!@tracked);
-       }
 
        my $reference = get_diff_reference($patch_mode_revision);
        for (run_cmd_pipe(qw(git diff-index --cached
                             --numstat --summary), $reference,
-                            '--', @tracked)) {
+                            '--', @ARGV)) {
                if (($add, $del, $file) =
                    /^([-\d]+)  ([-\d]+)        (.*)/) {
                        my ($change, $bin);
                        $file = unquote_path($file);
                        if ($add eq '-' && $del eq '-') {
-                               $change = 'binary';
+                               $change = __('binary');
                                $bin = 1;
                        }
                        else {
@@ -322,7 +294,7 @@ sub list_modified {
                        $data{$file} = {
                                INDEX => $change,
                                BINARY => $bin,
-                               FILE => 'nothing',
+                               FILE => __('nothing'),
                        }
                }
                elsif (($adddel, $file) =
@@ -332,13 +304,13 @@ sub list_modified {
                }
        }
 
-       for (run_cmd_pipe(qw(git diff-files --numstat --summary --raw --), @tracked)) {
+       for (run_cmd_pipe(qw(git diff-files --numstat --summary --raw --), @ARGV)) {
                if (($add, $del, $file) =
                    /^([-\d]+)  ([-\d]+)        (.*)/) {
                        $file = unquote_path($file);
                        my ($change, $bin);
                        if ($add eq '-' && $del eq '-') {
-                               $change = 'binary';
+                               $change = __('binary');
                                $bin = 1;
                        }
                        else {
@@ -358,7 +330,7 @@ sub list_modified {
                        $file = unquote_path($2);
                        if (!exists $data{$file}) {
                                $data{$file} = +{
-                                       INDEX => 'unchanged',
+                                       INDEX => __('unchanged'),
                                        BINARY => 0,
                                };
                        }
@@ -373,10 +345,10 @@ sub list_modified {
 
                if ($only) {
                        if ($only eq 'index-only') {
-                               next if ($it->{INDEX} eq 'unchanged');
+                               next if ($it->{INDEX} eq __('unchanged'));
                        }
                        if ($only eq 'file-only') {
-                               next if ($it->{FILE} eq 'nothing');
+                               next if ($it->{FILE} eq __('nothing'));
                        }
                }
                push @return, +{
@@ -614,12 +586,12 @@ sub list_and_choose {
                        else {
                                $bottom = $top = find_unique($choice, @stuff);
                                if (!defined $bottom) {
-                                       error_msg "Huh ($choice)?\n";
+                                       error_msg sprintf(__("Huh (%s)?\n"), $choice);
                                        next TOPLOOP;
                                }
                        }
                        if ($opts->{SINGLETON} && $bottom != $top) {
-                               error_msg "Huh ($choice)?\n";
+                               error_msg sprintf(__("Huh (%s)?\n"), $choice);
                                next TOPLOOP;
                        }
                        for ($i = $bottom-1; $i <= $top-1; $i++) {
@@ -638,7 +610,7 @@ sub list_and_choose {
 }
 
 sub singleton_prompt_help_cmd {
-       print colored $help_color, <<\EOF ;
+       print colored $help_color, __ <<'EOF' ;
 Prompt help:
 1          - select a numbered item
 foo        - select item based on unique prefix
@@ -647,7 +619,7 @@ sub singleton_prompt_help_cmd {
 }
 
 sub prompt_help_cmd {
-       print colored $help_color, <<\EOF ;
+       print colored $help_color, __ <<'EOF' ;
 Prompt help:
 1          - select a single item
 3-5        - select a range of items
@@ -668,12 +640,18 @@ sub status_cmd {
 sub say_n_paths {
        my $did = shift @_;
        my $cnt = scalar @_;
-       print "$did ";
-       if (1 < $cnt) {
-               print "$cnt paths\n";
-       }
-       else {
-               print "one path\n";
+       if ($did eq 'added') {
+               printf(__n("added %d path\n", "added %d paths\n",
+                          $cnt), $cnt);
+       } elsif ($did eq 'updated') {
+               printf(__n("updated %d path\n", "updated %d paths\n",
+                          $cnt), $cnt);
+       } elsif ($did eq 'reverted') {
+               printf(__n("reverted %d path\n", "reverted %d paths\n",
+                          $cnt), $cnt);
+       } else {
+               printf(__n("touched %d path\n", "touched %d paths\n",
+                          $cnt), $cnt);
        }
 }
 
@@ -716,7 +694,7 @@ sub revert_cmd {
                                    $_->{INDEX_ADDDEL} eq 'create') {
                                        system(qw(git update-index --force-remove --),
                                               $_->{VALUE});
-                                       print "note: $_->{VALUE} is untracked now.\n";
+                                       printf(__("note: %s is untracked now.\n"), $_->{VALUE});
                                }
                        }
                }
@@ -752,8 +730,8 @@ sub parse_diff {
        if (defined $diff_algorithm) {
                splice @diff_cmd, 1, 0, "--diff-algorithm=${diff_algorithm}";
        }
-       if ($diff_compaction_heuristic) {
-               splice @diff_cmd, 1, 0, "--compaction-heuristic";
+       if ($diff_indent_heuristic) {
+               splice @diff_cmd, 1, 0, "--indent-heuristic";
        }
        if (defined $patch_mode_revision) {
                push @diff_cmd, get_diff_reference($patch_mode_revision);
@@ -1047,29 +1025,55 @@ sub color_diff {
        } @_;
 }
 
+my %edit_hunk_manually_modes = (
+       stage => N__(
+"If the patch applies cleanly, the edited hunk will immediately be
+marked for staging."),
+       stash => N__(
+"If the patch applies cleanly, the edited hunk will immediately be
+marked for stashing."),
+       reset_head => N__(
+"If the patch applies cleanly, the edited hunk will immediately be
+marked for unstaging."),
+       reset_nothead => N__(
+"If the patch applies cleanly, the edited hunk will immediately be
+marked for applying."),
+       checkout_index => N__(
+"If the patch applies cleanly, the edited hunk will immediately be
+marked for discarding."),
+       checkout_head => N__(
+"If the patch applies cleanly, the edited hunk will immediately be
+marked for discarding."),
+       checkout_nothead => N__(
+"If the patch applies cleanly, the edited hunk will immediately be
+marked for applying."),
+);
+
 sub edit_hunk_manually {
        my ($oldtext) = @_;
 
        my $hunkfile = $repo->repo_path . "/addp-hunk-edit.diff";
        my $fh;
        open $fh, '>', $hunkfile
-               or die "failed to open hunk edit file for writing: " . $!;
-       print $fh "# Manual hunk edit mode -- see bottom for a quick guide\n";
+               or die sprintf(__("failed to open hunk edit file for writing: %s"), $!);
+       print $fh Git::comment_lines __("Manual hunk edit mode -- see bottom for a quick guide.\n");
        print $fh @$oldtext;
-       my $participle = $patch_mode_flavour{PARTICIPLE};
        my $is_reverse = $patch_mode_flavour{IS_REVERSE};
        my ($remove_plus, $remove_minus) = $is_reverse ? ('-', '+') : ('+', '-');
-       print $fh <<EOF;
-# ---
-# To remove '$remove_minus' lines, make them ' ' lines (context).
-# To remove '$remove_plus' lines, delete them.
-# Lines starting with # will be removed.
-#
-# If the patch applies cleanly, the edited hunk will immediately be
-# marked for $participle. If it does not apply cleanly, you will be given
-# an opportunity to edit again. If all lines of the hunk are removed,
-# then the edit is aborted and the hunk is left unchanged.
+       my $comment_line_char = Git::get_comment_line_char;
+       print $fh Git::comment_lines sprintf(__ <<EOF, $remove_minus, $remove_plus, $comment_line_char),
+---
+To remove '%s' lines, make them ' ' lines (context).
+To remove '%s' lines, delete them.
+Lines starting with %s will be removed.
 EOF
+__($edit_hunk_manually_modes{$patch_mode}),
+# TRANSLATORS: 'it' refers to the patch mentioned in the previous messages.
+__ <<EOF2 ;
+If it does not apply cleanly, you will be given an opportunity to
+edit again.  If all lines of the hunk are removed, then the edit is
+aborted and the hunk is left unchanged.
+EOF2
        close $fh;
 
        chomp(my $editor = run_cmd_pipe(qw(git var GIT_EDITOR)));
@@ -1080,8 +1084,8 @@ sub edit_hunk_manually {
        }
 
        open $fh, '<', $hunkfile
-               or die "failed to open hunk edit file for reading: " . $!;
-       my @newtext = grep { !/^#/ } <$fh>;
+               or die sprintf(__("failed to open hunk edit file for reading: %s"), $!);
+       my @newtext = grep { !/^$comment_line_char/ } <$fh>;
        close $fh;
        unlink $hunkfile;
 
@@ -1178,15 +1182,53 @@ sub edit_hunk_loop {
        }
 }
 
+my %help_patch_modes = (
+       stage => N__(
+"y - stage this hunk
+n - do not stage this hunk
+q - quit; do not stage this hunk or any of the remaining ones
+a - stage this hunk and all later hunks in the file
+d - do not stage this hunk or any of the later hunks in the file"),
+       stash => N__(
+"y - stash this hunk
+n - do not stash this hunk
+q - quit; do not stash this hunk or any of the remaining ones
+a - stash this hunk and all later hunks in the file
+d - do not stash this hunk or any of the later hunks in the file"),
+       reset_head => N__(
+"y - unstage this hunk
+n - do not unstage this hunk
+q - quit; do not unstage this hunk or any of the remaining ones
+a - unstage this hunk and all later hunks in the file
+d - do not unstage this hunk or any of the later hunks in the file"),
+       reset_nothead => N__(
+"y - apply this hunk to index
+n - do not apply this hunk to index
+q - quit; do not apply this hunk or any of the remaining ones
+a - apply this hunk and all later hunks in the file
+d - do not apply this hunk or any of the later hunks in the file"),
+       checkout_index => N__(
+"y - discard this hunk from worktree
+n - do not discard this hunk from worktree
+q - quit; do not discard this hunk or any of the remaining ones
+a - discard this hunk and all later hunks in the file
+d - do not discard this hunk or any of the later hunks in the file"),
+       checkout_head => N__(
+"y - discard this hunk from index and worktree
+n - do not discard this hunk from index and worktree
+q - quit; do not discard this hunk or any of the remaining ones
+a - discard this hunk and all later hunks in the file
+d - do not discard this hunk or any of the later hunks in the file"),
+       checkout_nothead => N__(
+"y - apply this hunk to index and worktree
+n - do not apply this hunk to index and worktree
+q - quit; do not apply this hunk or any of the remaining ones
+a - apply this hunk and all later hunks in the file
+d - do not apply this hunk or any of the later hunks in the file"),
+);
+
 sub help_patch_cmd {
-       my $verb = lc $patch_mode_flavour{VERB};
-       my $target = $patch_mode_flavour{TARGET};
-       print colored $help_color, <<EOF ;
-y - $verb this hunk$target
-n - do not $verb this hunk$target
-q - quit; do not $verb this hunk or any of the remaining ones
-a - $verb this hunk and all later hunks in the file
-d - do not $verb this hunk or any of the later hunks in the file
+       print colored $help_color, __($help_patch_modes{$patch_mode}), "\n", __ <<EOF ;
 g - select a hunk to go to
 / - search for a hunk matching the given regex
 j - leave this hunk undecided, see next undecided hunk
@@ -1233,7 +1275,7 @@ sub apply_patch_for_checkout_commit {
 
 sub patch_update_cmd {
        my @all_mods = list_modified($patch_mode_flavour{FILTER});
-       error_msg "ignoring unmerged: $_->{VALUE}\n"
+       error_msg sprintf(__("ignoring unmerged: %s\n"), $_->{VALUE})
                for grep { $_->{UNMERGED} } @all_mods;
        @all_mods = grep { !$_->{UNMERGED} } @all_mods;
 
@@ -1248,7 +1290,7 @@ sub patch_update_cmd {
                }
                return 0;
        }
-       if ($patch_mode) {
+       if ($patch_mode_only) {
                @them = @mods;
        }
        else {
@@ -1302,6 +1344,44 @@ sub display_hunks {
        return $i;
 }
 
+my %patch_update_prompt_modes = (
+       stage => {
+               mode => N__("Stage mode change [y,n,q,a,d,/%s,?]? "),
+               deletion => N__("Stage deletion [y,n,q,a,d,/%s,?]? "),
+               hunk => N__("Stage this hunk [y,n,q,a,d,/%s,?]? "),
+       },
+       stash => {
+               mode => N__("Stash mode change [y,n,q,a,d,/%s,?]? "),
+               deletion => N__("Stash deletion [y,n,q,a,d,/%s,?]? "),
+               hunk => N__("Stash this hunk [y,n,q,a,d,/%s,?]? "),
+       },
+       reset_head => {
+               mode => N__("Unstage mode change [y,n,q,a,d,/%s,?]? "),
+               deletion => N__("Unstage deletion [y,n,q,a,d,/%s,?]? "),
+               hunk => N__("Unstage this hunk [y,n,q,a,d,/%s,?]? "),
+       },
+       reset_nothead => {
+               mode => N__("Apply mode change to index [y,n,q,a,d,/%s,?]? "),
+               deletion => N__("Apply deletion to index [y,n,q,a,d,/%s,?]? "),
+               hunk => N__("Apply this hunk to index [y,n,q,a,d,/%s,?]? "),
+       },
+       checkout_index => {
+               mode => N__("Discard mode change from worktree [y,n,q,a,d,/%s,?]? "),
+               deletion => N__("Discard deletion from worktree [y,n,q,a,d,/%s,?]? "),
+               hunk => N__("Discard this hunk from worktree [y,n,q,a,d,/%s,?]? "),
+       },
+       checkout_head => {
+               mode => N__("Discard mode change from index and worktree [y,n,q,a,d,/%s,?]? "),
+               deletion => N__("Discard deletion from index and worktree [y,n,q,a,d,/%s,?]? "),
+               hunk => N__("Discard this hunk from index and worktree [y,n,q,a,d,/%s,?]? "),
+       },
+       checkout_nothead => {
+               mode => N__("Apply mode change to index and worktree [y,n,q,a,d,/%s,?]? "),
+               deletion => N__("Apply deletion to index and worktree [y,n,q,a,d,/%s,?]? "),
+               hunk => N__("Apply this hunk to index and worktree [y,n,q,a,d,/%s,?]? "),
+       },
+);
+
 sub patch_update_file {
        my $quit = 0;
        my ($ix, $num);
@@ -1374,12 +1454,9 @@ sub patch_update_file {
                for (@{$hunk[$ix]{DISPLAY}}) {
                        print;
                }
-               print colored $prompt_color, $patch_mode_flavour{VERB},
-                 ($hunk[$ix]{TYPE} eq 'mode' ? ' mode change' :
-                  $hunk[$ix]{TYPE} eq 'deletion' ? ' deletion' :
-                  ' this hunk'),
-                 $patch_mode_flavour{TARGET},
-                 " [y,n,q,a,d,/$other,?]? ";
+               print colored $prompt_color,
+                       sprintf(__($patch_update_prompt_modes{$patch_mode}{$hunk[$ix]{TYPE}}), $other);
+
                my $line = prompt_single_character;
                last unless defined $line;
                if ($line) {
@@ -1415,11 +1492,13 @@ sub patch_update_file {
                                        chomp $response;
                                }
                                if ($response !~ /^\s*\d+\s*$/) {
-                                       error_msg "Invalid number: '$response'\n";
+                                       error_msg sprintf(__("Invalid number: '%s'\n"),
+                                                            $response);
                                } elsif (0 < $response && $response <= $num) {
                                        $ix = $response - 1;
                                } else {
-                                       error_msg "Sorry, only $num hunks available.\n";
+                                       error_msg sprintf(__n("Sorry, only %d hunk available.\n",
+                                                             "Sorry, only %d hunks available.\n", $num), $num);
                                }
                                next;
                        }
@@ -1457,7 +1536,7 @@ sub patch_update_file {
                                if ($@) {
                                        my ($err,$exp) = ($@, $1);
                                        $err =~ s/ at .*git-add--interactive line \d+, <STDIN> line \d+.*$//;
-                                       error_msg "Malformed search regexp $exp: $err\n";
+                                       error_msg sprintf(__("Malformed search regexp %s: %s\n"), $exp, $err);
                                        next;
                                }
                                my $iy = $ix;
@@ -1514,8 +1593,10 @@ sub patch_update_file {
                        elsif ($other =~ /s/ && $line =~ /^s/) {
                                my @split = split_hunk($hunk[$ix]{TEXT}, $hunk[$ix]{DISPLAY});
                                if (1 < @split) {
-                                       print colored $header_color, "Split into ",
-                                       scalar(@split), " hunks.\n";
+                                       print colored $header_color, sprintf(
+                                               __n("Split into %d hunk.\n",
+                                                   "Split into %d hunks.\n",
+                                                   scalar(@split)), scalar(@split));
                                }
                                splice (@hunk, $ix, 1, @split);
                                $num = scalar @hunk;
@@ -1581,12 +1662,14 @@ sub quit_cmd {
 }
 
 sub help_cmd {
-       print colored $help_color, <<\EOF ;
+# TRANSLATORS: please do not translate the command names
+# 'status', 'update', 'revert', etc.
+       print colored $help_color, __ <<'EOF' ;
 status        - show paths with changes
 update        - add working tree state to the staged set of changes
 revert        - revert staged set of changes back to the HEAD version
 patch         - pick hunks and update selectively
-diff         - view diff between HEAD and index
+diff          - view diff between HEAD and index
 add untracked - add contents of untracked files to the staged set of changes
 EOF
 }
@@ -1620,18 +1703,19 @@ sub process_args {
                                $patch_mode = $1;
                                $arg = shift @ARGV or die __("missing --");
                        } else {
-                               die "unknown --patch mode: $1";
+                               die sprintf(__("unknown --patch mode: %s"), $1);
                        }
                } else {
                        $patch_mode = 'stage';
                        $arg = shift @ARGV or die __("missing --");
                }
-               die "invalid argument $arg, expecting --"
-                   unless $arg eq "--";
+               die sprintf(__("invalid argument %s, expecting --"),
+                              $arg) unless $arg eq "--";
                %patch_mode_flavour = %{$patch_modes{$patch_mode}};
+               $patch_mode_only = 1;
        }
        elsif ($arg ne "--") {
-               die "invalid argument $arg, expecting --";
+               die sprintf(__("invalid argument %s, expecting --"), $arg);
        }
 }
 
@@ -1665,7 +1749,7 @@ sub main_loop {
 
 process_args();
 refresh();
-if ($patch_mode) {
+if ($patch_mode_only) {
        patch_update_cmd();
 }
 else {