{"thread":{"id":"41547","subject":"[PATCH] add--interactive: allow custom diff highlighting programs","startedAt":"2016-02-27T05:37:06Z","lastAt":"2016-02-27T05:37:06Z","messageCount":1,"participants":["Jeff King"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"279604","messageId":"20160227053706.GA21117@sigill.intra.peff.net","threadId":"41547","inReplyTo":null,"subject":"[PATCH] add--interactive: allow custom diff highlighting programs","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-27T05:37:06Z","receivedAt":"2016-02-27T05:37:06Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"The patch hunk selector of add--interactive knows how ask\ngit for colorized diffs, and correlate them with the\nuncolored diffs we apply. But there's not any way for\nsomebody who uses a diff-filter tool like contrib's\ndiff-highlight to see their normal highlighting.\n\nThis patch lets users define an arbitrary shell command to\npipe the colorized diff through. The exact output shouldn't\nmatter (since we just show the result to humans) as long as\nit is line-compatible with the original diff (so that\nhunk-splitting can split the colorized version, too).\n\nI left two minor issues with the new system that I don't\nthink are worth fixing right now, but could be done later:\n\n  1. We only filter colorized diffs. Theoretically a user\n     could want to filter a non-colorized diff, but I find\n     it unlikely in practice. Users who are doing things\n     like diff-highlighting are likely to want color, too.\n\n  2. add--interactive will re-colorize a diff which has been\n     hand-edited, but it won't have run through the filter.\n     Fixing this is conceptually easy (just pipe the diff\n     through the filter), but practically hard to do without\n     using tempfiles (it would need to feed data to and read\n     the result from the filter without deadlocking; this\n     raises portability questions with respect to Windows).\n\nI've punted on both issues for now, and if somebody really\ncares later, they can do a patch on top.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\nThis is a little hack I whipped up after the diff-so-fancy people asked\nme about it in:\n\n  https://github.com/so-fancy/diff-so-fancy/issues/35\n\nIt's something I've wanted for a while with diff-highlight. I made sure\nit works (the final hunk of this patch was added via highlighted \"add\n-p\". Woohoo!), but other than that it hasn't been exposed to a lot of\ncorner cases.\n\nI'm actually not sure whether it will work well with diff-so-fancy or\nnot; they change the diff header around a bit, and there's not a\ncomplete 1:1 correspondence in the lines. _But_ I think it might work OK\nin practice, because their diff header remains 4 lines long, and the\nhunks themselves have 1:1 line correspondence.\n\n Documentation/config.txt  |  8 ++++++++\n git-add--interactive.perl | 12 ++++++++++--\n 2 files changed, 18 insertions(+), 2 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 2cd6bdd..f5834ec 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -1886,6 +1886,14 @@ interactive.singleKey::\n \tsetting is silently ignored if portable keystroke input\n \tis not available; requires the Perl module Term::ReadKey.\n \n+interactive.diffFilter::\n+\tWhen an interactive command (such as `git add --patch`) shows\n+\ta colorized diff, git will pipe the diff through the shell\n+\tcommand defined by this configuration variable. The command may\n+\tmark up the diff further for human consumption, provided that it\n+\tretains a one-to-one correspondence with the lines in the\n+\toriginal diff. Defaults to disabled (no filtering).\n+\n log.abbrevCommit::\n \tIf true, makes linkgit:git-log[1], linkgit:git-show[1], and\n \tlinkgit:git-whatchanged[1] assume `--abbrev-commit`. You may\ndiff --git a/git-add--interactive.perl b/git-add--interactive.perl\nindex 77876d4..822f857 100755\n--- a/git-add--interactive.perl\n+++ b/git-add--interactive.perl\n@@ -45,6 +45,7 @@ my ($diff_new_color) =\n my $normal_color = $repo->get_color(\"\", \"reset\");\n \n my $diff_algorithm = $repo->config('diff.algorithm');\n+my $diff_filter = $repo->config('interactive.difffilter');\n \n my $use_readkey = 0;\n my $use_termcap = 0;\n@@ -754,7 +755,14 @@ sub parse_diff {\n \tmy @diff = run_cmd_pipe(\"git\", @diff_cmd, \"--\", $path);\n \tmy @colored = ();\n \tif ($diff_use_color) {\n-\t\t@colored = run_cmd_pipe(\"git\", @diff_cmd, qw(--color --), $path);\n+\t\tmy @display_cmd = (\"git\", @diff_cmd, qw(--color --), $path);\n+\t\tif (defined $diff_filter) {\n+\t\t\t# quotemeta is overkill, but sufficient for shell-quoting\n+\t\t\tmy $diff = join(' ', map { quotemeta } @display_cmd);\n+\t\t\t@display_cmd = (\"$diff | $diff_filter\");\n+\t\t}\n+\n+\t\t@colored = run_cmd_pipe(@display_cmd);\n \t}\n \tmy (@hunk) = { TEXT => [], DISPLAY => [], TYPE => 'header' };\n \n@@ -765,7 +773,7 @@ sub parse_diff {\n \t\t}\n \t\tpush @{$hunk[-1]{TEXT}}, $diff[$i];\n \t\tpush @{$hunk[-1]{DISPLAY}},\n-\t\t\t($diff_use_color ? $colored[$i] : $diff[$i]);\n+\t\t\t(@colored ? $colored[$i] : $diff[$i]);\n \t}\n \treturn @hunk;\n }\n-- \n2.7.2.767.g705917e\n"}]}