From: Andrew Lorimer Date: Sun, 13 Oct 2019 10:59:07 +0000 (+1100) Subject: general UI improvements X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/05293f9a4e87b61d85d70e20f669ac83c6fb882e general UI improvements --- diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 7fef19fe59..6f6c2e0de7 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -110,6 +110,9 @@ sub evaluate_uri { # filename of html text to include at bottom of each page our $site_footer = "++GITWEB_SITE_FOOTER++"; +# Whether to show table header row on index page +our $index_header = 1; + # URI of stylesheets our @stylesheets = ("++GITWEB_CSS++"); # URI of a single stylesheet, which can be overridden in GITWEB_CONFIG. @@ -145,6 +148,9 @@ sub evaluate_uri { # valid values are none, project, descr, owner, and age our $default_projects_order = "project"; +# show table header row for projects list on index page +our $projects_table_headers = 1; + # show repository only if this file exists # (only effective if this variable evaluates to true) our $export_ok = "++GITWEB_EXPORT_OK++"; @@ -155,6 +161,12 @@ sub evaluate_uri { # don't generate information about owners of repositories our $omit_owner=0; +# Hide links to each repo's pages in the index +our $omit_shortcuts = 0; + +# Hide .git extension in index table +our $omit_git_extension = 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"; } @@ -182,6 +194,18 @@ sub evaluate_uri { # could be even 'utf-8' for the old behavior) our $fallback_encoding = 'latin1'; +# number of characters to truncate commit hashes to +# Added by Andrew Lorimer, October 2019 +our $hash_char = 7; + +# whether to show OPML feed link on homepage +# Added by Andrew Lorimer, October 2019 +our $opml = 1; + +# whether to show TXT link on homepage +# Added by Andrew Lorimer, October 2019 +our $txt = 1; + # rename detection options for git-diff and git-diff-tree # - default is '-M', with the cost proportional to # (number of removed files) * (number of new files). @@ -290,6 +314,7 @@ sub evaluate_uri { (map { $_ => 'pl' } qw(pl perl pm)), # perhaps also 'cgi' (map { $_ => 'make'} qw(make mak mk)), (map { $_ => 'xml' } qw(xml xhtml html htm)), + (map { $_ => 'markdown' } qw(md markdown)) ); # You define site-wide feature defaults here; override them with @@ -324,6 +349,17 @@ sub evaluate_uri { 'override' => 0, 'default' => [0]}, + # Regex filter for paths (files and directories) to display in the + # tree view. Currently this only affects the files listed in the tree, + # and files that do not match this regex can still be accessed through + # the full URL. This value can be overriden for individual projects. + # Note that double-escaping is necessary for backslashes (i.e. to match + # a literal full stop, use `\\.`). + 'tree_filter' => { + 'sub' => \&feature_tree_filter, + 'override' => 0, + 'default' => [".*"]}, + # Enable the 'snapshot' link, providing a compressed archive of any # tree. This can potentially generate high traffic if you have large # project. @@ -619,6 +655,12 @@ sub feature_bool { } } +sub feature_tree_filter { + my @pattern_global = shift; + my @pattern_project = git_get_project_config('tree_filter'); + return (scalar(@pattern_project) > 0 ? $pattern_project[0] : $pattern_global[0]); +} + sub feature_snapshot { my (@fmts) = @_; @@ -868,8 +910,8 @@ sub oid_nlen_prefix_infix_regex { "blobdiff_plain" => \&git_blobdiff_plain, "blob" => \&git_blob, "blob_plain" => \&git_blob_plain, - "commitdiff" => \&git_commitdiff, - "commitdiff_plain" => \&git_commitdiff_plain, + "diff" => \&git_diff, + "diff_plain" => \&git_diff_plain, "commit" => \&git_commit, "forks" => \&git_forks, "heads" => \&git_heads, @@ -1223,7 +1265,7 @@ sub handle_errors_html { # HTTP headers are already written, so it cannot write them itself die_error(undef, undef, $msg, -error_handler => 1, -no_http_header => 1); } -set_message(\&handle_errors_html); +#set_message(\&handle_errors_html); # dispatch sub dispatch { @@ -2117,25 +2159,34 @@ sub format_ref_marker { $class .= " indirect" if $indirect; my $dest_action = "shortlog"; + my $dest = ""; + $dest .= "refs/" unless $ref =~ m!^refs/!; + $dest .= $ref; if ($indirect) { $dest_action = "tag" unless $action eq "tag"; + $markers .= $cgi->a({ + -href => href( + action=>$dest_action, + hash=>$dest + )}, '' + . '' . esc_html($name) . ''); } elsif ($action =~ /^(history|(short)?log)$/) { $dest_action = $action; + $markers .= $cgi->a({ + -href => href( + action=>$dest_action, + hash=>$dest + )}, '' + . '' . esc_html($name) . ''); } - my $dest = ""; - $dest .= "refs/" unless $ref =~ m!^refs/!; - $dest .= $ref; - my $link = $cgi->a({ - -href => href( - action=>$dest_action, - hash=>$dest - )}, esc_html($name)); - $markers .= " " . - $link . ""; } } @@ -3529,7 +3580,8 @@ sub parse_commit_text { foreach my $title (@commit_lines) { $title =~ s/^ //; if ($title ne "") { - $co{'title'} = chop_str($title, 80, 5); + #$co{'title'} = chop_str($title, 80, 5); + $co{'title'} = $title; # remove leading stuff of merges to make the interesting part visible if (length($title) > 50) { $title =~ s/^Automatic //; @@ -3547,7 +3599,8 @@ sub parse_commit_text { $title =~ s/\/pub\/scm//; } } - $co{'title_short'} = chop_str($title, 50, 5); + #$co{'title_short'} = chop_str($title, 50, 5); + $co{'title_short'} = $title; last; } } @@ -4112,10 +4165,24 @@ sub print_nav_breadcrumbs_path { sub print_nav_breadcrumbs { my %opts = @_; + # Modified by Andrew Lorimer, October 2019 + # Do not show trailing slash in breadcrumb for last item + #my @crumbs = (@extra_breadcrumbs, [ $home_link_str => $home_link ]); + #for my $i (0 .. (length @crumbs - 1)) { + # print $cgi->a({-href => esc_url($crumbs[$i]->[1])}, $crumbs[$i]->[0]); + # if ($i != $#crumbs) { + # print " / "; + # } + #} + my @base_links = (); for my $crumb (@extra_breadcrumbs, [ $home_link_str => $home_link ]) { - print $cgi->a({-href => esc_url($crumb->[1])}, $crumb->[0]) . " / "; + if (defined $crumb && length $crumb && $crumb ne "") { + push(@base_links, $cgi->a({-href => esc_url($crumb->[1])}, $crumb->[0])); + } } + print join(" / ", @base_links); if (defined $project) { + print " / "; my @dirname = split '/', $project; my $projectbasename = pop @dirname; print_nav_breadcrumbs_path(@dirname); @@ -4154,8 +4221,8 @@ sub print_search_form { if ($use_pathinfo) { $action .= "/".esc_url($project); } + print "
"; print $cgi->start_form(-method => "get", -action => $action) . - "
\n" . (!$use_pathinfo && $cgi->input({-name=>"p", -value=>$project, -type=>"hidden"}) . "\n") . $cgi->input({-name=>"a", -value=>"search", -type=>"hidden"}) . "\n" . @@ -4163,14 +4230,14 @@ sub print_search_form { $cgi->popup_menu(-name => 'st', -default => 'commit', -values => ['commit', 'grep', 'author', 'committer', 'pickaxe']) . " " . $cgi->a({-href => href(action=>"search_help"), - -title => "search help" }, "?") . " search:\n", - $cgi->textfield(-name => "s", -value => $searchtext, -override => 1) . "\n" . + -title => "search help" }, "?"), + $cgi->textfield(-name => "s", -value => $searchtext, -override => 1, -placeholder => "search " . $project) . "\n" . "" . $cgi->checkbox(-name => 'sr', -value => 1, -label => 're', -checked => $search_use_regexp) . "" . - "
" . $cgi->end_form() . "\n"; + print "
"; } sub git_header_html { @@ -4188,12 +4255,14 @@ sub git_header_html { - + + + $title EOF # the stylesheet, favicon etc urls won't work correctly with path_info @@ -4208,14 +4277,35 @@ sub git_header_html { } print "\n" . - "\n"; + ' + + + + + + + + '; if (defined $site_header && -f $site_header) { insert_file($site_header); } - print "
\n"; - if (defined $logo) { + print "
\n"; + + # Modified by Andrew Lorimer, October 2019 + # Do not print logo if the image source is empty + if (defined $logo && $logo ne "") { print $cgi->a({-href => esc_url($logo_url), -title => $logo_label}, $cgi->img({-src => esc_url($logo), @@ -4225,23 +4315,13 @@ sub git_header_html { } print_nav_breadcrumbs(%opts); print "
\n"; - - my $have_search = gitweb_check_feature('search'); - if (defined $project && $have_search) { - print_search_form(); - } } sub git_footer_html { my $feed_class = 'rss_logo'; - print "
\n"; + print "
\n"; if (defined $project) { - my $descr = git_get_project_description($project); - if (defined $descr) { - print "\n"; - } - my %href_params = get_feed_info(); if (!%href_params) { $feed_class .= ' generic'; @@ -4256,25 +4336,27 @@ sub git_footer_html { } } else { + if ($opml) { print $cgi->a({-href => href(project=>undef, action=>"opml", project_filter => $project_filter), -class => $feed_class}, "OPML") . " "; + } + if ($txt) { print $cgi->a({-href => href(project=>undef, action=>"project_index", project_filter => $project_filter), -class => $feed_class}, "TXT") . "\n"; + } } - print "
\n"; # class="page_footer" - if (defined $t0 && gitweb_check_feature('timed')) { print "
\n"; print 'This page took '. ''. tv_interval($t0, [ gettimeofday() ]). - ' seconds '. + ' s'. ' and '. ''. $number_of_git_cmds. - ' git commands '. + ' git commands '. " to generate.\n"; print "
\n"; # class="page_footer" } @@ -4282,6 +4364,8 @@ sub git_footer_html { if (defined $site_footer && -f $site_footer) { insert_file($site_footer); } + print "\n"; + print qq!\n!; if (defined $action && @@ -4339,7 +4423,6 @@ sub die_error { ); git_header_html($http_responses{$status}, undef, %opts); print <

$status - $error
@@ -4348,7 +4431,6 @@ sub die_error { print "
\n" . "$extra\n"; } - print "
\n"; git_footer_html(); goto DONE_GITWEB @@ -4362,17 +4444,17 @@ sub git_print_page_nav { my ($current, $suppress, $head, $treehead, $treebase, $extra) = @_; $extra = '' if !defined $extra; # pager or formats - my @navs = qw(summary shortlog log commit commitdiff tree); + my @navs = qw(summary shortlog log commit diff tree); if ($suppress) { @navs = grep { $_ ne $suppress } @navs; } my %arg = map { $_ => {action=>$_} } @navs; if (defined $head) { - for (qw(commit commitdiff)) { + for (qw(commit diff)) { $arg{$_}{'hash'} = $head; } - if ($current =~ m/^(tree | log | shortlog | commit | commitdiff | search)$/x) { + if ($current =~ m/^(tree | log | shortlog | commit | diff | search)$/x) { for (qw(shortlog log)) { $arg{$_}{'hash'} = $head; } @@ -4399,13 +4481,20 @@ sub git_print_page_nav { $arg{$label}{'_href'} = $link; } - print "
\n" . + print "
"; + print "
\n"; + print "
\n$extra
\n" if ($extra); + print "\n"; + + my $have_search = gitweb_check_feature('search'); + if (defined $project && $have_search) { + print_search_form(); + } + print ""; } # returns a submenu for the navigation of the refs views (tags, heads, @@ -4451,17 +4540,19 @@ sub format_paging_nav { ## functions printing or outputting HTML: div sub git_print_header_div { - my ($action, $title, $hash, $hash_base) = @_; + my ($action, $title, $refstr, $hash, $hash_base) = @_; my %args = (); $args{'action'} = $action; $args{'hash'} = $hash if $hash; $args{'hash_base'} = $hash_base if $hash_base; - print "
\n" . - $cgi->a({-href => href(%args), -class => "title"}, - $title ? $title : $action) . - "\n
\n"; + if (defined $title && length $title) { + print "
\n" . + $cgi->a({-href => href(%args), -class => "title"}, + $title ? $title : $action) . + "\n
\n"; + } } sub format_repo_url { @@ -4555,16 +4646,18 @@ sub git_print_authorship_rows { @people = ('author', 'committer') unless @people; foreach my $who (@people) { my %wd = parse_date($co->{"${who}_epoch"}, $co->{"${who}_tz"}); - print "$who" . + print "$who" . format_search_author($co->{"${who}_name"}, $who, esc_html($co->{"${who}_name"})) . " " . format_search_author($co->{"${who}_email"}, $who, esc_html("<" . $co->{"${who}_email"} . ">")) . - "" . - git_get_avatar($co->{"${who}_email"}, -size => 'double') . - "\n" . - "" . - "" . + ""; + if ($git_avatar) { + print "" + . git_get_avatar($co->{"${who}_email"}, -size => 'double') + . ""; + } + print "\n" . format_timestamp_html(\%wd) . "" . "\n"; @@ -4575,12 +4668,12 @@ sub git_print_page_path { my $name = shift; my $type = shift; my $hb = shift; + my $noprint = shift; - print "
"; - print $cgi->a({-href => href(action=>"tree", hash_base=>$hb), + my $output = $cgi->a({-href => href(action=>"tree", hash_base=>$hb), -title => 'tree root'}, to_utf8("[$project]")); - print " / "; + $output .= " / "; if (defined $name) { my @dirname = split '/', $name; my $basename = pop @dirname; @@ -4588,25 +4681,75 @@ sub git_print_page_path { foreach my $dir (@dirname) { $fullname .= ($fullname ? '/' : '') . $dir; - print $cgi->a({-href => href(action=>"tree", file_name=>$fullname, + $output .= $cgi->a({-href => href(action=>"tree", file_name=>$fullname, hash_base=>$hb), -title => $fullname}, esc_path($dir)); - print " / "; + $output .= " / "; } if (defined $type && $type eq 'blob') { - print $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name, + $output .= $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name, hash_base=>$hb), -title => $name}, esc_path($basename)); } elsif (defined $type && $type eq 'tree') { - print $cgi->a({-href => href(action=>"tree", file_name=>$file_name, + $output .= $cgi->a({-href => href(action=>"tree", file_name=>$file_name, hash_base=>$hb), -title => $name}, esc_path($basename)); - print " / "; + $output .= " / "; } else { - print esc_path($basename); + $output .= esc_path($basename); } } - print "
\n"; + $output .= "
\n"; + unless ($noprint) { + print $output; + } + return $output; +} + + +sub git_path_header { + my $name = shift; + my $type = shift; + my $hb = shift; + my $noprint = shift; + my $title = shift; + my $ref = shift; + my $hash = shift; + + my $output = ""; + if (defined $name) { + my @dirname = split '/', $name; + my $basename = pop @dirname; + my $fullname = ''; + + foreach my $dir (@dirname) { + $fullname .= ($fullname ? '/' : '') . $dir; + $output .= $cgi->a({-href => href(action=>"tree", file_name=>$fullname, + hash_base=>$hb), + -title => $fullname, -class => "title"}, esc_path($dir)); + $output .= " / "; + } + if (defined $type && $type eq 'blob') { + $output .= $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name, + hash_base=>$hb), + -title => $name, -class => "title"}, esc_path($basename)); + } elsif (defined $type && $type eq 'tree') { + $output .= $cgi->a({-href => href(action=>"tree", file_name=>$file_name, + hash_base=>$hb), + -title => $name, -class => "title"}, esc_path($basename)); + $output .= " / "; + } else { + $output .= esc_path($basename); + } + } + + $output .= "on commit " + . $cgi->a({-href => href(action => 'commit', hash => $ref)}, "$title (" . substr($hash, 0, $hash_char) . ")") + . ""; + unless ($noprint) { + print $output; + } + return $output; } sub git_print_log { @@ -4730,7 +4873,13 @@ sub git_print_tree_entry { # the mode of the entry, list is the name of the entry, an href, # and link is the action links of the entry. - print "" . mode_str($t->{'mode'}) . "\n"; + print ""; + if (S_ISDIR(oct $t->{'mode'} & S_IFMT)) { + print '' + . ''; + } + print mode_str($t->{'mode'}) . "\n"; if (exists $t->{'size'}) { print "$t->{'size'}\n"; } @@ -4855,18 +5004,18 @@ sub git_difftree_body { my ($difftree, $hash, @parents) = @_; my ($parent) = $parents[0]; my $have_blame = gitweb_check_feature('blame'); - print "
\n"; if ($#{$difftree} > 10) { + print "
\n"; print(($#{$difftree} + 1) . " files changed:\n"); + print "
\n"; } - print "
\n"; print " 1 ? "combined " : "") . "diff_tree\">\n"; - # header only for combined diff in 'commitdiff' view - my $has_header = @$difftree && @parents > 1 && $action eq 'commitdiff'; + # header only for combined diff in 'diff' view + my $has_header = @$difftree && @parents > 1 && $action eq 'diff'; if ($has_header) { # table header print "\n" . @@ -4874,9 +5023,9 @@ sub git_difftree_body { for (my $i = 0; $i < @parents; $i++) { my $par = $parents[$i]; print "\n"; @@ -4915,7 +5064,7 @@ sub git_difftree_body { "\n"; } - if ($action eq 'commitdiff') { + if ($action eq 'diff') { # link to patch $patchno++; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n" . "\n"; } + + # Added by Andrew Lorimer, October 2019 + # Optionally remove ".git" extension in table + my $prname = esc_html_match_hl($pr->{'path'}, $search_regexp); + if ($omit_git_extension) { + $prname =~ s/\.git//; + } + print "\n" . "\n"; + unless ($omit_owner) { - print "\n"; + print "\n"; } + + # Modified by Andrew Lorimer, October 2019 + # Link date field to latest commit unless ($omit_age_column) { print "\n"; + (defined $pr->{'age_string'} ? $cgi->a({-href => href(project=>$pr->{'path'}, + action=>"commit"), -class => "list"}, $pr->{'age_string'}) : "No commits") . "\n"; } - print"\n" . - "\n"; + "\n"; + } + print "\n"; } } @@ -5833,7 +6000,7 @@ sub git_project_list_body { } print "
" . - $cgi->a({-href => href(action=>"commitdiff", + $cgi->a({-href => href(action=>"diff", hash=>$hash, hash_parent=>$par), - -title => 'commitdiff to parent number ' . + -title => 'diff to parent number ' . ($i+1) . ': ' . substr($par,0,7)}, $i+1) . " " . @@ -5014,7 +5163,7 @@ sub git_difftree_body { print "$mode_chng"; - if ($action eq 'commitdiff') { + if ($action eq 'diff') { # link to patch $patchno++; print $cgi->a({-href => href(-anchor=>"patch$patchno")}, @@ -5035,7 +5184,7 @@ sub git_difftree_body { print "$mode_chng"; - if ($action eq 'commitdiff') { + if ($action eq 'diff') { # link to patch $patchno++; print $cgi->a({-href => href(-anchor=>"patch$patchno")}, @@ -5078,7 +5227,7 @@ sub git_difftree_body { print "$mode_chnge"; - if ($action eq 'commitdiff') { + if ($action eq 'diff') { # link to patch $patchno++; print $cgi->a({-href => href(-anchor=>"patch$patchno")}, @@ -5124,7 +5273,7 @@ sub git_difftree_body { -class => "list"}, esc_path($diff->{'from_file'})) . " with " . (int $diff->{'similarity'}) . "% similarity$mode_chng]"; - if ($action eq 'commitdiff') { + if ($action eq 'diff') { # link to patch $patchno++; print $cgi->a({-href => href(-anchor=>"patch$patchno")}, @@ -5570,12 +5719,13 @@ sub git_project_search_form { if (defined $project_filter); print $cgi->textfield(-name => 's', -value => $searchtext, -title => "Search project by name and description$limit", - -size => 60) . "\n" . + -size => 60, + -placeholder => "search repos") . "\n" . + $cgi->submit(-name => 'btnS', -value => 'search') . "" . $cgi->checkbox(-name => 'sr', -value => 1, -label => 're', -checked => $search_use_regexp) . "\n" . - $cgi->submit(-name => 'btnS', -value => 'Search') . $cgi->end_form() . "\n" . $cgi->a({-href => href(project => undef, searchtext => undef, project_filter => $project_filter)}, @@ -5756,9 +5906,16 @@ sub git_project_list_rows { } print "" . $cgi->a({-href => href(project=>$pr->{'path'}, action=>"summary"), - -class => "list"}, - esc_html_match_hl($pr->{'path'}, $search_regexp)) . + -class => "list"}, $prname) . "" . $cgi->a({-href => href(project=>$pr->{'path'}, action=>"summary"), -class => "list", @@ -5768,21 +5925,31 @@ sub git_project_list_rows { $pr->{'descr'}, $search_regexp) : esc_html($pr->{'descr'})) . "" . chop_and_escape_str($pr->{'owner'}, 15) . "" . chop_and_escape_str($pr->{'owner'}, 15) . "{'age'}) . "\">" . - (defined $pr->{'age_string'} ? $pr->{'age_string'} : "No commits") . "" . + + # Added by Andrew Lorimer, October 2019 + # Optionally hide repo-specific page shortcuts in project list + unless ($omit_shortcuts) { + print"" . $cgi->a({-href => href(project=>$pr->{'path'}, action=>"summary")}, "summary") . " | " . $cgi->a({-href => href(project=>$pr->{'path'}, action=>"shortlog")}, "shortlog") . " | " . $cgi->a({-href => href(project=>$pr->{'path'}, action=>"log")}, "log") . " | " . $cgi->a({-href => href(project=>$pr->{'path'}, action=>"tree")}, "tree") . ($pr->{'forks'} ? " | " . $cgi->a({-href => href(project=>$pr->{'path'}, action=>"forks")}, "forks") : '') . - "
\n"; - unless ($no_header) { + unless ($no_header || not $index_header) { print "\n"; if ($check_forks) { print "\n"; @@ -5891,13 +6058,11 @@ sub git_log_body { my $ref = format_ref_marker($refs, $commit); git_print_header_div('commit', "$co{'age_string'}" . - esc_html($co{'title'}) . $ref, + esc_html($co{'title'}), $ref, $commit); print "
\n" . "
\n" . - $cgi->a({-href => href(action=>"commit", hash=>$commit)}, "commit") . - " | " . - $cgi->a({-href => href(action=>"commitdiff", hash=>$commit)}, "commitdiff") . + $cgi->a({-href => href(action=>"diff", hash=>$commit)}, "diff") . " | " . $cgi->a({-href => href(action=>"tree", hash=>$commit, hash_base=>$commit)}, "tree") . "
\n" . @@ -5910,9 +6075,9 @@ sub git_log_body { print "
\n"; } if ($extra) { - print "
\n"; + print "
\n"; + print "\n"; } } @@ -5935,15 +6100,14 @@ sub git_shortlog_body { print "
\n"; } $alternate ^= 1; - # git_summary() used print "\n" . - print "\n" . + print "\n" . + "" . format_author_html('td', \%co, 10) . "\n" . "\n"; } $alternate ^= 1; - print "\n" . + print "\n" . # shortlog: format_author_html('td', \%co, 10) format_author_html('td', \%co, 15, 3) . "\n" . "\n"; + print "\n"; } else { print "\n"; } @@ -6104,7 +6268,7 @@ sub git_heads_body { print "\n"; } $alternate ^= 1; - print "\n" . + print "\n" . ($curr ? "\n" . ""; } - if (defined $extra) { + if (defined $extra && $extra != "") { print "\n" . "\n" . "\n"; @@ -6151,7 +6315,7 @@ sub git_remote_block { my $dots; if (defined $limit && $limit < @$heads) { - $dots = $cgi->a({-href => href(action=>"remotes", hash=>$remote)}, "..."); + $dots = $cgi->a({-href => href(action=>"remotes", hash=>$remote)}, "show all remotes"); } print $urls_table; @@ -6195,7 +6359,7 @@ sub git_remotes_list { if ($limited) { print "\n" . "\n" . "\n"; } @@ -6315,8 +6479,8 @@ sub git_search_changes { $alternate ^= 1; %co = parse_commit($set{'commit'}); my $author = chop_and_escape_str($co{'author_name'}, 15, 5); - print "\n" . - "\n" . + print "\n" . + "\n" . "\n"; - if ($alternate++) { - print "\n"; - } else { - print "\n"; - } + if ($in_table) { + print "\t\t
$co{'age_string'}$co{'age_string_date'}$co{'age_string_date'}"; print format_subject_html($co{'title'}, $co{'title_short'}, href(action=>"commit", hash=>$commit), $ref); print "" . - $cgi->a({-href => href(action=>"commit", hash=>$commit)}, "commit") . " | " . - $cgi->a({-href => href(action=>"commitdiff", hash=>$commit)}, "commitdiff") . " | " . + $cgi->a({-href => href(action=>"diff", hash=>$commit)}, "diff") . " | " . $cgi->a({-href => href(action=>"tree", hash=>$commit, hash_base=>$commit)}, "tree"); my $snapshot_links = format_snapshot_links($commit); if (defined $snapshot_links) { @@ -5985,7 +6149,7 @@ sub git_history_body { print "
$co{'age_string_date'}$co{'age_string_date'}"; # originally git_history used chop_str($co{'title'}, 50) @@ -5994,7 +6158,7 @@ sub git_history_body { print "" . $cgi->a({-href => href(action=>$ftype, hash_base=>$commit, file_name=>$file_name)}, $ftype) . " | " . - $cgi->a({-href => href(action=>"commitdiff", hash=>$commit)}, "commitdiff"); + $cgi->a({-href => href(action=>"diff", hash=>$commit)}, "diff"); if ($ftype eq 'blob') { print " | " . @@ -6046,7 +6210,7 @@ sub git_tags_body { } $alternate ^= 1; if (defined $tag{'age'}) { - print "$tag{'age'}$tag{'age'}
$ref{'age'}$ref{'age'}" : "") . $cgi->a({-href => href(action=>"shortlog", hash=>$ref{'fullname'}), -class => "list name"},esc_html($ref{'name'})) . @@ -6116,7 +6280,7 @@ sub git_heads_body { "
$extra
" . - $cgi->a({-href => href(action=>"remotes")}, "...") . + $cgi->a({-href => href(action=>"remotes")}, "show all remotes") . "
$co{'age_string_date'}$author$co{'age_string_date'}$author" . $cgi->a({-href => href(action=>"commit", hash=>$co{'id'}), -class => "list subject"}, @@ -6371,10 +6535,10 @@ sub git_search_files { my $matches = 0; my $lastfile = ''; my $file_href; + my $in_table = 0; while (my $line = <$fd>) { chomp $line; my ($file, $lno, $ltext, $binary); - last if ($matches++ > 1000); if ($line =~ /^Binary file (.+) matches$/) { $file = $1; $binary = 1; @@ -6383,21 +6547,27 @@ sub git_search_files { $file =~ s/^$co{'tree'}://; } if ($file ne $lastfile) { - $lastfile and print "
\n\t\n\n"; + $in_table = 0; + } + if ($alternate++) { + print "\n"; + } else { + print "\n"; + } $file_href = href(action=>"blob", hash_base=>$co{'id'}, file_name=>$file); - print "". + print "\t". $cgi->a({-href => $file_href, -class => "list"}, esc_path($file)); - print "\n"; + print "\t\n"; + print "\t\n\t\t\n"; + $in_table = 1; $lastfile = $file; } + last if ($matches++ > 1000); if ($binary) { - print "
Binary file
\n"; + print "\t\t\t\n\t\t\t\t\n\t\t\t\n"; } else { $ltext = untabify($ltext); if ($ltext =~ m/^(.*)($search_regexp)(.*)$/i) { @@ -6409,23 +6579,27 @@ sub git_search_files { } else { $ltext = esc_html($ltext, -nbsp=>1); } - print "
" . - $cgi->a({-href => $file_href.'#l'.$lno, - -class => "linenr"}, sprintf('%4i', $lno)) . - ' ' . $ltext . "
\n"; + print "\t\t\t\n\t\t\t\t\n"; + print "\t\t\t\t\n\t\t\t\n"; } } if ($lastfile) { - print "\n"; if ($matches > 1000) { - print "
Too many matches, listing trimmed
\n"; + print "\n"; } + print "\n
Binary file
\n\t\t\t\t\t" + . $cgi->a({-href => $file_href.'#l'.$lno, + -class => "linenr"}, sprintf('%4i', $lno)) . "\n\t\t\t\t\n\t\t\t\t\t
$ltext
\n\t\t\t\t
Too many matches, listing trimmed
\n"; } else { - print "
No matches found
\n"; + print "
No matches found
\n"; + $in_table = 0; } close $fd; - print "\n"; + if ($in_table) { + print "\t\t\n\t\n"; + $in_table = 0; + } git_footer_html(); } @@ -6449,7 +6623,7 @@ sub git_search_grep_body { print "\n"; } $alternate ^= 1; - print "$co{'age_string_date'}\n" . + print "$co{'age_string_date'}\n" . format_author_html('td', \%co, 15, 5) . "" . $cgi->a({-href => href(action=>"commit", hash=>$co{'id'}), @@ -6474,15 +6648,13 @@ sub git_search_grep_body { } print "\n" . "" . - $cgi->a({-href => href(action=>"commit", hash=>$co{'id'})}, "commit") . - " | " . - $cgi->a({-href => href(action=>"commitdiff", hash=>$co{'id'})}, "commitdiff") . + $cgi->a({-href => href(action=>"diff", hash=>$co{'id'})}, "diff") . " | " . $cgi->a({-href => href(action=>"tree", hash=>$co{'tree'}, hash_base=>$co{'id'})}, "tree"); print "\n" . "\n"; } - if (defined $extra) { + if (defined $extra && $extra != "") { print "\n" . "$extra\n" . "\n"; @@ -6595,7 +6767,6 @@ sub git_summary { git_header_html(); git_print_page_nav('summary','', $head); - print "
 
\n"; print "\n" . "\n"; if ($owner and not $omit_owner) { @@ -6649,21 +6820,21 @@ sub git_summary { git_print_header_div('shortlog'); git_shortlog_body(\@commitlist, 0, 15, $refs, $#commitlist <= 15 ? undef : - $cgi->a({-href => href(action=>"shortlog")}, "...")); + $cgi->a({-href => href(action=>"shortlog")}, "show all commits")); } if (@taglist) { git_print_header_div('tags'); git_tags_body(\@taglist, 0, 15, $#taglist <= 15 ? undef : - $cgi->a({-href => href(action=>"tags")}, "...")); + $cgi->a({-href => href(action=>"tags")}, "show all tags")); } if (@headlist) { git_print_header_div('heads'); git_heads_body(\@headlist, $head, 0, 15, $#headlist <= 15 ? undef : - $cgi->a({-href => href(action=>"heads")}, "...")); + $cgi->a({-href => href(action=>"heads")}, "show all branches")); } if (%remotedata) { @@ -6675,7 +6846,7 @@ sub git_summary { git_print_header_div('forks'); git_project_list_body(\@forklist, 'age', 0, 15, $#forklist <= 15 ? undef : - $cgi->a({-href => href(action=>"forks")}, "..."), + $cgi->a({-href => href(action=>"forks")}, "show all forks"), 'no_header'); } @@ -6707,13 +6878,13 @@ sub git_tag { } print "
description" . esc_html($descr) . "
\n\n" . "\n"; - print "
"; + print "
"; my $comment = $tag{'comment'}; foreach my $line (@$comment) { chomp $line; - print esc_html($line, -nbsp=>1) . "
\n"; + print esc_html($line, -nbsp=>1) . "\n"; } - print "
\n"; + print "\n"; git_footer_html(); } @@ -6824,7 +6995,6 @@ sub git_blame_common { print qq!
\n!; } - print qq!
\n!; print qq!
... / ...
\n! if ($format eq 'incremental'); print qq!\n!. @@ -7140,38 +7310,40 @@ sub git_blob { $cgi->a({-href => href(action=>"blob_plain", -replay=>1)}, "raw"); } - git_print_page_nav('','', $hash_base,$co{'tree'},$hash_base, $formats_nav); - git_print_header_div('commit', esc_html($co{'title'}), $hash_base); + git_print_page_nav('','', $hash_base,$co{'tree'},$hash_base); + print "
\n"; + print git_path_header($file_name, "blob", $hash_base, 1, esc_html($co{'title'}), $co{'id'}, $co{'id'}); + print "
" } else { - print "
\n" . - "

\n" . + print "\n" . "
".esc_html($hash)."
\n"; } - git_print_page_path($file_name, "blob", $hash_base); - print "
\n"; + print ""; + if ($mimetype =~ m!^image/!) { - print qq!"blob_plain", hash=>$hash, + hash_base=>$hash_base, file_name=>$file_name); + print qq!!.esc_attr($file_name).qq!$hash, - hash_base=>$hash_base, file_name=>$file_name) . - qq!" />\n!; + print qq! src="! .$img_src . qq!" />\n!; } else { my $nr; + print "
";
 		while (my $line = <$fd>) {
 			chomp $line;
 			$nr++;
-			$line = untabify($line);
-			printf qq!
%4i %s
\n!, + # $line = untabify($line); + printf qq!%4i%s\n!, $nr, esc_attr(href(-replay => 1)), $nr, $nr, $highlight ? sanitize($line) : esc_html($line, -nbsp=>1); } + print "
"; } close $fd or print "Reading blob failed.\n"; - print "
"; git_footer_html(); } @@ -7221,14 +7393,17 @@ sub git_tree { # FIXME: Should be available when we have no hash base as well. push @views_nav, $snapshot_links; } - git_print_page_nav('tree','', $hash_base, undef, undef, - join(' | ', @views_nav)); - git_print_header_div('commit', esc_html($co{'title'}) . $ref, $hash_base); + git_print_page_nav('tree','', $hash_base, undef, undef); + if (scalar(@views_nav) > 0) { + print ""; + } + unless ($hash_base eq "HEAD") { + git_print_header_div('commit', esc_html($co{'title'}), $ref, $hash_base); + } } else { undef $hash_base; - print "
\n"; - print "

\n"; - print "
".esc_html($hash)."
\n"; + print "".esc_html($hash)."\n"; } if (defined $file_name) { $basedir = $file_name; @@ -7237,51 +7412,41 @@ sub git_tree { } git_print_page_path($file_name, 'tree', $hash_base); } - print "
\n"; print "
\n"; - my $alternate = 1; # '..' (top directory) link if possible if (defined $hash_base && defined $file_name && $file_name =~ m![^/]+$!) { - if ($alternate) { - print "\n"; - } else { - print "\n"; - } - $alternate ^= 1; - + print "\n"; my $up = $file_name; $up =~ s!/?[^/]+$!!; undef $up unless $up; # based on git_print_tree_entry - print '\n"; + print '\n"; print ''."\n" if $show_sizes; print '\n"; print "\n"; print "\n"; } + my @treefilter_pattern = gitweb_get_feature('tree_filter'); foreach my $line (@entries) { - my %t = parse_ls_tree_line($line, -z => 1, -l => $show_sizes); - - if ($alternate) { - print "\n"; - } else { - print "\n"; - } - $alternate ^= 1; - - git_print_tree_entry(\%t, $basedir, $hash_base, $have_blame); - - print "\n"; + my $t = parse_ls_tree_line($line, -z => 1, -l => $show_sizes); + if ($t->{'name'} =~ /@treefilter_pattern/) { + print "\n"; + git_print_tree_entry($t, $basedir, $hash_base, $have_blame); + print "\n"; + } } - print "
' . mode_str('040000') . "'; + print '' + . ''; + print mode_str('040000') . " '; print $cgi->a({-href => href(action=>"tree", hash_base=>$hash_base, file_name=>$up)}, - ".."); + "parent"); print "
\n" . - "
"; + print "\n"; git_footer_html(); } @@ -7511,7 +7676,7 @@ sub git_commit { # we need to prepare $formats_nav before any parameter munging my $formats_nav; if (!defined $parent) { - # --root commitdiff + # --root diff $formats_nav .= '(initial)'; } elsif (@$parents == 1) { # single parent commit @@ -7519,7 +7684,7 @@ sub git_commit { '(parent: ' . $cgi->a({-href => href(action=>"commit", hash=>$parent)}, - esc_html(substr($parent, 0, 7))) . + esc_html(substr($parent, 0, $hash_char))) . ')'; } else { # merge commit @@ -7528,7 +7693,7 @@ sub git_commit { join(' ', map { $cgi->a({-href => href(action=>"commit", hash=>$_)}, - esc_html(substr($_, 0, 7))); + esc_html(substr($_, 0, $hash_char))); } @$parents ) . ')'; } @@ -7560,60 +7725,78 @@ sub git_commit { git_header_html(undef, $expires); git_print_page_nav('commit', '', - $hash, $co{'tree'}, $hash, - $formats_nav); + $hash, $co{'tree'}, $hash); if (defined $co{'parent'}) { - git_print_header_div('commitdiff', esc_html($co{'title'}) . $ref, $hash); + git_print_header_div('diff', esc_html($co{'title'}), $ref, $hash); } else { - git_print_header_div('tree', esc_html($co{'title'}) . $ref, $co{'tree'}, $hash); + git_print_header_div('tree', esc_html($co{'title'}), $ref, $co{'tree'}, $hash); } print "
\n" . "\n"; git_print_authorship_rows(\%co); - print "\n"; + print "\n"; print "" . - "" . + "" . "" . - "" . + print ")" . "\n"; foreach my $par (@$parents) { print "" . - "" . + "" . "" . - "" . + truncate_hash($par, "parent_hash", href(action=>"commit", hash=>$par)) . + " (" . + $cgi->a({-href => href(action=>"diff", hash=>$hash, hash_parent=>$par)}, "diff") . + ")" . "\n"; } print "
commit$co{'id'}
commit" . truncate_hash($co{'id'}) + . "
treetree" . - $cgi->a({-href => href(action=>"tree", hash=>$co{'tree'}, hash_base=>$hash), - class => "list"}, $co{'tree'}) . - "" . - $cgi->a({-href => href(action=>"tree", hash=>$co{'tree'}, hash_base=>$hash)}, + truncate_hash($co{'tree'}, "tree_hash", href(action=>"tree", hash=>$co{'tree'}, hash_base=>$hash)) . + " (" . $cgi->a({-href => href(action=>"tree", hash=>$co{'tree'}, hash_base=>$hash)}, "tree"); my $snapshot_links = format_snapshot_links($hash); if (defined $snapshot_links) { print " | " . $snapshot_links; } - print "
parentparent" . - $cgi->a({-href => href(action=>"commit", hash=>$par), - class => "list"}, $par) . - "" . - $cgi->a({-href => href(action=>"commit", hash=>$par)}, "commit") . - " | " . - $cgi->a({-href => href(action=>"commitdiff", hash=>$hash, hash_parent=>$par)}, "diff") . - "
". "
\n"; - - print "
\n"; - git_print_log($co{'comment'}); - print "
\n"; + print ""; git_difftree_body(\@difftree, $hash, @$parents); git_footer_html(); } +sub truncate_hash { + # Truncate an SHA1 hash into HTML code tags & add link + my ($value, $elem_id, $href) = @_; + my $truncated = (defined $elem_id ? "" : ""); + my $span_content = "" . esc_html(substr($value, 0, $hash_char)) + . "..." + . esc_html(substr($value, $hash_char + 1)) + . ""; + if (defined $href) { + $truncated .= $cgi->a({-href => $href, -class => "list"}, $span_content); + } else { + $truncated .= $span_content; + } + $truncated .= (defined $elem_id ? copy_svg($elem_id) : "") . ""; + return $truncated; +} + +sub copy_svg { + # Return an HTML string containing an SVG button to copy the content of + # an element to the clipboard. + my ($elem_id) = @_; + return "" + . "copy hash to clipboard" + . ""; +} + sub git_object { # object is defined by: # - hash or hash_base alone @@ -7745,10 +7928,9 @@ sub git_blobdiff { $formats_nav .= diff_style_nav($diff_style); git_header_html(undef, $expires); if (defined $hash_base && (my %co = parse_commit($hash_base))) { - git_print_page_nav('','', $hash_base,$co{'tree'},$hash_base, $formats_nav); + git_print_page_nav('','', $hash_base,$co{'tree'},$hash_base); git_print_header_div('commit', esc_html($co{'title'}), $hash_base); } else { - print "

$formats_nav
\n"; print "
".esc_html("$hash vs $hash_parent")."
\n"; } if (defined $file_name) { @@ -7772,13 +7954,10 @@ sub git_blobdiff { # patch if ($format eq 'html') { - print "
\n"; - git_patchset_body($fd, $diff_style, [ \%diffinfo ], $hash_base, $hash_parent_base); close $fd; - print "
\n"; # class="page_body" git_footer_html(); } else { @@ -7821,7 +8000,7 @@ sub diff_style_nav { } @styles; } -sub git_commitdiff { +sub git_diff { my %params = @_; my $format = $params{-format} || 'html'; my $diff_style = $input_params{'diff_style'} || 'inline'; @@ -7835,7 +8014,7 @@ sub git_commitdiff { my %co = parse_commit($hash) or die_error(404, "Unknown commit object"); - # choose format for commitdiff for merge + # choose format for diff for merge if (! defined $hash_parent && @{$co{'parents'}} > 1) { $hash_parent = '--cc'; } @@ -7843,7 +8022,7 @@ sub git_commitdiff { my $formats_nav; if ($format eq 'html') { $formats_nav = - $cgi->a({-href => href(action=>"commitdiff_plain", -replay=>1)}, + $cgi->a({-href => href(action=>"diff_plain", -replay=>1)}, "raw"); if ($patch_max && @{$co{'parents'}} <= 1) { $formats_nav .= " | " . @@ -7854,7 +8033,7 @@ sub git_commitdiff { if (defined $hash_parent && $hash_parent ne '-c' && $hash_parent ne '--cc') { - # commitdiff with two commits given + # diff with two commits given my $hash_parent_short = $hash_parent; if ($hash_parent =~ m/^$oid_regex$/) { $hash_parent_short = substr($hash_parent, 0, 7); @@ -7873,7 +8052,7 @@ sub git_commitdiff { esc_html($hash_parent_short)) . ')'; } elsif (!$co{'parent'}) { - # --root commitdiff + # --root diff $formats_nav .= ' (initial)'; } elsif (scalar @{$co{'parents'}} == 1) { # single parent commit @@ -7914,7 +8093,7 @@ sub git_commitdiff { @{$co{'parents'}} > 1 ? '--cc' : $co{'parent'} || '--root'; } - # read commitdiff + # read diff my $fd; my @difftree; if ($format eq 'html') { @@ -7960,7 +8139,7 @@ sub git_commitdiff { '--encoding=utf8', '--stdout', @commit_spec or die_error(500, "Open git-format-patch failed"); } else { - die_error(400, "Unknown commitdiff format"); + die_error(400, "Unknown diff format"); } # non-textual hash id's can be cached @@ -7975,14 +8154,13 @@ sub git_commitdiff { my $ref = format_ref_marker($refs, $co{'id'}); git_header_html(undef, $expires); - git_print_page_nav('commitdiff','', $hash,$co{'tree'},$hash, $formats_nav); - git_print_header_div('commit', esc_html($co{'title'}) . $ref, $hash); + git_print_page_nav('diff','', $hash,$co{'tree'},$hash); + git_print_header_div('commit', esc_html($co{'title'}), $ref, $hash); print "
\n" . "\n"; git_print_authorship_rows(\%co); print "
". "
\n"; - print "
\n"; if (@{$co{'comment'}} > 1) { print "
\n"; git_print_log($co{'comment'}, -final_empty_line=> 1, -remove_title => 1); @@ -8027,13 +8205,12 @@ sub git_commitdiff { $hash_parent eq '-c' || $hash_parent eq '--cc'; git_difftree_body(\@difftree, $hash, $use_parents ? @{$co{'parents'}} : $hash_parent); - print "
\n"; + print ""; git_patchset_body($fd, $diff_style, \@difftree, $hash, $use_parents ? @{$co{'parents'}} : $hash_parent); close $fd; - print "
\n"; # class="page_body" git_footer_html(); } elsif ($format eq 'plain') { @@ -8049,17 +8226,17 @@ sub git_commitdiff { } } -sub git_commitdiff_plain { - git_commitdiff(-format => 'plain'); +sub git_diff_plain { + git_diff(-format => 'plain'); } # format-patch-style patches sub git_patch { - git_commitdiff(-format => 'patch', -single => 1); + git_diff(-format => 'patch', -single => 1); } sub git_patches { - git_commitdiff(-format => 'patch'); + git_diff(-format => 'patch'); } sub git_history { @@ -8223,9 +8400,8 @@ sub git_feed { if (defined $descr) { $descr = esc_html($descr); } else { - $descr = "$project " . - ($format eq 'rss' ? 'RSS' : 'Atom') . - " feed"; + $descr = ($format eq 'rss' ? 'RSS' : 'Atom') . + " feed of $project"; } my $owner = git_get_project_owner($project); $owner = esc_html($owner); @@ -8315,7 +8491,7 @@ sub git_feed { or next; # print element (entry, item) - my $co_url = href(-full=>1, action=>"commitdiff", hash=>$commit); + my $co_url = href(-full=>1, action=>"diff", hash=>$commit); if ($format eq 'rss') { print "\n" . "" . esc_html($co{'title'}) . "\n" .