[perl #35847] File::Find not performing as documented
[p5sagit/p5-mst-13.2.git] / lib / Pod / Text.pm
index 4f8a222..1028f2e 100644 (file)
@@ -1,15 +1,16 @@
 # 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
@@ -42,7 +43,7 @@ use vars qw(@ISA @EXPORT %ESCAPES $VERSION);
 # 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;
 
 
 ##############################################################################
@@ -176,6 +177,7 @@ sub initialize {
 
     $$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};
@@ -194,8 +196,11 @@ sub initialize {
         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;
 
@@ -217,7 +222,6 @@ sub command {
     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 (@_);
@@ -227,7 +231,7 @@ sub 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;
     }
 }
@@ -264,18 +268,18 @@ sub textblock {
     }
 }
 
-# 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');
@@ -291,14 +295,13 @@ sub interior_sequence {
             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.
@@ -316,9 +319,8 @@ sub interior_sequence {
     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";
     }
 }
 
@@ -343,61 +345,33 @@ sub preprocess_paragraph {
 
 # 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);
@@ -406,6 +380,7 @@ sub cmd_over {
 # 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;
@@ -421,7 +396,7 @@ sub cmd_item {
     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
@@ -457,11 +432,11 @@ sub cmd_for {
 
 
 ##############################################################################
-# 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] . '*' }
@@ -488,7 +463,7 @@ sub seq_c {
        | \$+ [\#^]? \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
@@ -512,6 +487,30 @@ sub seq_l {
 
 
 ##############################################################################
+# 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
 ##############################################################################
 
@@ -533,19 +532,28 @@ sub item {
     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 ($_);
@@ -716,6 +724,13 @@ it's the expected formatting for manual pages; if you're formatting
 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
@@ -769,7 +784,7 @@ and the input file it was given could not be opened.
 (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.
@@ -779,9 +794,9 @@ 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
@@ -813,6 +828,10 @@ subclass of it does.  Look for L<Pod::Text::Termcap>.
 
 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
@@ -821,7 +840,7 @@ Pod::Parser by Brad Appleton <bradapp@enteract.com>.
 
 =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.