aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArne Georg Gleditsch <argggh@lxr.linpro.no>2008-02-17 23:02:22 +0100
committerArne Georg Gleditsch <argggh@lxr.linpro.no>2008-02-17 23:02:22 +0100
commit2d684362a152e9407ae143536fec2c33ffd48e6d (patch)
treee4653c9af0a6fd2c4f10e1deaf4781feb2f2c965
parentdb9049079b4a34b270283512941cfa19ac8d20aa (diff)
Better PDF generation, improved line split handling.
-rw-r--r--lib/LXRng/Web.pm122
-rw-r--r--tmpl/print_pdf.tt23
-rw-r--r--tmpl/tex_funcs.tt239
3 files changed, 104 insertions, 60 deletions
diff --git a/lib/LXRng/Web.pm b/lib/LXRng/Web.pm
index d7f9be4..6888b49 100644
--- a/lib/LXRng/Web.pm
+++ b/lib/LXRng/Web.pm
@@ -37,9 +37,6 @@ 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;
@@ -592,25 +589,25 @@ sub generate_pdf {
my $tempdir = tempdir(CLEANUP => 1);
my %tspecials = (
- '$' => '\$', '*' => "\$\\ast\$",
- '&' => '\&', '%' => '\%',
- '#' => '\#', '_' => '\_',
- '^' => '\^{}', '{' => '\{',
- '}' => '\}', '|' => "\$|\$",
- '[' => '{[}', ']' => '{]}',
- "'" => "{'}", "\"" => "\\string\"",
- '~' => '\~{}', '<' => "\$<\$",
- '>' => "\$>\$", "\\" => "\$\\backslash\$",
- '-' => '\dash{}',
+ '$' => '\$', '*' => "\$\\ast\$",
+ '&' => '\&', '%' => '\%',
+ '#' => '\#', '_' => '\_',
+ '^' => '\^{}', '{' => '\{',
+ '}' => '\}', '|' => "\$|\$",
+ '[' => '{[}', ']' => '{]}',
+ "'" => "{'}", "\"" => "\\string\"",
+ '~' => '\~{}', '<' => "\$<\$",
+ '>' => "\$>\$", "\\" => "\$\\backslash\$",
+ '-' => '\dash{}',
# These are latin1-replacements, and interact badly with utf8...
- "\242" => '?', "\244" => '?',
- "\245" => '?', "\246" => '?',
- "\252" => "\$\252\$", "\254" => "\$\254\$",
- "\255" => "\\dash{}", "\260" => "\$\260\$",
- "\261" => "\$\261\$", "\262" => "\$\262\$",
- "\263" => "\$\263\$", "\265" => "\$\265\$",
- "\271" => "\$\271\$", "\272" => "\$\272\$",
- "\327" => "\$\327\$", "\367" => "\$\367\$",
+ "\242" => '?', "\244" => '?',
+ "\245" => '?', "\246" => '?',
+ "\252" => "\$\252\$", "\254" => "\$\254\$",
+ "\255" => "\\dash{}", "\260" => "\$\260\$",
+ "\261" => "\$\261\$", "\262" => "\$\262\$",
+ "\263" => "\$\263\$", "\265" => "\$\265\$",
+ "\271" => "\$\271\$", "\272" => "\$\272\$",
+ "\327" => "\$\327\$", "\367" => "\$\367\$",
);
my $tspecials = join('', map { quotemeta($_) } keys(%tspecials));
@@ -630,7 +627,7 @@ sub generate_pdf {
my $resre;
if (%$res) {
$resre = '(?:(?<=[\s\W])|^)('.
- join('|', map { my $c = $_; $c =~ s/\#/\\\#/g; quotemeta($c) }
+ join('|', map { "\Q$_\E" }
sort { length($b) <=> length($a) }
keys %$res).')(?=$|[\s\W])';
}
@@ -639,10 +636,12 @@ sub generate_pdf {
my $row = 1;
my $col = 0;
my $line = '\\lxrln{1}';
+ my %ptabs = ();
+ my %ntabs = ();
while (1) {
my ($btype, $frag) = $parse->nextfrag;
-
+
last unless defined $frag;
$btype ||= 'code';
@@ -655,6 +654,8 @@ sub generate_pdf {
if ($part eq "\n") {
push(@lines, $line);
+ %ptabs = %ntabs;
+ %ntabs = ();
$col = 0;
$row++;
@@ -667,56 +668,61 @@ sub generate_pdf {
next;
}
- if ($part =~ /^(.*? +)(.*)/) {
- unshift(@parts, $2);
+ if ($part =~ /^(.*?)( +)(.*)/) {
+ unshift(@parts, $3);
$part = $1;
- $align = 1;
- }
-
- $col += length($part);
-
- if ($col > PDF_LINELEN) {
- unshift(@parts,
- substr($part, PDF_LINELEN - $col, length($part), ''));
- if ($part =~ s/([^\s_,\(\)\{\}\/\=\-\+\*\<\>\[\]\.]+)$//) {
- if (length($1) < 20) {
- unshift(@parts, $1);
- }
- else {
- $part .= $1;
- }
+ if (length($2) > 2 or $ptabs{$col + length($1) + length($2)}) {
+ $align = 1;
+ $col += length($2);
+ $ntabs{$col + length($part)} = 1;
+ }
+ else {
+ $part .= $2;
}
- $align = 0;
- $cont = 1;
}
+ $col += length($part);
- $part =~ s(([$tspecials\0-\010\013\014\016-\037\200-\240]))
- (exists $tspecials{$1} ? $tspecials{$1} : '?')ge;
-
if ($btype eq 'code') {
- $part =~ s/$resre/\\textbf{$1}/g if $resre;
+ $part =~ s/$resre/\\bf{}\\sffamily{}$1\\sf{}/g if $resre;
}
elsif ($btype eq 'include') {
- $part =~ s/$resre/\\textbf{$1}/ if $resre;
+ # This is a bit of a special treatment for C...
+ $part =~ s((<[^>]*>|\"[^\"]*\")|$resre)
+ ($1 ? "$1" : "\\bf{}\\sffamily{}$2\\sf{}")ge if $resre;
}
elsif ($btype eq 'comment') {
- $part = '\textit{'.$part.'}';
+ $part = '\\em{}'.$part.'\\sf{}';
}
elsif ($btype eq 'string') {
- $part = '\texttt{'.$part.'}';
+ $part = '\\tt{}'.$part.'\\sf{}';
}
- # Common fixed-width "ascii-art" characters.
- $part =~ s/(\$\\ast\$|=)/'\\makebox['.PDF_CHARPTS."pt][c]{$1}"/ge;
+ $part =~ s{(\\(?:sf|bf|em|tt|sffamily)\{\})|
+ ([*=])|
+ ([ ]+)|
+ ([$tspecials\0-\010\013\014\016-\037\200-\240])|
+ ([[:alnum:]]+|.)}
+ {
+ if (defined $1) {
+ $1;
+ }
+ elsif (defined $2) {
+ "\\lxgr{".(exists $tspecials{$2} ? $tspecials{$2} : $2)."}";
+ }
+ elsif (defined $3) {
+ "\\lxws{$3}";
+ }
+ elsif (defined $4) {
+ "\\lxlt{".(exists $tspecials{$4} ? $tspecials{$4} : '?')."}";
+ }
+ else {
+ "\\lxlt{$5}";
+ }
+ }gex;
+
$line .= $part;
if ($align) {
- $line = '\\makebox['.int($col * PDF_CHARPTS).
- 'pt][l]{'.$line.'}';
- }
- if ($cont) {
- push(@lines, "$line\\raisebox{-2pt}{\\ArrowBoldRightStrobe}");
- $line = '\\raisebox{-2pt}{\\ArrowBoldDownRight} ';
- $col = 3;
+ $line .= "\\lxalign{$col}";
}
}
}
diff --git a/tmpl/print_pdf.tt2 b/tmpl/print_pdf.tt2
index 0577159..29aca7c 100644
--- a/tmpl/print_pdf.tt2
+++ b/tmpl/print_pdf.tt2
@@ -10,6 +10,7 @@
\usepackage{fancyhdr}
\usepackage{bbding}
\pagestyle{fancy}
+[% INCLUDE tex_funcs.tt2 %]
\begin{document}
\setlength\baselineskip{7pt}
\setlength\parskip{.3\baselineskip}
@@ -17,8 +18,6 @@
\renewcommand{\headrulewidth}{0pt}
\fancyhead{}
\fancyfoot{}
-\def\dash{\raise2.1pt\hbox{\rule{5pt}{0.3pt}}\hspace{1pt}}
-\newcommand\lxrln[1]{\tiny\hspace*{-4em}\makebox[4em][r]{#1\hspace{1.5ex}}\small}
\sffamily\small
%% I kinda like the proportional fonts, but expect they won't be
%% everyone's cup of tea. Uncomment next line to use monospace font.
diff --git a/tmpl/tex_funcs.tt2 b/tmpl/tex_funcs.tt2
new file mode 100644
index 0000000..36fee92
--- /dev/null
+++ b/tmpl/tex_funcs.tt2
@@ -0,0 +1,39 @@
+% -*- latex -*-
+
+% LXRng formatting functions
+\makeatletter
+\newbox\lx@box
+\newdimen\lx@charwd\advance\lx@charwd 6.4pt
+\newdimen\lx@wrapped
+\renewcommand\\{\newline\advance\lx@used-\lx@used\advance\lx@wrapped-\lx@wrapped}
+\newdimen\lx@used
+\newdimen\lx@linewd\advance\lx@linewd\textwidth\advance\lx@linewd-1em
+
+% Words
+\def\lxlt#1{\setbox\lx@box\hbox{#1}%
+\advance\lx@used\wd\lx@box%
+\ifdim\lx@used>\lx@linewd%
+\hspace*{-\lx@used}\hspace{\wd\lx@box}\hspace*{\lx@linewd}%
+\raisebox{-2pt}{\ArrowBoldRightStrobe}\\%
+\raisebox{-2pt}{\ArrowBoldDownRight} %
+\advance\lx@wrapped\lx@linewd
+\advance\lx@used-\lx@used%
+\advance\lx@used 3\lx@charwd%
+\advance\lx@used\wd\lx@box%
+\else\fi%
+\usebox\lx@box}
+
+% Alignment
+\def\lxalign#1{\hspace*{#1\lx@charwd}\hspace*{-\lx@wrapped}\hspace*{-\lx@used}%
+\advance\lx@used-\lx@used\advance\lx@used #1\lx@charwd}
+
+% Fixed-width chars
+\def\lxgr#1{\lxlt{\makebox[\lx@charwd][l]{#1}}}
+
+% Whitespace
+\def\lxws#1{\setbox\lx@box\hbox{#1}\hspace*{\wd\lx@box}\advance\lx@used\wd\lx@box}
+
+\newcommand\lxrln[1]{\tiny\hspace*{-4em}\makebox[4em][r]{#1\hspace{1.5ex}}\small}
+\def\dash{\raise2.1pt\hbox{\rule{5pt}{0.3pt}}\hspace{1pt}}
+
+\makeatother