Merge branch 'jk/diff-highlight-graph-fix'

"diff-highlight" filter (in contrib/) learned to undertand "git log
--graph" output better.

* jk/diff-highlight-graph-fix:
  diff-highlight: detect --graph by indent
  diff-highlight: use flush() helper consistently
  diff-highlight: test graphs with --color
  diff-highlight: test interleaved parallel lines of history
  diff-highlight: prefer "echo" to "cat" in tests
  diff-highlight: use test_tick in graph test
  diff-highlight: correct test graph diagram
This commit is contained in:
Junio C Hamano 2018-04-10 16:28:21 +09:00
commit d19e556529
2 changed files with 130 additions and 38 deletions

View file

@ -21,37 +21,82 @@ package DiffHighlight;
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 };
sub handle_line {
# 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 = $&;
# 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);
}
}
if (!$in_hunk) {
$line_cb->($_);
$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 = ();
$line_cb->($_);
$in_hunk = /^$GRAPH*$COLOR*[\@ ]/;
flush();
$line_cb->($orig);
$in_hunk = /^$COLOR*[\@ ]/;
}
# Most of the time there is enough output to keep things streaming,
@ -71,6 +116,8 @@ 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 = ();
}
sub highlight_stdin {
@ -226,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*$/;
}

View file

@ -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" &&
git checkout master &&
cat file2 >file &&
echo file2 >file &&
test_tick &&
git commit -a -m "E" &&
cat file3 >file &&
git commit -a -m "F"
git checkout master &&
echo file2 >file &&
test_tick &&
git commit -a -m "A" &&
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