{"thread":{"id":"11175","subject":"[PATCH] Teach \"git add -i\" to colorize whitespace errors","startedAt":"2007-12-07T12:35:10Z","lastAt":"2007-12-07T13:00:36Z","messageCount":2,"participants":["Wincent Colaiuta"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"62279","messageId":"1197030910-29638-1-git-send-email-win@wincent.com","threadId":"11175","inReplyTo":null,"subject":"[PATCH] Teach \"git add -i\" to colorize whitespace errors","fromName":"Wincent Colaiuta","fromEmail":"win@wincent.com","sentAt":"2007-12-07T12:35:10Z","receivedAt":"2007-12-07T12:35:10Z","isPatch":true,"sender":{"key":"greg@hurrell.net","avatar":"https://avatars.githubusercontent.com/u/7074?v=4"},"body":"Rather than replicating the colorization logic of \"git diff-files\" we\nrely on \"git diff-files\" itself. This guarantees consistent colorization\nin and outside \"git add -i\".\n\nSeeing as speed is not a concern here (the bottleneck is how fast the\nuser can read, not how fast \"git diff-files\" runs) we do this by\nactually running it twice, once without color and once with.\n\nIn this way as the whitespace colorization provided by \"git diff-files\"\nevolves (per-path attributes, new classes of whitespace error), \"git\nadd -i\" will automatically benefit from it and stay in synch.\n\nAlso, by working with two sets of diff output (an uncolorized one for\ninternal processing and a colorized one for display only) we minimize\nthe risk of regressions because the changes required to implement this\nare minimally invasive.\n\nSigned-off-by: Wincent Colaiuta <win@wincent.com>\n---\n\nThis applies on top of these patches that Junio sent out yesterday:\n\tgit config --get-colorbool\n\tColor support for \"git-add -i\"\n\nI've tested it here and it works for me but it would be nice if\nsomeone else could play with it and see if this is good.\n\n git-add--interactive.perl |   67 +++++++++++++++++++-------------------------\n 1 files changed, 29 insertions(+), 38 deletions(-)\n\ndiff --git a/git-add--interactive.perl b/git-add--interactive.perl\nindex 1019a72..e492fac 100755\n--- a/git-add--interactive.perl\n+++ b/git-add--interactive.perl\n@@ -525,42 +525,21 @@ sub add_untracked_cmd {\n sub parse_diff {\n \tmy ($path) = @_;\n \tmy @diff = run_cmd_pipe(qw(git diff-files -p --), $path);\n-\tmy (@hunk) = { TEXT => [] };\n+\tmy @colored = run_cmd_pipe(qw(git diff-files -p --color --), $path)\n+\t   if $diff_use_color;\n+\tmy (@hunk) = { TEXT => [], DISPLAY => [] };\n \n-\tfor (@diff) {\n-\t\tif (/^@@ /) {\n-\t\t\tpush @hunk, { TEXT => [] };\n+\tfor (my $i = 0; $i < @diff; $i++) {\n+\t\tif ($diff[$i] =~ /^@@ /) {\n+\t\t\tpush @hunk, { TEXT => [], DISPLAY => [] };\n \t\t}\n-\t\tpush @{$hunk[-1]{TEXT}}, $_;\n+\t\tpush @{$hunk[-1]{TEXT}}, $diff[$i];\n+\t\tpush @{$hunk[-1]{DISPLAY}},\n+\t\t    $diff_use_color ? $colored[$i] : $diff[$i];\n \t}\n \treturn @hunk;\n }\n \n-sub colored_diff_hunk {\n-\tmy ($text) = @_;\n-\t# return the text, so that it can be passed to print()\n-\tmy @ret;\n-\tfor (@$text) {\n-\t\tif (!$diff_use_color) {\n-\t\t\tpush @ret, $_;\n-\t\t\tnext;\n-\t\t}\n-\n-\t\tif (/^\\+/) {\n-\t\t\tpush @ret, colored($new_color, $_);\n-\t\t} elsif (/^\\-/) {\n-\t\t\tpush @ret, colored($old_color, $_);\n-\t\t} elsif (/^\\@/) {\n-\t\t\tpush @ret, colored($fraginfo_color, $_);\n-\t\t} elsif (/^ /) {\n-\t\t\tpush @ret, colored($normal_color, $_);\n-\t\t} else {\n-\t\t\tpush @ret, colored($metainfo_color, $_);\n-\t\t}\n-\t}\n-\treturn @ret;\n-}\n-\n sub hunk_splittable {\n \tmy ($text) = @_;\n \n@@ -578,7 +557,9 @@ sub parse_hunk_header {\n }\n \n sub split_hunk {\n-\tmy ($text) = @_;\n+\tmy $text = shift;\n+\tmy $display = shift;\n+\t$display = $text unless $display;\n \tmy @split = ();\n \n \t# If there are context lines in the middle of a hunk,\n@@ -594,16 +575,19 @@ sub split_hunk {\n \t\tmy $i = $hunk_start - 1;\n \t\tmy $this = +{\n \t\t\tTEXT => [],\n+\t\t\tDISPLAY => [],\n \t\t\tOLD => $o_ofs,\n \t\t\tNEW => $n_ofs,\n \t\t\tOCNT => 0,\n \t\t\tNCNT => 0,\n \t\t\tADDDEL => 0,\n \t\t\tPOSTCTX => 0,\n+\t\t\tUSE => undef,\n \t\t};\n \n \t\twhile (++$i < @$text) {\n \t\t\tmy $line = $text->[$i];\n+\t\t\tmy $display = $display->[$i];\n \t\t\tif ($line =~ /^ /) {\n \t\t\t\tif ($this->{ADDDEL} &&\n \t\t\t\t    !defined $next_hunk_start) {\n@@ -615,6 +599,7 @@ sub split_hunk {\n \t\t\t\t\t$next_hunk_start = $i;\n \t\t\t\t}\n \t\t\t\tpush @{$this->{TEXT}}, $line;\n+\t\t\t\tpush @{$this->{DISPLAY}}, $display;\n \t\t\t\t$this->{OCNT}++;\n \t\t\t\t$this->{NCNT}++;\n \t\t\t\tif (defined $next_hunk_start) {\n@@ -637,6 +622,7 @@ sub split_hunk {\n \t\t\t\tredo OUTER;\n \t\t\t}\n \t\t\tpush @{$this->{TEXT}}, $line;\n+\t\t\tpush @{$this->{DISPLAY}}, $display;\n \t\t\t$this->{ADDDEL}++;\n \t\t\tif ($line =~ /^-/) {\n \t\t\t\t$this->{OCNT}++;\n@@ -662,8 +648,10 @@ sub split_hunk {\n \t\t\t    (($n_cnt != 1) ? \",$n_cnt\" : '') .\n \t\t\t    \" @@\\n\");\n \t\tunshift @{$hunk->{TEXT}}, $head;\n+\t\tunshift @{$hunk->{DISPLAY}},\n+\t\t    $use_color ? (colored $fraginfo_color, $head) : $head;\n \t}\n-\treturn map { $_->{TEXT} } @split;\n+\treturn @split;\n }\n \n sub find_last_o_ctx {\n@@ -794,7 +782,9 @@ sub patch_update_file {\n \tmy ($ix, $num);\n \tmy $path = shift;\n \tmy ($head, @hunk) = parse_diff($path);\n-\tprint colored_diff_hunk($head->{TEXT});\n+\tfor (@{$head->{DISPLAY}}) {\n+\t\tprint;\n+\t}\n \t$num = scalar @hunk;\n \t$ix = 0;\n \n@@ -836,7 +826,9 @@ sub patch_update_file {\n \t\tif (hunk_splittable($hunk[$ix]{TEXT})) {\n \t\t\t$other .= '/s';\n \t\t}\n-\t\tprint colored_diff_hunk($hunk[$ix]{TEXT});\n+\t\tfor (@{$hunk[$ix]{DISPLAY}}) {\n+\t\t\tprint;\n+\t\t}\n \t\tprint colored $prompt_color, \"Stage this hunk [y/n/a/d$other/?]? \";\n \t\tmy $line = <STDIN>;\n \t\tif ($line) {\n@@ -889,14 +881,13 @@ sub patch_update_file {\n \t\t\t\tnext;\n \t\t\t}\n \t\t\telsif ($other =~ /s/ && $line =~ /^s/) {\n-\t\t\t\tmy @split = split_hunk($hunk[$ix]{TEXT});\n+\t\t\t\tmy @split = split_hunk($hunk[$ix]{TEXT},\n+\t\t\t\t    $hunk[$ix]{DISPLAY});\n \t\t\t\tif (1 < @split) {\n \t\t\t\t\tprint colored $header_color, \"Split into \",\n \t\t\t\t\tscalar(@split), \" hunks.\\n\";\n \t\t\t\t}\n-\t\t\t\tsplice(@hunk, $ix, 1,\n-\t\t\t\t       map { +{ TEXT => $_, USE => undef } }\n-\t\t\t\t       @split);\n+\t\t\t\tsplice (@hunk, $ix, 1, @split);\n \t\t\t\t$num = scalar @hunk;\n \t\t\t\tnext;\n \t\t\t}\n-- \n1.5.3.7.1079.gb270a-dirty\n"},{"id":"62284","messageId":"822D2B27-2280-4A53-A242-B69726CF129D@wincent.com","threadId":"11175","inReplyTo":"1197030910-29638-1-git-send-email-win@wincent.com","subject":"Re: [PATCH] Teach \"git add -i\" to colorize whitespace errors","fromName":"Wincent Colaiuta","fromEmail":"win@wincent.com","sentAt":"2007-12-07T13:00:36Z","receivedAt":"2007-12-07T13:00:36Z","isPatch":true,"sender":{"key":"greg@hurrell.net","avatar":"https://avatars.githubusercontent.com/u/7074?v=4"},"body":"El 7/12/2007, a las 13:35, Wincent Colaiuta escribió:\n\n> @@ -662,8 +648,10 @@ sub split_hunk {\n> \t\t\t    (($n_cnt != 1) ? \",$n_cnt\" : '') .\n> \t\t\t    \" @@\\n\");\n> \t\tunshift @{$hunk->{TEXT}}, $head;\n> +\t\tunshift @{$hunk->{DISPLAY}},\n> +\t\t    $use_color ? (colored $fraginfo_color, $head) : $head;\n> \t}\n> -\treturn map { $_->{TEXT} } @split;\n> +\treturn @split;\n> }\n\n\nActually, $diff_use_color would probably be more appropriate than  \n$use_color above.\n\nWincent\n"}]}