+
+ if ($diffinfo->{'status'} eq "A") { # added
+ print "<div class=\"diff_info\">" . file_type($diffinfo->{'to_mode'}) . ":" .
+ $cgi->a({-href => href(action=>"blob", hash_base=>$hash,
+ hash=>$diffinfo->{'to_id'}, file_name=>$diffinfo->{'file'})},
+ $diffinfo->{'to_id'}) . "(new)" .
+ "</div>\n"; # class="diff_info"
+
+ } elsif ($diffinfo->{'status'} eq "D") { # deleted
+ print "<div class=\"diff_info\">" . file_type($diffinfo->{'from_mode'}) . ":" .
+ $cgi->a({-href => href(action=>"blob", hash_base=>$hash_parent,
+ hash=>$diffinfo->{'from_id'}, file_name=>$diffinfo->{'file'})},
+ $diffinfo->{'from_id'}) . "(deleted)" .
+ "</div>\n"; # class="diff_info"
+
+ } elsif ($diffinfo->{'status'} eq "R" || # renamed
+ $diffinfo->{'status'} eq "C" || # copied
+ $diffinfo->{'status'} eq "2") { # with two filenames (from git_blobdiff)
+ print "<div class=\"diff_info\">" .
+ file_type($diffinfo->{'from_mode'}) . ":" .
+ $cgi->a({-href => href(action=>"blob", hash_base=>$hash_parent,
+ hash=>$diffinfo->{'from_id'}, file_name=>$diffinfo->{'from_file'})},
+ $diffinfo->{'from_id'}) .
+ " -> " .
+ file_type($diffinfo->{'to_mode'}) . ":" .
+ $cgi->a({-href => href(action=>"blob", hash_base=>$hash,
+ hash=>$diffinfo->{'to_id'}, file_name=>$diffinfo->{'to_file'})},
+ $diffinfo->{'to_id'});
+ print "</div>\n"; # class="diff_info"
+
+ } else { # modified, mode changed, ...
+ print "<div class=\"diff_info\">" .
+ file_type($diffinfo->{'from_mode'}) . ":" .
+ $cgi->a({-href => href(action=>"blob", hash_base=>$hash_parent,
+ hash=>$diffinfo->{'from_id'}, file_name=>$diffinfo->{'file'})},
+ $diffinfo->{'from_id'}) .
+ " -> " .
+ file_type($diffinfo->{'to_mode'}) . ":" .
+ $cgi->a({-href => href(action=>"blob", hash_base=>$hash,
+ hash=>$diffinfo->{'to_id'}, file_name=>$diffinfo->{'file'})},
+ $diffinfo->{'to_id'});
+ print "</div>\n"; # class="diff_info"
+ }
+
+ #print "<div class=\"diff extended_header\">\n";
+ $in_header = 1;
+ next LINE;
+ } # start of patch in patchset
+
+
+ if ($in_header && $patch_line =~ m/^---/) {
+ #print "</div>\n"; # class="diff extended_header"
+ $in_header = 0;
+
+ my $file = $diffinfo->{'from_file'};
+ $file ||= $diffinfo->{'file'};
+ $file = $cgi->a({-href => href(action=>"blob", hash_base=>$hash_parent,
+ hash=>$diffinfo->{'from_id'}, file_name=>$file),
+ -class => "list"}, esc_html($file));
+ $patch_line =~ s|a/.*$|a/$file|g;
+ print "<div class=\"diff from_file\">$patch_line</div>\n";
+
+ $patch_line = <$fd>;
+ chomp $patch_line;
+
+ #$patch_line =~ m/^+++/;
+ $file = $diffinfo->{'to_file'};
+ $file ||= $diffinfo->{'file'};
+ $file = $cgi->a({-href => href(action=>"blob", hash_base=>$hash,
+ hash=>$diffinfo->{'to_id'}, file_name=>$file),
+ -class => "list"}, esc_html($file));
+ $patch_line =~ s|b/.*|b/$file|g;
+ print "<div class=\"diff to_file\">$patch_line</div>\n";
+
+ next LINE;
+ }
+ next LINE if $in_header;
+
+ print format_diff_line($patch_line);
+ }
+ print "</div>\n" if $patch_found; # class="patch"
+
+ print "</div>\n"; # class="patchset"
+}
+
+# . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+
+sub git_shortlog_body {
+ # uses global variable $project
+ my ($revlist, $from, $to, $refs, $extra) = @_;
+
+ my ($ctype, $suffix, $command) = gitweb_check_feature('snapshot');
+ my $have_snapshot = (defined $ctype && defined $suffix);
+
+ $from = 0 unless defined $from;
+ $to = $#{$revlist} if (!defined $to || $#{$revlist} < $to);
+
+ print "<table class=\"shortlog\" cellspacing=\"0\">\n";
+ my $alternate = 0;
+ for (my $i = $from; $i <= $to; $i++) {
+ my $commit = $revlist->[$i];
+ #my $ref = defined $refs ? format_ref_marker($refs, $commit) : '';
+ my $ref = format_ref_marker($refs, $commit);
+ my %co = parse_commit($commit);
+ if ($alternate) {
+ print "<tr class=\"dark\">\n";
+ } else {
+ print "<tr class=\"light\">\n";
+ }
+ $alternate ^= 1;
+ # git_summary() used print "<td><i>$co{'age_string'}</i></td>\n" .
+ print "<td title=\"$co{'age_string_age'}\"><i>$co{'age_string_date'}</i></td>\n" .
+ "<td><i>" . esc_html(chop_str($co{'author_name'}, 10)) . "</i></td>\n" .
+ "<td>";
+ print format_subject_html($co{'title'}, $co{'title_short'},
+ href(action=>"commit", hash=>$commit), $ref);
+ print "</td>\n" .
+ "<td class=\"link\">" .
+ $cgi->a({-href => href(action=>"commit", hash=>$commit)}, "commit") . " | " .
+ $cgi->a({-href => href(action=>"commitdiff", hash=>$commit)}, "commitdiff");
+ if ($have_snapshot) {
+ print " | " . $cgi->a({-href => href(action=>"snapshot", hash=>$commit)}, "snapshot");
+ }
+ print "</td>\n" .
+ "</tr>\n";
+ }
+ if (defined $extra) {
+ print "<tr>\n" .
+ "<td colspan=\"4\">$extra</td>\n" .
+ "</tr>\n";
+ }
+ print "</table>\n";
+}
+
+sub git_history_body {
+ # Warning: assumes constant type (blob or tree) during history
+ my ($fd, $refs, $hash_base, $ftype, $extra) = @_;
+
+ print "<table class=\"history\" cellspacing=\"0\">\n";
+ my $alternate = 0;
+ while (my $line = <$fd>) {
+ if ($line !~ m/^([0-9a-fA-F]{40})/) {
+ next;
+ }
+
+ my $commit = $1;
+ my %co = parse_commit($commit);
+ if (!%co) {
+ next;
+ }
+
+ my $ref = format_ref_marker($refs, $commit);
+
+ if ($alternate) {
+ print "<tr class=\"dark\">\n";
+ } else {
+ print "<tr class=\"light\">\n";
+ }
+ $alternate ^= 1;
+ print "<td title=\"$co{'age_string_age'}\"><i>$co{'age_string_date'}</i></td>\n" .
+ # shortlog uses chop_str($co{'author_name'}, 10)
+ "<td><i>" . esc_html(chop_str($co{'author_name'}, 15, 3)) . "</i></td>\n" .
+ "<td>";
+ # originally git_history used chop_str($co{'title'}, 50)
+ print format_subject_html($co{'title'}, $co{'title_short'},
+ href(action=>"commit", hash=>$commit), $ref);
+ print "</td>\n" .
+ "<td class=\"link\">" .
+ $cgi->a({-href => href(action=>"commit", hash=>$commit)}, "commit") . " | " .
+ $cgi->a({-href => href(action=>"commitdiff", hash=>$commit)}, "commitdiff") . " | " .
+ $cgi->a({-href => href(action=>$ftype, hash_base=>$commit, file_name=>$file_name)}, $ftype);
+
+ if ($ftype eq 'blob') {
+ my $blob_current = git_get_hash_by_path($hash_base, $file_name);
+ my $blob_parent = git_get_hash_by_path($commit, $file_name);
+ if (defined $blob_current && defined $blob_parent &&
+ $blob_current ne $blob_parent) {
+ print " | " .
+ $cgi->a({-href => href(action=>"blobdiff",
+ hash=>$blob_current, hash_parent=>$blob_parent,
+ hash_base=>$hash_base, hash_parent_base=>$commit,
+ file_name=>$file_name)},
+ "diff to current");
+ }
+ }
+ print "</td>\n" .
+ "</tr>\n";
+ }
+ if (defined $extra) {
+ print "<tr>\n" .
+ "<td colspan=\"4\">$extra</td>\n" .
+ "</tr>\n";
+ }
+ print "</table>\n";
+}
+
+sub git_tags_body {
+ # uses global variable $project
+ my ($taglist, $from, $to, $extra) = @_;
+ $from = 0 unless defined $from;
+ $to = $#{$taglist} if (!defined $to || $#{$taglist} < $to);
+
+ print "<table class=\"tags\" cellspacing=\"0\">\n";
+ my $alternate = 0;
+ for (my $i = $from; $i <= $to; $i++) {
+ my $entry = $taglist->[$i];
+ my %tag = %$entry;
+ my $comment_lines = $tag{'comment'};
+ my $comment = shift @$comment_lines;
+ my $comment_short;
+ if (defined $comment) {
+ $comment_short = chop_str($comment, 30, 5);
+ }
+ if ($alternate) {
+ print "<tr class=\"dark\">\n";
+ } else {
+ print "<tr class=\"light\">\n";
+ }
+ $alternate ^= 1;
+ print "<td><i>$tag{'age'}</i></td>\n" .
+ "<td>" .
+ $cgi->a({-href => href(action=>$tag{'reftype'}, hash=>$tag{'refid'}),
+ -class => "list name"}, esc_html($tag{'name'})) .
+ "</td>\n" .
+ "<td>";
+ if (defined $comment) {
+ print format_subject_html($comment, $comment_short,
+ href(action=>"tag", hash=>$tag{'id'}));