App-sdview

 view release on metacpan or  search on metacpan

lib/App/sdview.pm  view on Meta::CPAN


   $ sdview README.md

   $ sdview man/somelib.3

Various output plugins exist. By default it will output a terminal-formatted
rendering of the document via the F<less> pager, but it can also output
plaintext, Pod, Markdown.

   $ sdview Some::Module -o plain > module.txt

   $ sdview Some::Module -o Markdown > module.md

=cut

# Permit loaded output modules to override
our $DEFAULT_OUTPUT = "terminal";

use Module::Pluggable
   search_path => "App::sdview::Parser",
   sub_name    => "PARSERS",
   inner       => 0,
   require     => 1;

use Module::Pluggable
   search_path => "App::sdview::Output",
   sub_name    => "OUTPUTS",
   inner       => 0,
   require     => 1;

# Must call this *before* ->run entersub so that DEFAULT_OUTPUT is overridden properly
my @OUTPUT_CLASSES = OUTPUTS();

method run ( $file,
   :$format = undef,
   :$output //= $DEFAULT_OUTPUT,
   :$highlight = 0,
   :$output_options //= [],
   %opts
) {
   my @PARSER_CLASSES = sort { $a->sort_order <=> $b->sort_order } PARSERS();

   if( ( $format // "" ) eq "?" ) {
      say "Parser format types:";
      $_->can( "format" ) and say "  " . $_->format . "  (provided by $_)"
         for @PARSER_CLASSES;
      exit 0;
   }
   if( ( $output // "" ) eq "?" ) {
      say "Output format types:";
      $_->can( "format" ) and say "  " . $_->format . "  (provided by $_)"
         for @OUTPUT_CLASSES;
      exit 0;
   }

   if( -f( my $configpath = "$ENV{HOME}/.sdviewrc" ) ) {
      App::sdview::Style->load_config( $configpath );
   }

   my %output_options = map {
      map { m/^(.*?)=(.*)$/ ? ( $1 => $2 ) : ( $_ => !!1 ) } split m/,/, $_;
   } $output_options->@*;

   my $parser_class;

   if( defined $format ) {
      $parser_class = first { $_->can( "format" ) and $_->format eq $format } @PARSER_CLASSES or
         die "Unrecognised format name $format\n";
   }

   if( !defined $file ) {
      die "Require a FILE to read - such as doc.md or doc.pod\n";
   }

   if( ! -f $file ) {
      my $name = $file;

      foreach my $class ( $parser_class ? ( $parser_class ) : @PARSER_CLASSES ) {
         defined( $file = $class->find_file( $name ) ) and
            $parser_class = $class, last;
      }

      defined $file or
         die "Unable to find a file for '$name'\n";
   }

   $parser_class //= do {
      first { $_->can_parse_file( $file ) } @PARSER_CLASSES or
         die "Unable to find a handler for $file\n";
   };

   my $output_class = first { $_->can( "format" ) and $_->format eq $output } @OUTPUT_CLASSES or
      die "Unrecognised output name $output\n";

   my @paragraphs = $parser_class->new->parse_file( $file );

   if( $highlight ) {
      apply_highlights( $_ ) for @paragraphs;
   }

   # TODO: unrecognised output option key names will not look very neat here
   $output_class->new( %output_options )->output( @paragraphs );
}

sub apply_highlights ( $para )
{
   if( $para->type eq "verbatim" and defined( my $language = $para->language ) ) {
      App::sdview::Highlighter->highlight_str( $para->text, $language );
   }

   if( $para->type =~ m/^list-/ ) {
      apply_highlights( $_ ) for $para->items;
   }
}

=head1 TODO

=over 4

=item *



( run in 1.509 second using v1.01-cache-2.11-cpan-39bf76dae61 )