summaryrefslogtreecommitdiff
path: root/contrib/diff-highlight
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/diff-highlight')
-rw-r--r--contrib/diff-highlight/.gitignore2
-rw-r--r--[-rwxr-xr-x]contrib/diff-highlight/DiffHighlight.pm (renamed from contrib/diff-highlight/diff-highlight)119
-rw-r--r--contrib/diff-highlight/Makefile24
-rw-r--r--contrib/diff-highlight/README30
-rw-r--r--contrib/diff-highlight/diff-highlight.perl8
-rwxr-xr-xcontrib/diff-highlight/t/t9400-diff-highlight.sh81
6 files changed, 211 insertions, 53 deletions
diff --git a/contrib/diff-highlight/.gitignore b/contrib/diff-highlight/.gitignore
new file mode 100644
index 0000000000..c07454824e
--- /dev/null
+++ b/contrib/diff-highlight/.gitignore
@@ -0,0 +1,2 @@
+shebang.perl
+diff-highlight
diff --git a/contrib/diff-highlight/diff-highlight b/contrib/diff-highlight/DiffHighlight.pm
index 81bd8040e3..536754583b 100755..100644
--- a/contrib/diff-highlight/diff-highlight
+++ b/contrib/diff-highlight/DiffHighlight.pm
@@ -1,4 +1,4 @@
-#!/usr/bin/perl
+package DiffHighlight;
use 5.008;
use warnings FATAL => 'all';
@@ -21,36 +21,82 @@ my $RESET = "\x1b[m";
my $COLOR = qr/\x1b\[[0-9;]*m/;
my $BORING = qr/$COLOR|\s/;
-# The patch portion of git log -p --graph should only ever have preceding | and
-# not / or \ as merge history only shows up on the commit line.
-my $GRAPH = qr/$COLOR?\|$COLOR?\s+/;
-
my @removed;
my @added;
my $in_hunk;
+my $graph_indent = 0;
+
+our $line_cb = sub { print @_ };
+our $flush_cb = sub { local $| = 1 };
+
+# Count the visible width of a string, excluding any terminal color sequences.
+sub visible_width {
+ local $_ = shift;
+ my $ret = 0;
+ while (length) {
+ if (s/^$COLOR//) {
+ # skip colors
+ } elsif (s/^.//) {
+ $ret++;
+ }
+ }
+ return $ret;
+}
+
+# Return a substring of $str, omitting $len visible characters from the
+# beginning, where terminal color sequences do not count as visible.
+sub visible_substr {
+ my ($str, $len) = @_;
+ while ($len > 0) {
+ if ($str =~ s/^$COLOR//) {
+ next
+ }
+ $str =~ s/^.//;
+ $len--;
+ }
+ return $str;
+}
+
+sub handle_line {
+ my $orig = shift;
+ local $_ = $orig;
+
+ # match a graph line that begins a commit
+ if (/^(?:$COLOR?\|$COLOR?[ ])* # zero or more leading "|" with space
+ $COLOR?\*$COLOR?[ ] # a "*" with its trailing space
+ (?:$COLOR?\|$COLOR?[ ])* # zero or more trailing "|"
+ [ ]* # trailing whitespace for merges
+ /x) {
+ my $graph_prefix = $&;
-# Some scripts may not realize that SIGPIPE is being ignored when launching the
-# pager--for instance scripts written in Python.
-$SIG{PIPE} = 'DEFAULT';
+ # We must flush before setting graph indent, since the
+ # new commit may be indented differently from what we
+ # queued.
+ flush();
+ $graph_indent = visible_width($graph_prefix);
+
+ } elsif ($graph_indent) {
+ if (length($_) < $graph_indent) {
+ $graph_indent = 0;
+ } else {
+ $_ = visible_substr($_, $graph_indent);
+ }
+ }
-while (<>) {
if (!$in_hunk) {
- print;
- $in_hunk = /^$GRAPH*$COLOR*\@\@ /;
+ $line_cb->($orig);
+ $in_hunk = /^$COLOR*\@\@ /;
}
- elsif (/^$GRAPH*$COLOR*-/) {
- push @removed, $_;
+ elsif (/^$COLOR*-/) {
+ push @removed, $orig;
}
- elsif (/^$GRAPH*$COLOR*\+/) {
- push @added, $_;
+ elsif (/^$COLOR*\+/) {
+ push @added, $orig;
}
else {
- show_hunk(\@removed, \@added);
- @removed = ();
- @added = ();
-
- print;
- $in_hunk = /^$GRAPH*$COLOR*[\@ ]/;
+ flush();
+ $line_cb->($orig);
+ $in_hunk = /^$COLOR*[\@ ]/;
}
# Most of the time there is enough output to keep things streaming,
@@ -62,15 +108,24 @@ while (<>) {
# place to flush. Flushing on a blank line is a heuristic that
# happens to match git-log output.
if (!length) {
- local $| = 1;
+ $flush_cb->();
}
}
-# Flush any queued hunk (this can happen when there is no trailing context in
-# the final diff of the input).
-show_hunk(\@removed, \@added);
+sub flush {
+ # Flush any queued hunk (this can happen when there is no trailing
+ # context in the final diff of the input).
+ show_hunk(\@removed, \@added);
+ @removed = ();
+ @added = ();
+}
-exit 0;
+sub highlight_stdin {
+ while (<STDIN>) {
+ handle_line($_);
+ }
+ flush();
+}
# Ideally we would feed the default as a human-readable color to
# git-config as the fallback value. But diff-highlight does
@@ -88,7 +143,7 @@ sub show_hunk {
# If one side is empty, then there is nothing to compare or highlight.
if (!@$a || !@$b) {
- print @$a, @$b;
+ $line_cb->(@$a, @$b);
return;
}
@@ -97,17 +152,17 @@ sub show_hunk {
# stupid, and only handle multi-line hunks that remove and add the same
# number of lines.
if (@$a != @$b) {
- print @$a, @$b;
+ $line_cb->(@$a, @$b);
return;
}
my @queue;
for (my $i = 0; $i < @$a; $i++) {
my ($rm, $add) = highlight_pair($a->[$i], $b->[$i]);
- print $rm;
+ $line_cb->($rm);
push @queue, $add;
}
- print @queue;
+ $line_cb->(@queue);
}
sub highlight_pair {
@@ -218,8 +273,8 @@ sub is_pair_interesting {
my $suffix_a = join('', @$a[($sa+1)..$#$a]);
my $suffix_b = join('', @$b[($sb+1)..$#$b]);
- return $prefix_a !~ /^$GRAPH*$COLOR*-$BORING*$/ ||
- $prefix_b !~ /^$GRAPH*$COLOR*\+$BORING*$/ ||
+ return visible_substr($prefix_a, $graph_indent) !~ /^$COLOR*-$BORING*$/ ||
+ visible_substr($prefix_b, $graph_indent) !~ /^$COLOR*\+$BORING*$/ ||
$suffix_a !~ /^$BORING*$/ ||
$suffix_b !~ /^$BORING*$/;
}
diff --git a/contrib/diff-highlight/Makefile b/contrib/diff-highlight/Makefile
index 9018724524..f2be7cc924 100644
--- a/contrib/diff-highlight/Makefile
+++ b/contrib/diff-highlight/Makefile
@@ -1,5 +1,23 @@
-# nothing to build
-all:
+all: diff-highlight
-test:
+PERL_PATH = /usr/bin/perl
+-include ../../config.mak
+
+PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH))
+
+diff-highlight: shebang.perl DiffHighlight.pm diff-highlight.perl
+ cat $^ >$@+
+ chmod +x $@+
+ mv $@+ $@
+
+shebang.perl: FORCE
+ @echo '#!$(PERL_PATH_SQ)' >$@+
+ @cmp $@+ $@ >/dev/null 2>/dev/null || mv $@+ $@
+
+test: all
$(MAKE) -C t
+
+clean:
+ $(RM) diff-highlight
+
+.PHONY: FORCE
diff --git a/contrib/diff-highlight/README b/contrib/diff-highlight/README
index 836b97a730..d4c2343175 100644
--- a/contrib/diff-highlight/README
+++ b/contrib/diff-highlight/README
@@ -99,6 +99,36 @@ newHighlight = "black #aaffaa"
---------------------------------------------
+Using diff-highlight as a module
+--------------------------------
+
+If you want to pre- or post- process the highlighted lines as part of
+another perl script, you can use the DiffHighlight module. You can
+either "require" it or just cat the module together with your script (to
+avoid run-time dependencies).
+
+Your script may set up one or more of the following variables:
+
+ - $DiffHighlight::line_cb - this should point to a function which is
+ called whenever DiffHighlight has lines (which may contain
+ highlights) to output. The default function prints each line to
+ stdout. Note that the function may be called with multiple lines.
+
+ - $DiffHighlight::flush_cb - this should point to a function which
+ flushes the output (because DiffHighlight believes it has completed
+ processing a logical chunk of input). The default function flushes
+ stdout.
+
+The script may then feed lines, one at a time, to DiffHighlight::handle_line().
+When lines are done processing, they will be fed to $line_cb. Note that
+DiffHighlight may queue up many input lines (to analyze a whole hunk)
+before calling $line_cb. After providing all lines, call
+DiffHighlight::flush() to flush any unprocessed lines.
+
+If you just want to process stdin, DiffHighlight::highlight_stdin()
+is a convenience helper which will loop and flush for you.
+
+
Bugs
----
diff --git a/contrib/diff-highlight/diff-highlight.perl b/contrib/diff-highlight/diff-highlight.perl
new file mode 100644
index 0000000000..9b3e9c1f4d
--- /dev/null
+++ b/contrib/diff-highlight/diff-highlight.perl
@@ -0,0 +1,8 @@
+package main;
+
+# Some scripts may not realize that SIGPIPE is being ignored when launching the
+# pager--for instance scripts written in Python.
+$SIG{PIPE} = 'DEFAULT';
+
+DiffHighlight::highlight_stdin();
+exit 0;
diff --git a/contrib/diff-highlight/t/t9400-diff-highlight.sh b/contrib/diff-highlight/t/t9400-diff-highlight.sh
index 3b43dbed74..f6f5195d00 100755
--- a/contrib/diff-highlight/t/t9400-diff-highlight.sh
+++ b/contrib/diff-highlight/t/t9400-diff-highlight.sh
@@ -52,15 +52,17 @@ test_strip_patch_header () {
# dh_test_setup_history generates a contrived graph such that we have at least
# 1 nesting (E) and 2 nestings (F).
#
-# A branch
-# /
-# D---E---F master
+# A---B master
+# /
+# D---E---F branch
#
# git log --all --graph
# * commit
-# | A
+# | B
# | * commit
# | | F
+# * | commit
+# | | A
# | * commit
# |/
# | E
@@ -68,24 +70,30 @@ test_strip_patch_header () {
# D
#
dh_test_setup_history () {
- echo "file1" >file1 &&
- echo "file2" >file2 &&
- echo "file3" >file3 &&
-
- cat file1 >file &&
+ echo file1 >file &&
git add file &&
+ test_tick &&
git commit -m "D" &&
git checkout -b branch &&
- cat file2 >file &&
- git commit -a -m "A" &&
+ echo file2 >file &&
+ test_tick &&
+ git commit -a -m "E" &&
git checkout master &&
- cat file2 >file &&
- git commit -a -m "E" &&
+ echo file2 >file &&
+ test_tick &&
+ git commit -a -m "A" &&
- cat file3 >file &&
- git commit -a -m "F"
+ git checkout branch &&
+ echo file3 >file &&
+ test_tick &&
+ git commit -a -m "F" &&
+
+ git checkout master &&
+ echo file3 >file &&
+ test_tick &&
+ git commit -a -m "B"
}
left_trim () {
@@ -246,16 +254,25 @@ test_expect_failure 'diff-highlight treats combining code points as a unit' '
test_expect_success 'diff-highlight works with the --graph option' '
dh_test_setup_history &&
- # topo-order so that the order of the commits is the same as with --graph
+ # date-order so that the commits are interleaved for both
# trim graph elements so we can do a diff
# trim leading space because our trim_graph is not perfect
- git log --branches -p --topo-order |
+ git log --branches -p --date-order |
"$DIFF_HIGHLIGHT" | left_trim >graph.exp &&
- git log --branches -p --graph |
+ git log --branches -p --date-order --graph |
"$DIFF_HIGHLIGHT" | trim_graph | left_trim >graph.act &&
test_cmp graph.exp graph.act
'
+# Just reuse the previous graph test, but with --color. Our trimming
+# doesn't know about color, so just sanity check that something got
+# highlighted.
+test_expect_success 'diff-highlight works with color graph' '
+ git log --branches -p --date-order --graph --color |
+ "$DIFF_HIGHLIGHT" | trim_graph | left_trim >graph &&
+ grep "\[7m" graph
+'
+
# Most combined diffs won't meet diff-highlight's line-number filter. So we
# create one here where one side drops a line and the other modifies it. That
# should result in a diff like:
@@ -293,4 +310,32 @@ test_expect_success 'diff-highlight ignores combined diffs' '
test_cmp expect actual
'
+test_expect_success 'diff-highlight handles --graph with leading dash' '
+ cat >file <<-\EOF &&
+ before
+ the old line
+ -leading dash
+ EOF
+ git add file &&
+ git commit -m before &&
+
+ sed s/old/new/ <file >file.tmp &&
+ mv file.tmp file &&
+ git add file &&
+ git commit -m after &&
+
+ cat >expect <<-EOF &&
+ --- a/file
+ +++ b/file
+ @@ -1,3 +1,3 @@
+ before
+ -the ${CW}old${CR} line
+ +the ${CW}new${CR} line
+ -leading dash
+ EOF
+ git log --graph -p -1 | "$DIFF_HIGHLIGHT" >actual.raw &&
+ trim_graph <actual.raw | sed -n "/^---/,\$p" >actual &&
+ test_cmp expect actual
+'
+
test_done