package Pod::LaTeX;
-# Copyright (C) 2000 by Tim Jenness <t.jenness@jach.hawaii.edu>
-# All Rights Reserved.
-
=head1 NAME
Pod::LaTeX - Convert Pod data to formatted Latex
use vars qw/ $VERSION %HTML_Escapes @LatexSections /;
-$VERSION = '0.53';
+$VERSION = '0.54';
# Definitions of =headN -> latex mapping
@LatexSections = (qw/
# Up to "yuml" these are taken from the original pod2latex
# command written by Taro Kawagish (kawagish@imslab.co.jp)
+
%HTML_Escapes = (
- 'amp' => '&', # ampersand
- 'lt' => '$<$', # ' left chevron, less-than
- 'gt' => '$>$', # ' right chevron, greater-than
+ # lt, gt and verbar are inserted without math mode
+ # since the $$ will be added during general correction
+ # for those escpae characters
+ 'amp' => '\&', # ampersand
+ 'lt' => '<', # ' left chevron, less-than
+ 'gt' => '>', # ' right chevron, greater-than
'quot' => '"', # double quote
'sol' => '/',
- 'verbar' => '$|$',
+ 'verbar' => '|',
"Aacute" => "\\'{A}", # capital A, acute accent
"aacute" => "\\'{a}", # small a, acute accent
# Internals
$self->{_Lists} = []; # For nested lists
$self->{_suppress_all_para} = 0; # For =begin blocks
- $self->{_suppress_next_para} = 0; # For =for blocks
$self->{_dont_modify_any_para}=0; # For =begin blocks
- $self->{_dont_modify_next_para}=0; # For =for blocks
$self->{_CURRENT_HEAD1} = ''; # Name of current HEAD1 section
# Options - only initialise if not already set
\end{document}
-but can be more complicated if an index is required.
+but can be more complicated if a index is required.
Can be used to set or retrieve the current value.
$add = $parser->AddPostamble();
# return if we dont care
return if $command eq 'pod';
+ # Store a copy of the raw text in case we are in a =for
+ # block and need to preserve the existing latex
+ my $rawpara = $paragraph;
+
+ # Do the latex escapes
$paragraph = $self->_replace_special_chars($paragraph);
# Interpolate pod sequences in paragraph
$paragraph = $self->interpolate($paragraph, $line_num);
-
$paragraph =~ s/\s+$//;
+ # Replace characters that can only be done after
+ # interpolation of interior sequences
+ $paragraph = $self->_replace_special_chars_late($paragraph);
+
# Now run the command
if ($command eq 'over') {
} elsif ($command eq 'for') {
- # pass through if latex
- if ($paragraph =~ /^latex/i) {
+ # =for latex
+ # some latex
+
+ # With =for we will get the text for the full paragraph
+ # as well as the format name.
+ # We do not get an additional paragraph later on. The next
+ # paragraph is not governed by the =for
+
+ # The first line contains the format and the rest is the
+ # raw code.
+ my ($format, $chunk) = split(/\n/, $rawpara, 2);
+
+ # If we have got some latex code print it out immediately
+ # unmodified. Else do nothing.
+ if ($format =~ /^latex/i) {
# Make sure that next paragraph is not modfied before printing
- $self->{_dont_modify_next_para} = 1;
+ $self->_output( $chunk );
- } else {
- # Suppress the next paragraph unless it is latex
- $self->{_suppress_next_para} = 1
}
} elsif ($command eq 'end') {
my $self = shift;
my ($paragraph, $line_num, $parobj) = @_;
- # Expand paragraph unless in =for or =begin block
- if ($self->{_dont_modify_any_para} || $self->{_dont_modify_next_para}) {
+ # Expand paragraph unless in =begin block
+ if ($self->{_dont_modify_any_para}) {
# Just print as is
$self->_output($paragraph);
- # Reset flag if in =for
- $self->{_dont_modify_next_para} = 0;
-
} else {
return if $paragraph =~ /^\s+$/;
# Clean trailing space
$paragraph =~ s/\s+$//;
- # Clean tabs
- $paragraph =~ s/\t/ /g;
+ # Clean tabs. Routine taken from Tabs.pm
+ # by David Muir Sharnoff muir@idiom.com,
+ # slightly modified by hsmyers@sdragons.com 10/22/01
+ my @l = split("\n",$paragraph);
+ foreach (@l) {
+ 1 while s/(^|\n)([^\t\n]*)(\t+)/
+ $1. $2 . (" " x
+ (8 * length($3)
+ - (length($2) % 8)))
+ /sex;
+ }
+ $paragraph = join("\n",@l);
+ # End of change.
+
+
$self->_output('\begin{verbatim}' . "\n$paragraph\n". '\end{verbatim}'."\n");
}
my ($paragraph, $line_num, $parobj) = @_;
# print Dumper($self);
-
- # Expand paragraph unless in =for or =begin block
- if ($self->{_dont_modify_any_para} || $self->{_dont_modify_next_para}) {
+
+ # Expand paragraph unless in =begin block
+ if ($self->{_dont_modify_any_para}) {
# Just print as is
$self->_output($paragraph);
- # Reset flag if in =for
- $self->{_dont_modify_next_para} = 0;
-
return;
- }
+ }
+
-
# Escape latex special characters
$paragraph = $self->_replace_special_chars($paragraph);
my $expansion = $self->interpolate($paragraph, $line_num);
$expansion =~ s/\s+$//;
+ # Escape special characters that can not be done earlier
+ $expansion = $self->_replace_special_chars_late($expansion);
# If we are replacing 'head1 NAME' with a section
# we need to look in the paragraph and rewrite things
} elsif ($seq_command eq 'P') {
# Special markup for Pod::Hyperlink
- # Replace :: with /
+ # Replace :: with / - but not sure if I want to do this
+ # any more.
my $link = $seq_argument;
$link =~ s/::/\//g;
} elsif ($seq_command eq 'Q') {
# Special markup for Pod::Hyperlink
- return "\\textsf{$seq_argument}\n";
+ return "\\textsf{$seq_argument}";
} elsif ($seq_command eq 'X') {
# Index entries
# If paragraphs printing is turned off via =begin/=end or whatver
# simply return immediately
- return if ($self->{_suppress_all_para} || $self->{_suppress_next_para});
+ return if $self->{_suppress_all_para};
# Check to see whether we are starting a new lists
if (scalar($self->lists->[-1]->item) == 0) {
if ($type eq 'description') {
# Handle long items - long items do not wrap
- if (length($paragraph) < 40) {
- # A real description list item
- $self->_output("\\item[$paragraph] \\mbox{}");
+ # If the string is longer than 40 characters we split
+ # it into a real item header and some bold text.
+ my $maxlen = 40;
+ my ($hunk1, $hunk2) = $self->_split_delimited( $paragraph, $maxlen );
+
+ # Print the first hunk
+ $self->_output("\n\\item[$hunk1] ");
+
+ # and the second hunk if it is defined
+ if ($hunk2) {
+ $self->_output("\\textbf{$hunk2}");
} else {
- # The item is now simply bold text
- $self->_output(qq{\\item \\textbf{$paragraph}});
+ # Not there so make sure we have a new line
+ $self->_output("\\mbox{}");
}
} else {
# out the something
my $extra_info = $paragraph;
$extra_info =~ s/^\*\s*//;
- $self->_output("\\item $extra_info");
+ $self->_output("\n\\item $extra_info");
}
# Store the item name in the object. Required so that
my $star = ($level >= $self->LevelNoNum ? '*' : '');
# Section
- $self->_output("\\" .$LatexSections[$level] .$star ."{$paragraph\\label{".$label ."}\\index{".$index."}}");
+ $self->_output("\\" .$LatexSections[$level] .$star ."{$paragraph\\label{".$label ."}\\index{".$index."}}\n");
}
$parser->_output($text);
-Does not write anything if a =begin or =for is active that should be
+Does not write anything if a =begin is active that should be
ignored.
=cut
my $self = shift;
my $text = shift;
- print { $self->output_handle } $text
- unless $self->{_suppress_all_para} ||
- $self->{_suppress_next_para};
+ print { $self->output_handle } $text
+ unless $self->{_suppress_all_para};
- # Reset pargraph stuff for =for
- $self->{_suppress_next_para} = 0
- if $self->{_suppress_next_para};
}
$escaped = $parser->_replace_special_chars($paragraph);
-Need to call this routine before interior_sequences are munged but
-not if verbatim.
+Need to call this routine before interior_sequences are munged but not
+if verbatim. It must be called before interpolation of interior
+sequences so that curly brackets and special latex characters inserted
+during interpolation are not themselves escaped. This means that < and
+> can not be modified here since the text still contains interior
+sequences.
Special characters and the C<latex> equivalents are:
\ $\backslash$
^ \^{}
~ \~{}
- | $|$
=cut
# Replace tilde (~) with \texttt{\~{}}
$paragraph =~ s/~/\\texttt\{\\~\{\}\}/g;
+ # Now add the dollars around each \backslash
+ $paragraph =~ s/(\\backslash)/\$$1\$/g;
+ return $paragraph;
+}
+
+=item B<_replace_special_chars_late>
+
+Replace special characters that can not be replaced before interior
+sequence interpolation. See C<_replace_special_chars> for a routine
+to replace special characters prior to interpolation of interior
+sequences.
+
+Does the following transformation:
+
+ < $<$
+ > $>$
+ | $|$
+
+
+=cut
+
+sub _replace_special_chars_late {
+ my $self = shift;
+ my $paragraph = shift;
+
+ # < and >
+ $paragraph =~ s/(<|>)/\$$1\$/g;
+
# Replace | with $|$
$paragraph =~ s'\|'$|$'g;
- # Now add the dollars around each \backslash
- $paragraph =~ s/(\\backslash)/\$$1\$/g;
return $paragraph;
}
return $paragraph
}
+=item B<_split_delimited>
+
+Split the supplied string into two parts at approximately the
+specified word boundary. Special care is made to make sure that it
+does not split in the middle of some curly brackets.
+
+e.g. "this text is \textbf{very bold}" would not be split into
+"this text is \textbf{very" and " bold".
+
+ ($hunk1, $hunk2) = $self->_split_delimited( $para, $length);
+
+The length indicates the maximum length of hunk1.
+
+=cut
+
+# initially Supplied by hsmyers@sdragons.com
+# 10/25/01, utility to split \hbox
+# busting lines. Reformatted by TimJ to match module style.
+sub _split_delimited {
+ my $self = shift;
+ my $input = shift;
+ my $limit = shift;
+
+ # Return immediately if already small
+ return ($input, '') if length($input) < $limit;
+
+ my @output;
+ my $s = '';
+ my $t = '';
+ my $depth = 0;
+ my $token;
+
+ $input =~ s/\n/ /gm;
+ $input .= ' ';
+ foreach ( split ( //, $input ) ) {
+ $token .= $_;
+ if (/\{/) {
+ $depth++;
+ } elsif ( /}/ ) {
+ $depth--;
+ } elsif ( / / and $depth == 0) {
+ push @output, $token if ( $token and $token ne ' ' );
+ $token = '';
+ }
+ }
+
+ foreach (@output) {
+ if (length($s) < $limit) {
+ $s .= $_;
+ } else {
+ $t .= $_;
+ }
+ }
+
+ # Tidy up
+ $s =~ s/\s+$//;
+ $t =~ s/\s+$//;
+ return ($s,$t);
+}
+
=back
=end __PRIVATE__
Tim Jenness E<lt>t.jenness@jach.hawaii.eduE<gt>
+Bug fixes have been received from: Simon Cozens
+E<lt>simon@cozens.netE<gt>, Mark A. Hershberger
+E<lt>mah@everybody.orgE<gt>, Marcel Grunauer
+E<lt>marcel@codewerk.comE<gt> and Hugh S Myers
+E<lt>hsmyers@sdragons.comE<gt>.
+
=head1 COPYRIGHT
-Copyright (C) 2000 Tim Jenness. All Rights Reserved.
+Copyright (C) 2000-2001 Tim Jenness. All Rights Reserved.
-This program is free software; you can redistribute it and/or modify it
-under the same terms as Perl itself.
+This program is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself.
=begin __PRIVATE__
=head1 REVISION
-$Id: LaTeX.pm,v 1.6 2000/08/21 09:05:03 timj Exp $
+$Id: LaTeX.pm,v 1.12 2001/11/20 20:59:26 timj Exp $
=end __PRIVATE__