Thread (61 messages) flat view 61 messages, 3 authors, 2016-06-15

Re: [PATCH 6/8] gitweb: Highlight interesting parts of diff

From: Michał Kiedrowicz <hidden>
Date: 2016-06-15 22:53:04

Jakub Narebski [off-list ref] wrote:
A few issues I have just noticed about this series.


First, about naming.  "Highlighting interesting parts of diff" is
acceptable name, but "syntax highlighting for diff" is not: gitweb
already use syntax highlighting in diff views.  Call it "diff refinement
highlighting", "highlighting changes / changed sections", "intraline
highlighting".
OK, I'll make sure the naming is correct and consistent.

Second, I think (but I am not sure) that there is a bug in code that
finds common suffix and prefix.

If I understand correctly the idea is to highlight changed part if
there is at least one of common non-whitespace suffix or prefix.
So syntax highlighting should look like this:

1. Both prefix and suffix are non empty and non whitespace only

  -foo -{bar} baz
  +foo +{quux} baz

2. Non empty and non whitespace only prefix

  -foo -{bar}
  +foo +{quux}

2. Non empty and non whitespace only suffix

  --{bar} baz
  ++{quux} baz

But in your code $prefix is not the length of common prefix, but
the position of end of prefix in the original line of diff.  So
you start with $prefix = 1... even though the prefix is empty.

How is that supposed to work?
But see the check:

+	# Mark lines that are different from each other, but have some common
+	# part that isn't whitespace.  If lines are completely different, don't
+	# mark them because that would make output unreadable, especially if
+	# diff consists of multiple lines.
+	if (($prefix == 1 && $suffix_rem == $#r && $suffix_add == $#a)
                        ^
                        |
                        This part.

+		|| ($prefix_is_space && $suffix_is_space)) {
+		$esc_rem = esc_html($rem);
+		$esc_add = esc_html($add);
+	} else {
+		$esc_rem = esc_html_mark_range(\@r, $prefix, $suffix_rem);
+		$esc_add = esc_html_mark_range(\@a, $prefix, $suffix_add);
+	}

I guess it's still not correct because it should be equal to number of
parents or $prefix_length should start from 0 like you wrote later.

On Mon, 13 Feb 2012, Michał Kiedrowicz wrote:
quoted
Jakub Narebski [off-list ref] wrote:
quoted
On Mon, 13 Feb 2012, Michal Kiedrowicz wrote:
quoted
quoted
quoted
I haven't found *examples* on GitHub and Trac sites, but what about
these ones:

https://github.com/gitster/git/commit/8cad4744ee37ebec1d9491a1381ec1771a1ba795
http://trac.edgewall.org/changeset/10973
[...]
quoted
quoted
BTW GitHub is closed source, but we can check what algorithm does Trac
use for diff refinement highlighting (highlighting changed portions of
diff).
I think it's
http://trac.edgewall.org/browser/trunk/trac/versioncontrol/diff.py
(see markup intraline_changes()).
 
It is get_change_extent() that finds extent of changes, as a pair
containing the offset at which the changes start, and the negative offset
at which the changes end.  So it is the same solution you use, only
without ignoring whitespace-only prefixes and suffixes...  This code can
be easily ported to Perl, BTW.

The markup_intraline_changes() function compares lines from preimage and
from postimage pairwise, requiring that number of lines matches, the same
like in your algorithm.
So using Jeff's diff-highlight we remain quite consistent with Trac
output. There's nothing we can "steal" from it. 
quoted
quoted
quoted
I would also consider ignoring prefixes/suffixes with punctuation, like:

	- * I like you.
	+ * Alice had a little lamb.
But this patch doesn't implement this feature yet, isn't it?
No, but is a matter of adding

	-$prefix_is_space = 0 if ($r[$prefix] !~ /\s/);
	+$prefix_is_space = 0 if ($r[$prefix] !~ /\s|[[:punct:]]/);

(and the same for suffix)
All right.  But it is better added as separate patch.
Sure 
Perhaps even
requiring that not only there is at least one of common prefix or common
suffix, but at least one of them is not whitespace only could be put
in a separate commit...
quoted
quoted
quoted
quoted
quoted
+sub format_rem_add_line {
+	my ($rem, $add) = @_;
+	my @r = split(//, $rem);
+	my @a = split(//, $add);
BTW the name of variable can be just @add and @rem.
I know they are different scopes but I don't like it. It makes the code
more confusing IMO. But I won't insist.
In my opinion if the variable refers to the same entity in different
forms, using @foo and %foo (used in gitweb), or $foo and @foo (could be
used here) is all right, and even better than trying to come up with
different name for the same thing because of sigil.
OK. I'll follow that convention then.
 
quoted
quoted
quoted
quoted
Shouldn't
$prefix / $prefix_len start from 0, not from 1?
It starts from 1 because it skips first +/-. It should become obvious
after reading the comment from last patch :).
This means that $prefix is true even if prefix is empty ($prefix == 1).
Wouldn't it be better for $prefix_len to count length of true prefix,
without diff adornment?  Or make @r / @rem skip initial characters...
quoted
quoted
quoted
+	# In combined diff we must ignore two +/- characters.
+	$prefix = 2 if ($is_combined);
Anyway comment about that fact would be nice.
Will do.
BTW. it is not "2" but "scalar @{$co{'parents'}}".
OK.
quoted
quoted
quoted
The splitting and comparing by characters is taken from diff-highlight.
I don't think it's worth changing here.
You are right.

I'll try to come with hacky algorithm using string bitwise xor and regexp,
and benchmark it comparing to your C-like solution, but it can be left for
later (simple is better than clever, usually).
If you have time :).
Anyway it would be separate commit.  Better to just copy tested code
from contrib/diff-highlight

BTW. would "git blame -C -C -C -w" detect this correctly as code
movement^W copying?
 
Cannot say. Have you considered what I wrote in a separate e-mail,
about using diff-highlight output directly / as a library? 
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help