diff --git a/gitweb/gitweb.css b/gitweb/gitweb.css
index e19e6bc2ef..974b47f19c 100644
--- a/gitweb/gitweb.css
+++ b/gitweb/gitweb.css
@@ -298,40 +298,82 @@ td.mode {
font-family: monospace;
}
-div.diff a.list {
- text-decoration: none;
+/* styling of diffs (patchsets): commitdiff and blobdiff views */
+div.diff.header,
+div.diff.extended_header {
+ white-space: normal;
}
-div.diff a.list:hover {
+div.diff.header {
+ font-weight: bold;
+
+ background-color: #edece6;
+
+ margin-top: 4px;
+ padding: 4px 0px 2px 0px;
+ border: solid #d9d8d1;
+ border-width: 1px 0px 1px 0px;
+}
+
+div.diff.header a.path {
text-decoration: underline;
}
-div.diff.to_file a.list,
-div.diff.to_file,
+div.diff.extended_header,
+div.diff.extended_header a.path,
+div.diff.extended_header a.hash {
+ color: #777777;
+}
+
+div.diff.extended_header .info {
+ color: #b0b0b0;
+}
+
+div.diff.extended_header {
+ background-color: #f6f5ee;
+ padding: 2px 0px 2px 0px;
+}
+
+div.diff a.path,
+div.diff a.hash {
+ text-decoration: none;
+}
+
+div.diff a.path:hover,
+div.diff a.hash:hover {
+ text-decoration: underline;
+}
+
+div.diff.to_file a.path,
+div.diff.to_file {
+ color: #007000;
+}
+
div.diff.add {
color: #008800;
}
-div.diff.from_file a.list,
-div.diff.from_file,
+div.diff.from_file a.path,
+div.diff.from_file {
+ color: #aa0000;
+}
+
div.diff.rem {
color: #cc0000;
}
div.diff.chunk_header {
color: #990099;
+
+ border: dotted #ffe0ff;
+ border-width: 1px 0px 0px 0px;
+ margin-top: 2px;
}
div.diff.incomplete {
color: #cccccc;
}
-div.diff_info {
- font-family: monospace;
- color: #000099;
- background-color: #edece6;
- font-style: italic;
-}
div.index_include {
border: solid #d9d8d1;
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index b80fc6070b..f937ee1aec 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -785,6 +785,32 @@ sub file_type {
}
}
+# convert file mode in octal to file type description string
+sub file_type_long {
+ my $mode = shift;
+
+ if ($mode !~ m/^[0-7]+$/) {
+ return $mode;
+ } else {
+ $mode = oct $mode;
+ }
+
+ if (S_ISDIR($mode & S_IFMT)) {
+ return "directory";
+ } elsif (S_ISLNK($mode)) {
+ return "symlink";
+ } elsif (S_ISREG($mode)) {
+ if ($mode & S_IXUSR) {
+ return "executable";
+ } else {
+ return "file";
+ };
+ } else {
+ return "unknown";
+ }
+}
+
+
## ----------------------------------------------------------------------
## functions returning short HTML fragments, or transforming HTML fragments
## which don't beling to other sections
@@ -2171,6 +2197,7 @@ sub git_patchset_body {
my $in_header = 0;
my $patch_found = 0;
my $diffinfo;
+ my (%from, %to);
print "
\n";
@@ -2181,6 +2208,10 @@ sub git_patchset_body {
if ($patch_line =~ m/^diff /) { # "git diff" header
# beginning of patch (in patchset)
if ($patch_found) {
+ # close extended header for previous empty patch
+ if ($in_header) {
+ print "
\n" # class="diff extended_header"
+ }
# close previous patch
print "\n"; # class="patch"
} else {
@@ -2189,89 +2220,113 @@ sub git_patchset_body {
}
print "\n";
+ # read and prepare patch information
if (ref($difftree->[$patch_idx]) eq "HASH") {
+ # pre-parsed (or generated by hand)
$diffinfo = $difftree->[$patch_idx];
} else {
$diffinfo = parse_difftree_raw_line($difftree->[$patch_idx]);
}
+ $from{'file'} = $diffinfo->{'from_file'} || $diffinfo->{'file'};
+ $to{'file'} = $diffinfo->{'to_file'} || $diffinfo->{'file'};
+ if ($diffinfo->{'status'} ne "A") { # not new (added) file
+ $from{'href'} = href(action=>"blob", hash_base=>$hash_parent,
+ hash=>$diffinfo->{'from_id'},
+ file_name=>$from{'file'});
+ }
+ if ($diffinfo->{'status'} ne "D") { # not deleted file
+ $to{'href'} = href(action=>"blob", hash_base=>$hash,
+ hash=>$diffinfo->{'to_id'},
+ file_name=>$to{'file'});
+ }
$patch_idx++;
- if ($diffinfo->{'status'} eq "A") { # added
- print "
" . 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)" .
- "
\n"; # class="diff_info"
-
- } elsif ($diffinfo->{'status'} eq "D") { # deleted
- print "
" . 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)" .
- "
\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 "
" .
- 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 "
\n"; # class="diff_info"
-
- } else { # modified, mode changed, ...
- print "
" .
- 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 "
\n"; # class="diff_info"
+ # print "git diff" header
+ $patch_line =~ s!^(diff (.*?) )"?a/.*$!$1!;
+ if ($from{'href'}) {
+ $patch_line .= $cgi->a({-href => $from{'href'}, -class => "path"},
+ 'a/' . esc_path($from{'file'}));
+ } else { # file was added
+ $patch_line .= 'a/' . esc_path($from{'file'});
+ }
+ $patch_line .= ' ';
+ if ($to{'href'}) {
+ $patch_line .= $cgi->a({-href => $to{'href'}, -class => "path"},
+ 'b/' . esc_path($to{'file'}));
+ } else { # file was deleted
+ $patch_line .= 'b/' . esc_path($to{'file'});
}
- #print "
\n";
+ print "
$patch_line
\n";
+ print "
\n";
$in_header = 1;
next LINE;
- } # start of patch in patchset
+ }
+ if ($in_header) {
+ if ($patch_line !~ m/^---/) {
+ # match
+ if ($patch_line =~ s!^((copy|rename) from ).*$!$1! && $from{'href'}) {
+ $patch_line .= $cgi->a({-href=>$from{'href'}, -class=>"path"},
+ esc_path($from{'file'}));
+ }
+ if ($patch_line =~ s!^((copy|rename) to ).*$!$1! && $to{'href'}) {
+ $patch_line = $cgi->a({-href=>$to{'href'}, -class=>"path"},
+ esc_path($to{'file'}));
+ }
+ # match
+ if ($patch_line =~ m/\s(\d{6})$/) {
+ $patch_line .= ' (' .
+ file_type_long($1) .
+ ')';
+ }
+ # match
+ if ($patch_line =~ m/^index/) {
+ my ($from_link, $to_link);
+ if ($from{'href'}) {
+ $from_link = $cgi->a({-href=>$from{'href'}, -class=>"hash"},
+ substr($diffinfo->{'from_id'},0,7));
+ } else {
+ $from_link = '0' x 7;
+ }
+ if ($to{'href'}) {
+ $to_link = $cgi->a({-href=>$to{'href'}, -class=>"hash"},
+ substr($diffinfo->{'to_id'},0,7));
+ } else {
+ $to_link = '0' x 7;
+ }
+ my ($from_id, $to_id) = ($diffinfo->{'from_id'}, $diffinfo->{'to_id'});
+ $patch_line =~ s!$from_id\.\.$to_id!$from_link..$to_link!;
+ }
+ print $patch_line . "
\n";
- if ($in_header && $patch_line =~ m/^---/) {
- #print "\n"; # class="diff extended_header"
- $in_header = 0;
+ } else {
+ #$in_header && $patch_line =~ m/^---/;
+ print "
\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_path($file));
- $patch_line =~ s|a/.*$|a/$file|g;
- print "
$patch_line
\n";
+ if ($from{'href'}) {
+ $patch_line = '--- a/' .
+ $cgi->a({-href=>$from{'href'}, -class=>"path"},
+ esc_path($from{'file'}));
+ }
+ print "
$patch_line
\n";
- $patch_line = <$fd>;
- chomp $patch_line;
+ $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_path($file));
- $patch_line =~ s|b/.*|b/$file|g;
- print "
$patch_line
\n";
+ #$patch_line =~ m/^+++/;
+ if ($to{'href'}) {
+ $patch_line = '+++ b/' .
+ $cgi->a({-href=>$to{'href'}, -class=>"path"},
+ esc_path($to{'file'}));
+ }
+ print "
$patch_line
\n";
+
+ }
next LINE;
}
- next LINE if $in_header;
print format_diff_line($patch_line);
}