X-Git-Url: https://git.ladys.computer/Gitweb/blobdiff_plain/2ccb4d626f1a8d6c0e15e0c0253e100178d1fc7de65b383e9e090d2f20978bea..f3ddf5b87f42b68fad2aebdbbae36f5429051434461615ec57f828442f1c5259:/gitweb.perl
diff --git a/gitweb.perl b/gitweb.perl
index 244bde6..8d9e568 100755
--- a/gitweb.perl
+++ b/gitweb.perl
@@ -54,6 +54,11 @@ sub evaluate_uri {
# to build the base URL ourselves:
our $path_info = decode_utf8($ENV{"PATH_INFO"});
if ($path_info) {
+ # $path_info has already been URL-decoded by the web server, but
+ # $my_url and $my_uri have not. URL-decode them so we can properly
+ # strip $path_info.
+ $my_url = unescape($my_url);
+ $my_uri = unescape($my_uri);
if ($my_url =~ s,\Q$path_info\E$,, &&
$my_uri =~ s,\Q$path_info\E$,, &&
defined $ENV{'SCRIPT_NAME'}) {
@@ -134,6 +139,12 @@ our $default_projects_order = "project";
# (only effective if this variable evaluates to true)
our $export_ok = "++GITWEB_EXPORT_OK++";
+# don't generate age column on the projects list page
+our $omit_age_column = 0;
+
+# don't generate information about owners of repositories
+our $omit_owner=0;
+
# show repository only if this subroutine returns true
# when given the path to the project, for example:
# sub { return -e "$_[0]/git-daemon-export-ok"; }
@@ -260,16 +271,15 @@ our %highlight_basename = (
our %highlight_ext = (
# main extensions, defining name of syntax;
# see files in /usr/share/highlight/langDefs/ directory
- map { $_ => $_ }
- qw(py c cpp rb java css php sh pl js tex bib xml awk bat ini spec tcl sql make),
+ (map { $_ => $_ } qw(py rb java css js tex bib xml awk bat ini spec tcl sql)),
# alternate extensions, see /etc/highlight/filetypes.conf
- 'h' => 'c',
- map { $_ => 'sh' } qw(bash zsh ksh),
- map { $_ => 'cpp' } qw(cxx c++ cc),
- map { $_ => 'php' } qw(php3 php4 php5 phps),
- map { $_ => 'pl' } qw(perl pm), # perhaps also 'cgi'
- map { $_ => 'make'} qw(mak mk),
- map { $_ => 'xml' } qw(xhtml html htm),
+ (map { $_ => 'c' } qw(c h)),
+ (map { $_ => 'sh' } qw(sh bash zsh ksh)),
+ (map { $_ => 'cpp' } qw(cpp cxx c++ cc)),
+ (map { $_ => 'php' } qw(php php3 php4 php5 phps)),
+ (map { $_ => 'pl' } qw(pl perl pm)), # perhaps also 'cgi'
+ (map { $_ => 'make'} qw(make mak mk)),
+ (map { $_ => 'xml' } qw(xml xhtml html htm)),
);
# You define site-wide feature defaults here; override them with
@@ -2431,19 +2441,25 @@ sub format_cc_diff_chunk_header {
}
# process patch (diff) line (not to be used for diff headers),
-# returning HTML-formatted (but not wrapped) line
+# returning HTML-formatted (but not wrapped) line.
+# If the line is passed as a reference, it is treated as HTML and not
+# esc_html()'ed.
sub format_diff_line {
my ($line, $diff_class, $from, $to) = @_;
- chomp $line;
- $line = untabify($line);
-
- if ($from && $to && $line =~ m/^\@{2} /) {
- $line = format_unidiff_chunk_header($line, $from, $to);
- } elsif ($from && $to && $line =~ m/^\@{3}/) {
- $line = format_cc_diff_chunk_header($line, $from, $to);
+ if (ref($line)) {
+ $line = $$line;
} else {
- $line = esc_html($line, -nbsp=>1);
+ chomp $line;
+ $line = untabify($line);
+
+ if ($from && $to && $line =~ m/^\@{2} /) {
+ $line = format_unidiff_chunk_header($line, $from, $to);
+ } elsif ($from && $to && $line =~ m/^\@{3}/) {
+ $line = format_cc_diff_chunk_header($line, $from, $to);
+ } else {
+ $line = esc_html($line, -nbsp=>1);
+ }
}
my $diff_classes = "diff";
@@ -3007,9 +3023,11 @@ sub git_get_projects_list {
}
if (check_export_ok("$projectroot/$path")) {
my $pr = {
- path => $path,
- owner => to_utf8($owner),
+ path => $path
};
+ if ($owner) {
+ $pr->{'owner'} = to_utf8($owner);
+ }
push @list, $pr;
}
}
@@ -4471,30 +4489,33 @@ sub git_print_log {
}
# print log
- my $signoff = 0;
- my $empty = 0;
+ my $skip_blank_line = 0;
foreach my $line (@$log) {
- if ($line =~ m/^ *(signed[ \-]off[ \-]by[ :]|acked[ \-]by[ :]|cc[ :])/i) {
- $signoff = 1;
- $empty = 0;
+ if ($line =~ m/^\s*([A-Z][-A-Za-z]*-[Bb]y|C[Cc]): /) {
if (! $opts{'-remove_signoff'}) {
print "" . esc_html($line) . "
\n";
- next;
- } else {
- # remove signoff lines
- next;
+ $skip_blank_line = 1;
}
- } else {
- $signoff = 0;
+ next;
+ }
+
+ if ($line =~ m,\s*([a-z]*link): (https?://\S+),i) {
+ if (! $opts{'-remove_signoff'}) {
+ print "" . esc_html($1) . ": " .
+ "" . esc_html($2) . "" .
+ "
\n";
+ $skip_blank_line = 1;
+ }
+ next;
}
# print only one empty line
# do not print empty line after signoff
if ($line eq "") {
- next if ($empty || $signoff);
- $empty = 1;
+ next if ($skip_blank_line);
+ $skip_blank_line = 1;
} else {
- $empty = 0;
+ $skip_blank_line = 0;
}
print format_log_line_html($line) . "
\n";
@@ -4502,7 +4523,7 @@ sub git_print_log {
if ($opts{'-final_empty_line'}) {
# end with single empty line
- print "
\n" unless $empty;
+ print "
\n" unless $skip_blank_line;
}
}
@@ -5057,9 +5078,117 @@ sub print_inline_diff_lines {
print @$ctx, @$rem, @$add;
}
+# 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, $num_parents) = @_;
+
+ # We need to untabify lines before split()'ing them;
+ # otherwise offsets would be invalid.
+ chomp $rem;
+ chomp $add;
+ $rem = untabify($rem);
+ $add = untabify($add);
+
+ my @rem = split(//, $rem);
+ my @add = split(//, $add);
+ my ($esc_rem, $esc_add);
+ # 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;
+ while ($prefix_len < $shorter) {
+ last if ($rem[$prefix_len] ne $add[$prefix_len]);
+
+ $prefix_has_nonspace = 1 if ($rem[$prefix_len] !~ /\s/);
+ $prefix_len++;
+ }
+
+ while ($prefix_len + $suffix_len < $shorter) {
+ last if ($rem[-1 - $suffix_len] ne $add[-1 - $suffix_len]);
+
+ $suffix_has_nonspace = 1 if ($rem[-1 - $suffix_len] !~ /\s/);
+ $suffix_len++;
+ }
+
+ # 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_has_nonspace || $suffix_has_nonspace) {
+ $esc_rem = esc_html_hl_regions($rem, 'marked',
+ [$prefix_len, @rem - $suffix_len], -nbsp=>1);
+ $esc_add = esc_html_hl_regions($add, 'marked',
+ [$prefix_len, @add - $suffix_len], -nbsp=>1);
+ } else {
+ $esc_rem = esc_html($rem, -nbsp=>1);
+ $esc_add = esc_html($add, -nbsp=>1);
+ }
+
+ return format_diff_line(\$esc_rem, 'rem'),
+ format_diff_line(\$esc_add, 'add');
+}
+
+# HTML-format diff context, removed and added lines.
+sub format_ctx_rem_add_lines {
+ 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.
+ 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], $num_parents);
+ push @new_rem, $line_rem;
+ push @new_add, $line_add;
+ }
+ } else {
+ @new_rem = map { format_diff_line($_, 'rem') } @$rem;
+ @new_add = map { format_diff_line($_, 'add') } @$add;
+ }
+
+ @new_ctx = map { format_diff_line($_, 'ctx') } @$ctx;
+
+ return (\@new_ctx, \@new_rem, \@new_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,
+ $num_parents);
if ($diff_style eq 'sidebyside' && !$is_combined) {
print_sidebyside_diff_lines($ctx, $rem, $add);
@@ -5070,7 +5199,7 @@ sub print_diff_lines {
}
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.
@@ -5092,11 +5221,9 @@ sub print_diff_chunk {
foreach my $line_info (@chunk) {
my ($class, $line) = @$line_info;
- $line = format_diff_line($line, $class, $from, $to);
-
# print chunk headers
if ($class && $class eq 'chunk_header') {
- print $line;
+ print format_diff_line($line, $class, $from, $to);
next;
}
@@ -5107,7 +5234,7 @@ sub print_diff_chunk {
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 = ();
}
@@ -5250,7 +5377,7 @@ sub git_patchset_body {
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 = ();
}
@@ -5259,7 +5386,7 @@ sub git_patchset_body {
} 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 "\n"; # class="patch"
@@ -5499,11 +5626,15 @@ sub git_project_list_rows {
? esc_html_match_hl_chopped($pr->{'descr_long'},
$pr->{'descr'}, $search_regexp)
: esc_html($pr->{'descr'})) .
- "\n" .
- "
| description | " . esc_html($descr) . " |
| owner | " . esc_html($owner) . " |
| description | " . esc_html($descr) . " |
| owner | " . esc_html($owner) . " |
| last change | " . "".format_timestamp_html(\%cd)." |