aboutsummaryrefslogtreecommitdiffstats
path: root/lib/LXRng/Web.pm
diff options
context:
space:
mode:
Diffstat (limited to 'lib/LXRng/Web.pm')
-rw-r--r--lib/LXRng/Web.pm140
1 files changed, 99 insertions, 41 deletions
diff --git a/lib/LXRng/Web.pm b/lib/LXRng/Web.pm
index 4334981..d7f9be4 100644
--- a/lib/LXRng/Web.pm
+++ b/lib/LXRng/Web.pm
@@ -34,13 +34,17 @@ use IO::Handle;
use Digest::SHA1 qw(sha1_hex);
use CGI::Ajax;
use File::Temp qw(tempdir tempfile);
+use File::Path qw(mkpath);
use POSIX qw(waitpid);
use constant PDF_LINELEN => 95;
use constant PDF_CHARPTS => 6.6;
+# Cache must be purged if this is changed.
+use constant FRAGMENT_SIZE => 250;
+
use vars qw($has_gzip_io);
-# eval { require PerlIO::gzip; $has_gzip_io = 1; };
+eval { require PerlIO::gzip; $has_gzip_io = 1; };
# Return 1 if gzip compression of html is desired.
@@ -77,39 +81,49 @@ sub print_markedup_file {
return;
}
else {
- # Grmble. We assume the identifiers to markup are identical
- # from one version to another, but if the same revision of a
- # file exists both in an indexed and un-indexed release, one
- # of them will have its identifiers highlighted and the other
- # not. So we can't share a cache slot across releases without
- # adding some extra logic here. Bummer.
- # TODO: Resolve by caching only accesses to releases that are
- # is_indexed.
+ my $line = 0;
+ my $focus = 1;
+ my $fline = $context->param('line');
+
+ $focus = $fline < 100 if defined($fline);
+
my $shaid = sha1_hex(join("\0", $node->name, $node->revision,
$context->release));
my $cfile;
+ $shaid =~ s,^(..)(..),$1/$2/,;
$cfile = $context->config->{'cache'}.'/'.$shaid
if exists $context->config->{'cache'};
- if ($cfile and -e $cfile) {
- open(my $cache, '<', $cfile);
-
- my $focus = $context->param('line') || 0;
- $focus = 0 if $context->param('full');
- my $class = $focus ? 'partial' : 'full';
- my $start = $focus > 5 ? " start=".($focus - 5) : "";
- print("<pre id=\"file_contents\" class=\"$class\"><ol$start><span>");
- while (<$cache>) {
- next if $focus and $. < $focus - 5;
- print($_);
- last if $focus and $. > $focus + 70;
+ if ($cfile and -d $cfile) {
+ print("<pre id=\"file_contents\">");
+ while (-r "$cfile/$line") {
+ print("<div class=\"".($focus ? "done" : "pending").
+ "\" id=\"$shaid/$line\">");
+ if ($focus) {
+ open(my $cache, '<', "$cfile/$line");
+ my $buf;
+ while (read($cache, $buf, 16384) > 0) {
+ print($buf);
+ }
+ close($cache);
+ }
+ else {
+ print("\n" x FRAGMENT_SIZE);
+ }
+ print("</div>");
+ $line += FRAGMENT_SIZE;
+
+ if (defined($fline)) {
+ $focus = ($line <= ($fline + 100)
+ and $line > ($fline - FRAGMENT_SIZE));
+ }
}
- print("</span></ol></pre>");
- close($cache);
+ print("</pre>\n");
}
else {
my $cache;
- open($cache, '>', $cfile) if $cfile;
+ mkpath($cfile, 0, 0777);
+ open($cache, '>', "$cfile/0") if $cfile;
my $handle = $node->handle();
LXRng::Lang->init($context);
my $lang = LXRng::Lang->new($node);
@@ -117,21 +131,39 @@ sub print_markedup_file {
@{$lang->parsespec});
my $markup = LXRng::Markup::File->new('context' => $context);
my $subst = $lang->markuphandlers($context, $node, $markup);
-
- # Possible optimization: store cached file also as .gz,
- # and pass that on if the client accepts gzip-encoded
- # data. Saves us from compressing the cached file each
- # time it's needed, but requires a bit of fiddling with
- # perlio and the streams to get right. Also messes up
- # partial transfers.
- print("<pre id=\"file_contents\" class=\"full\"><ol><span>");
+
+ print("<pre id=\"file_contents\">".
+ "<div class=\"".($focus ? "done" : "pending").
+ "\" id=\"$shaid/0\">");
while (1) {
- my @frags = $markup->markupfile($subst, $parse);
+ my @frags = map { split(/(?<=\n)/, $_) }
+ $markup->markupfile($subst, $parse);
last unless @frags;
- print(@frags);
- print($cache @frags) if $cache;
+ foreach my $f (@frags) {
+ print($f) if $focus;
+ print($cache $f) if $cache;
+ if ($f =~ /\n$/s) {
+ $line++;
+ if ($line % FRAGMENT_SIZE == 0) {
+ print("\n" x FRAGMENT_SIZE) unless $focus;
+ if (defined($fline)) {
+ $focus = ($line <= ($fline + 100)
+ and $line > ($fline - FRAGMENT_SIZE));
+ }
+ print("</div>".
+ "<div class=\"".
+ ($focus ? "done" : "pending").
+ "\" id=\"$shaid/$line\">");
+ if ($cache) {
+ close($cache);
+ open($cache, '>', "$cfile/$line");
+ }
+ }
+ }
+ }
}
- print("</span></ol></pre>\n");
+ print("</div></pre>\n");
+ close($cache) if $cache;
}
return $shaid;
}
@@ -161,6 +193,7 @@ sub source {
my $pjx = CGI::Ajax->new('pjx_search' => '',
'pjx_load_file' => '',
+ 'pjx_load_fragment' => '',
'pjx_releases' => '');
$pjx->js_encode_function('escape');
@@ -181,10 +214,17 @@ sub source {
my $base = $context->base_url(1);
$base =~ s,/*$,/ajax+*/,;
+ # This is a bit fragile, but only covers a relatively
+ # esoteric corner case. (CGI::Ajax splits results on
+ # __pjx__, and there doesn't seem to be any provisions
+ # for escaping any randomly occurring split markers.)
+ my $js = $pjx->show_javascript();
+ $js =~ s/var splitval.*var data[^;]+/var data = rsp/;
+
$template->process('main.tt2',
{'context' => $context,
'base_url' => $base,
- 'javascript' => $pjx->show_javascript(),
+ 'javascript' => $js,
'is_ajax' => 1})
or die $template->error();
}
@@ -443,11 +483,13 @@ sub handle_ajax_request {
my $gzip = do_compress_response($query);
# $query->no_cache(1); FIXME -- not available with CGI.pm.
- print($query->header(-type => 'text/html',
- -charset => 'utf-8',
- -cache-control => 'no-store, no-cache, must-revalidate',
- $gzip ? (-content_encoding => 'gzip') : ()));
+ my %headers = (-type => 'text/html',
+ -charset => 'utf-8');
+ $headers{'-cache-control'} = 'no-store, no-cache, must-revalidate'
+ unless $context->param('fname') eq 'pjx_load_fragment';
+ $headers{'-content_encoding'} = 'gzip' if $gzip;
+ print($query->header(%headers));
binmode(\*STDOUT, ":gzip") if $gzip;
if ($context->param('fname') eq 'pjx_load_file') {
@@ -456,6 +498,22 @@ sub handle_ajax_request {
print_markedup_file($context, $template, $node);
}
+ elsif ($context->param('fname') eq 'pjx_load_fragment') {
+ my $shaid = $context->param('frag');
+ return unless $shaid =~
+ m|^[0-9a-z]{2}/[0-9a-z]{2}/[0-9a-z]{36}/[0-9]+$|;
+ return unless exists $context->config->{'cache'};
+ my $cfile = $context->config->{'cache'}.'/'.$shaid;
+ return unless -e $cfile;
+ open(my $cache, '<', $cfile) or return;
+
+ print($shaid.'|');
+ my $buf;
+ while (read($cache, $buf, 16384) > 0) {
+ print($buf);
+ }
+ close($cache);
+ }
elsif ($context->param('fname') eq 'pjx_search') {
if ($context->param('ajax_lookup') =~
/^[+ ](code|ident|file|text|ambig)=(.*)/)