# Format removed and added line, mark changed part and HTML-format them.
# Implementation is based on contrib/diff-highlight
sub format_rem_add_lines_pair {
- my ($rem, $add) = @_;
+ my ($rem, $add, $num_parents) = @_;
# We need to untabify lines before split()'ing them;
# otherwise offsets would be invalid.
my @rem = split(//, $rem);
my @add = split(//, $add);
my ($esc_rem, $esc_add);
- # Ignore +/- character, thus $prefix_len is set to 1.
- my ($prefix_len, $suffix_len) = (1, 0);
+ # Ignore leading +/- characters for each parent.
+ my ($prefix_len, $suffix_len) = ($num_parents, 0);
my ($prefix_has_nonspace, $suffix_has_nonspace);
my $shorter = (@rem < @add) ? @rem : @add;
# HTML-format diff context, removed and added lines.
sub format_ctx_rem_add_lines {
- my ($ctx, $rem, $add, $is_combined) = @_;
+ my ($ctx, $rem, $add, $num_parents) = @_;
my (@new_ctx, @new_rem, @new_add);
+ my $can_highlight = 0;
+ my $is_combined = ($num_parents > 1);
# Highlight if every removed line has a corresponding added line.
- # Combined diffs are not supported at this moment.
- if (!$is_combined && @$add > 0 && @$add == @$rem) {
+ if (@$add > 0 && @$add == @$rem) {
+ $can_highlight = 1;
+
+ # Highlight lines in combined diff only if the chunk contains
+ # diff between the same version, e.g.
+ #
+ # - a
+ # - b
+ # + c
+ # + d
+ #
+ # Otherwise the highlightling would be confusing.
+ if ($is_combined) {
+ for (my $i = 0; $i < @$add; $i++) {
+ my $prefix_rem = substr($rem->[$i], 0, $num_parents);
+ my $prefix_add = substr($add->[$i], 0, $num_parents);
+
+ $prefix_rem =~ s/-/+/g;
+
+ if ($prefix_rem ne $prefix_add) {
+ $can_highlight = 0;
+ last;
+ }
+ }
+ }
+ }
+
+ if ($can_highlight) {
for (my $i = 0; $i < @$add; $i++) {
my ($line_rem, $line_add) = format_rem_add_lines_pair(
- $rem->[$i], $add->[$i]);
+ $rem->[$i], $add->[$i], $num_parents);
push @new_rem, $line_rem;
push @new_add, $line_add;
}
# Print context lines and then rem/add lines.
sub print_diff_lines {
- my ($ctx, $rem, $add, $diff_style, $is_combined) = @_;
+ my ($ctx, $rem, $add, $diff_style, $num_parents) = @_;
+ my $is_combined = $num_parents > 1;
($ctx, $rem, $add) = format_ctx_rem_add_lines($ctx, $rem, $add,
- $is_combined);
+ $num_parents);
if ($diff_style eq 'sidebyside' && !$is_combined) {
print_sidebyside_diff_lines($ctx, $rem, $add);
}
sub print_diff_chunk {
- my ($diff_style, $is_combined, $from, $to, @chunk) = @_;
+ my ($diff_style, $num_parents, $from, $to, @chunk) = @_;
my (@ctx, @rem, @add);
# The class of the previous line.
if (!$class || ((@rem || @add) && $class eq 'ctx') ||
(@rem && @add && $class ne $prev_class)) {
print_diff_lines(\@ctx, \@rem, \@add,
- $diff_style, $is_combined);
+ $diff_style, $num_parents);
@ctx = @rem = @add = ();
}
my $class = diff_line_class($patch_line, \%from, \%to);
if ($class eq 'chunk_header') {
- print_diff_chunk($diff_style, $is_combined, \%from, \%to, @chunk);
+ print_diff_chunk($diff_style, scalar @hash_parents, \%from, \%to, @chunk);
@chunk = ();
}
} continue {
if (@chunk) {
- print_diff_chunk($diff_style, $is_combined, \%from, \%to, @chunk);
+ print_diff_chunk($diff_style, scalar @hash_parents, \%from, \%to, @chunk);
@chunk = ();
}
print "</div>\n"; # class="patch"