use strict;
use Git;
-# Prompt colors:
-my ($prompt_color, $header_color, $help_color, $normal_color);
-# Diff colors:
-my ($new_color, $old_color, $fraginfo_color, $metainfo_color, $whitespace_color);
-
-my ($use_color, $diff_use_color);
my $repo = Git->repository();
-$use_color = $repo->get_colorbool('color.interactive');
-
-if ($use_color) {
- # Set interactive colors:
+my $menu_use_color = $repo->get_colorbool('color.interactive');
+my ($prompt_color, $header_color, $help_color) =
+ $menu_use_color ? (
+ $repo->get_color('color.interactive.prompt', 'bold blue'),
+ $repo->get_color('color.interactive.header', 'bold'),
+ $repo->get_color('color.interactive.help', 'red bold'),
+ ) : ();
- # Grab the 3 main colors in git color string format, with sane
- # (visible) defaults:
- $prompt_color = $repo->get_color("color.interactive.prompt", "bold blue");
- $header_color = $repo->get_color("color.interactive.header", "bold");
- $help_color = $repo->get_color("color.interactive.help", "red bold");
- $normal_color = $repo->get_color("", "reset");
+my $diff_use_color = $repo->get_colorbool('color.diff');
+my ($fraginfo_color) =
+ $diff_use_color ? (
+ $repo->get_color('color.diff.frag', 'cyan'),
+ ) : ();
- # Do we also set diff colors?
- $diff_use_color = $repo->get_colorbool('color.diff');
- if ($diff_use_color) {
- $new_color = $repo->get_color("color.diff.new", "green");
- $old_color = $repo->get_color("color.diff.old", "red");
- $fraginfo_color = $repo->get_color("color.diff.frag", "cyan");
- $metainfo_color = $repo->get_color("color.diff.meta", "bold");
- $whitespace_color = $repo->get_color("color.diff.whitespace", "normal red");
- }
-}
+my $normal_color = $repo->get_color("", "reset");
sub colored {
my $color = shift;
my $string = join("", @_);
- if ($use_color) {
+ if (defined $color) {
# Put a color code at the beginning of each line, a reset at the end
# color after newlines that are not at the end of the string
$string =~ s/(\n+)(.)/$1$color$2/g;
my $status_fmt = '%12s %12s %s';
my $status_head = sprintf($status_fmt, 'staged', 'unstaged', 'path');
+{
+ my $initial;
+ sub is_initial_commit {
+ $initial = system('git rev-parse HEAD -- >/dev/null 2>&1') != 0
+ unless defined $initial;
+ return $initial;
+ }
+}
+
+sub get_empty_tree {
+ return '4b825dc642cb6eb9a060e54bf8d69288fbee4904';
+}
+
# Returns list of hashes, contents of each of which are:
# VALUE: pathname
# BINARY: is a binary path
return if (!@tracked);
}
+ my $reference = is_initial_commit() ? get_empty_tree() : 'HEAD';
for (run_cmd_pipe(qw(git diff-index --cached
- --numstat --summary HEAD --), @tracked)) {
+ --numstat --summary), $reference,
+ '--', @tracked)) {
if (($add, $del, $file) =
/^([-\d]+) ([-\d]+) (.*)/) {
my ($change, $bin);
return "$prefix$remainder";
}
- if (!$use_color) {
+ if (!$menu_use_color) {
return "[$prefix]$remainder";
}
HEADER => $status_head, },
list_modified());
if (@update) {
- my @lines = run_cmd_pipe(qw(git ls-tree HEAD --),
- map { $_->{VALUE} } @update);
- my $fh;
- open $fh, '| git update-index --index-info'
- or die;
- for (@lines) {
- print $fh $_;
+ if (is_initial_commit()) {
+ system(qw(git rm --cached),
+ map { $_->{VALUE} } @update);
}
- close($fh);
- for (@update) {
- if ($_->{INDEX_ADDDEL} &&
- $_->{INDEX_ADDDEL} eq 'create') {
- system(qw(git update-index --force-remove --),
- $_->{VALUE});
- print "note: $_->{VALUE} is untracked now.\n";
+ else {
+ my @lines = run_cmd_pipe(qw(git ls-tree HEAD --),
+ map { $_->{VALUE} } @update);
+ my $fh;
+ open $fh, '| git update-index --index-info'
+ or die;
+ for (@lines) {
+ print $fh $_;
+ }
+ close($fh);
+ for (@update) {
+ if ($_->{INDEX_ADDDEL} &&
+ $_->{INDEX_ADDDEL} eq 'create') {
+ system(qw(git update-index --force-remove --),
+ $_->{VALUE});
+ print "note: $_->{VALUE} is untracked now.\n";
+ }
}
}
refresh();
return @hunk;
}
+sub parse_diff_header {
+ my $src = shift;
+
+ my $head = { TEXT => [], DISPLAY => [] };
+ my $mode = { TEXT => [], DISPLAY => [] };
+
+ for (my $i = 0; $i < @{$src->{TEXT}}; $i++) {
+ my $dest = $src->{TEXT}->[$i] =~ /^(old|new) mode (\d+)$/ ?
+ $mode : $head;
+ push @{$dest->{TEXT}}, $src->{TEXT}->[$i];
+ push @{$dest->{DISPLAY}}, $src->{DISPLAY}->[$i];
+ }
+ return ($head, $mode);
+}
+
sub hunk_splittable {
my ($text) = @_;
my ($ix, $num);
my $path = shift;
my ($head, @hunk) = parse_diff($path);
+ ($head, my $mode) = parse_diff_header($head);
for (@{$head->{DISPLAY}}) {
print;
}
+
+ if (@{$mode->{TEXT}}) {
+ while (1) {
+ print @{$mode->{DISPLAY}};
+ print colored $prompt_color,
+ "Stage mode change [y/n/a/d/?]? ";
+ my $line = <STDIN>;
+ 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;
+ }
+ }
+ }
+
$num = scalar @hunk;
$ix = 0;
my $n_lofs = 0;
my @result = ();
+ if ($mode->{USE}) {
+ push @result, @{$mode->{TEXT}};
+ }
for (@hunk) {
my $text = $_->{TEXT};
my ($o_ofs, $o_cnt, $n_ofs, $n_cnt) =
HEADER => $status_head, },
@mods);
return if (!@them);
- system(qw(git diff -p --cached HEAD --), map { $_->{VALUE} } @them);
+ my $reference = is_initial_commit() ? get_empty_tree() : 'HEAD';
+ system(qw(git diff -p --cached), $reference, '--',
+ map { $_->{VALUE} } @them);
}
sub quit_cmd {