]> git.ipfire.org Git - thirdparty/git.git/blame - contrib/diff-highlight/diff-highlight
Merge branch 'sn/http-auth-with-netrc-fix'
[thirdparty/git.git] / contrib / diff-highlight / diff-highlight
CommitLineData
927a13fe
JK
1#!/usr/bin/perl
2
3# Highlight by reversing foreground and background. You could do
4# other things like bold or underline if you prefer.
5my $HIGHLIGHT = "\x1b[7m";
6my $UNHIGHLIGHT = "\x1b[27m";
7my $COLOR = qr/\x1b\[[0-9;]*m/;
8
9my @window;
10
11while (<>) {
12 # We highlight only single-line changes, so we need
13 # a 4-line window to make a decision on whether
14 # to highlight.
15 push @window, $_;
16 next if @window < 4;
17 if ($window[0] =~ /^$COLOR*(\@| )/ &&
18 $window[1] =~ /^$COLOR*-/ &&
19 $window[2] =~ /^$COLOR*\+/ &&
20 $window[3] !~ /^$COLOR*\+/) {
21 print shift @window;
22 show_pair(shift @window, shift @window);
23 }
24 else {
25 print shift @window;
26 }
27
28 # Most of the time there is enough output to keep things streaming,
29 # but for something like "git log -Sfoo", you can get one early
30 # commit and then many seconds of nothing. We want to show
31 # that one commit as soon as possible.
32 #
33 # Since we can receive arbitrary input, there's no optimal
34 # place to flush. Flushing on a blank line is a heuristic that
35 # happens to match git-log output.
36 if (!length) {
37 local $| = 1;
38 }
39}
40
41# Special case a single-line hunk at the end of file.
42if (@window == 3 &&
43 $window[0] =~ /^$COLOR*(\@| )/ &&
44 $window[1] =~ /^$COLOR*-/ &&
45 $window[2] =~ /^$COLOR*\+/) {
46 print shift @window;
47 show_pair(shift @window, shift @window);
48}
49
50# And then flush any remaining lines.
51while (@window) {
52 print shift @window;
53}
54
55exit 0;
56
57sub show_pair {
58 my @a = split_line(shift);
59 my @b = split_line(shift);
60
61 # Find common prefix, taking care to skip any ansi
62 # color codes.
63 my $seen_plusminus;
64 my ($pa, $pb) = (0, 0);
65 while ($pa < @a && $pb < @b) {
66 if ($a[$pa] =~ /$COLOR/) {
67 $pa++;
68 }
69 elsif ($b[$pb] =~ /$COLOR/) {
70 $pb++;
71 }
72 elsif ($a[$pa] eq $b[$pb]) {
73 $pa++;
74 $pb++;
75 }
76 elsif (!$seen_plusminus && $a[$pa] eq '-' && $b[$pb] eq '+') {
77 $seen_plusminus = 1;
78 $pa++;
79 $pb++;
80 }
81 else {
82 last;
83 }
84 }
85
86 # Find common suffix, ignoring colors.
87 my ($sa, $sb) = ($#a, $#b);
88 while ($sa >= $pa && $sb >= $pb) {
89 if ($a[$sa] =~ /$COLOR/) {
90 $sa--;
91 }
92 elsif ($b[$sb] =~ /$COLOR/) {
93 $sb--;
94 }
95 elsif ($a[$sa] eq $b[$sb]) {
96 $sa--;
97 $sb--;
98 }
99 else {
100 last;
101 }
102 }
103
104 print highlight(\@a, $pa, $sa);
105 print highlight(\@b, $pb, $sb);
106}
107
108sub split_line {
109 local $_ = shift;
110 return map { /$COLOR/ ? $_ : (split //) }
111 split /($COLOR*)/;
112}
113
114sub highlight {
115 my ($line, $prefix, $suffix) = @_;
116
117 return join('',
118 @{$line}[0..($prefix-1)],
119 $HIGHLIGHT,
120 @{$line}[$prefix..$suffix],
121 $UNHIGHLIGHT,
122 @{$line}[($suffix+1)..$#$line]
123 );
124}