Teach "git add -i" to colorize whitespace errors
Rather than replicating the colorization logic of "git diff-files" we rely on "git diff-files" itself. This guarantees consistent colorization in and outside "git add -i". Seeing as speed is not a concern here (the bottleneck is how fast the user can read, not how fast "git diff-files" runs) we do this by actually running it twice, once without color and once with. In this way as the whitespace colorization provided by "git diff-files" evolves (per-path attributes, new classes of whitespace error), "git add -i" will automatically benefit from it and stay in synch. Also, by working with two sets of diff output (an uncolorized one for internal processing and a colorized one for display only) we minimize the risk of regressions because the changes required to implement this are minimally invasive. Signed-off-by: Wincent Colaiuta <win@wincent.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>maint
parent
8e566f24b3
commit
4af756f31b
|
@ -525,42 +525,23 @@ sub add_untracked_cmd {
|
||||||
sub parse_diff {
|
sub parse_diff {
|
||||||
my ($path) = @_;
|
my ($path) = @_;
|
||||||
my @diff = run_cmd_pipe(qw(git diff-files -p --), $path);
|
my @diff = run_cmd_pipe(qw(git diff-files -p --), $path);
|
||||||
my (@hunk) = { TEXT => [] };
|
my @colored = ();
|
||||||
|
if ($diff_use_color) {
|
||||||
for (@diff) {
|
@colored = run_cmd_pipe(qw(git diff-files -p --color --), $path);
|
||||||
if (/^@@ /) {
|
|
||||||
push @hunk, { TEXT => [] };
|
|
||||||
}
|
}
|
||||||
push @{$hunk[-1]{TEXT}}, $_;
|
my (@hunk) = { TEXT => [], DISPLAY => [] };
|
||||||
|
|
||||||
|
for (my $i = 0; $i < @diff; $i++) {
|
||||||
|
if ($diff[$i] =~ /^@@ /) {
|
||||||
|
push @hunk, { TEXT => [], DISPLAY => [] };
|
||||||
|
}
|
||||||
|
push @{$hunk[-1]{TEXT}}, $diff[$i];
|
||||||
|
push @{$hunk[-1]{DISPLAY}},
|
||||||
|
($diff_use_color ? $colored[$i] : $diff[$i]);
|
||||||
}
|
}
|
||||||
return @hunk;
|
return @hunk;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub colored_diff_hunk {
|
|
||||||
my ($text) = @_;
|
|
||||||
# return the text, so that it can be passed to print()
|
|
||||||
my @ret;
|
|
||||||
for (@$text) {
|
|
||||||
if (!$diff_use_color) {
|
|
||||||
push @ret, $_;
|
|
||||||
next;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (/^\+/) {
|
|
||||||
push @ret, colored($new_color, $_);
|
|
||||||
} elsif (/^\-/) {
|
|
||||||
push @ret, colored($old_color, $_);
|
|
||||||
} elsif (/^\@/) {
|
|
||||||
push @ret, colored($fraginfo_color, $_);
|
|
||||||
} elsif (/^ /) {
|
|
||||||
push @ret, colored($normal_color, $_);
|
|
||||||
} else {
|
|
||||||
push @ret, colored($metainfo_color, $_);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return @ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub hunk_splittable {
|
sub hunk_splittable {
|
||||||
my ($text) = @_;
|
my ($text) = @_;
|
||||||
|
|
||||||
|
@ -578,9 +559,11 @@ sub parse_hunk_header {
|
||||||
}
|
}
|
||||||
|
|
||||||
sub split_hunk {
|
sub split_hunk {
|
||||||
my ($text) = @_;
|
my ($text, $display) = @_;
|
||||||
my @split = ();
|
my @split = ();
|
||||||
|
if (!defined $display) {
|
||||||
|
$display = $text;
|
||||||
|
}
|
||||||
# If there are context lines in the middle of a hunk,
|
# If there are context lines in the middle of a hunk,
|
||||||
# it can be split, but we would need to take care of
|
# it can be split, but we would need to take care of
|
||||||
# overlaps later.
|
# overlaps later.
|
||||||
|
@ -594,16 +577,19 @@ sub split_hunk {
|
||||||
my $i = $hunk_start - 1;
|
my $i = $hunk_start - 1;
|
||||||
my $this = +{
|
my $this = +{
|
||||||
TEXT => [],
|
TEXT => [],
|
||||||
|
DISPLAY => [],
|
||||||
OLD => $o_ofs,
|
OLD => $o_ofs,
|
||||||
NEW => $n_ofs,
|
NEW => $n_ofs,
|
||||||
OCNT => 0,
|
OCNT => 0,
|
||||||
NCNT => 0,
|
NCNT => 0,
|
||||||
ADDDEL => 0,
|
ADDDEL => 0,
|
||||||
POSTCTX => 0,
|
POSTCTX => 0,
|
||||||
|
USE => undef,
|
||||||
};
|
};
|
||||||
|
|
||||||
while (++$i < @$text) {
|
while (++$i < @$text) {
|
||||||
my $line = $text->[$i];
|
my $line = $text->[$i];
|
||||||
|
my $display = $display->[$i];
|
||||||
if ($line =~ /^ /) {
|
if ($line =~ /^ /) {
|
||||||
if ($this->{ADDDEL} &&
|
if ($this->{ADDDEL} &&
|
||||||
!defined $next_hunk_start) {
|
!defined $next_hunk_start) {
|
||||||
|
@ -615,6 +601,7 @@ sub split_hunk {
|
||||||
$next_hunk_start = $i;
|
$next_hunk_start = $i;
|
||||||
}
|
}
|
||||||
push @{$this->{TEXT}}, $line;
|
push @{$this->{TEXT}}, $line;
|
||||||
|
push @{$this->{DISPLAY}}, $display;
|
||||||
$this->{OCNT}++;
|
$this->{OCNT}++;
|
||||||
$this->{NCNT}++;
|
$this->{NCNT}++;
|
||||||
if (defined $next_hunk_start) {
|
if (defined $next_hunk_start) {
|
||||||
|
@ -637,6 +624,7 @@ sub split_hunk {
|
||||||
redo OUTER;
|
redo OUTER;
|
||||||
}
|
}
|
||||||
push @{$this->{TEXT}}, $line;
|
push @{$this->{TEXT}}, $line;
|
||||||
|
push @{$this->{DISPLAY}}, $display;
|
||||||
$this->{ADDDEL}++;
|
$this->{ADDDEL}++;
|
||||||
if ($line =~ /^-/) {
|
if ($line =~ /^-/) {
|
||||||
$this->{OCNT}++;
|
$this->{OCNT}++;
|
||||||
|
@ -661,9 +649,14 @@ sub split_hunk {
|
||||||
" +$n_ofs" .
|
" +$n_ofs" .
|
||||||
(($n_cnt != 1) ? ",$n_cnt" : '') .
|
(($n_cnt != 1) ? ",$n_cnt" : '') .
|
||||||
" @@\n");
|
" @@\n");
|
||||||
|
my $display_head = $head;
|
||||||
unshift @{$hunk->{TEXT}}, $head;
|
unshift @{$hunk->{TEXT}}, $head;
|
||||||
|
if ($diff_use_color) {
|
||||||
|
$display_head = colored($fraginfo_color, $head);
|
||||||
}
|
}
|
||||||
return map { $_->{TEXT} } @split;
|
unshift @{$hunk->{DISPLAY}}, $display_head;
|
||||||
|
}
|
||||||
|
return @split;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub find_last_o_ctx {
|
sub find_last_o_ctx {
|
||||||
|
@ -794,7 +787,9 @@ sub patch_update_file {
|
||||||
my ($ix, $num);
|
my ($ix, $num);
|
||||||
my $path = shift;
|
my $path = shift;
|
||||||
my ($head, @hunk) = parse_diff($path);
|
my ($head, @hunk) = parse_diff($path);
|
||||||
print colored_diff_hunk($head->{TEXT});
|
for (@{$head->{DISPLAY}}) {
|
||||||
|
print;
|
||||||
|
}
|
||||||
$num = scalar @hunk;
|
$num = scalar @hunk;
|
||||||
$ix = 0;
|
$ix = 0;
|
||||||
|
|
||||||
|
@ -836,7 +831,9 @@ sub patch_update_file {
|
||||||
if (hunk_splittable($hunk[$ix]{TEXT})) {
|
if (hunk_splittable($hunk[$ix]{TEXT})) {
|
||||||
$other .= '/s';
|
$other .= '/s';
|
||||||
}
|
}
|
||||||
print colored_diff_hunk($hunk[$ix]{TEXT});
|
for (@{$hunk[$ix]{DISPLAY}}) {
|
||||||
|
print;
|
||||||
|
}
|
||||||
print colored $prompt_color, "Stage this hunk [y/n/a/d$other/?]? ";
|
print colored $prompt_color, "Stage this hunk [y/n/a/d$other/?]? ";
|
||||||
my $line = <STDIN>;
|
my $line = <STDIN>;
|
||||||
if ($line) {
|
if ($line) {
|
||||||
|
@ -889,14 +886,12 @@ sub patch_update_file {
|
||||||
next;
|
next;
|
||||||
}
|
}
|
||||||
elsif ($other =~ /s/ && $line =~ /^s/) {
|
elsif ($other =~ /s/ && $line =~ /^s/) {
|
||||||
my @split = split_hunk($hunk[$ix]{TEXT});
|
my @split = split_hunk($hunk[$ix]{TEXT}, $hunk[$ix]{DISPLAY});
|
||||||
if (1 < @split) {
|
if (1 < @split) {
|
||||||
print colored $header_color, "Split into ",
|
print colored $header_color, "Split into ",
|
||||||
scalar(@split), " hunks.\n";
|
scalar(@split), " hunks.\n";
|
||||||
}
|
}
|
||||||
splice(@hunk, $ix, 1,
|
splice (@hunk, $ix, 1, @split);
|
||||||
map { +{ TEXT => $_, USE => undef } }
|
|
||||||
@split);
|
|
||||||
$num = scalar @hunk;
|
$num = scalar @hunk;
|
||||||
next;
|
next;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue