@@ -3,10 +3,11 @@ package DiffHighlight;
3
3
use 5.008;
4
4
use warnings FATAL => ' all' ;
5
5
use strict;
6
- use Encode;
7
- use File::Spec; # For devnull
8
6
9
- my $NULL = File::Spec-> devnull(); # get correct value for unix/win
7
+ # Use the correct value for both UNIX and Windows (/dev/null vs nul)
8
+ use File::Spec;
9
+
10
+ my $NULL = File::Spec-> devnull();
10
11
11
12
# Highlight by reversing foreground and background. You could do
12
13
# other things like bold or underline if you prefer.
@@ -21,41 +22,88 @@ our @NEW_HIGHLIGHT = (
21
22
$OLD_HIGHLIGHT [2],
22
23
);
23
24
25
+
26
+
24
27
my $RESET = " \x1b [m" ;
25
28
my $COLOR = qr /\x1b\[ [0-9;]*m/ ;
26
29
my $BORING = qr /$COLOR |\s / ;
27
30
28
- # The patch portion of git log -p --graph should only ever have preceding | and
29
- # not / or \ as merge history only shows up on the commit line.
30
- my $GRAPH = qr /$COLOR ?\| $COLOR ?\s +/ ;
31
-
32
31
my @removed ;
33
32
my @added ;
34
33
my $in_hunk ;
34
+ my $graph_indent = 0;
35
35
36
36
our $line_cb = sub { print @_ };
37
37
our $flush_cb = sub { local $| = 1 };
38
38
39
- sub handle_line {
39
+ # Count the visible width of a string, excluding any terminal color sequences.
40
+ sub visible_width {
40
41
local $_ = shift ;
42
+ my $ret = 0;
43
+ while (length ) {
44
+ if (s / ^$COLOR// ) {
45
+ # skip colors
46
+ } elsif (s / ^.// ) {
47
+ $ret ++;
48
+ }
49
+ }
50
+ return $ret ;
51
+ }
52
+
53
+ # Return a substring of $str, omitting $len visible characters from the
54
+ # beginning, where terminal color sequences do not count as visible.
55
+ sub visible_substr {
56
+ my ($str , $len ) = @_ ;
57
+ while ($len > 0) {
58
+ if ($str =~ s / ^$COLOR// ) {
59
+ next
60
+ }
61
+ $str =~ s / ^.// ;
62
+ $len --;
63
+ }
64
+ return $str ;
65
+ }
66
+
67
+ sub handle_line {
68
+ my $orig = shift ;
69
+ local $_ = $orig ;
70
+
71
+ # match a graph line that begins a commit
72
+ if (/ ^(?:$COLOR ?\| $COLOR ?[ ])* # zero or more leading "|" with space
73
+ $COLOR ?\* $COLOR ?[ ] # a "*" with its trailing space
74
+ (?:$COLOR ?\| $COLOR ?[ ])* # zero or more trailing "|"
75
+ [ ]* # trailing whitespace for merges
76
+ /x ) {
77
+ my $graph_prefix = $& ;
78
+
79
+ # We must flush before setting graph indent, since the
80
+ # new commit may be indented differently from what we
81
+ # queued.
82
+ flush();
83
+ $graph_indent = visible_width($graph_prefix );
84
+
85
+ } elsif ($graph_indent ) {
86
+ if (length ($_ ) < $graph_indent ) {
87
+ $graph_indent = 0;
88
+ } else {
89
+ $_ = visible_substr($_ , $graph_indent );
90
+ }
91
+ }
41
92
42
93
if (!$in_hunk ) {
43
- $line_cb -> ($_ );
44
- $in_hunk = /^$GRAPH * $ COLOR *\@\@ /;
94
+ $line_cb -> ($orig );
95
+ $in_hunk = /^$COLOR *\@\@ /;
45
96
}
46
- elsif (/ ^$GRAPH * $ COLOR *-/ ) {
47
- push @removed , $_ ;
97
+ elsif (/ ^$COLOR *-/ ) {
98
+ push @removed , $orig ;
48
99
}
49
- elsif (/ ^$GRAPH * $ COLOR *\+ / ) {
50
- push @added , $_ ;
100
+ elsif (/ ^$COLOR *\+ / ) {
101
+ push @added , $orig ;
51
102
}
52
103
else {
53
- show_hunk(\@removed , \@added );
54
- @removed = ();
55
- @added = ();
56
-
57
- $line_cb -> ($_ );
58
- $in_hunk = /^$GRAPH *$COLOR *[\@ ]/;
104
+ flush();
105
+ $line_cb -> ($orig );
106
+ $in_hunk = /^$COLOR *[\@ ]/;
59
107
}
60
108
61
109
# Most of the time there is enough output to keep things streaming,
@@ -75,6 +123,8 @@ sub flush {
75
123
# Flush any queued hunk (this can happen when there is no trailing
76
124
# context in the final diff of the input).
77
125
show_hunk(\@removed , \@added );
126
+ @removed = ();
127
+ @added = ();
78
128
}
79
129
80
130
sub highlight_stdin {
@@ -125,7 +175,6 @@ sub show_hunk {
125
175
sub highlight_pair {
126
176
my @a = split_line(shift );
127
177
my @b = split_line(shift );
128
- my $opts = shift ();
129
178
130
179
# Find common prefix, taking care to skip any ansi
131
180
# color codes.
@@ -170,18 +219,9 @@ sub highlight_pair {
170
219
}
171
220
}
172
221
173
- my @OLD_COLOR_SPEC = @OLD_HIGHLIGHT ;
174
- my @NEW_COLOR_SPEC = @NEW_HIGHLIGHT ;
175
-
176
- # If we're only highlight the differences temp disable the old/new normal colors
177
- if ($opts -> {' only_diff' }) {
178
- $OLD_COLOR_SPEC [0] = ' ' ;
179
- $NEW_COLOR_SPEC [0] = ' ' ;
180
- }
181
-
182
222
if (is_pair_interesting(\@a , $pa , $sa , \@b , $pb , $sb )) {
183
- return highlight_line(\@a , $pa , $sa , \@OLD_COLOR_SPEC ),
184
- highlight_line(\@b , $pb , $sb , \@NEW_COLOR_SPEC );
223
+ return highlight_line(\@a , $pa , $sa , \@OLD_HIGHLIGHT ),
224
+ highlight_line(\@b , $pb , $sb , \@NEW_HIGHLIGHT );
185
225
}
186
226
else {
187
227
return join (' ' , @a ),
@@ -194,8 +234,8 @@ sub highlight_pair {
194
234
# or "+"
195
235
sub split_line {
196
236
local $_ = shift ;
197
- return eval { $_ = Encode ::decode(' UTF-8 ' , $_ , 1); 1 } ?
198
- map { Encode ::encode(' UTF-8 ' , $_ ) }
237
+ return utf8 ::decode($_ ) ?
238
+ map { utf8 ::encode($_ ); $_ }
199
239
map { / $COLOR / ? $_ : (split //) }
200
240
split /($COLOR +)/ :
201
241
map { / $COLOR / ? $_ : (split //) }
@@ -240,8 +280,8 @@ sub is_pair_interesting {
240
280
my $suffix_a = join (' ' , @$a [($sa +1)..$#$a ]);
241
281
my $suffix_b = join (' ' , @$b [($sb +1)..$#$b ]);
242
282
243
- return $prefix_a !~ / ^$GRAPH * $COLOR *-$BORING *$ / ||
244
- $prefix_b !~ / ^$GRAPH * $COLOR *\+ $BORING *$ / ||
283
+ return visible_substr( $prefix_a , $graph_indent ) !~ / ^$COLOR *-$BORING *$ / ||
284
+ visible_substr( $prefix_b , $graph_indent ) !~ / ^$COLOR *\+ $BORING *$ / ||
245
285
$suffix_a !~ / ^$BORING *$ / ||
246
286
$suffix_b !~ / ^$BORING *$ / ;
247
287
}
0 commit comments