Skip to content

Commit 0c977db

Browse files
peffgitster
authored andcommitted
diff-highlight: split code into module
The diff-so-fancy project is also written in perl, and most of its users pipe diffs through both diff-highlight and diff-so-fancy. It would be nice if this could be done in a single script. So let's pull most of diff-highlight's code into its own module which can be used by diff-so-fancy. In addition, we'll abstract a few basic items like reading from stdio so that a script using the module can do more processing before or after diff-highlight handles the lines. See the README update for more details. One small downside is that the diff-highlight script must now be built using the Makefile. There are ways around this, but it quickly gets into perl arcana. Let's go with the simple solution. As a bonus, our Makefile now respects the PERL_PATH variable if it is set. Signed-off-by: Jeff King <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent fd99e2b commit 0c977db

File tree

5 files changed

+82
-19
lines changed

5 files changed

+82
-19
lines changed

contrib/diff-highlight/.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
shebang.perl
2+
diff-highlight

contrib/diff-highlight/diff-highlight contrib/diff-highlight/DiffHighlight.pm

+24-16
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#!/usr/bin/perl
1+
package DiffHighlight;
22

33
use 5.008;
44
use warnings FATAL => 'all';
@@ -29,13 +29,14 @@ my @removed;
2929
my @added;
3030
my $in_hunk;
3131

32-
# Some scripts may not realize that SIGPIPE is being ignored when launching the
33-
# pager--for instance scripts written in Python.
34-
$SIG{PIPE} = 'DEFAULT';
32+
our $line_cb = sub { print @_ };
33+
our $flush_cb = sub { local $| = 1 };
34+
35+
sub handle_line {
36+
local $_ = shift;
3537

36-
while (<>) {
3738
if (!$in_hunk) {
38-
print;
39+
$line_cb->($_);
3940
$in_hunk = /^$GRAPH*$COLOR*\@\@ /;
4041
}
4142
elsif (/^$GRAPH*$COLOR*-/) {
@@ -49,7 +50,7 @@ while (<>) {
4950
@removed = ();
5051
@added = ();
5152

52-
print;
53+
$line_cb->($_);
5354
$in_hunk = /^$GRAPH*$COLOR*[\@ ]/;
5455
}
5556

@@ -62,15 +63,22 @@ while (<>) {
6263
# place to flush. Flushing on a blank line is a heuristic that
6364
# happens to match git-log output.
6465
if (!length) {
65-
local $| = 1;
66+
$flush_cb->();
6667
}
6768
}
6869

69-
# Flush any queued hunk (this can happen when there is no trailing context in
70-
# the final diff of the input).
71-
show_hunk(\@removed, \@added);
70+
sub flush {
71+
# Flush any queued hunk (this can happen when there is no trailing
72+
# context in the final diff of the input).
73+
show_hunk(\@removed, \@added);
74+
}
7275

73-
exit 0;
76+
sub highlight_stdin {
77+
while (<STDIN>) {
78+
handle_line($_);
79+
}
80+
flush();
81+
}
7482

7583
# Ideally we would feed the default as a human-readable color to
7684
# git-config as the fallback value. But diff-highlight does
@@ -88,7 +96,7 @@ sub show_hunk {
8896

8997
# If one side is empty, then there is nothing to compare or highlight.
9098
if (!@$a || !@$b) {
91-
print @$a, @$b;
99+
$line_cb->(@$a, @$b);
92100
return;
93101
}
94102

@@ -97,17 +105,17 @@ sub show_hunk {
97105
# stupid, and only handle multi-line hunks that remove and add the same
98106
# number of lines.
99107
if (@$a != @$b) {
100-
print @$a, @$b;
108+
$line_cb->(@$a, @$b);
101109
return;
102110
}
103111

104112
my @queue;
105113
for (my $i = 0; $i < @$a; $i++) {
106114
my ($rm, $add) = highlight_pair($a->[$i], $b->[$i]);
107-
print $rm;
115+
$line_cb->($rm);
108116
push @queue, $add;
109117
}
110-
print @queue;
118+
$line_cb->(@queue);
111119
}
112120

113121
sub highlight_pair {

contrib/diff-highlight/Makefile

+18-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,20 @@
1-
# nothing to build
2-
all:
1+
all: diff-highlight
32

4-
test:
3+
PERL_PATH = /usr/bin/perl
4+
-include ../../config.mak
5+
6+
PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH))
7+
8+
diff-highlight: shebang.perl DiffHighlight.pm diff-highlight.perl
9+
cat $^ >$@+
10+
chmod +x $@+
11+
mv $@+ $@
12+
13+
shebang.perl: FORCE
14+
@echo '#!$(PERL_PATH_SQ)' >$@+
15+
@cmp $@+ $@ >/dev/null 2>/dev/null || mv $@+ $@
16+
17+
test: all
518
$(MAKE) -C t
19+
20+
.PHONY: FORCE

contrib/diff-highlight/README

+30
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,36 @@ newHighlight = "black #aaffaa"
9999
---------------------------------------------
100100

101101

102+
Using diff-highlight as a module
103+
--------------------------------
104+
105+
If you want to pre- or post- process the highlighted lines as part of
106+
another perl script, you can use the DiffHighlight module. You can
107+
either "require" it or just cat the module together with your script (to
108+
avoid run-time dependencies).
109+
110+
Your script may set up one or more of the following variables:
111+
112+
- $DiffHighlight::line_cb - this should point to a function which is
113+
called whenever DiffHighlight has lines (which may contain
114+
highlights) to output. The default function prints each line to
115+
stdout. Note that the function may be called with multiple lines.
116+
117+
- $DiffHighlight::flush_cb - this should point to a function which
118+
flushes the output (because DiffHighlight believes it has completed
119+
processing a logical chunk of input). The default function flushes
120+
stdout.
121+
122+
The script may then feed lines, one at a time, to DiffHighlight::handle_line().
123+
When lines are done processing, they will be fed to $line_cb. Note that
124+
DiffHighlight may queue up many input lines (to analyze a whole hunk)
125+
before calling $line_cb. After providing all lines, call
126+
DiffHighlight::flush() to flush any unprocessed lines.
127+
128+
If you just want to process stdin, DiffHighlight::highlight_stdin()
129+
is a convenience helper which will loop and flush for you.
130+
131+
102132
Bugs
103133
----
104134

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package main;
2+
3+
# Some scripts may not realize that SIGPIPE is being ignored when launching the
4+
# pager--for instance scripts written in Python.
5+
$SIG{PIPE} = 'DEFAULT';
6+
7+
DiffHighlight::highlight_stdin();
8+
exit 0;

0 commit comments

Comments
 (0)