Algorithm-Diff

 view release on metacpan or  search on metacpan

diffnew.pl  view on Meta::CPAN


    # At first, a hunk will have just one Block in it
    my $hunk = {
	    "start1" => $start1,
	    "start2" => $start2,
	    "end1" => $end1,
	    "end2" => $end2,
	    "blocks" => [$block],
              };
    bless $hunk, $class;

    $hunk->flag_context($context_items);

    return $hunk;
}

# Change the "start" and "end" fields to note that context should be added
# to this hunk
sub flag_context {
    my ($hunk, $context_items) = @_;
    return unless $context_items; # no context

    # add context before
    my $start1 = $hunk->{"start1"};
    my $num_added = $context_items > $start1 ? $start1 : $context_items;
    $hunk->{"start1"} -= $num_added;
    $hunk->{"start2"} -= $num_added;

    # context after
    my $end1 = $hunk->{"end1"};
    $num_added = ($end1+$context_items > $#f1) ?
                  $#f1 - $end1 :
                  $context_items;
    $hunk->{"end1"} += $num_added;
    $hunk->{"end2"} += $num_added;
}

# Is there an overlap between hunk arg0 and old hunk arg1?
# Note: if end of old hunk is one less than beginning of second, they overlap
sub does_overlap {
    my ($hunk, $oldhunk) = @_;
    return "" unless $oldhunk; # first time through, $oldhunk is empty

    # Do I actually need to test both?
    return ($hunk->{"start1"} - $oldhunk->{"end1"} <= 1 ||
            $hunk->{"start2"} - $oldhunk->{"end2"} <= 1);
}

# Prepend hunk arg1 to hunk arg0
# Note that arg1 isn't updated! Only arg0 is.
sub prepend_hunk {
    my ($hunk, $oldhunk) = @_;

    $hunk->{"start1"} = $oldhunk->{"start1"};
    $hunk->{"start2"} = $oldhunk->{"start2"};

    unshift (@{$hunk->{"blocks"}}, @{$oldhunk->{"blocks"}});
}


# DIFF OUTPUT ROUTINES. THESE ROUTINES CONTAIN DIFF FORMATTING INFO...
sub output_diff {
# First arg is the current hunk of course
# Next args are refs to the files
# last arg is type of diff
    my $diff_type = $_[-1];
    my %funchash  = ("OLD"        => \&output_old_diff,
                     "CONTEXT"    => \&output_context_diff,
		     "ED"         => \&store_ed_diff,
		     "REVERSE_ED" => \&output_ed_diff,
                     "UNIFIED"    => \&output_unified_diff,
	            );
    if (exists $funchash{$diff_type}) {
        &{$funchash{$diff_type}}(@_); # pass in all args
    } else {die "unknown diff type $diff_type"}
}

sub output_old_diff {
# Note that an old diff can't have any context. Therefore, we know that
# there's only one block in the hunk.
    my ($hunk, $fileref1, $fileref2) = @_;
    my %op_hash = ('+' => 'a', '-' => 'd', '!' => 'c');

    my @blocklist = @{$hunk->{"blocks"}};
    warn ("Expecting one block in an old diff hunk!") if scalar @blocklist != 1;
    my $block = $blocklist[0];
    my $op = $block->op; # +, -, or !

    # Calculate item number range.
    # old diff range is just like a context diff range, except the ranges
    # are on one line with the action between them.
    my $range1 = $hunk->context_range(1);
    my $range2 = $hunk->context_range(2);
    my $action = $op_hash{$op} || warn "unknown op $op";
    print "$range1$action$range2\n";

    # If removing anything, just print out all the remove lines in the hunk
    # which is just all the remove lines in the block
    if ($block->remove) {
	my @outlist = @$fileref1[$hunk->{"start1"}..$hunk->{"end1"}];
	map {$_ = "< $_\n"} @outlist; # all lines will be '< text\n'
	print @outlist;
    }

    print "---\n" if $op eq '!'; # only if inserting and removing
    if ($block->insert) {
	my @outlist = @$fileref2[$hunk->{"start2"}..$hunk->{"end2"}];
	map {$_ = "> $_\n"} @outlist; # all lines will be '> text\n'
	print @outlist;
    }
}

sub output_unified_diff {
    my ($hunk, $fileref1, $fileref2) = @_;
    my @blocklist;

    # Calculate item number range.
    my $range1 = $hunk->unified_range(1);
    my $range2 = $hunk->unified_range(2);
    print "@@ -$range1 +$range2 @@\n";



( run in 0.679 second using v1.01-cache-2.11-cpan-02777c243ea )