{"thread":{"id":"10270","subject":"[PATCH] Add color to git-add--interactive diffs (Take 2: now without spurious line break!)","startedAt":"2007-10-14T08:44:54Z","lastAt":"2007-10-23T11:13:41Z","messageCount":9,"participants":["Tom Tobin","Wincent Colaiuta","Johannes Schindelin","Andreas Ericsson","Peter Baumann"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"55674","messageId":"1192351494.7226.18.camel@athena","threadId":"10270","inReplyTo":null,"subject":"[PATCH] Add color to git-add--interactive diffs (Take 2: now without spurious line break!)","fromName":"Tom Tobin","fromEmail":"korpios@korpios.com","sentAt":"2007-10-14T08:44:54Z","receivedAt":"2007-10-14T08:44:54Z","isPatch":true,"sender":{"key":"korpios@korpios.com","avatar":null},"body":"(This is repost; my damned mail client wrapped a line in the patch last\ntime, and now I've got that under control.  My apologies!)  :(\n\nSeeing the recent discussion and code regarding adding color to\ngit-add--interactive, I thought I'd throw in my recent attempt at\ncolorizing the diffs.  (This doesn't handle anything else, such as the\nprompts.)\n\nAfter banging my head against parsing colorized output of git-add-files,\nI gave up and implemented internal colorization keying off of the\ncolor.diff configuration.\n\nHopefully this can be of some use towards fully colorizing\ngit-add--interactive; I'll admit up front that Perl isn't my primary\nlanguage, so I apologize in advance for whatever stupidities I've\nintroduced.  ;) \n\nSigned-off-by: Tom Tobin <korpios@korpios.com>\n---\n git-add--interactive.perl |  111 ++++++++++++++++++++++++++++++++++++++++++++-\n 1 files changed, 109 insertions(+), 2 deletions(-)\n\ndiff --git a/git-add--interactive.perl b/git-add--interactive.perl\nindex be68814..eeb38e6 100755\n--- a/git-add--interactive.perl\n+++ b/git-add--interactive.perl\n@@ -1,5 +1,6 @@\n #!/usr/bin/perl -w\n \n+use List::Util qw(first);\n use strict;\n \n sub run_cmd_pipe {\n@@ -22,6 +23,112 @@ if (!defined $GIT_DIR) {\n }\n chomp($GIT_DIR);\n \n+my ($use_color) = 0;\n+my (%term_color_codes) = (\n+\t\"normal\", \"\", \"black\", \"0\", \"red\", \"1\",\n+\t\"green\", \"2\", \"yellow\", \"3\", \"blue\", \"4\",\n+\t\"magenta\", \"5\", \"cyan\", \"6\", \"white\", \"7\"\n+);\n+my (%term_attr_codes) = (\n+\t\"bold\", \"1\", \"dim\", \"2\", \"ul\", \"4\", \"blink\", \"5\", \"reverse\", \"7\"\n+);\n+my %colorconfig = (\n+\t'color.diff' => 'never',\n+\t'color.diff.plain' => '',\n+\t'color.diff.meta' => 'bold',\n+\t'color.diff.frag' => 'cyan',\n+\t'color.diff.old' => 'red',\n+\t'color.diff.new' => 'green',\n+\t'color.diff.commit' => 'yellow',\n+\t'color.diff.whitespace' => 'normal red'\n+\t);\n+for (split(\"\\n\", `git-config --get-regexp '^color\\.diff'`)) {\n+\tmy ($var, $val) = $_ =~ /^([^\\s]+)\\s(.*)$/;\n+\t$colorconfig{$var} = $val;\n+}\n+if (first { $_ eq $colorconfig{'color.diff'} } (\"true\", \"always\", \"auto\")) {\n+\t$use_color = 1;\n+}\n+\n+sub parse_color {\n+\tmy ($fg, $bg, $attr, $lookup);\n+\tmy ($fg_code, $bg_code, $attr_code, $output_code) = (\"\", \"\", \"\", \"\");\n+\tmy (@color) = @_;\n+\tmy (@colorvals) = defined($color[0]) ? split(\" \", $color[0]) : ();\n+\n+\tfor (@colorvals) {\n+\t\t$lookup = $term_color_codes{$_};\n+\t\tif (defined($lookup)) {\n+\t\t\tif (!defined($fg)) {\n+\t\t\t\t$fg = 1;\n+\t\t\t\t$fg_code = \"3$lookup\";\n+\t\t\t} elsif (!defined($bg)) {\n+\t\t\t\t$bg = 1;\n+\t\t\t\t$bg_code = \"4$lookup\";\n+\t\t\t} else {\n+\t\t\t\tdie(\"Color slots only take up to two colors!\");\n+\t\t\t}\n+\t\t\tnext;\n+\t\t}\n+\t\t$lookup = $term_attr_codes{$_};\n+\t\tif (defined($lookup)) {\n+\t\t\tif (!defined($attr)) {\n+\t\t\t\t$attr = 1;\n+\t\t\t\t$attr_code = $lookup;\n+\t\t\t} else {\n+\t\t\t\tdie(\"Color slots only take a single attribute!\");\n+\t\t\t}\n+\t\t} else {\n+\t\t\tdie(\"Unrecognized value for color slot!\");\n+\t\t}\n+\t}\n+\tfor ($fg_code, $bg_code, $attr_code) {\n+\t\tif ($_ eq \"\") {\n+\t\t\tnext;\n+\t\t}\n+\t\tif ($output_code ne \"\") {\n+\t\t\t$output_code = $output_code . \";\";\n+\t\t}\n+\t\t$output_code = $output_code . $_;\n+\t}\n+\tif (length($output_code)) {\n+\t\treturn \"\\e[${output_code}m\";\n+\t} else {\n+\t\treturn \"\";\n+\t}\n+}\n+\n+sub colorize_head_line {\n+\tmy $line = shift @_;\n+\tif ($use_color) {\n+\t\t# git doesn't colorize these by default, soooo\n+\t\t# if ($line =~ /^\\+/) {\n+\t\t#\t return parse_color($colorconfig{'color.diff.new'}) . \"$line\\e[m\";\n+\t\t# }\n+\t\t# if ($line =~ /^-/) {\n+\t\t#\t return parse_color($colorconfig{'color.diff.old'}) . \"$line\\e[m\";\n+\t\t# }\n+\t\treturn parse_color($colorconfig{'color.diff.meta'}) . \"$line\\e[m\";\n+\t}\n+\treturn $line;\n+}\n+\n+sub colorize_hunk_line {\n+\tmy $line = shift @_;\n+\tif ($use_color) {\n+\t\tif ($line =~ /^\\+/) {\n+\t\t\treturn parse_color($colorconfig{'color.diff.new'}) . \"$line\\e[m\";\n+\t\t}\n+\t\tif ($line =~ /^-/) {\n+\t\t\treturn parse_color($colorconfig{'color.diff.old'}) . \"$line\\e[m\";\n+\t\t}\n+\t\tif ($line =~ /^@@ /) {\n+\t\t\treturn parse_color($colorconfig{'color.diff.frag'}) . \"$line\\e[m\";\n+\t\t}\n+\t}\n+\treturn $line;\n+}\n+\n sub refresh {\n \tmy $fh;\n \topen $fh, 'git update-index --refresh |'\n@@ -573,7 +680,7 @@ sub patch_update_cmd {\n \tmy $path = $it->{VALUE};\n \tmy ($head, @hunk) = parse_diff($path);\n \tfor (@{$head->{TEXT}}) {\n-\t\tprint;\n+\t\tprint colorize_head_line($_);\n \t}\n \t$num = scalar @hunk;\n \t$ix = 0;\n@@ -617,7 +724,7 @@ sub patch_update_cmd {\n \t\t\t$other .= '/s';\n \t\t}\n \t\tfor (@{$hunk[$ix]{TEXT}}) {\n-\t\t\tprint;\n+\t\t\tprint colorize_hunk_line($_);\n \t\t}\n \t\tprint \"Stage this hunk [y/n/a/d$other/?]? \";\n \t\tmy $line = <STDIN>;\n-- \n1.5.3.4\n"},{"id":"55701","messageId":"EFADE863-FC59-4A50-B165-9D30D9648B97@wincent.com","threadId":"10270","inReplyTo":"1192351494.7226.18.camel@athena","subject":"Re: [PATCH] Add color to git-add--interactive diffs (Take 2: now without spurious line break!)","fromName":"Wincent Colaiuta","fromEmail":"win@wincent.com","sentAt":"2007-10-14T11:36:32Z","receivedAt":"2007-10-14T11:36:32Z","isPatch":true,"sender":{"key":"greg@hurrell.net","avatar":"https://avatars.githubusercontent.com/u/7074?v=4"},"body":"El 14/10/2007, a las 10:44, Tom Tobin escribió:\n\n> After banging my head against parsing colorized output of git-add- \n> files,\n> I gave up and implemented internal colorization keying off of the\n> color.diff configuration.\n\nGreat!\n\n> +sub parse_color {\n\nYou could simplify the manual escape sequence construction that  \nyou're doing here by using Term::ANSIColor like the other patches  \ndid. I see that git-send-email.perl uses that module too, so I guess  \ndepending on that module is ok.\n\nI also wonder whether the config code should be using the git.pm  \nmodule like git-send-email.perl and a couple others do (although it  \nwould be slower than slurping in all the config in one shot like you  \ndo; perhaps there's justification for a new function in git.pm that  \nwraps git-config --get-regexp...).\n\n> +sub colorize_head_line {\n> +\tmy $line = shift @_;\n> +\tif ($use_color) {\n> +\t\t# git doesn't colorize these by default, soooo\n> +\t\t# if ($line =~ /^\\+/) {\n> +\t\t#\t return parse_color($colorconfig{'color.diff.new'}) . \"$line\\e \n> [m\";\n> +\t\t# }\n> +\t\t# if ($line =~ /^-/) {\n> +\t\t#\t return parse_color($colorconfig{'color.diff.old'}) . \"$line\\e \n> [m\";\n> +\t\t# }\n> +\t\treturn parse_color($colorconfig{'color.diff.meta'}) . \"$line\\e[m\";\n> +\t}\n> +\treturn $line;\n> +}\n> +\n> +sub colorize_hunk_line {\n> +\tmy $line = shift @_;\n> +\tif ($use_color) {\n> +\t\tif ($line =~ /^\\+/) {\n> +\t\t\treturn parse_color($colorconfig{'color.diff.new'}) . \"$line\\e[m\";\n> +\t\t}\n> +\t\tif ($line =~ /^-/) {\n> +\t\t\treturn parse_color($colorconfig{'color.diff.old'}) . \"$line\\e[m\";\n> +\t\t}\n> +\t\tif ($line =~ /^@@ /) {\n> +\t\t\treturn parse_color($colorconfig{'color.diff.frag'}) . \"$line\\e[m\";\n> +\t\t}\n> +\t}\n> +\treturn $line;\n> +}\n\nThis is a good start but to completely match the colorized output  \nproduced by diff it will need some additional logic; for example,  \nhighlighting spurious whitespace. Search for  \nneed_highlight_leading_space in diff.c and you'll see that the test  \nis basically for any space which precedes a tab in the leading  \nwhitespace on newly inserted lines. In this case the spaces are  \nhighlighted using the whitespace color (normally red background).\n\nI don't know when color.diff.commit is ever used in diff output, but  \nperhaps that would need to be handled as well.\n\nCheers,\nWincent\n"},{"id":"55744","messageId":"Pine.LNX.4.64.0710141814100.25221@racer.site","threadId":"10270","inReplyTo":"EFADE863-FC59-4A50-B165-9D30D9648B97@wincent.com","subject":"Re: [PATCH] Add color to git-add--interactive diffs (Take 2: now without spurious line break!)","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-10-14T17:15:24Z","receivedAt":"2007-10-14T17:15:24Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Sun, 14 Oct 2007, Wincent Colaiuta wrote:\n\n> > +sub parse_color {\n> \n> You could simplify the manual escape sequence construction that you're \n> doing here by using Term::ANSIColor like the other patches did. I see \n> that git-send-email.perl uses that module too, so I guess depending on \n> that module is ok.\n\nWrong.  Depending on that module is not correct, you always have to wrap \nit into an \"if (<is_color>) {...}\".\n\nI use git add -i quite often, and I _never_ use git send-email.  My guess \nis that I am not alone with that.\n\nCiao,\nDscho\n"},{"id":"55753","messageId":"471257F9.2090705@op5.se","threadId":"10270","inReplyTo":"Pine.LNX.4.64.0710141814100.25221@racer.site","subject":"Re: [PATCH] Add color to git-add--interactive diffs (Take 2: now without spurious line break!)","fromName":"Andreas Ericsson","fromEmail":"ae@op5.se","sentAt":"2007-10-14T17:55:05Z","receivedAt":"2007-10-14T17:55:05Z","isPatch":true,"sender":{"key":"ae@op5.se","avatar":"https://gravatar.com/avatar/426e89595c75a8f5252dd0c989e5fabe5bcac616e68557427ad9aef6b0ca342a?d=mp&s=160"},"body":"Johannes Schindelin wrote:\n> Hi,\n> \n> On Sun, 14 Oct 2007, Wincent Colaiuta wrote:\n> \n>>> +sub parse_color {\n>> You could simplify the manual escape sequence construction that you're \n>> doing here by using Term::ANSIColor like the other patches did. I see \n>> that git-send-email.perl uses that module too, so I guess depending on \n>> that module is ok.\n> \n> Wrong.  Depending on that module is not correct, you always have to wrap \n> it into an \"if (<is_color>) {...}\".\n> \n> I use git add -i quite often, and I _never_ use git send-email.  My guess \n> is that I am not alone with that.\n> \n\nNot by a longshot, no. Personally I find git-send-email so tricky to use I've\nrolled my own sender. I circulated it on the list a year or so back, but it's\nnot nearly so feature-full as git-send-email, so it never got much of an\naudience.\n\n-- \nAndreas Ericsson                   andreas.ericsson@op5.se\nOP5 AB                             www.op5.se\nTel: +46 8-230225                  Fax: +46 8-230231\n"},{"id":"55774","messageId":"DFCD949F-2E7E-417A-9B58-A220A83695F5@wincent.com","threadId":"10270","inReplyTo":"Pine.LNX.4.64.0710141814100.25221@racer.site","subject":"Re: [PATCH] Add color to git-add--interactive diffs (Take 2: now without spurious line break!)","fromName":"Wincent Colaiuta","fromEmail":"win@wincent.com","sentAt":"2007-10-14T21:01:27Z","receivedAt":"2007-10-14T21:01:27Z","isPatch":true,"sender":{"key":"greg@hurrell.net","avatar":"https://avatars.githubusercontent.com/u/7074?v=4"},"body":"El 14/10/2007, a las 19:15, Johannes Schindelin escribió:\n\n> On Sun, 14 Oct 2007, Wincent Colaiuta wrote:\n>\n>>> +sub parse_color {\n>>\n>> You could simplify the manual escape sequence construction that  \n>> you're\n>> doing here by using Term::ANSIColor like the other patches did. I see\n>> that git-send-email.perl uses that module too, so I guess  \n>> depending on\n>> that module is ok.\n>\n> Wrong.  Depending on that module is not correct, you always have to  \n> wrap\n> it into an \"if (<is_color>) {...}\".\n>\n> I use git add -i quite often, and I _never_ use git send-email.  My  \n> guess\n> is that I am not alone with that.\n\nIn that case I propose factoring out the escape sequence generation  \ninto git.pm, where it can be used by git-send-email, git-add-- \ninteractive, or any other Perl script in Git. Do you think that's a  \ngood idea? If so I'll try whipping up a patch along those lines.\n\nWincent\n"},{"id":"56914","messageId":"20071022204719.GA23348@xp.machine.xx","threadId":"10270","inReplyTo":"1192351494.7226.18.camel@athena","subject":"Re: [PATCH] Add color to git-add--interactive diffs (Total different idea to solve the problem)","fromName":"Peter Baumann","fromEmail":"waste.manager@gmx.de","sentAt":"2007-10-22T20:47:19Z","receivedAt":"2007-10-22T20:47:19Z","isPatch":true,"sender":{"key":"waste.manager@gmx.de","avatar":null},"body":"On Sun, Oct 14, 2007 at 03:44:54AM -0500, Tom Tobin wrote:\n> (This is repost; my damned mail client wrapped a line in the patch last\n> time, and now I've got that under control.  My apologies!)  :(\n> \n> Seeing the recent discussion and code regarding adding color to\n> git-add--interactive, I thought I'd throw in my recent attempt at\n> colorizing the diffs.  (This doesn't handle anything else, such as the\n> prompts.)\n> \n> After banging my head against parsing colorized output of git-add-files,\n> I gave up and implemented internal colorization keying off of the\n> color.diff configuration.\n> \n> Hopefully this can be of some use towards fully colorizing\n> git-add--interactive; I'll admit up front that Perl isn't my primary\n> language, so I apologize in advance for whatever stupidities I've\n> introduced.  ;) \n> \n> Signed-off-by: Tom Tobin <korpios@korpios.com>\n\n[...skiping patch ...]\n\nTossing around ideas, so feel free to ignore me.\n\nWouldn't it make more sense to implement the diff coloring inside git apply\nso that you could use something like\n\n        diff file1 file2|git apply --color\n\nto make the generated diff with colors [1]? It already implements the\nsame semantic for generating a diffstat, using\n\n        diff file1 file2|git apply --stat\n\nso we would get a generic diff colorizing tool and you could use inside\ngit add -i the diff without color and just print it out with the\ngit apply --color filter. So if someone implements another tool which\nneeds color handling he could use this output filter.\n\n-Peter\n\n[1]: there is a programm colordiff which does exactly this, but AFAIK git\n     colorization has more features.\n"},{"id":"56930","messageId":"Pine.LNX.4.64.0710230054130.25221@racer.site","threadId":"10270","inReplyTo":"20071022204719.GA23348@xp.machine.xx","subject":"Re: [PATCH] Add color to git-add--interactive diffs (Total different idea to solve the problem)","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-10-22T23:55:44Z","receivedAt":"2007-10-22T23:55:44Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Mon, 22 Oct 2007, Peter Baumann wrote:\n\n> Wouldn't it make more sense to implement the diff coloring inside git \n> apply so that you could use something like\n> \n>         diff file1 file2|git apply --color\n> \n> to make the generated diff with colors [1]? It already implements the\n> same semantic for generating a diffstat, using\n> \n>         diff file1 file2|git apply --stat\n\nNo.  In both cases, \"git diff\" realises that the output is no terminal, \nand switches off color generation.  (Just try with diff.color=true instead \nof =auto.)\n\nCiao,\nDscho\n"},{"id":"56962","messageId":"20071023053401.GB9330@xp.machine.xx","threadId":"10270","inReplyTo":"Pine.LNX.4.64.0710230054130.25221@racer.site","subject":"Re: [PATCH] Add color to git-add--interactive diffs (Total different idea to solve the problem)","fromName":"Peter Baumann","fromEmail":"waste.manager@gmx.de","sentAt":"2007-10-23T05:34:01Z","receivedAt":"2007-10-23T05:34:01Z","isPatch":true,"sender":{"key":"waste.manager@gmx.de","avatar":null},"body":"On Tue, Oct 23, 2007 at 12:55:44AM +0100, Johannes Schindelin wrote:\n> Hi,\n> \n> On Mon, 22 Oct 2007, Peter Baumann wrote:\n> \n> > Wouldn't it make more sense to implement the diff coloring inside git \n> > apply so that you could use something like\n> > \n> >         diff file1 file2|git apply --color\n> > \n> > to make the generated diff with colors [1]? It already implements the\n> > same semantic for generating a diffstat, using\n> > \n> >         diff file1 file2|git apply --stat\n> \n> No.  In both cases, \"git diff\" realises that the output is no terminal, \n> and switches off color generation.  (Just try with diff.color=true instead \n> of =auto.)\n> \n\nI didn't mean git-diff here, instead I meant diff, so no coloring involved\non the diff side. The git-apply would be enhanced to do the coloring on\nevery diff it gets on its STDIN.\n\nIn the git-add -i case, the perl script whould do something along these\nlines:\n\n\tforeach my $file (@files) {\n\t\t# read in the diff of a file *WITHOUT* using color\n\t\t@diff = `git-diff-files $file`;\n\n\t\t# ... store it away for later use in hunk selection ...\n\n\n\t\t# print out a nice colored diff for the user\n\t\t`echo @diff | git apply --color`\n\t}\n\nInstead of handcoding the colorization in the git-add--interactive perl\nscript, just enhance git-apply to do the colorization *after the fact* for\nyou on _any_ patch you throw at it in its STDIN.\n\n-Peter\n"},{"id":"56996","messageId":"Pine.LNX.4.64.0710231213140.25221@racer.site","threadId":"10270","inReplyTo":"20071023053401.GB9330@xp.machine.xx","subject":"Re: [PATCH] Add color to git-add--interactive diffs (Total different idea to solve the problem)","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-10-23T11:13:41Z","receivedAt":"2007-10-23T11:13:41Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Tue, 23 Oct 2007, Peter Baumann wrote:\n\n> On Tue, Oct 23, 2007 at 12:55:44AM +0100, Johannes Schindelin wrote:\n> \n> > On Mon, 22 Oct 2007, Peter Baumann wrote:\n> > \n> > > Wouldn't it make more sense to implement the diff coloring inside \n> > > git apply so that you could use something like\n> > > \n> > >         diff file1 file2|git apply --color\n> > > \n> > > to make the generated diff with colors [1]? It already implements \n> > > the same semantic for generating a diffstat, using\n> > > \n> > >         diff file1 file2|git apply --stat\n> > \n> > No.  In both cases, \"git diff\" realises that the output is no terminal, \n> > and switches off color generation.  (Just try with diff.color=true instead \n> > of =auto.)\n> > \n> \n> I didn't mean git-diff here, instead I meant diff, so no coloring involved\n> on the diff side. The git-apply would be enhanced to do the coloring on\n> every diff it gets on its STDIN.\n\nAh!  I completely misunderstood indeed.  Clever...\n\nCiao,\nDscho\n"}]}