diff options
-rw-r--r-- | MANIFEST | 2 | ||||
-rw-r--r-- | lib/Pod/Text.pm | 1133 | ||||
-rw-r--r-- | lib/Pod/Text/Color.pm | 116 | ||||
-rw-r--r-- | lib/Pod/Text/Termcap.pm | 141 | ||||
-rw-r--r-- | pod/pod2text.PL | 165 |
5 files changed, 987 insertions, 570 deletions
@@ -610,6 +610,8 @@ lib/Pod/Parser.pm Pod-Parser - define base class for parsing POD lib/Pod/PlainText.pm Pod-Parser - convert POD data to formatted ASCII text lib/Pod/Select.pm Pod-Parser - select portions of POD docs lib/Pod/Text.pm Convert POD data to formatted ASCII text +lib/Pod/Text/Color.pm Convert POD data to color ASCII text +lib/Pod/Text/Termcap.pm Convert POD data to ASCII text with format escapes lib/Pod/Usage.pm Pod-Parser - print usage messages lib/Search/Dict.pm Perform binary search on dictionaries lib/SelectSaver.pm Enforce proper select scoping diff --git a/lib/Pod/Text.pm b/lib/Pod/Text.pm index d62b7a3241..88c594fdd4 100644 --- a/lib/Pod/Text.pm +++ b/lib/Pod/Text.pm @@ -1,631 +1,634 @@ -package Pod::Text; - -=head1 NAME +# Pod::Text -- Convert POD data to formatted ASCII text. +# $Id: Text.pm,v 0.2 1999/06/13 02:44:01 eagle Exp $ +# +# Copyright 1999 by Russ Allbery <rra@stanford.edu> +# +# This program is free software; you can redistribute it and/or modify it +# under the same terms as Perl itself. +# +# This module may potentially be a replacement for Pod::Text, although it +# does not (at the current time) attempt to match the output of Pod::Text +# and makes several different formatting choices (mostly in the direction of +# less markup). It uses Pod::Parser and is designed to be very easy to +# subclass. + +############################################################################ +# Modules and declarations +############################################################################ -Pod::Text - convert POD data to formatted ASCII text +package Pod::Text; -=head1 SYNOPSIS +require 5.004; + +use Carp qw(carp); +use Pod::Parser (); + +use strict; +use vars qw(@ISA %ESCAPES $VERSION); + +@ISA = qw(Pod::Parser); + +$VERSION = '0.01'; + + +############################################################################ +# Table of supported E<> escapes +############################################################################ + +# This table is taken near verbatim from Pod::PlainText in Pod::Parser, +# which got it near verbatim from Pod::Text. It is therefore credited to +# Tom Christiansen, and I'm glad I didn't have to write it. :) +%ESCAPES = ( + 'amp' => '&', # ampersand + 'lt' => '<', # left chevron, less-than + 'gt' => '>', # right chevron, greater-than + 'quot' => '"', # double quote + + "Aacute" => "\xC1", # capital A, acute accent + "aacute" => "\xE1", # small a, acute accent + "Acirc" => "\xC2", # capital A, circumflex accent + "acirc" => "\xE2", # small a, circumflex accent + "AElig" => "\xC6", # capital AE diphthong (ligature) + "aelig" => "\xE6", # small ae diphthong (ligature) + "Agrave" => "\xC0", # capital A, grave accent + "agrave" => "\xE0", # small a, grave accent + "Aring" => "\xC5", # capital A, ring + "aring" => "\xE5", # small a, ring + "Atilde" => "\xC3", # capital A, tilde + "atilde" => "\xE3", # small a, tilde + "Auml" => "\xC4", # capital A, dieresis or umlaut mark + "auml" => "\xE4", # small a, dieresis or umlaut mark + "Ccedil" => "\xC7", # capital C, cedilla + "ccedil" => "\xE7", # small c, cedilla + "Eacute" => "\xC9", # capital E, acute accent + "eacute" => "\xE9", # small e, acute accent + "Ecirc" => "\xCA", # capital E, circumflex accent + "ecirc" => "\xEA", # small e, circumflex accent + "Egrave" => "\xC8", # capital E, grave accent + "egrave" => "\xE8", # small e, grave accent + "ETH" => "\xD0", # capital Eth, Icelandic + "eth" => "\xF0", # small eth, Icelandic + "Euml" => "\xCB", # capital E, dieresis or umlaut mark + "euml" => "\xEB", # small e, dieresis or umlaut mark + "Iacute" => "\xCD", # capital I, acute accent + "iacute" => "\xED", # small i, acute accent + "Icirc" => "\xCE", # capital I, circumflex accent + "icirc" => "\xEE", # small i, circumflex accent + "Igrave" => "\xCD", # capital I, grave accent + "igrave" => "\xED", # small i, grave accent + "Iuml" => "\xCF", # capital I, dieresis or umlaut mark + "iuml" => "\xEF", # small i, dieresis or umlaut mark + "Ntilde" => "\xD1", # capital N, tilde + "ntilde" => "\xF1", # small n, tilde + "Oacute" => "\xD3", # capital O, acute accent + "oacute" => "\xF3", # small o, acute accent + "Ocirc" => "\xD4", # capital O, circumflex accent + "ocirc" => "\xF4", # small o, circumflex accent + "Ograve" => "\xD2", # capital O, grave accent + "ograve" => "\xF2", # small o, grave accent + "Oslash" => "\xD8", # capital O, slash + "oslash" => "\xF8", # small o, slash + "Otilde" => "\xD5", # capital O, tilde + "otilde" => "\xF5", # small o, tilde + "Ouml" => "\xD6", # capital O, dieresis or umlaut mark + "ouml" => "\xF6", # small o, dieresis or umlaut mark + "szlig" => "\xDF", # small sharp s, German (sz ligature) + "THORN" => "\xDE", # capital THORN, Icelandic + "thorn" => "\xFE", # small thorn, Icelandic + "Uacute" => "\xDA", # capital U, acute accent + "uacute" => "\xFA", # small u, acute accent + "Ucirc" => "\xDB", # capital U, circumflex accent + "ucirc" => "\xFB", # small u, circumflex accent + "Ugrave" => "\xD9", # capital U, grave accent + "ugrave" => "\xF9", # small u, grave accent + "Uuml" => "\xDC", # capital U, dieresis or umlaut mark + "uuml" => "\xFC", # small u, dieresis or umlaut mark + "Yacute" => "\xDD", # capital Y, acute accent + "yacute" => "\xFD", # small y, acute accent + "yuml" => "\xFF", # small y, dieresis or umlaut mark + + "lchevron" => "\xAB", # left chevron (double less than) + "rchevron" => "\xBB", # right chevron (double greater than) +); - use Pod::Text; - pod2text("perlfunc.pod"); +############################################################################ +# Initialization +############################################################################ -Also: +# Initialize the object. Must be sure to call our parent initializer. +sub initialize { + my $self = shift; - pod2text [B<-a>] [B<->I<width>] < input.pod + $$self{alt} = 0 unless defined $$self{alt}; + $$self{indent} = 4 unless defined $$self{indent}; + $$self{loose} = 0 unless defined $$self{loose}; + $$self{sentence} = 0 unless defined $$self{sentence}; + $$self{width} = 76 unless defined $$self{width}; -=head1 DESCRIPTION + $$self{BEGUN} = []; # Stack of =begin blocks. + $$self{INDENTS} = []; # Stack of indentations. + $$self{MARGIN} = $$self{indent}; # Current left margin in spaces. -Pod::Text is a module that can convert documentation in the POD format (such -as can be found throughout the Perl distribution) into formatted ASCII. -Termcap is optionally supported for boldface/underline, and can enabled via -C<$Pod::Text::termcap=1>. If termcap has not been enabled, then backspaces -will be used to simulate bold and underlined text. + $self->SUPER::initialize; +} -A separate F<pod2text> program is included that is primarily a wrapper for -Pod::Text. -The single function C<pod2text()> can take the optional options B<-a> -for an alternative output format, then a B<->I<width> option with the -max terminal width, followed by one or two arguments. The first -should be the name of a file to read the pod from, or "E<lt>&STDIN" to read from -STDIN. A second argument, if provided, should be a filehandle glob where -output should be sent. +############################################################################ +# Core overrides +############################################################################ + +# Called for each command paragraph. Gets the command, the associated +# paragraph, the line number, and a Pod::Paragraph object. Just dispatches +# the command to a method named the same as the command. =cut is handled +# internally by Pod::Parser. +sub command { + my $self = shift; + my $command = shift; + return if $command eq 'pod'; + return if ($$self{EXCLUDE} && $command ne 'end'); + $self->item ("\n") if defined $$self{ITEM}; + $command = 'cmd_' . $command; + $self->$command (@_); +} -=head1 AUTHOR +# Called for a verbatim paragraph. Gets the paragraph, the line number, and +# a Pod::Paragraph object. Just output it verbatim, but with tabs converted +# to spaces. +sub verbatim { + my $self = shift; + return if $$self{EXCLUDE}; + $self->item if defined $$self{ITEM}; + local $_ = shift; + return if /^\s*$/; + s/^(\s*\S+)/(' ' x $$self{MARGIN}) . $1/gme; + $self->output ($_); +} -Tom Christiansen E<lt>F<tchrist@mox.perl.com>E<gt> +# Called for a regular text block. Gets the paragraph, the line number, and +# a Pod::Paragraph object. Perform interpolation and output the results. +sub textblock { + my ($self, $text, $line) = @_; + return if $$self{EXCLUDE}; + local $_ = $text; + + # Perform a little magic to collapse multiple L<> references. This is + # here mostly for backwards-compatibility with Pod::Text. We'll just + # rewrite the whole thing into actual text at this part, bypassing the + # whole internal sequence parsing thing. + s{ + ( + L< # A link of the form L</something>. + / + ( + [:\w]+ # The item has to be a simple word... + (\(\))? # ...or simple function. + ) + > + ( + ,?\s+(and\s+)? # Allow lots of them, conjuncted. + L< + / + ( + [:\w]+ + (\(\))? + ) + > + )+ + ) + } { + local $_ = $1; + s%L</([^>]+)>%$1%g; + my @items = split /(?:,?\s+(?:and\s+)?)/; + my $string = "the "; + my $i; + for ($i = 0; $i < @items; $i++) { + $string .= $items[$i]; + $string .= ", " if @items > 2 && $i != $#items; + $string .= " and " if ($i == $#items - 1); + } + $string .= " entries elsewhere in this document"; + $string; + }gex; + + # Now actually interpolate and output the paragraph. + $_ = $self->interpolate ($_, $line); + s/\s+$/\n/; + if (defined $$self{ITEM}) { + $self->item ($_ . "\n"); + } else { + $self->output ($self->reformat ($_ . "\n")); + } +} -=head1 TODO +# Called for an interior sequence. 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. +sub interior_sequence { + my $self = shift; + my $command = shift; + local $_ = shift; + return '' if ($command eq 'X' || $command eq 'Z'); -Cleanup work. The input and output locations need to be more flexible, -termcap shouldn't be a global variable, and the terminal speed needs to -be properly calculated. + # Expand escapes into the actual character now, carping if invalid. + if ($command eq 'E') { + return $ESCAPES{$_} if defined $ESCAPES{$_}; + carp "Unknown escape: E<$_>"; + return "E<$_>"; + } -=cut + # For all the other sequences, empty content produces no output. + return unless $_; -use Term::Cap; -require Exporter; -@ISA = Exporter; -@EXPORT = qw(pod2text); + # For S<>, compress all internal whitespace and then map spaces to \01. + # When we output the text, we'll map this back. + if ($command eq 'S') { + s/\s{2,}/ /g; + tr/ /\01/; + return $_; + } -use vars qw($VERSION); -$VERSION = "1.0204"; + # Anything else needs to get dispatched to another method. + if ($command eq 'B') { return $self->seq_b ($_) } + elsif ($command eq 'C') { return $self->seq_c ($_) } + elsif ($command eq 'F') { return $self->seq_f ($_) } + elsif ($command eq 'I') { return $self->seq_i ($_) } + elsif ($command eq 'L') { return $self->seq_l ($_) } + else { carp "Unknown sequence $command<$_>" } +} -use locale; # make \w work right in non-ASCII lands +# Called for each paragraph that's actually part of the POD. We take +# advantage of this opportunity to untabify the input. +sub preprocess_paragraph { + my $self = shift; + local $_ = shift; + 1 while s/^(.*?)(\t+)/$1 . ' ' x (length ($2) * 8 - length ($1) % 8)/me; + $_; +} -$termcap=0; -$opt_alt_format = 0; +############################################################################ +# Command paragraphs +############################################################################ -#$use_format=1; +# All command paragraphs take the paragraph and the line number. -$UNDL = "\x1b[4m"; -$INV = "\x1b[7m"; -$BOLD = "\x1b[1m"; -$NORM = "\x1b[0m"; +# First level heading. +sub cmd_head1 { + my $self = shift; + local $_ = shift; + s/\s+$//; + if ($$self{alt}) { + $self->output ("\n==== $_ ====\n\n"); + } else { + $_ .= "\n" if $$self{loose}; + $self->output ($_ . "\n"); + } +} -sub pod2text { -shift if $opt_alt_format = ($_[0] eq '-a'); +# Second level heading. +sub cmd_head2 { + my $self = shift; + local $_ = shift; + s/\s+$//; + if ($$self{alt}) { + $self->output ("\n== $_ ==\n\n"); + } else { + $self->output (' ' x ($$self{indent} / 2) . $_ . "\n\n"); + } +} -if($termcap and !$setuptermcap) { - $setuptermcap=1; +# Start a list. +sub cmd_over { + my $self = shift; + local $_ = shift; + unless (/^[-+]?\d+\s+$/) { $_ = $$self{indent} } + push (@{ $$self{INDENTS} }, $$self{MARGIN}); + $$self{MARGIN} += ($_ + 0); +} - my($term) = Tgetent Term::Cap { TERM => undef, OSPEED => 9600 }; - $UNDL = $term->{'_us'}; - $INV = $term->{'_mr'}; - $BOLD = $term->{'_md'}; - $NORM = $term->{'_me'}; +# End a list. +sub cmd_back { + my $self = shift; + $$self{MARGIN} = pop @{ $$self{INDENTS} }; + unless (defined $$self{MARGIN}) { + carp "Unmatched =back"; + $$self{MARGIN} = $$self{indent}; + } } -$SCREEN = ($_[0] =~ /^-(\d+)/ && (shift, $1)) - || $ENV{COLUMNS} - || ($ENV{TERMCAP} =~ /co#(\d+)/)[0] - || ($^O ne 'MSWin32' && $^O ne 'dos' && (`stty -a 2>/dev/null` =~ /(\d+) columns/)[0]) - || 72; +# An individual list item. +sub cmd_item { + my $self = shift; + if (defined $$self{ITEM}) { $self->item } + local $_ = shift; + s/\s+$//; + $$self{ITEM} = $self->interpolate ($_); +} -@_ = ("<&STDIN") unless @_; -local($file,*OUTPUT) = @_; -*OUTPUT = *STDOUT if @_<2; +# Begin a block for a particular translator. To allow for weird nested +# =begin blocks, keep track of how many blocks we were excluded from and +# only unwind one level with each =end. +sub cmd_begin { + my $self = shift; + local $_ = shift; + my ($kind) = /^(\S+)/ or return; + push (@{ $$self{BEGUN} }, $kind); + $$self{EXCLUDE}++ unless $kind eq 'text'; +} -local $: = $:; -$: = " \n" if $opt_alt_format; # Do not break ``-L/lib/'' into ``- L/lib/''. +# End a block for a particular translator. We assume that all =begin/=end +# pairs are properly nested and just pop the previous one. +sub cmd_end { + my $self = shift; + my $kind = pop @{ $$self{BEGUN} }; + $$self{EXCLUDE}-- if $$self{EXCLUDE}; +} + +# One paragraph for a particular translator. Ignore it unless it's intended +# for text, in which case we treat it as either a normal text block or a +# verbatim text block, depending on whether it's indented. +sub cmd_for { + my $self = shift; + local $_ = shift; + my $line = shift; + return unless s/^text\b[ \t]*//; + if (/^\n\s+/) { + $self->verbatim ($_, $line); + } else { + $self->textblock ($_, $line); + } +} -$/ = ""; -$FANCY = 0; +############################################################################ +# Interior sequences +############################################################################ -$cutting = 1; -$DEF_INDENT = 4; -$indent = $DEF_INDENT; -$needspace = 0; -$begun = ""; +# The simple formatting ones. These are here mostly so that subclasses can +# override them and do more complicated things. +sub seq_b { my $self = shift; return $$self{alt} ? "``$_[0]''" : $_[0] } +sub seq_c { my $self = shift; return $$self{alt} ? "``$_[0]''" : "`$_[0]'" } +sub seq_f { my $self = shift; return $$self{alt} ? "\"$_[0]\"" : $_[0] } +sub seq_i { return '*' . $_[1] . '*' } -open(IN, $file) || die "Couldn't open $file: $!"; +# The complicated one. Handle links. Since this is plain text, we can't +# actually make any real links, so this is all to figure out what text we +# print out. +sub seq_l { + my $self = shift; + local $_ = shift; -POD_DIRECTIVE: while (<IN>) { - if ($cutting) { - next unless /^=/; - $cutting = 0; - } - if ($begun) { - if (/^=end\s+$begun/) { - $begun = ""; - } - elsif ($begun eq "text") { - print OUTPUT $_; - } - next; - } - 1 while s{^(.*?)(\t+)(.*)$}{ - $1 - . (' ' x (length($2) * 8 - length($1) % 8)) - . $3 - }me; - # Translate verbatim paragraph - if (/^\s/) { - output($_); - next; - } + # Smash whitespace in case we were split across multiple lines. + s/\s+/ /g; - if (/^=for\s+(\S+)\s*(.*)/s) { - if ($1 eq "text") { - print OUTPUT $2,""; - } else { - # ignore unknown for - } - next; - } - elsif (/^=begin\s+(\S+)\s*(.*)/s) { - $begun = $1; - if ($1 eq "text") { - print OUTPUT $2.""; - } - next; + # If we were given any explicit text, just output it. + if (/^([^|]+)\|/) { return $1 } + + # Okay, leading and trailing whitespace isn't important; get rid of it. + s/^\s+//; + s/\s+$//; + chomp; + + # Default to using the whole content of the link entry as a section + # name. Note that L<manpage/> forces a manpage interpretation, as does + # something looking like L<manpage(section)>. The latter is an + # enhancement over the original Pod::Text. + my ($manpage, $section) = ('', $_); + if (/^"\s*(.*?)\s*"$/) { + $section = '"' . $1 . '"'; + } elsif (m/^[-:.\w]+(?:\(\S+\))?$/) { + ($manpage, $section) = ($_, ''); + } elsif (m%/%) { + ($manpage, $section) = split (/\s*\/\s*/, $_, 2); } -sub prepare_for_output { - - s/\s*$/\n/; - &init_noremap; - - # need to hide E<> first; they're processed in clear_noremap - s/(E<[^<>]+>)/noremap($1)/ge; - $maxnest = 10; - while ($maxnest-- && /[A-Z]</) { - unless ($FANCY) { - if ($opt_alt_format) { - s/[BC]<(.*?)>/``$1''/sg; - s/F<(.*?)>/"$1"/sg; - } else { - s/C<(.*?)>/`$1'/sg; - } - } else { - s/C<(.*?)>/noremap("E<lchevron>${1}E<rchevron>")/sge; - } - # s/[IF]<(.*?)>/italic($1)/ge; - s/I<(.*?)>/*$1*/sg; - # s/[CB]<(.*?)>/bold($1)/ge; - s/X<.*?>//sg; - - # LREF: a la HREF L<show this text|man/section> - s:L<([^|>]+)\|[^>]+>:$1:g; - - # LREF: a manpage(3f) - s:L<([a-zA-Z][^\s\/]+)(\([^\)]+\))?>:the $1$2 manpage:g; - # LREF: an =item on another manpage - s{ - L< - ([^/]+) - / - ( - [:\w]+ - (\(\))? - ) - > - } {the "$2" entry in the $1 manpage}gx; - - # LREF: an =item on this manpage - s{ - ((?: - L< - / - ( - [:\w]+ - (\(\))? - ) - > - (,?\s+(and\s+)?)? - )+) - } { internal_lrefs($1) }gex; - - # LREF: a =head2 (head1?), maybe on a manpage, maybe right here - # the "func" can disambiguate - s{ - L< - (?: - ([a-zA-Z]\S+?) / - )? - "?(.*?)"? - > - }{ - do { - $1 # if no $1, assume it means on this page. - ? "the section on \"$2\" in the $1 manpage" - : "the section on \"$2\"" - } - }sgex; - - s/[A-Z]<(.*?)>/$1/sg; + # Now build the actual output text. + my $text = ''; + if (!length $section) { + $text = "the $manpage manpage" if length $manpage; + } elsif ($section =~ /^[:\w]+(?:\(\))?/) { + $text .= 'the ' . $section . ' entry'; + $text .= (length $manpage) ? " in the $manpage manpage" + : " elsewhere in this document"; + } else { + $section =~ s/^\"\s*//; + $section =~ s/\s*\"$//; + $text .= 'the section on "' . $section . '"'; + $text .= " in the $manpage manpage" if length $manpage; } - clear_noremap(1); + $text; } - &prepare_for_output; - - if (s/^=//) { - # $needspace = 0; # Assume this. - # s/\n/ /g; - ($Cmd, $_) = split(' ', $_, 2); - # clear_noremap(1); - if ($Cmd eq 'cut') { - $cutting = 1; - } - elsif ($Cmd eq 'pod') { - $cutting = 0; - } - elsif ($Cmd eq 'head1') { - makespace(); - if ($opt_alt_format) { - print OUTPUT "\n"; - s/^(.+?)[ \t]*$/==== $1 ====/; - } - print OUTPUT; - # print OUTPUT uc($_); - $needspace = $opt_alt_format; - } - elsif ($Cmd eq 'head2') { - makespace(); - # s/(\w+)/\u\L$1/g; - #print ' ' x $DEF_INDENT, $_; - # print "\xA7"; - s/(\w)/\xA7 $1/ if $FANCY; - if ($opt_alt_format) { - s/^(.+?)[ \t]*$/== $1 ==/; - print OUTPUT "\n", $_; - } else { - print OUTPUT ' ' x ($DEF_INDENT/2), $_, "\n"; - } - $needspace = $opt_alt_format; - } - elsif ($Cmd eq 'over') { - push(@indent,$indent); - $indent += ($_ + 0) || $DEF_INDENT; - } - elsif ($Cmd eq 'back') { - $indent = pop(@indent); - warn "Unmatched =back\n" unless defined $indent; - } - elsif ($Cmd eq 'item') { - makespace(); - # s/\A(\s*)\*/$1\xb7/ if $FANCY; - # s/^(\s*\*\s+)/$1 /; - { - if (length() + 3 < $indent) { - my $paratag = $_; - $_ = <IN>; - if (/^[=\s]/) { # tricked!, or verbatim paragraph - local($indent) = $indent[$#indent - 1] || $DEF_INDENT; - output($paratag); - redo POD_DIRECTIVE; - } - &prepare_for_output; - IP_output($paratag, $_); - } else { - local($indent) = $indent[$#indent - 1] || $DEF_INDENT; - output($_, 0); - } - } - } - else { - warn "Unrecognized directive: $Cmd\n"; - } + +############################################################################ +# List handling +############################################################################ + +# This method is called whenever an =item command is complete (in other +# words, we've seen its associated paragraph or know for certain that it +# doesn't have one). It gets the paragraph associated with the item as an +# argument. If that argument is empty, just output the item tag; if it +# contains a newline, output the item tag followed by the newline. +# Otherwise, see if there's enough room for us to output the item tag in the +# margin of the text or if we have to put it on a separate line. +sub item { + my $self = shift; + local $_ = shift; + my $tag = $$self{ITEM}; + unless (defined $tag) { + carp "item called without tag"; + return; } - else { - # clear_noremap(1); - makespace(); - output($_, 1); + undef $$self{ITEM}; + my $indent = $$self{INDENTS}[-1]; + unless (defined $indent) { $indent = $$self{indent} } + my $space = ' ' x $indent; + $space =~ s/^ /:/ if $$self{alt}; + if (!$_ || /^\s+$/ || ($$self{MARGIN} - $indent < length ($tag) + 1)) { + $self->output ($space . $tag . "\n"); + $self->output ($self->reformat ($_)) if /\S/; + } else { + $_ = $self->reformat ($_); + s/^ /:/ if ($$self{alt} && $indent > 0); + my $tagspace = ' ' x length $tag; + s/^($space)$tagspace/$1$tag/ or warn "Bizarre space in item"; + $self->output ($_); } } -close(IN); -} - -######################################################################### +############################################################################ +# Output formatting +############################################################################ -sub makespace { - if ($needspace) { - print OUTPUT "\n"; - $needspace = 0; +# Wrap a line, indenting by the current left margin. We can't use +# Text::Wrap because it plays games with tabs. We can't use formline, even +# though we'd really like to, because it screws up non-printing characters. +# So we have to do the wrapping ourselves. +sub wrap { + my $self = shift; + local $_ = shift; + my $output = ''; + my $spaces = ' ' x $$self{MARGIN}; + my $width = $$self{width} - $$self{MARGIN}; + while (length > $width) { + if (s/^([^\n]{0,$width})\s+// || s/^([^\n]{$width})//) { + $output .= $spaces . $1 . "\n"; + } else { + last; + } } + $output .= $spaces . $_; + $output =~ s/\s+$/\n\n/; + $output; } -sub bold { - my $line = shift; - return $line if $use_format; - if($termcap) { - $line = "$BOLD$line$NORM"; - } else { - $line =~ s/(.)/$1\b$1/g; - } -# $line = "$BOLD$line$NORM" if $ansify; - return $line; -} +# Reformat a paragraph of text for the current margin. Takes the text to +# reformat and returns the formatted text. +sub reformat { + my $self = shift; + local $_ = shift; -sub italic { - my $line = shift; - return $line if $use_format; - if($termcap) { - $line = "$UNDL$line$NORM"; + # If we're trying to preserve two spaces after sentences, do some + # munging to support that. Otherwise, smash all repeated whitespace. + if ($$self{sentence}) { + s/ +$//mg; + s/\.\n/. \n/g; + s/\n/ /g; + s/ +/ /g; } else { - $line =~ s/(.)/$1\b_/g; + s/\s+/ /g; } -# $line = "$UNDL$line$NORM" if $ansify; - return $line; + $self->wrap ($_); } -# Fill a paragraph including underlined and overstricken chars. -# It's not perfect for words longer than the margin, and it's probably -# slow, but it works. -sub fill { - local $_ = shift; - my $par = ""; - my $indent_space = " " x $indent; - my $marg = $SCREEN-$indent; - my $line = $indent_space; - my $line_length; - foreach (split) { - my $word_length = length; - $word_length -= 2 while /\010/g; # Subtract backspaces - - if ($line_length + $word_length > $marg) { - $par .= $line . "\n"; - $line= $indent_space . $_; - $line_length = $word_length; - } - else { - if ($line_length) { - $line_length++; - $line .= " "; - } - $line_length += $word_length; - $line .= $_; - } - } - $par .= "$line\n" if $line; - $par .= "\n"; - return $par; -} +# Output text to the output device. +sub output { $_[1] =~ tr/\01/ /; print { $_[0]->output_handle } $_[1] } -sub IP_output { - local($tag, $_) = @_; - local($tag_indent) = $indent[$#indent - 1] || $DEF_INDENT; - $tag_cols = $SCREEN - $tag_indent; - $cols = $SCREEN - $indent; - $tag =~ s/\s*$//; - s/\s+/ /g; - s/^ //; - $str = "format OUTPUT = \n" - . (($opt_alt_format && $tag_indent > 1) - ? ":" . " " x ($tag_indent - 1) - : " " x ($tag_indent)) - . '@' . ('<' x ($indent - $tag_indent - 1)) - . "^" . ("<" x ($cols - 1)) . "\n" - . '$tag, $_' - . "\n~~" - . (" " x ($indent-2)) - . "^" . ("<" x ($cols - 5)) . "\n" - . '$_' . "\n\n.\n1"; - #warn $str; warn "tag is $tag, _ is $_"; - eval $str || die; - write OUTPUT; -} -sub output { - local($_, $reformat) = @_; - if ($reformat) { - $cols = $SCREEN - $indent; - s/\s+/ /g; - s/^ //; - $str = "format OUTPUT = \n~~" - . (" " x ($indent-2)) - . "^" . ("<" x ($cols - 5)) . "\n" - . '$_' . "\n\n.\n1"; - eval $str || die; - write OUTPUT; - } else { - s/^/' ' x $indent/gem; - s/^\s+\n$/\n/gm; - s/^ /: /s if defined($reformat) && $opt_alt_format; - print OUTPUT; - } -} +############################################################################ +# Module return value and documentation +############################################################################ -sub noremap { - local($thing_to_hide) = shift; - $thing_to_hide =~ tr/\000-\177/\200-\377/; - return $thing_to_hide; -} +1; +__END__ -sub init_noremap { - die "unmatched init" if $mapready++; - #mask off high bit characters in input stream - s/([\200-\377])/"E<".ord($1).">"/ge; -} +=head1 NAME -sub clear_noremap { - my $ready_to_print = $_[0]; - die "unmatched clear" unless $mapready--; - tr/\200-\377/\000-\177/; - # now for the E<>s, which have been hidden until now - # otherwise the interative \w<> processing would have - # been hosed by the E<gt> - s { - E< - ( - ( \d+ ) - | ( [A-Za-z]+ ) - ) - > - } { - do { - defined $2 - ? chr($2) - : - defined $HTML_Escapes{$3} - ? do { $HTML_Escapes{$3} } - : do { - warn "Unknown escape: E<$1> in $_"; - "E<$1>"; - } - } - }egx if $ready_to_print; -} +Pod::Text - Convert POD data to formatted ASCII text -sub internal_lrefs { - local($_) = shift; - s{L</([^>]+)>}{$1}g; - my(@items) = split( /(?:,?\s+(?:and\s+)?)/ ); - my $retstr = "the "; - my $i; - for ($i = 0; $i <= $#items; $i++) { - $retstr .= "C<$items[$i]>"; - $retstr .= ", " if @items > 2 && $i != $#items; - $retstr .= " and " if $i+2 == @items; - } +=head1 SYNOPSIS - $retstr .= " entr" . ( @items > 1 ? "ies" : "y" ) - . " elsewhere in this document "; + use Pod::Text; + my $parser = Pod::Text->new (sentence => 0, width => 78); - return $retstr; + # Read POD from STDIN and write to STDOUT. + $parser->parse_from_filehandle; -} + # Read POD from file.pod and write to file.txt. + $parser->parse_from_file ('file.pod', 'file.txt'); -BEGIN { - -if (ord("\t") == 9) { -%HTML_Escapes = ( - 'amp' => '&', # ampersand - 'lt' => '<', # left chevron, less-than - 'gt' => '>', # right chevron, greater-than - 'quot' => '"', # double quote - - "Aacute" => "\xC1", # capital A, acute accent - "aacute" => "\xE1", # small a, acute accent - "Acirc" => "\xC2", # capital A, circumflex accent - "acirc" => "\xE2", # small a, circumflex accent - "AElig" => "\xC6", # capital AE diphthong (ligature) - "aelig" => "\xE6", # small ae diphthong (ligature) - "Agrave" => "\xC0", # capital A, grave accent - "agrave" => "\xE0", # small a, grave accent - "Aring" => "\xC5", # capital A, ring - "aring" => "\xE5", # small a, ring - "Atilde" => "\xC3", # capital A, tilde - "atilde" => "\xE3", # small a, tilde - "Auml" => "\xC4", # capital A, dieresis or umlaut mark - "auml" => "\xE4", # small a, dieresis or umlaut mark - "Ccedil" => "\xC7", # capital C, cedilla - "ccedil" => "\xE7", # small c, cedilla - "Eacute" => "\xC9", # capital E, acute accent - "eacute" => "\xE9", # small e, acute accent - "Ecirc" => "\xCA", # capital E, circumflex accent - "ecirc" => "\xEA", # small e, circumflex accent - "Egrave" => "\xC8", # capital E, grave accent - "egrave" => "\xE8", # small e, grave accent - "ETH" => "\xD0", # capital Eth, Icelandic - "eth" => "\xF0", # small eth, Icelandic - "Euml" => "\xCB", # capital E, dieresis or umlaut mark - "euml" => "\xEB", # small e, dieresis or umlaut mark - "Iacute" => "\xCD", # capital I, acute accent - "iacute" => "\xED", # small i, acute accent - "Icirc" => "\xCE", # capital I, circumflex accent - "icirc" => "\xEE", # small i, circumflex accent - "Igrave" => "\xCD", # capital I, grave accent - "igrave" => "\xED", # small i, grave accent - "Iuml" => "\xCF", # capital I, dieresis or umlaut mark - "iuml" => "\xEF", # small i, dieresis or umlaut mark - "Ntilde" => "\xD1", # capital N, tilde - "ntilde" => "\xF1", # small n, tilde - "Oacute" => "\xD3", # capital O, acute accent - "oacute" => "\xF3", # small o, acute accent - "Ocirc" => "\xD4", # capital O, circumflex accent - "ocirc" => "\xF4", # small o, circumflex accent - "Ograve" => "\xD2", # capital O, grave accent - "ograve" => "\xF2", # small o, grave accent - "Oslash" => "\xD8", # capital O, slash - "oslash" => "\xF8", # small o, slash - "Otilde" => "\xD5", # capital O, tilde - "otilde" => "\xF5", # small o, tilde - "Ouml" => "\xD6", # capital O, dieresis or umlaut mark - "ouml" => "\xF6", # small o, dieresis or umlaut mark - "szlig" => "\xDF", # small sharp s, German (sz ligature) - "THORN" => "\xDE", # capital THORN, Icelandic - "thorn" => "\xFE", # small thorn, Icelandic - "Uacute" => "\xDA", # capital U, acute accent - "uacute" => "\xFA", # small u, acute accent - "Ucirc" => "\xDB", # capital U, circumflex accent - "ucirc" => "\xFB", # small u, circumflex accent - "Ugrave" => "\xD9", # capital U, grave accent - "ugrave" => "\xF9", # small u, grave accent - "Uuml" => "\xDC", # capital U, dieresis or umlaut mark - "uuml" => "\xFC", # small u, dieresis or umlaut mark - "Yacute" => "\xDD", # capital Y, acute accent - "yacute" => "\xFD", # small y, acute accent - "yuml" => "\xFF", # small y, dieresis or umlaut mark - - "lchevron" => "\xAB", # left chevron (double less than) - "rchevron" => "\xBB", # right chevron (double greater than) -); +=head1 DESCRIPTION -} -else { - -# This hash assumes code page IBM-1047: -%HTML_Escapes = ( - 'amp' => '&', # ampersand - 'lt' => '<', # left chevron, less-than - 'gt' => '>', # right chevron, greater-than - 'quot' => '"', # double quote - - "Aacute" => "\x65", # capital A, acute accent - "aacute" => "\x45", # small a, acute accent - "Acirc" => "\x62", # capital A, circumflex accent - "acirc" => "\x42", # small a, circumflex accent - "AElig" => "\x9E", # capital AE diphthong (ligature) - "aelig" => "\x9C", # small ae diphthong (ligature) - "Agrave" => "\x64", # capital A, grave accent - "agrave" => "\x44", # small a, grave accent - "Aring" => "\x67", # capital A, ring - "aring" => "\x47", # small a, ring - "Atilde" => "\x66", # capital A, tilde - "atilde" => "\x46", # small a, tilde - "Auml" => "\x63", # capital A, dieresis or umlaut mark - "auml" => "\x43", # small a, dieresis or umlaut mark - "Ccedil" => "\x68", # capital C, cedilla - "ccedil" => "\x48", # small c, cedilla - "Eacute" => "\x71", # capital E, acute accent - "eacute" => "\x51", # small e, acute accent - "Ecirc" => "\x72", # capital E, circumflex accent - "ecirc" => "\x52", # small e, circumflex accent - "Egrave" => "\x74", # capital E, grave accent - "egrave" => "\x54", # small e, grave accent - "ETH" => "\xAC", # capital Eth, Icelandic - "eth" => "\x8C", # small eth, Icelandic - "Euml" => "\x73", # capital E, dieresis or umlaut mark - "euml" => "\x53", # small e, dieresis or umlaut mark - "Iacute" => "\x75", # capital I, acute accent - "iacute" => "\x55", # small i, acute accent - "Icirc" => "\x76", # capital I, circumflex accent - "icirc" => "\x56", # small i, circumflex accent - "Igrave" => "\x75", # capital I, grave accent - "igrave" => "\x55", # small i, grave accent - "Iuml" => "\x77", # capital I, dieresis or umlaut mark - "iuml" => "\x57", # small i, dieresis or umlaut mark - "Ntilde" => "\x69", # capital N, tilde - "ntilde" => "\x49", # small n, tilde - "Oacute" => "\xEE", # capital O, acute accent - "oacute" => "\xCE", # small o, acute accent - "Ocirc" => "\xEB", # capital O, circumflex accent - "ocirc" => "\xCB", # small o, circumflex accent - "Ograve" => "\xED", # capital O, grave accent - "ograve" => "\xCD", # small o, grave accent - "Oslash" => "\x80", # capital O, slash - "oslash" => "\x70", # small o, slash - "Otilde" => "\xEF", # capital O, tilde - "otilde" => "\xCF", # small o, tilde - "Ouml" => "\xEC", # capital O, dieresis or umlaut mark - "ouml" => "\xCC", # small o, dieresis or umlaut mark - "szlig" => "\x59", # small sharp s, German (sz ligature) - "THORN" => "\xAE", # capital THORN, Icelandic - "thorn" => "\x8E", # small thorn, Icelandic - "Uacute" => "\xFE", # capital U, acute accent - "uacute" => "\xDE", # small u, acute accent - "Ucirc" => "\xFB", # capital U, circumflex accent - "ucirc" => "\xDB", # small u, circumflex accent - "Ugrave" => "\xFD", # capital U, grave accent - "ugrave" => "\xDD", # small u, grave accent - "Uuml" => "\xFC", # capital U, dieresis or umlaut mark - "uuml" => "\xDC", # small u, dieresis or umlaut mark - "Yacute" => "\xBA", # capital Y, acute accent - "yacute" => "\x8D", # small y, acute accent - "yuml" => "\xDF", # small y, dieresis or umlaut mark - - "lchevron" => "\x8A", # left chevron (double less than) - "rchevron" => "\x8B", # right chevron (double greater than) -); - -} -} +Pod::Text is a module that can convert documentation in the POD format +(such as can be found throughout the Perl distribution) into formatted +ASCII. It uses no special formatting controls or codes whatsoever, and its +output is therefore suitable for nearly any device. -1; +As a derived class from Pod::Parser, Pod::Text supports the same +methods and interfaces. See L<Pod::Parser> for all the details; briefly, +one creates a new parser with C<Pod::Text-E<gt>new()> and then calls +either C<parse_from_filehandle()> or C<parse_from_file()>. + +C<new()> can take options, in the form of key/value pairs, that control the +behavior of the parser. The currently recognized options are: + +=over 4 + +=item alt + +If set to a true value, selects an alternate output format that, among other +things, uses a different heading style and marks C<=item> entries with a +colon in the left margin. Defaults to false. + +=item indent + +The number of spaces to indent regular text, and the default indentation for +C<=over> blocks. Defaults to 4. + +=item loose + +If set to a true value, a blank line is printed after a C<=head1> heading. +If set to false (the default), no blank line is printed after C<=head1>, +although one is still printed after C<=head2>. This is the default because +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 sentence + +If set to a true value, Pod::Text will assume that each sentence ends +in two spaces, and will try to preserve that spacing. If set to false, all +consecutive whitespace in non-verbatim paragraphs is compressed into a +single space. Defaults to true. + +=item width + +The column at which to wrap text on the right-hand side. Defaults to 76. + +=back + +The standard Pod::Parser method C<parse_from_filehandle()> takes up to two +arguments, the first being the file handle to read POD from and the second +being the file handle to write the formatted output to. The first defaults +to STDIN if not given, and the second defaults to STDOUT. The method +C<parse_from_file()> is almost identical, except that its two arguments are +the input and output disk files instead. See L<Pod::Parser> for the +specific details. + +=head1 DIAGNOSTICS + +=over 4 + +=item Unknown escape: %s + +The POD source contained an C<EE<lt>E<gt>> escape that Pod::Text +didn't know about. + +=item Unknown sequence: %s + +The POD source contained a non-standard internal sequence (something of the +form C<XE<lt>E<gt>>) that Pod::Text didn't know about. + +=item Unmatched =back + +Pod::Text encountered a C<=back> command that didn't correspond to an +C<=over> command. + +=back + +=head1 NOTES + +I'm hoping this module will eventually replace Pod::Text in Perl core once +Pod::Parser has been added to Perl core. Accordingly, don't be surprised if +the name of this module changes to Pod::Text down the road. + +The original Pod::Text contained code to do formatting via termcap +sequences, although it wasn't turned on by default and it was problematic to +get it to work at all. This module doesn't even try to do that, but a +subclass of it does. Look for Pod::Text::Termcap. + +=head1 SEE ALSO + +L<Pod::Parser|Pod::Parser>, L<Pod::Text::Termcap|Pod::Text::Termcap> + +=head1 AUTHOR + +Russ Allbery E<lt>rra@stanford.eduE<gt>, based I<very> heavily on the +original Pod::Text by Tom Christiansen E<lt>tchrist@mox.perl.comE<gt> and +its conversion to Pod::Parser by Brad Appleton +E<lt>bradapp@enteract.comE<gt>. + +=cut diff --git a/lib/Pod/Text/Color.pm b/lib/Pod/Text/Color.pm new file mode 100644 index 0000000000..5eac57ca9f --- /dev/null +++ b/lib/Pod/Text/Color.pm @@ -0,0 +1,116 @@ +# Pod::Text::Color -- Convert POD data to formatted color ASCII text +# $Id: Color.pm,v 0.1 1999/06/13 02:41:06 eagle Exp $ +# +# Copyright 1999 by Russ Allbery <rra@stanford.edu> +# +# This program is free software; you can redistribute it and/or modify it +# under the same terms as Perl itself. +# +# This is just a basic proof of concept. It should later be modified to +# make better use of color, take options changing what colors are used for +# what text, and the like. + +############################################################################ +# Modules and declarations +############################################################################ + +package Pod::Text::Color; + +require 5.004; + +use Pod::Text (); +use Term::ANSIColor qw(colored); + +use strict; +use vars qw(@ISA $VERSION); + +@ISA = qw(Pod::Text); + +# Use the CVS revision of this file as its version number. +($VERSION = (split (' ', q$Revision: 0.1 $ ))[1]) =~ s/\.(\d)$/.0$1/; + + +############################################################################ +# Overrides +############################################################################ + +# Make level one headings bold. +sub cmd_head1 { + my $self = shift; + local $_ = shift; + s/\s+$//; + $self->SUPER::cmd_head1 (colored ($_, 'bold')); +} + +# Make level two headings bold. +sub cmd_head2 { + my $self = shift; + local $_ = shift; + s/\s+$//; + $self->SUPER::cmd_head2 (colored ($_, 'bold')); +} + +# Fix the various interior sequences. +sub seq_b { return colored ($_[1], 'bold') } +sub seq_f { return colored ($_[1], 'cyan') } +sub seq_i { return colored ($_[1], 'yellow') } + +# We unfortunately have to override the wrapping code here, since the normal +# wrapping code gets really confused by all the escape sequences. +sub wrap { + my $self = shift; + local $_ = shift; + my $output = ''; + my $spaces = ' ' x $$self{MARGIN}; + my $width = $$self{width} - $$self{MARGIN}; + while (length > $width) { + if (s/^((?:(?:\e\[[\d;]+m)?[^\n]){0,$width})\s+// + || s/^((?:(?:\e\[[\d;]+m)?[^\n]){$width})//) { + $output .= $spaces . $1 . "\n"; + } else { + last; + } + } + $output .= $spaces . $_; + $output =~ s/\s+$/\n\n/; + $output; +} + +############################################################################ +# Module return value and documentation +############################################################################ + +1; +__END__ + +=head1 NAME + +Pod::Text::Color - Convert POD data to formatted color ASCII text + +=head1 SYNOPSIS + + use Pod::Text::Color; + my $parser = Pod::Text::Color->new (sentence => 0, width => 78); + + # Read POD from STDIN and write to STDOUT. + $parser->parse_from_filehandle; + + # Read POD from file.pod and write to file.txt. + $parser->parse_from_file ('file.pod', 'file.txt'); + +=head1 DESCRIPTION + +Pod::Text::Color is a simple subclass of Pod::Text that highlights +output text using ANSI color escape sequences. Apart from the color, it in +all ways functions like Pod::Text. See L<Pod::Text> for details +and available options. + +=head1 SEE ALSO + +L<Pod::Text|Pod::Text>, L<Pod::Parser|Pod::Parser> + +=head1 AUTHOR + +Russ Allbery E<lt>rra@stanford.eduE<gt>. + +=cut diff --git a/lib/Pod/Text/Termcap.pm b/lib/Pod/Text/Termcap.pm new file mode 100644 index 0000000000..efb71a69ba --- /dev/null +++ b/lib/Pod/Text/Termcap.pm @@ -0,0 +1,141 @@ +# Pod::Text::Termcap -- Convert POD data to ASCII text with format escapes. +# $Id: Termcap.pm,v 0.1 1999/06/13 02:41:06 eagle Exp $ +# +# Copyright 1999 by Russ Allbery <rra@stanford.edu> +# +# This program is free software; you can redistribute it and/or modify it +# under the same terms as Perl itself. +# +# This is a simple subclass of Pod::Text that overrides a few key +# methods to output the right termcap escape sequences for formatted text +# on the current terminal type. + +############################################################################ +# Modules and declarations +############################################################################ + +package Pod::Text::Termcap; + +require 5.004; + +use Pod::Text (); +use POSIX (); +use Term::Cap; +use strict; +use vars qw(@ISA $VERSION); + +@ISA = qw(Pod::Text); + +# Use the CVS revision of this file as its version number. +($VERSION = (split (' ', q$Revision: 0.1 $ ))[1]) =~ s/\.(\d)$/.0$1/; + + +############################################################################ +# Overrides +############################################################################ + +# In the initialization method, grab our terminal characteristics as well as +# do all the stuff we normally do. +sub initialize { + my $self = shift; + + # The default Term::Cap path won't work on Solaris. + $ENV{TERMPATH} = "$ENV{HOME}/.termcap:/etc/termcap" + . ":/usr/share/misc/termcap:/usr/share/lib/termcap"; + + my $termios = POSIX::Termios->new; + $termios->getattr; + my $ospeed = $termios->getospeed; + my $term = Tgetent Term::Cap { TERM => undef, OSPEED => $ospeed }; + $$self{BOLD} = $$term{_md} or die 'BOLD'; + $$self{UNDL} = $$term{_us} or die 'UNDL'; + $$self{NORM} = $$term{_me} or die 'NORM'; + + unless (defined $$self{width}) { + $$self{width} = $ENV{COLUMNS} || $$term{_co} || 78; + $$self{width} -= 2; + } + + $self->SUPER::initialize; +} + +# Make level one headings bold. +sub cmd_head1 { + my $self = shift; + local $_ = shift; + s/\s+$//; + $self->SUPER::cmd_head1 ("$$self{BOLD}$_$$self{NORM}"); +} + +# Make level two headings bold. +sub cmd_head2 { + my $self = shift; + local $_ = shift; + s/\s+$//; + $self->SUPER::cmd_head2 ("$$self{BOLD}$_$$self{NORM}"); +} + +# Fix up B<> and I<>. Note that we intentionally don't do F<>. +sub seq_b { my $self = shift; return "$$self{BOLD}$_[0]$$self{NORM}" } +sub seq_i { my $self = shift; return "$$self{UNDL}$_[0]$$self{NORM}" } + +# Override the wrapping code to igore the special sequences. +sub wrap { + my $self = shift; + local $_ = shift; + my $output = ''; + my $spaces = ' ' x $$self{MARGIN}; + my $width = $$self{width} - $$self{MARGIN}; + my $code = "(?:\Q$$self{BOLD}\E|\Q$$self{UNDL}\E|\Q$$self{NORM}\E)"; + while (length > $width) { + if (s/^((?:$code?[^\n]){0,$width})\s+// + || s/^((?:$code?[^\n]){$width})//) { + $output .= $spaces . $1 . "\n"; + } else { + last; + } + } + $output .= $spaces . $_; + $output =~ s/\s+$/\n\n/; + $output; +} + + +############################################################################ +# Module return value and documentation +############################################################################ + +1; +__END__ + +=head1 NAME + +Pod::Text::Color - Convert POD data to ASCII text with format escapes + +=head1 SYNOPSIS + + use Pod::Text::Termcap; + my $parser = Pod::Text::Termcap->new (sentence => 0, width => 78); + + # Read POD from STDIN and write to STDOUT. + $parser->parse_from_filehandle; + + # Read POD from file.pod and write to file.txt. + $parser->parse_from_file ('file.pod', 'file.txt'); + +=head1 DESCRIPTION + +Pod::Text::Termcap is a simple subclass of Pod::Text that highlights +output text using the correct termcap escape sequences for the current +terminal. Apart from the format codes, it in all ways functions like +Pod::Text. See L<Pod::Text> for details and available options. + +=head1 SEE ALSO + +L<Pod::Text|Pod::Text>, L<Pod::Parser|Pod::Parser> + +=head1 AUTHOR + +Russ Allbery E<lt>rra@stanford.eduE<gt>. + +=cut diff --git a/pod/pod2text.PL b/pod/pod2text.PL index 94516c3997..92b26feceb 100644 --- a/pod/pod2text.PL +++ b/pod/pod2text.PL @@ -35,14 +35,169 @@ $Config{startperl} print OUT <<'!NO!SUBS!'; -use Pod::Text; +$ID = q$Id: pod2text,v 0.1 1999/06/13 02:42:18 eagle Exp $; -if(@ARGV) { - pod2text($ARGV[0]); -} else { - pod2text("<&STDIN"); +# pod2text -- Convert POD data to formatted ASCII text. +# Copyright 1999 by Russ Allbery <rra@stanford.edu> +# +# This program is free software; you can redistribute it and/or modify it +# under the same terms as Perl itself. +# +# The driver script for Pod::Text, Pod::Text::Termcap, and +# Pod::Text::Color, invoked by perldoc -t among other things. + +require 5.004; + +use Getopt::Long qw(GetOptions); +use Pod::Text (); +use Pod::Usage qw(pod2usage); + +use strict; +use vars qw($ID); + +# Take an initial pass through our options, looking for one of the form +# -<number>. We turn that into -w <number> for compatibility with the +# original pod2text script. +for (my $i = 0; $i < @ARGV; $i++) { + last if $ARGV[$i] =~ /^--$/; + if ($ARGV[$i] =~ /^-(\d+)$/) { + splice (@ARGV, $i++, 1, '-w', $1); + } +} + +# Parse our options. Use the same names as Pod::Text for simplicity, +# and default to sentence boundaries turned off for compatibility. +my %options; +$options{termcap} = -t STDOUT; +$options{sentence} = 0; +Getopt::Long::config ('bundling'); +GetOptions (\%options, 'alt|a', 'color|c', 'help|h', 'indent|i=i', + 'loose|l', 'sentence|s', 'termcap|t!', 'width|w=i') or exit 1; +pod2usage (1) if $options{help}; + +# Figure out what formatter we're going to use. -c overrides -t. +my $formatter = 'Pod::Text'; +if ($options{color}) { + $formatter = 'Pod::Text::Color'; + require Pod::Text::Color; +} elsif ($options{termcap}) { + $formatter = 'Pod::Text::Termcap'; + require Pod::Text::Termcap; } +delete @options{'color', 'termcap'}; + +# Initialize and run the formatter. +my $parser = $formatter->new (%options); +$parser->parse_from_file (@ARGV); + +__END__ + +=head1 NAME + +pod2text - Convert POD data to formatted ASCII text + +=head1 SYNOPSIS + +pod2text [B<-aclst>] [B<-i> I<indent>] [B<-w> I<width>] [I<input> [I<output>]] + +pod2text B<-h> + +=head1 DESCRIPTION + +B<pod2text> is a front-end for Pod::Text and its subclasses. It uses +them to generate formatted ASCII text from POD source. It can optionally +use either termcap sequences or ANSI color escape sequences to format the +text. + +I<input> is the file to read for POD source (the POD can be embedded in +code). If I<input> isn't given, it defaults to STDIN. I<output>, if given, +is the file to which to write the formatted output. If I<output> isn't +given, the formatted output is written to STDOUT. + +=head1 OPTIONS + +=over 4 + +=item B<-a>, B<--alt> + +Use an alternate output format that, among other things, uses a different +heading style and marks C<=item> entries with a colon in the left margin. + +=item B<-c>, B<--color> + +Format the output with ANSI color escape sequences. Using this option +requires that Term::ANSIColor be installed on your system. + +=item B<-i> I<indent>, B<--indent=>I<indent> + +Set the number of spaces to indent regular text, and the default indentation +for C<=over> blocks. Defaults to 4 spaces if this option isn't given. + +=item B<-l>, B<--loose> + +Print a blank line after a C<=head1> heading. Normally, no blank line is +printed after C<=head1>, although one is still printed after C<=head2>. +This is the default because it's the expected formatting for manual pages; +if you're formatting arbitrary text documents, using this option is +recommended. + +=item B<-s>, B<--sentence> + +Assume each sentence ends in two spaces and try to preserve that spacing. +Without this option, all consecutive whitespace in non-verbatim paragraphs +is compressed into a single space. + +=item B<-t>, B<--termcap> + +Try to determine the width of the screen and the bold and underline +sequences for the terminal from termcap, and use that information in +formatting the output. Output will be wrapped at two columns less than the +width of your terminal device. Using this option requires that your system +have a termcap file somewhere where Term::Cap can find it. With this +option, the output of B<pod2text> will contain terminal control sequences for +your current terminal type. + +=item B<-w>, B<--width=>I<width>, B<->I<width> + +The column at which to wrap text on the right-hand side. Defaults to 76, +unless B<-t> is given, in which case it's two columns less than the width of +your terminal device. + +=back + +=head1 ENVIRONMENT + +=over 4 + +=item COLUMNS + +If B<-t> is given, B<pod2text> will take the current width of your screen +from this environment variable, if available. It overrides terminal width +information in TERMCAP. + +=item TERMCAP + +If B<-t> is given, B<pod2text> will use the contents of this environment +variable if available to determine the correct formatting sequences for your +current terminal device. + +=back + +=head1 DIAGNOSTICS + +If B<pod2text> fails with POD errors, see L<Pod::Text> and +L<Pod::Parser> for information about what those errors might mean. + +=head1 SEE ALSO + +L<Pod::Text|Pod::Text>, L<Pod::Text::Color|Pod::Text::Color>, +L<Pod::Text::Termcap|Pod::Text::Termcap>, L<Pod::Parser|Pod::Parser> + +=head1 AUTHOR + +Russ Allbery E<lt>rra@stanford.eduE<gt>. +=cut !NO!SUBS! close OUT or die "Can't close $file: $!"; |