# Pod::Text -- Convert POD data to formatted ASCII text.
-# $Id: Text.pm,v 2.14 2001/11/15 08:03:18 eagle Exp $
+# $Id: Text.pm,v 2.21 2002/08/04 03:34:58 eagle Exp $
#
-# Copyright 1999, 2000, 2001 by Russ Allbery <rra@stanford.edu>
+# Copyright 1999, 2000, 2001, 2002 by Russ Allbery <rra@stanford.edu>
#
# This program is free software; you may redistribute it and/or modify it
# under the same terms as Perl itself.
#
-# This module replaces the old Pod::Text that came with versions of Perl prior
-# to 5.6.0, and attempts to match its output except for some specific
-# circumstances where other decisions seemed to produce better output. It
-# uses Pod::Parser and is designed to be very easy to subclass.
+# This module converts POD to formatted text. It replaces the old Pod::Text
+# module that came with versions of Perl prior to 5.6.0 and attempts to match
+# its output except for some specific circumstances where other decisions
+# seemed to produce better output. It uses Pod::Parser and is designed to be
+# very easy to subclass.
#
# Perl core hackers, please note that this module is also separately
# maintained outside of the Perl core as part of the podlators. Please send
# Don't use the CVS revision as the version, since this module is also in Perl
# core and too many things could munge CVS magic revision strings. This
# number should ideally be the same as the CVS revision in podlators, however.
-$VERSION = 2.14;
+$VERSION = 2.21;
##############################################################################
$$self{alt} = 0 unless defined $$self{alt};
$$self{indent} = 4 unless defined $$self{indent};
+ $$self{margin} = 0 unless defined $$self{margin};
$$self{loose} = 0 unless defined $$self{loose};
$$self{sentence} = 0 unless defined $$self{sentence};
$$self{width} = 76 unless defined $$self{width};
croak qq(Invalid quote specification "$$self{quotes}");
}
- $$self{INDENTS} = []; # Stack of indentations.
- $$self{MARGIN} = $$self{indent}; # Current left margin in spaces.
+ # Stack of indentations.
+ $$self{INDENTS} = [];
+
+ # Current left margin.
+ $$self{MARGIN} = $$self{indent} + $$self{margin};
$self->SUPER::initialize;
my $command = shift;
return if $command eq 'pod';
return if ($$self{EXCLUDE} && $command ne 'end');
- $self->item ("\n") if defined $$self{ITEM};
if ($self->can ('cmd_' . $command)) {
$command = 'cmd_' . $command;
$self->$command (@_);
($file, $line) = $paragraph->file_line;
$text =~ s/\n+\z//;
$text = " $text" if ($text =~ /^\S/);
- warn qq($file:$line: Unknown command paragraph "=$command$text"\n);
+ warn qq($file:$line: Unknown command paragraph: =$command$text\n);
return;
}
}
}
}
-# Called for an interior sequence. Gets the command, argument, and a
+# Called for a formatting code. Gets the command, argument, and a
# Pod::InteriorSequence object and is expected to return the resulting text.
-# Calls code, bold, italic, file, and link to handle those types of sequences,
-# and handles S<>, E<>, X<>, and Z<> directly.
+# Calls methods for code, bold, italic, file, and link to handle those types
+# of codes, and handles S<>, E<>, X<>, and Z<> directly.
sub interior_sequence {
local $_;
my ($self, $command, $seq);
($self, $command, $_, $seq) = @_;
# We have to defer processing of the inside of an L<> formatting code. If
- # this sequence is nested inside an L<> sequence, return the literal raw
- # text of it.
+ # this code is nested inside an L<> code, return the literal raw text of
+ # it.
my $parent = $seq->nested;
while (defined $parent) {
return $seq->raw_text if ($parent->cmd_name eq 'L');
return chr;
} else {
return $ESCAPES{$_} if defined $ESCAPES{$_};
- my $seq = shift;
my ($file, $line) = $seq->file_line;
warn "$file:$line: Unknown escape: E<$_>\n";
return "E<$_>";
}
}
- # For all the other sequences, empty content produces no output.
+ # For all the other formatting codes, empty content produces no output.
return if $_ eq '';
# For S<>, compress all internal whitespace and then map spaces to \01.
elsif ($command eq 'I') { return $self->seq_i ($_) }
elsif ($command eq 'L') { return $self->seq_l ($_, $seq) }
else {
- my $seq = shift;
my ($file, $line) = $seq->file_line;
- warn "$file:$line: Unknown sequence $command<$_>\n";
+ warn "$file:$line: Unknown formatting code: $command<$_>\n";
}
}
# First level heading.
sub cmd_head1 {
- my $self = shift;
- local $_ = shift;
- s/\s+$//;
- $_ = $self->interpolate ($_, shift);
- if ($$self{alt}) {
- $self->output ("\n==== $_ ====\n\n");
- } else {
- $_ .= "\n" if $$self{loose};
- $self->output ($_ . "\n");
- }
+ my ($self, $text, $line) = @_;
+ $self->heading ($text, $line, 0, '====');
}
# Second level heading.
sub cmd_head2 {
- my $self = shift;
- local $_ = shift;
- s/\s+$//;
- $_ = $self->interpolate ($_, shift);
- if ($$self{alt}) {
- $self->output ("\n== $_ ==\n\n");
- } else {
- $self->output (' ' x ($$self{indent} / 2) . $_ . "\n\n");
- }
+ my ($self, $text, $line) = @_;
+ $self->heading ($text, $line, $$self{indent} / 2, '== ');
}
# Third level heading.
sub cmd_head3 {
- my $self = shift;
- local $_ = shift;
- s/\s+$//;
- $_ = $self->interpolate ($_, shift);
- if ($$self{alt}) {
- $self->output ("\n= $_ =\n\n");
- } else {
- $self->output (' ' x ($$self{indent} * 2 / 3 + 0.5) . $_ . "\n\n");
- }
+ my ($self, $text, $line) = @_;
+ $self->heading ($text, $line, $$self{indent} * 2 / 3 + 0.5, '= ');
}
# Third level heading.
sub cmd_head4 {
- my $self = shift;
- local $_ = shift;
- s/\s+$//;
- $_ = $self->interpolate ($_, shift);
- if ($$self{alt}) {
- $self->output ("\n- $_ -\n\n");
- } else {
- $self->output (' ' x ($$self{indent} * 3 / 4 + 0.5) . $_ . "\n\n");
- }
+ my ($self, $text, $line) = @_;
+ $self->heading ($text, $line, $$self{indent} * 3 / 4 + 0.5, '- ');
}
# Start a list.
sub cmd_over {
my $self = shift;
local $_ = shift;
+ $self->item ("\n\n") if defined $$self{ITEM};
unless (/^[-+]?\d+\s+$/) { $_ = $$self{indent} }
push (@{ $$self{INDENTS} }, $$self{MARGIN});
$$self{MARGIN} += ($_ + 0);
# End a list.
sub cmd_back {
my ($self, $text, $line, $paragraph) = @_;
+ $self->item ("\n\n") if defined $$self{ITEM};
$$self{MARGIN} = pop @{ $$self{INDENTS} };
unless (defined $$self{MARGIN}) {
my $file;
if (defined $$self{ITEM}) { $self->item }
local $_ = shift;
s/\s+$//;
- $$self{ITEM} = $self->interpolate ($_);
+ $$self{ITEM} = $_ ? $self->interpolate ($_) : '*';
}
# Begin a block for a particular translator. Setting VERBATIM triggers
##############################################################################
-# Interior sequences
+# Formatting codes
##############################################################################
-# The simple formatting ones. These are here mostly so that subclasses can
-# override them and do more complicated things.
+# The simple ones. These are here mostly so that subclasses can override them
+# and do more complicated things.
sub seq_b { return $_[0]{alt} ? "``$_[1]''" : $_[1] }
sub seq_f { return $_[0]{alt} ? "\"$_[1]\"" : $_[1] }
sub seq_i { return '*' . $_[1] . '*' }
| \$+ [\#^]? \S $index # special ($^Foo, $")
| [\$\@%&*]+ \#? [:\'\w]+ $index # plain var or func
| [\$\@%&*]* [:\'\w]+ (?: -> )? \(\s*[^\s,]\s*\) # 0/1-arg func call
- | [+-]? [\d.]+ (?: [eE] [+-]? \d+ )? # a number
+ | [+-]? ( \d[\d.]* | \.\d+ ) (?: [eE][+-]?\d+ )? # a number
| 0x [a-fA-F\d]+ # a hex constant
)
\s*\z
##############################################################################
+# Header handling
+##############################################################################
+
+# The common code for handling all headers. Takes the interpolated header
+# text, the line number, the indentation, and the surrounding marker for the
+# alt formatting method.
+sub heading {
+ my ($self, $text, $line, $indent, $marker) = @_;
+ $self->item ("\n\n") if defined $$self{ITEM};
+ $text =~ s/\s+$//;
+ $text = $self->interpolate ($text, $line);
+ if ($$self{alt}) {
+ my $closemark = reverse (split (//, $marker));
+ my $margin = ' ' x $$self{margin};
+ $self->output ("\n" . "$margin$marker $text $closemark" . "\n\n");
+ } else {
+ $text .= "\n" if $$self{loose};
+ my $margin = ' ' x ($$self{margin} + $indent);
+ $self->output ($margin . $text . "\n");
+ }
+}
+
+
+##############################################################################
# List handling
##############################################################################
undef $$self{ITEM};
my $indent = $$self{INDENTS}[-1];
unless (defined $indent) { $indent = $$self{indent} }
- my $space = ' ' x $indent;
- $space =~ s/^ /:/ if $$self{alt};
+ my $margin = ' ' x $$self{margin};
if (!$_ || /^\s+$/ || ($$self{MARGIN} - $indent < length ($tag) + 1)) {
- my $margin = $$self{MARGIN};
+ my $realindent = $$self{MARGIN};
$$self{MARGIN} = $indent;
my $output = $self->reformat ($tag);
+ $output =~ s/^$margin /$margin:/ if ($$self{alt} && $indent > 0);
$output =~ s/\n*$/\n/;
+
+ # If the text is just whitespace, we have an empty item paragraph;
+ # this can result from =over/=item/=back without any intermixed
+ # paragraphs. Insert some whitespace to keep the =item from merging
+ # into the next paragraph.
+ $output .= "\n" if $_ && $_ =~ /^\s*$/;
+
$self->output ($output);
- $$self{MARGIN} = $margin;
- $self->output ($self->reformat ($_)) if /\S/;
+ $$self{MARGIN} = $realindent;
+ $self->output ($self->reformat ($_)) if $_ && /\S/;
} else {
+ my $space = ' ' x $indent;
+ $space =~ s/^$margin /$margin:/ if $$self{alt};
$_ = $self->reformat ($_);
- s/^ /:/ if ($$self{alt} && $indent > 0);
+ s/^$margin /$margin:/ if ($$self{alt} && $indent > 0);
my $tagspace = ' ' x length $tag;
s/^($space)$tagspace/$1$tag/ or warn "Bizarre space in item";
$self->output ($_);
arbitrary text documents, setting this to true may result in more pleasing
output.
+=item margin
+
+The width of the left margin in spaces. Defaults to 0. This is the margin
+for all text, including headings, not the amount by which regular text is
+indented; for the latter, see the I<indent> option. To set the right
+margin, see the I<width> option.
+
=item quotes
Sets the quote marks used to surround CE<lt>> text. If the value is a
(F) The quote specification given (the quotes option to the constructor) was
invalid. A quote specification must be one, two, or four characters long.
-=item %s:%d: Unknown command paragraph "%s".
+=item %s:%d: Unknown command paragraph: %s
(W) The POD source contained a non-standard command paragraph (something of
the form C<=command args>) that Pod::Man didn't know about. It was ignored.
(W) The POD source contained an C<EE<lt>E<gt>> escape that Pod::Text didn't
know about.
-=item %s:%d: Unknown sequence: %s
+=item %s:%d: Unknown formatting code: %s
-(W) The POD source contained a non-standard internal sequence (something of
+(W) The POD source contained a non-standard formatting code (something of
the form C<XE<lt>E<gt>>) that Pod::Text didn't know about.
=item %s:%d: Unmatched =back
L<Pod::Parser>, L<Pod::Text::Termcap>, L<pod2text(1)>
+The current version of this module is always available from its web site at
+L<http://www.eyrie.org/~eagle/software/podlators/>. It is also part of the
+Perl core distribution as of 5.6.0.
+
=head1 AUTHOR
Russ Allbery <rra@stanford.edu>, based I<very> heavily on the original
=head1 COPYRIGHT AND LICENSE
-Copyright 1999, 2000, 2001 by Russ Allbery <rra@stanford.edu>.
+Copyright 1999, 2000, 2001, 2002 by Russ Allbery <rra@stanford.edu>.
This program is free software; you may redistribute it and/or modify it
under the same terms as Perl itself.