about summary refs log tree commit homepage
path: root/lib/PublicInbox
diff options
context:
space:
mode:
authorEric Wong <e@80x24.org>2015-12-24 01:56:22 +0000
committerEric Wong <e@80x24.org>2016-04-05 18:58:27 +0000
commit49d99dc0f71ab2d0f23a074765ef10d55d5d5547 (patch)
tree7a16acd9e9b92035c654843f445e921d27542754 /lib/PublicInbox
parent854862946453e829243735e22c6cabc43b47a70c (diff)
downloadpublic-inbox-49d99dc0f71ab2d0f23a074765ef10d55d5d5547.tar.gz
Hopefully we'll show some names properly in our pages now,
as well as simplify our code when escaping text for HTML
display.

Additionally, tweak our diff display by using <ins> and
<del> tags for added/removed text, respectively.  This should
allow users to choose their own styles when viewing diffs
in their browser while being meaningful to people who cannot
differentiate colors.
Diffstat (limited to 'lib/PublicInbox')
-rw-r--r--lib/PublicInbox/Hval.pm7
-rw-r--r--lib/PublicInbox/RepoBrowseGitCommit.pm125
2 files changed, 91 insertions, 41 deletions
diff --git a/lib/PublicInbox/Hval.pm b/lib/PublicInbox/Hval.pm
index a16cd4a1..2974c683 100644
--- a/lib/PublicInbox/Hval.pm
+++ b/lib/PublicInbox/Hval.pm
@@ -10,7 +10,7 @@ use Encode qw(find_encoding);
 use URI::Escape qw(uri_escape_utf8);
 use PublicInbox::MID qw/mid_clean/;
 use base qw/Exporter/;
-our @EXPORT_OK = qw/ascii_html/;
+our @EXPORT_OK = qw/ascii_html utf8_html/;
 
 # for user-generated content (UGC) which may have excessively long lines
 # and screw up rendering on some browsers.  This is the only CSS style
@@ -71,6 +71,11 @@ sub ascii_html {
         $enc_ascii->encode($s, Encode::HTMLCREF);
 }
 
+sub utf8_html {
+        my ($raw) = @_;
+        ascii_html($enc_utf8->decode($raw));
+}
+
 sub as_html { ascii_html($_[0]->{raw}) }
 sub as_href { ascii_html(uri_escape_utf8($_[0]->{href})) }
 
diff --git a/lib/PublicInbox/RepoBrowseGitCommit.pm b/lib/PublicInbox/RepoBrowseGitCommit.pm
index 21f8f960..8b831a15 100644
--- a/lib/PublicInbox/RepoBrowseGitCommit.pm
+++ b/lib/PublicInbox/RepoBrowseGitCommit.pm
@@ -1,10 +1,12 @@
 # Copyright (C) 2015 all contributors <meta@public-inbox.org>
 # License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
 
+# shows the /commit/ endpoint for git repositories
 package PublicInbox::RepoBrowseGitCommit;
 use strict;
 use warnings;
 use base qw(PublicInbox::RepoBrowseBase);
+use PublicInbox::Hval qw(utf8_html);
 use PublicInbox::Git;
 use PublicInbox::RepoBrowseGit qw(git_unquote git_commit_title);
 
@@ -16,10 +18,10 @@ sub git_commit_stream {
         my ($req, $q, $H, $log, $fh) = @_;
         chomp(my $h = <$log>); # abbreviated commit
         my $l;
-        my $s = PublicInbox::Hval->new_oneline($l = <$log>)->as_html; # subject
-        my $au = PublicInbox::Hval->new_oneline($l = <$log>)->as_html; # author
+        chomp(my $s = utf8_html($l = <$log>)); # subject
+        chomp(my $au = utf8_html($l = <$log>)); # author
         chomp(my $ad = <$log>);
-        my $cu = PublicInbox::Hval->new_oneline($l = <$log>)->as_html;
+        chomp(my $cu = utf8_html($l = <$log>));
         chomp(my $cd = <$log>);
         chomp(my $t = <$log>); # tree
         chomp(my $p = <$log>); # parents
@@ -28,55 +30,64 @@ sub git_commit_stream {
         my $git = $req->{repo_info}->{git};
 
         my $rel = $req->{relcmd};
+        my $qs = $q->qs(id => $h);
+        chomp $H;
         my $x = "<html><head><title>$s</title></head><body>" .
                 PublicInbox::Hval::PRE .
-                "   commit $H" .
+                "   commit $H (<a\nhref=\"${rel}patch$qs\">patch</a>)\n" .
                 "     tree <a\nhref=\"${rel}tree?id=$h\">$t</a>";
+
+        # extra show path information, if any
         my $extra = $req->{extra};
+        my $path = '';
         if (@$extra) {
                 my @t;
-                $x .= ' [';
+                my $ep;
+                $x .= ' -- ';
                 $x .= join('/', map {
                         push @t, $_;
                         my $e = PublicInbox::Hval->new_bin($_, join('/', @t));
-                        my $ep = $e->as_path;
+                        $ep = $e->as_path;
                         my $eh = $e->as_html;
                         "<a\nhref=\"${rel}tree/$ep?id=$h\">$eh</a>";
                 } @$extra);
-                $x .= ']';
+                $path = "/$ep";
         }
+
         $x .= "\n   author $au\t$ad\ncommitter $cu\t$cd\n";
         if (scalar(@p) == 1) {
                 $x .= '   parent ';
                 my $p = $p[0];
                 my $t = git_commit_title_html($git, $p);
-                $x .= qq(<a\nhref="${rel}commit?id=$p">$p</a> $t\n);
+                $qs = $q->qs(id => $p);
+                $x .= qq(<a\nhref="${rel}commit$path$qs">$p</a> $t\n);
         } elsif (scalar(@p) > 1) {
                 foreach my $p (@p) {
                         $x .= '    merge ';
-                        $x .= "<a\nhref=\"${rel}commit?id=$p\">$p</a> (";
-                        $x .= "<a\nhref=\"${rel}diff?id=$p&id2=$h\">";
+                        $qs = $q->qs(id => $p);
+                        $x .= "<a\nhref=\"${rel}commit$path$qs\">$p</a> (";
+                        $qs = $q->qs(id => $p, id2 => $h);
+                        $x .= "<a\nhref=\"${rel}diff$path$qs\">";
                         $x .= "diff</a>) ";
                         $x .= git_commit_title_html($git, $p);
                         $x .= "\n";
                 }
         }
-        $fh->write($x .= "\n$s\n\n");
+        $fh->write($x .= "\n<b>$s</b>\n\n");
 
         # body:
         local $/ = "\0";
         $l = <$log>;
         chomp $l;
-        $x = PublicInbox::Hval->new_bin($l)->as_html; # body
-        $fh->write($x."\n");
-
+        $x = utf8_html($l); # body
+        $fh->write($x."---\n");
         git_show_diffstat($req, $h, $fh, $log);
 
         # diff
         local $/ = "\n";
         my $cmt = '[a-f0-9]+';
         my $diff = { h => $h, p => \@p, rel => $rel };
-        my $cc_add;
+        my $cc_mod;
         while (defined($l = <$log>)) {
                 if ($l =~ m{^diff --git ("?a/.+) ("?b/.+)$}) { # regular
                         $l = git_diff_ab_hdr($diff, $1, $2) . "\n";
@@ -86,18 +97,15 @@ sub git_commit_stream {
                         $l = git_diff_ab_index($diff, $1, $2, $3) . "\n";
                 } elsif ($l =~ /^@@ (\S+) (\S+) @@(.*)$/) { # regular
                         $l = git_diff_ab_hunk($diff, $1, $2, $3) . "\n";
-                } elsif ($l =~ /^\+/ || (defined($cc_add) && $l =~ $cc_add)) {
-                        # added hunk
-                        chomp $l;
-                        $l = '<b>'.PublicInbox::Hval->new_bin($l)->as_html.
-                                "</b>\n";
+                } elsif ($l =~ /^[-\+]/ || ($cc_mod && $l =~ $cc_mod)) {
+                        $l = git_diff_mod($l) . "\n";
                 } elsif ($l =~ /^index ($cmt,[^\.]+)\.\.($cmt)(.*)$/o) { # --cc
                         $l = git_diff_cc_index($diff, $1, $2, $3) . "\n";
-                        $cc_add ||= $diff->{cc_add};
+                        $cc_mod ||= $diff->{cc_mod};
                 } elsif ($l =~ /^(@@@+) (\S+.*\S+) @@@+(.*)$/) { # --cc
                         $l = git_diff_cc_hunk($diff, $1, $2, $3) . "\n";
                 } else {
-                        $l = PublicInbox::Hval->new_bin($l)->as_html;
+                        $l = utf8_html($l);
                 }
                 $fh->write($l);
         }
@@ -114,7 +122,7 @@ sub call_git_commit {
         $id eq '' and $id = 'HEAD';
         my $git = $repo_info->{git} ||= PublicInbox::Git->new($dir);
 
-        my @cmd = qw(show -z --numstat -p --cc
+        my @cmd = qw(show -z --numstat -p --cc --encoding=UTF-8
                         --no-notes --no-color --abbrev=10);
         my @path;
 
@@ -128,7 +136,9 @@ sub call_git_commit {
 
         my $log = $git->popen(@cmd, GIT_FMT, $id, '--', @path);
         my $H = <$log>;
-        defined $H or return;
+
+        # maybe the path didn't exist, yet, zip them back up
+        return git_commit_404($req, $q, $path[0]) unless defined $H;
         sub {
                 my ($res) = @_; # Plack callback
                 my $fh = $res->([200, ['Content-Type'=>'text/html']]);
@@ -137,6 +147,27 @@ sub call_git_commit {
         }
 }
 
+sub git_commit_404 {
+        my ($req, $q, $path) = @_;
+        my $x = 'Missing commit or path';
+        my $pfx = "$req->{relcmd}commit";
+
+        # print STDERR "path: $path\n";
+        my $try = 'try';
+        $x = "<html><head><title>$x</title></head><body><pre><b>$x</b>\n\n";
+        if (defined $path) {
+                my $qs = $q->qs;
+                $x .= "<a\nhref=\"$pfx$qs\">" .
+                        "try without the path <s>$path</s></a>\n";
+                $try = 'or';
+        }
+        my $qs = $q->qs(id => '');
+        $x .= "<a\nhref=\"$pfx$qs\">$try the latest commit in HEAD</a>\n";
+        $x .= '</pre></body>';
+
+        [ 404, ['Content-Type'=>'text/html'], [ $x ] ];
+}
+
 sub git_show_diffstat {
         my ($req, $h, $fh, $log) = @_;
         local $/ = "\0\0";
@@ -168,9 +199,9 @@ sub git_show_diffstat {
                         $l = git_diffstat_rename($rel, $h, $from, $to);
                 }
                 ++$nr;
-                $fh->write($num."\t".$l."\n");
+                $fh->write(' '.$num."\t".$l."\n");
         }
-        $l = "\n$nr ";
+        $l = "\n $nr ";
         $l .= $nr == 1 ? 'file changed, ' : 'files changed, ';
         $l .= $nadd;
         $l .= $nadd == 1 ? ' insertion(+), ' : ' insertions(+), ';
@@ -184,15 +215,15 @@ sub git_diff_ab_index {
         my ($diff, $xa, $xb, $end) = @_;
         # not wasting bandwidth on links here, yet
         # links in hunk headers are far more useful with line offsets
-        $end = PublicInbox::Hval->new_bin($end)->as_html;
+        $end = utf8_html($end);
         "index $xa..<b>$xb</b>$end";
 }
 
 # diff --git a/foo.c b/bar.c
 sub git_diff_ab_hdr {
         my ($diff, $fa, $fb) = @_;
-        my $html_a = PublicInbox::Hval->new_bin($fa)->as_html;
-        my $html_b = PublicInbox::Hval->new_bin($fb)->as_html;
+        my $html_a = utf8_html($fa);
+        my $html_b = utf8_html($fb);
         $fa = git_unquote($fa);
         $fb = git_unquote($fb);
         $fa =~ s!\Aa/!!;
@@ -230,12 +261,12 @@ sub git_diff_ab_hunk {
                 $rv .= "<a\nhref=\"${rel}tree/$diff->{path_b}?id=$h#n$nb\">";
                 $rv .= "<b>$cb</b></a>";
         }
-        $rv . ' @@' . PublicInbox::Hval->new_bin($ctx)->as_html;
+        $rv . ' @@' . utf8_html($ctx);
 }
 
 sub git_diff_cc_hdr {
         my ($diff, $path) = @_;
-        my $html_path = PublicInbox::Hval->new_bin($path)->as_html;
+        my $html_path = utf8_html($path);
         my $cc = $diff->{cc} = PublicInbox::Hval->new_bin(git_unquote($path));
         $diff->{path_cc} = $cc->as_path;
         "diff --cc <b>$html_path</b>";
@@ -244,12 +275,12 @@ sub git_diff_cc_hdr {
 # index abcdef09,01234567..76543210
 sub git_diff_cc_index {
         my ($diff, $before, $last, $end) = @_;
-        $end = PublicInbox::Hval->new_bin($end)->as_html;
+        $end = utf8_html($end);
         my @before = split(',', $before);
         $diff->{pobj_cc} = \@before;
-        $diff->{cc_add} ||= eval {
+        $diff->{cc_mod} ||= eval {
                 my $n = scalar(@before) - 1;
-                qr/^ {0,$n}\+/;
+                qr/^ {0,$n}[-\+]/;
         };
 
         # not wasting bandwidth on links here, yet
@@ -292,14 +323,14 @@ sub git_diff_cc_hunk {
                 $rv .= " <a\nhref=\"${rel}tree/$path?id=$h#n$n\">";
                 $rv .= "<b>$last</b></a>";
         }
-        $rv .= " $at" . PublicInbox::Hval->new_bin($ctx)->as_html;
+        $rv .= " $at" . utf8_html($ctx);
 }
 
 sub git_commit_title_html {
         my ($git, $id) = @_;
         my $t = git_commit_title($git, $id);
         return '' unless defined $t; # BUG?
-        '[' . PublicInbox::Hval->new_bin($t)->as_html . ']';
+        '[' . utf8_html($t) . ']';
 }
 
 sub git_diffstat_rename {
@@ -312,11 +343,9 @@ sub git_diffstat_rename {
                 push @base, shift(@to);
                 shift @from;
         }
-        if (@base) {
-                $base = PublicInbox::Hval->new_bin(join('/', @base))->as_html;
-        }
 
-        $from = PublicInbox::Hval->new_bin(join('/', @from))->as_html;
+        $base = utf8_html(join('/', @base)) if @base;
+        $from = utf8_html(join('/', @from));
         $to = PublicInbox::Hval->new_bin(join('/', @to), $orig_to);
         my $tp = $to->as_path;
         my $th = $to->as_html;
@@ -324,4 +353,20 @@ sub git_diffstat_rename {
         @base ? "$base/{$from =&gt; $to}" : "$from =&gt; $to";
 }
 
+sub git_diff_mod {
+        my ($l) = @_;
+        chomp $l;
+        my ($pfx, $t);
+        if ($l =~ s/\A([\s\+]+)//) {
+                $pfx = "<b>$1</b>";
+                $t = 'ins';
+        } else {
+                $l =~ s/\A([\s\-]+)//;
+                $pfx = $1;
+                $t = 'del';
+        }
+        $l = utf8_html($l);
+        $pfx . (length($l) ? "<$t>$l</$t>" : $l);
+}
+
 1;