git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: Understanding and improving --word-diff

From
Jeff King <peff@peff.net>
Date
Nov 18, 2010, 06:40 UTC
Message-ID
<20101118064050.GA12825@sigill.intra.peff.net>
In-Reply-To
<20101109220136.GA5617@sigill.intra.peff.net>
On Tue, Nov 09, 2010 at 05:01:36PM -0500, Jeff King wrote:
Show 19 quoted lines
>   2. There is a buglet in git's color emitting code. For added lines, it
>      produces "<g>+</g><g>rest of line</g>" which is annoying to parse.
>      It is fixed by the patch below:
> 
> diff --git a/diff.c b/diff.c
> index b1b0d3d..0efcdb7 100644
> --- a/diff.c
> +++ b/diff.c
> @@ -363,9 +363,9 @@ static void emit_add_line(const char *reset,
>  		emit_line_0(ecbdata->opt, ws, reset, '+', line, len);
>  	else {
>  		/* Emit just the prefix, then the rest. */
> -		emit_line_0(ecbdata->opt, set, reset, '+', "", 0);
> +		emit_line_0(ecbdata->opt, set, "", '+', "", 0);
>  		ws_check_emit(line, len, ecbdata->ws_rule,
> -			      ecbdata->opt->file, set, reset, ws);
> +			      ecbdata->opt->file, "", reset, ws);
>  	}
>  }

FYI, I looked further at this patch, and it should not be used. There are cases where ws_check_emit will output a reset (e.g., because it has colored some whitespace), and needs to be able to set the proper color again. So while I think the intent of this patch is fine (to avoid duplicate colorizing in the output), the actual implementation would need to be much more complex.

Instead, here's an updated version of my color highlighting script that handles this case.

With the patch I posted earlier today:
  [PATCH 2/2] allow command-specific pagers in pager.<cmd>
  http://article.gmane.org/gmane.comp.version-control.git/161624
you can do:
  git config pager.log '/path/to/diff-highlight.pl | less'

and get automagic coloring. Still, this is a bit of a hack, and there are some funny corner cases, so something that used the internal diff machinery would be much nicer.

-Peff

-- >8 -- #!/usr/bin/perl

use strict; my $COLOR = qr/\x1b\[[0-9;]*m/; my $RESET = "\x1b[0m"; my $RED = "\x1b[31m"; my $GREEN = "\x1b[32m"; my $REVERSE = "\x1b[7m"; my $UNREVERSE = "\x1b[27m";

my @window;
while (<>) {
  chomp;
  my $plain = $_;
  $plain =~ s/$COLOR//g;
  push @window, [$_, $plain];
  if ($window[0] && $window[0]->[1] =~ /^(\@| )/ &&
      $window[1] && $window[1]->[1] =~ /^-/ &&
      $window[2] && $window[2]->[1] =~ /^\+/ &&
      $window[3] && $window[3]->[1] !~ /^\+/) {
    show_line(shift @window);
    show_pair(shift @window, shift @window);
  }
  if (@window >= 4) {
    show_line(shift @window);
  }
}
if (@window == 3 &&
    $window[0] && $window[0]->[1] =~ /^(\@| )/ &&
    $window[1] && $window[1]->[1] =~ /^-/ &&
    $window[2] && $window[2]->[1] =~ /^\+/) {
  show_line(shift @window);
  show_pair(shift @window, shift @window);
}
while (@window) {
  show_line(shift @window);
}
exit 0;
sub show_line {
  my $line = shift;
  print $line->[0], "\n";
}
sub show_pair {
  my ($from, $to) = @_;
  my @from = split //, $from->[1];
  my @to = split //, $to->[1];
  my $prefix = 1;
  while ($from[$prefix] eq $to[$prefix]) {
    $prefix++;
  }
  my $suffix = 0;
  while ($from[$#from-$suffix] eq $to[$#to-$suffix]) {
    $suffix++;
  }
  print $RED, highlight($from->[1], $prefix, $suffix), $RESET, "\n";
  print $GREEN, highlight($to->[1], $prefix, $suffix), $RESET, "\n";
}
sub highlight {
  my ($line, $prefix, $suffix) = @_;
  my $end = length($line) - $suffix;
  return $line unless $end > $prefix;
  return join('',
    substr($line, 0, $prefix),
    $REVERSE,
    substr($line, $prefix, $end - $prefix),
    $UNREVERSE,
    substr($line, $end)
  );
}
Previous: Jeff King
Message 10 of 10 in “Understanding and improving --word-diff”
  1. Matthijs KooijmanNov 8, 2010
  2. Matthieu MoyNov 8, 2010
  3. Matthijs KooijmanNov 8, 2010
  4. Thomas RastNov 8, 2010
  5. Wincent ColaiutaNov 8, 2010
  6. Thomas RastNov 8, 2010
  7. Jeff KingNov 9, 2010
  8. Johannes SchindelinNov 10, 2010
  9. Jeff KingNov 10, 2010
  10. Jeff KingNov 18, 2010

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.