Initial commit master
authorMarius Gavrilescu <marius@ieval.ro>
Sat, 31 Jan 2015 22:09:48 +0000 (00:09 +0200)
committerMarius Gavrilescu <marius@ieval.ro>
Sat, 31 Jan 2015 22:09:48 +0000 (00:09 +0200)
13 files changed:
Changes [new file with mode: 0644]
MANIFEST [new file with mode: 0644]
Makefile.PL [new file with mode: 0644]
README [new file with mode: 0644]
lib/App/Zealc.pm [new file with mode: 0644]
lib/App/Zealc/Command.pm [new file with mode: 0644]
lib/App/Zealc/Command/download.pm [new file with mode: 0644]
lib/App/Zealc/Command/expand.pm [new file with mode: 0644]
lib/App/Zealc/Command/list.pm [new file with mode: 0644]
lib/App/Zealc/Command/query.pm [new file with mode: 0644]
lib/App/Zealc/UsageExtractor.pm [new file with mode: 0644]
t/App-Zealc.t [new file with mode: 0644]
zealc [new file with mode: 0755]

diff --git a/Changes b/Changes
new file mode 100644 (file)
index 0000000..33a1ccc
--- /dev/null
+++ b/Changes
@@ -0,0 +1,4 @@
+Revision history for Perl extension App::Zealc.
+
+0.000_001 2015-02-01T00:10+02:00
+  - Initial release
diff --git a/MANIFEST b/MANIFEST
new file mode 100644 (file)
index 0000000..38cbc5d
--- /dev/null
+++ b/MANIFEST
@@ -0,0 +1,13 @@
+Changes
+lib/App/Zealc.pm
+lib/App/Zealc/Command.pm
+lib/App/Zealc/Command/download.pm
+lib/App/Zealc/Command/expand.pm
+lib/App/Zealc/Command/list.pm
+lib/App/Zealc/Command/query.pm
+lib/App/Zealc/UsageExtractor.pm
+Makefile.PL
+MANIFEST
+README
+t/App-Zealc.t
+zealc
diff --git a/Makefile.PL b/Makefile.PL
new file mode 100644 (file)
index 0000000..7055593
--- /dev/null
@@ -0,0 +1,39 @@
+use 5.014000;
+use ExtUtils::MakeMaker;
+
+WriteMakefile(
+       NAME              => 'App::Zealc',
+       VERSION_FROM      => 'lib/App/Zealc.pm',
+       ABSTRACT_FROM     => 'lib/App/Zealc.pm',
+       AUTHOR            => 'Marius Gavrilescu <marius@ieval.ro>',
+       MIN_PERL_VERSION  => '5.14.0',
+       LICENSE           => 'perl',
+       SIGN              => 1,
+       PREREQ_PM         => {
+               qw/Encode 0
+                  File::Spec::Functions 0
+                  File::Temp 0
+
+                  App::Cmd                 0
+                  Class::Accessor::Fast    0
+                  Class::Method::Modifiers 0
+                  Config::Auto             0
+                  File::Slurp              0
+                  File::Which              0
+                  HTML::FormatText         0
+                  IO::Prompter             0
+                  Pod::Simple::Methody     0
+                  Term::ANSIColor          0
+                  Term::FormatColumns      0
+                  Term::Pager              0
+                  Text::Wrap               0
+                  Zeal                     0
+                  Zeal::Feed               0/,
+       },
+       META_MERGE        => {
+               dynamic_config => 0,
+               resources      => {
+                       repository => 'https://git.ieval.ro/?p=app-zealc.git',
+               }
+       }
+);
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..e89d2d4
--- /dev/null
+++ b/README
@@ -0,0 +1,43 @@
+App-Zealc version 0.000_001
+===========================
+zealc is a command-line offline documentation browser inspired by
+http://kapeli.com/dash and |http://zealdocs.org. It uses Dash/Zeal
+format docsets via the Zeal library.
+
+INSTALLATION
+
+To install this module type the following:
+
+   perl Makefile.PL
+   make
+   make test
+   make install
+
+DEPENDENCIES
+
+This module requires these other modules and libraries:
+
+* App::Cmd
+* Class::Accessor::Fast
+* Class::Method::Modifiers
+* Config::Auto
+* File::Slurp
+* File::Which
+* HTML::FormatText
+* IO::Prompter
+* Pod::Simple
+* Term::ANSIColor
+* Term::FormatColumns
+* Term::Pager
+* Text::Wrap
+* Zeal
+
+COPYRIGHT AND LICENCE
+
+Copyright (C) 2015 by Marius Gavrilescu
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself, either Perl version 5.20.1 or,
+at your option, any later version of Perl 5 you may have available.
+
+
diff --git a/lib/App/Zealc.pm b/lib/App/Zealc.pm
new file mode 100644 (file)
index 0000000..8c9d879
--- /dev/null
@@ -0,0 +1,89 @@
+package App::Zealc;
+
+use 5.014000;
+use strict;
+use warnings;
+
+our $VERSION = '0.000_001';
+
+use App::Cmd::Setup '-app';
+use parent qw/Class::Accessor::Fast/;
+__PACKAGE__->mk_accessors(qw/path zeal config verbose/);
+
+use Class::Method::Modifiers qw/before/;
+use Config::Auto;
+
+use File::Spec::Functions qw/catfile/;
+
+use Zeal;
+
+use constant DEFAULT_PATH => $ENV{HOME} ? catfile $ENV{HOME}, '.docsets' : '.docsets';
+
+sub allow_any_unambiguous_abbrev () { 1 }
+sub default_command { 'commands' } # Show usage when called without arguments
+
+sub global_opt_spec {
+       (['config|c=s' => 'Path to configuration file'],
+        ['path|p=s'   => 'Path to docset directory',],
+        ['verbose|v!' => 'Print verbose debugging output'])
+}
+
+sub parse_config {
+       my ($cfg) = @_;
+       return Config::Auto::parse($cfg) if $cfg;
+       eval { Config::Auto::parse } or {}
+}
+
+before 'execute_command' => sub {
+       my ($self) = @_;
+       my %opts   = %{$self->global_options};
+       my $config = parse_config $ENV{ZEALC_CONFIG} || $opts{config};
+       my %config = %$config;
+       my $path   = $opts{path} || $config{path} || DEFAULT_PATH;
+       mkdir $path unless -d $path;
+
+       my $zeal   = Zeal->new($path);
+       $self->path($path);
+       $self->zeal($zeal);
+       $self->config($config);
+       $self->verbose($opts{verbose} || $config{verbose})
+};
+
+1;
+__END__
+
+=encoding utf-8
+
+=head1 NAME
+
+App::Zealc - command-line offline documentation browser for Dash/Zeal docsets
+
+=head1 SYNOPSIS
+
+  use App::Zealc;
+  App::Zealc->run;
+
+=head1 DESCRIPTION
+
+zealc is a command-line offline documentation browser inspired by
+L<Dash|http://kapeli.com/dash> and L<Zeal|http://zealdocs.org>. It
+uses Dash/Zeal format docsets via the L<Zeal> library.
+
+=head1 SEE ALSO
+
+L<zealc>, L<Zeal>
+
+=head1 AUTHOR
+
+Marius Gavrilescu, E<lt>marius@ieval.roE<gt>
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2015 by Marius Gavrilescu
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself, either Perl version 5.20.1 or,
+at your option, any later version of Perl 5 you may have available.
+
+
+=cut
diff --git a/lib/App/Zealc/Command.pm b/lib/App/Zealc/Command.pm
new file mode 100644 (file)
index 0000000..703bed3
--- /dev/null
@@ -0,0 +1,57 @@
+package App::Zealc::Command;
+
+use 5.014000;
+use strict;
+use warnings;
+
+our $VERSION = '0.000_001';
+
+use parent qw/App::Cmd::Command/;
+use App::Zealc::UsageExtractor;
+
+sub description {
+       my ($self) = @_;
+       my ($file) = (ref $self) =~ s,::,/,gr;
+       my $parser = App::Zealc::UsageExtractor->new;
+       $parser->parse_file($INC{"$file.pm"});
+       return $parser->usage
+}
+
+1;
+__END__
+
+=encoding utf-8
+
+=head1 NAME
+
+App::Zealc::Command - Base class for zealc commands
+
+=head1 SYNOPSIS
+
+  package App::Zealc::Command::foo;
+  use App::Zealc '-command';
+
+=head1 DESCRIPTION
+
+App::Zealc::Command is the base class of all zealc commands. Its only
+role is to supply a default C<description> method that extracts the
+SYNOPSIS and DESCRIPTION sections using L<App::Zealc::UsageExtractor>.
+
+=head1 SEE ALSO
+
+L<App::Zealc::UsageExtractor>, L<zealc>, L<Zeal>
+
+=head1 AUTHOR
+
+Marius Gavrilescu, E<lt>marius@ieval.roE<gt>
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2015 by Marius Gavrilescu
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself, either Perl version 5.20.1 or,
+at your option, any later version of Perl 5 you may have available.
+
+
+=cut
diff --git a/lib/App/Zealc/Command/download.pm b/lib/App/Zealc/Command/download.pm
new file mode 100644 (file)
index 0000000..7936a6a
--- /dev/null
@@ -0,0 +1,103 @@
+package App::Zealc::Command::download;
+
+use 5.014000;
+use strict;
+use warnings;
+
+our $VERSION = '0.000_001';
+
+use App::Zealc '-command';
+
+use File::Spec::Functions qw/rel2abs/;
+
+use Term::ANSIColor qw/:constants/;
+use Term::FormatColumns qw/format_columns/;
+use Zeal::Feed;
+
+use constant FEEDS => [qw/NET_Framework ActionScript ColdFusion Akka Android AngularJS Ansible Apache_HTTP_Server Appcelerator_Titanium AppleScript Arduino AWS_JavaScript BackboneJS Bash Boost Bootstrap_2 Bootstrap_3 Bourbon C CakePHP Cappuccino Chai Chef Clojure CMake Cocos2D Cocos3D CodeIgniter CoffeeScript Common_Lisp Compass Cordova Corona CSS D3JS Dart Django Dojo DOM Drupal_7 Drupal_8 ElasticSearch Elixir Emacs_Lisp EmberJS Emmet Erlang Express ExpressionEngine ExtJS Flask Font_Awesome Foundation Git GLib Go Grails Groovy Groovy_JDK Grunt Haml Haskell HTML iOS Jade Jasmine Java_EE6 Java_EE7 Java_SE6 Java_SE7 Java_SE8 JavaFX JavaScript Joomla jQuery jQuery_Mobile jQuery_UI KnockoutJS Kobold2D LaTeX Laravel Less Linux_Man_Pages Mac_OS_X Man_Pages MarionetteJS Markdown Meteor MomentJS MongoDB Mongoose Mono MooTools MySQL Neat Nginx NodeJS NumPy OCaml OpenCV_C OpenCV_Java OpenCV_Python OpenGL_2 OpenGL_3 OpenGL_4 Perl PhoneGap PHP PHPUnit Play_Java Play_Scala PostgreSQL Processing PrototypeJS Puppet Python_2 Python_3 Qt_4 Qt_5 R Redis RequireJS Ruby Ruby_2 Ruby_on_Rails_3 Ruby_on_Rails_4 RubyMotion Rust SaltStack Sass Scala SciPy Sencha_Touch Sinon Smarty Sparrow Spring_Framework SproutCore SQLAlchemy SQLite Statamic Stylus SVG Swift Symfony Tcl Tornado Twig Twisted TYPO3 UnderscoreJS Unity_3D Vagrant Vim VMware_vSphere WordPress Xamarin Xojo XSLT XUL Yii YUI Zend_Framework_1 Zend_Framework_2 ZeptoJS/];
+
+my %feeds = map { y/A-Z_/a-z-/r => $_ } @{FEEDS()};
+
+sub usage_desc { "%c download %o\n%c download %o DOCSET\n%c download URL_TO_FEED" }
+
+sub validate_args {
+       my ($self, $opts, $args) = @_;
+       my @args = @$args;
+       $self->usage_error("Too many arguments") if @args > 1;
+}
+
+sub _show_docset {
+       my ($file) = @_;
+       return $_                   unless -d $file;
+       return BOLD . "$_*" . RESET if -t select;
+       return "$_*";
+}
+
+sub execute {
+       my ($self, $opts, $args) = @_;
+       my ($name) = @$args;
+       if (!$name) {
+               my @feeds = map {
+                       my $fname = $feeds{$_} =~ y/_/ /r;
+                       my $file = rel2abs "$fname.docset", $self->app->path;
+                       _show_docset $file
+               } sort keys %feeds;
+               print format_columns @feeds;
+       } else {
+               my $feed = Zeal::Feed->new(exists $feeds{$name} ? "http://kapeli.com/feeds/$feeds{$name}.xml" : $name);
+               say "Downloading $feeds{$name} version ", $feed->version, ' from ', $feed->url;
+               $feed->download($self->app->path);
+       }
+}
+
+1;
+__END__
+
+=encoding utf-8
+
+=head1 NAME
+
+App::Zealc::Command::download - view available docsets and download them
+
+=head1 SYNOPSIS
+
+  zealc download
+  # <list of docsets>
+
+  zealc download latex
+  # Downloading LaTeX version /1 from http://london3.kapeli.com/feeds/LaTeX.tgz
+
+  zealc download http://kapeli.com/feeds/LaTeX.xml
+  # Downloading LaTeX version /1 from http://london3.kapeli.com/feeds/LaTeX.tgz
+
+=head1 DESCRIPTION
+
+When invoked with no arguments, the download command displays a list
+of known Dash docsets. The installed docsets have a * after their
+name.
+
+When invoked with an argument from the list of known Dash docsets it
+downloads that docset.
+
+When invoked with an argument not from the list of known Dash docsets
+it assumes the argument is a link to a L<Zeal::Feed> and downloads the
+docset described by the feed.
+
+=head1 SEE ALSO
+
+L<zealc>, L<Zeal>
+
+=head1 AUTHOR
+
+Marius Gavrilescu, E<lt>marius@ieval.roE<gt>
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2015 by Marius Gavrilescu
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself, either Perl version 5.20.1 or,
+at your option, any later version of Perl 5 you may have available.
+
+
+=cut
diff --git a/lib/App/Zealc/Command/expand.pm b/lib/App/Zealc/Command/expand.pm
new file mode 100644 (file)
index 0000000..df149db
--- /dev/null
@@ -0,0 +1,82 @@
+package App::Zealc::Command::expand;
+
+use 5.014000;
+use strict;
+use warnings;
+
+our $VERSION = '0.000_001';
+
+use App::Zealc '-command';
+
+sub usage_desc { "%c expand %o pattern"}
+
+sub opt_spec {
+       (['family|f!', 'Include docset family in output']),
+}
+
+sub validate_args {
+       my ($self, $opts, $args) = @_;
+       my @args = @$args;
+       $self->usage_error("No pattern specified") unless @args;
+       $self->usage_error("Too many arguments") if @args > 1;
+}
+
+sub execute {
+       my ($self, $opts, $args) = @_;
+       my @results = sort { $a->name cmp $b->name } $self->app->zeal->query($args->[0]);
+       exit 1 unless @results;
+       say join "\n", map {
+               my $family = $_->docset->family;
+               $opts->{family} ? "$family:" . $_->name : $_->name
+       } @results
+}
+
+1;
+__END__
+
+=encoding utf-8
+
+=head1 NAME
+
+App::Zealc::Command::expand - list all documents that match a pattern
+
+=head1 SYNOPSIS
+
+  zealc expand perlmo%
+  # perlmod
+  # perlmodinstall
+  # perlmodlib
+  # perlmodstyle
+
+  zealc expand -f perl_os
+  # perl:perldos
+  # perl:perlvos
+
+=head1 DESCRIPTION
+
+The expand command lists all documents that match a case-insensitive
+SQL LIKE pattern.
+
+A SQL LIKE pattern is similar to a shell glob. The "%" character
+matches zero or more characters (like "*" in a shell glob or ".*" in a
+regex) and "_" matches exactly one character (like "?" in a shell glob
+or "." in a regex). Matching is case-insensitive.
+
+=head1 SEE ALSO
+
+L<zealc>, L<Zeal>
+
+=head1 AUTHOR
+
+Marius Gavrilescu, E<lt>marius@ieval.roE<gt>
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2015 by Marius Gavrilescu
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself, either Perl version 5.20.1 or,
+at your option, any later version of Perl 5 you may have available.
+
+
+=cut
diff --git a/lib/App/Zealc/Command/list.pm b/lib/App/Zealc/Command/list.pm
new file mode 100644 (file)
index 0000000..66a67db
--- /dev/null
@@ -0,0 +1,74 @@
+package App::Zealc::Command::list;
+
+use 5.014000;
+use strict;
+use warnings;
+
+our $VERSION = '0.000_001';
+
+use App::Zealc '-command';
+use Term::FormatColumns qw/format_columns/;
+
+sub opt_spec {
+       (['long|l', 'Display more information about each docset'])
+}
+
+sub execute {
+       my ($self, $opts, $args) = @_;
+       if ($opts->{long}) {
+               my $maxlen = 0;
+               my @args;
+               for my $set (sort {$a->name cmp $b->name} $self->app->zeal->sets) {
+                       push @args, [$set->name, $set->family];
+                       $maxlen = length $set->name if length $set->name > $maxlen
+               }
+               printf "%-${maxlen}s %s:\n", @$_ for @args;
+       } else {
+               my @sets = sort map {$_->name} $self->app->zeal->sets;
+               print format_columns @sets;
+       }
+}
+
+1;
+__END__
+
+=encoding utf-8
+
+=head1 NAME
+
+App::Zealc::Command::list - list the installed docsets
+
+=head1 SYNOPSIS
+
+  zealc list
+  # Ansible       Bootstrap 3   Perl          Sass
+
+  zealc list -l
+  # Ansible     ansible:
+  # Bootstrap 3 bootstrap:
+  # Perl        perl:
+  # Sass        sass:
+
+=head1 DESCRIPTION
+
+The list command displays the installed docsets. With the -l argument
+it also displays their keywords.
+
+=head1 SEE ALSO
+
+L<zealc>, L<Zeal>
+
+=head1 AUTHOR
+
+Marius Gavrilescu, E<lt>marius@ieval.roE<gt>
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2015 by Marius Gavrilescu
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself, either Perl version 5.20.1 or,
+at your option, any later version of Perl 5 you may have available.
+
+
+=cut
diff --git a/lib/App/Zealc/Command/query.pm b/lib/App/Zealc/Command/query.pm
new file mode 100644 (file)
index 0000000..94cb5e5
--- /dev/null
@@ -0,0 +1,201 @@
+package App::Zealc::Command::query;
+
+use 5.014000;
+use strict;
+use warnings;
+
+our $VERSION = '0.000_001';
+
+use App::Zealc '-command';
+
+use IO::Prompter;
+use File::Slurp qw/write_file/;
+use File::Temp qw//;
+use File::Which;
+use HTML::FormatText;
+use Term::Pager;
+
+use Encode qw/encode/;
+
+# These set --format=html and --with=something
+use constant BROWSERS => [ qw/www-browser lynx links2 elinks w3m x-www-browser firefox/ ];
+my @BROWSERS = map { [$_, "Shorthand for --format=html --with=$_", {implies => {with => $_, format => 'html'}}] } @{BROWSERS()};
+
+# These set -format=something
+use constant FORMATTERS => [
+       [lynxdump => 'lynx -dump -nolist'],
+       [links2dump => 'links2 -dump'],
+       [elinksdump => 'elinks -dump -eval "set document.dump.references = 0" -eval "set document.dump.numbering = 0"'],
+];
+my @FORMATTERS = map {
+       my ($name, $format) = @$_;
+       [$name, "Shorthand for --format='$format'", {implies => {format => $format}}]
+} @{FORMATTERS()};
+
+# These set --with=something
+use constant PAGERS => [ qw/pager less most more pg/ ];
+my @PAGERS = map { [$_, "Shorthand for --with=$_", {implies => {with => $_}}] } @{PAGERS()};
+
+sub opt_spec {(
+       ['with|w=s', 'Open with this program'],
+       ['format|f=s', 'Convert html to this format'],
+
+       [], @BROWSERS,
+       [], @FORMATTERS,
+       [], @PAGERS,
+)}
+
+sub usage_desc { "%c query %o term" };
+
+sub validate_args {
+       my ($self, $opts, $args) = @_;
+       my @args = @$args;
+       $self->usage_error("No query specified") unless @args;
+       $self->usage_error("Too many arguments") if @args > 1;
+       $opts->{with}   //= $self->app->config->{with};
+       $opts->{format} //= $self->app->config->{format};
+
+       # If output is not a tty, do not choose browsers/pagers
+       $opts->{with} //= '' unless -t select;
+
+       # Try to default to a browser
+       if (!defined $opts->{with} && !defined $opts->{format}) {
+               for my $browser (@{BROWSERS()}) {
+                       warn "Trying to use $browser as a browser\n" if $self->app->verbose;
+                       next unless which $browser;
+                       $opts->{with}   = $browser;
+                       $opts->{format} = 'html';
+                       last
+               }
+       }
+
+       # If no browsers were found, try to choose a formatter
+       unless (defined $opts->{format}) {
+               for my $formatter (map { $_->[1] } @{FORMATTERS()}) {
+                       my ($exec) = $formatter =~ /^(\w+)/s;
+                       warn "Trying to use $exec ($formatter) as a formatter\n" if $self->app->verbose;
+                       next unless which $exec;
+                       $opts->{format} = $formatter;
+                       last
+               }
+       }
+
+       # If no browsers were found, try to choose a pager
+       unless (defined $opts->{with}) {
+               for my $pager (@{PAGERS()}) {
+                       warn "Trying to use $pager as a pager\n" if $self->app->verbose;
+                       next unless which $pager;
+                       $opts->{with} = $pager;
+                       last
+               }
+       }
+
+       # Default to HTML::FormatText and the internal pager
+       $opts->{format} //= 'text';
+       $opts->{with} //= '';
+}
+
+sub html_to_format {
+       my ($html, $format) = @_;
+       return $html if $format eq 'html';
+       return HTML::FormatText->format_string($html) if $format eq 'text';
+       my $tmp = File::Temp->new(TEMPLATE => 'zealcXXXX', SUFFIX => '.html');
+       write_file $tmp, $html;
+       my $fn = $tmp->filename;
+       `$format $fn`
+}
+
+sub show_document {
+       my ($self, $doc, %opts) = @_;
+       my $html = $doc->fetch;
+
+       say "Format: $opts{format}" if $self->app->verbose;
+       say "Open with: ", $opts{with} // 'internal pager' if $self->app->verbose;;
+
+       my $text = encode 'UTF-8', html_to_format $html, $opts{format};
+
+       if ($opts{with}) {
+               my $tmp = File::Temp->new(TEMPLATE => 'zealcXXXX', SUFFIX => '.html');
+               write_file $tmp, $text;
+               system $opts{with} . ' ' . $tmp->filename;
+       } elsif (!-t select) {
+               say $text
+       } else {
+               my ($rows, $cols) = split ' ', `stty size`;
+               my $pager = Term::Pager->new(text => $text, rows => $rows, cols => $cols);
+               $pager->more;
+       }
+}
+
+sub execute {
+       my ($self, $opts, $args) = @_;
+       my %opts = %$opts;
+       my ($query) = @$args;
+       my $zeal = $self->app->zeal;
+       my @results = $zeal->query($query);
+       @results    = $zeal->query("$query%") unless @results;
+       die "No results found for $query\n" unless @results;
+
+       my $doc = $results[0];
+       if (@results > 1 && -t select) {
+               my @args = '-single';
+               @args = '-number' if @results > 52;
+               my %menu = map {
+                       my $ds = $results[$_]->docset->name;
+                       $results[$_]->name . " ($ds)" => $_
+               } 0 .. $#results;
+               $doc = prompt 'Choose a document', -menu => \%menu, '-stdio', @args;
+               return unless $doc;
+               $doc = $results[$doc];
+       }
+
+       $self->show_document($doc, %opts);
+}
+
+1;
+__END__
+
+=encoding utf-8
+
+=head1 NAME
+
+App::Zealc::Command::query - view the documentation for a term
+
+=head1 SYNOPSIS
+
+  zealc query perldoc
+  # displays documentation for perldoc
+
+  zealc query --w3m perl:%Spec
+  # finds File::Spec and perlpodspec
+
+=head1 DESCRIPTION
+
+The query command displays the documentation for a given term. The
+term is a SQL LIKE pattern. If no documents are found, the search is
+retried after appending a % to the term. If multiple documents are
+found, the user will be prompted to choose one of them.
+
+A SQL LIKE pattern is similar to a shell glob. The "%" character
+matches zero or more characters (like "*" in a shell glob or ".*" in a
+regex) and "_" matches exactly one character (like "?" in a shell glob
+or "." in a regex). Matching is case-insensitive.
+
+=head1 SEE ALSO
+
+L<zealc>, L<Zeal>
+
+=head1 AUTHOR
+
+Marius Gavrilescu, E<lt>marius@ieval.roE<gt>
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2015 by Marius Gavrilescu
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself, either Perl version 5.20.1 or,
+at your option, any later version of Perl 5 you may have available.
+
+
+=cut
diff --git a/lib/App/Zealc/UsageExtractor.pm b/lib/App/Zealc/UsageExtractor.pm
new file mode 100644 (file)
index 0000000..7ba28f2
--- /dev/null
@@ -0,0 +1,109 @@
+package App::Zealc::UsageExtractor;
+
+use 5.014000;
+use strict;
+use warnings;
+
+our $VERSION = '0.000_001';
+
+use parent qw/Pod::Simple::Methody/;
+
+use Text::Wrap qw/fill/;
+
+sub start_head1 {
+       my ($self, $section) = @_;
+       $self->{section} = '';
+       $self->{insection} = 1;
+}
+
+sub end_head1 {
+       my ($self) = @_;
+       $self->{insection} = 0;
+       $self->{firstpara} = 1;
+}
+
+sub start_Para {
+       my ($self) = @_;
+       $self->handle_text("\n\n") unless $self->{firstpara};
+       $self->{firstpara} = 0;
+}
+
+sub handle_text {
+       my ($self, $text) = @_;
+       $self->{section}          .= $text if $self->{insection};
+       $self->{$self->{section}} .= $text if $self->{section} && !$self->{insection};
+}
+
+sub synopsis {
+       my ($self) = @_;
+       $self->{SYNOPSIS}
+}
+
+sub description {
+       my ($self) = @_;
+       fill '', '', $self->{DESCRIPTION}
+}
+
+sub usage {
+       my ($self) = @_;
+       $self->synopsis . "\n\n" . $self->description . "\n";
+}
+
+1;
+__END__
+
+=encoding utf-8
+
+=head1 NAME
+
+App::Zealc::UsageExtractor - Extract SYNOPSIS and DESCRIPTION sections from a module
+
+=head1 SYNOPSIS
+
+  use App::Zealc::UsageExtractor;
+  my $parser = App::Zealc::UsageExtractor->new;
+  $parser->parse_file("path/to/file.pm");
+
+  say $parser->synopsis;    # contents of synopsis section
+  say $parser->description; # contents of description, filled
+  say $parser->usage; # $parser->synopsis."\n\n".$parser->description."\n"
+
+=head1 DESCRIPTION
+
+App::Zealc::UsageExtractor is a L<Pod::Simple> subclass that extracts
+the SYNOPSIS and DESCRIPTION sections from a Pod file.
+
+=over
+
+=item synopsis
+
+The SYNOPSIS section of the file
+
+=item description
+
+The DESCRIPTION section of the file, filled using L<Text::Wrap>
+
+=item usage
+
+Equivalent to C<< $parser->synopsis."\n\n".$parser->description."\n" >>
+
+=back
+
+=head1 SEE ALSO
+
+L<zealc>, L<Zeal>
+
+=head1 AUTHOR
+
+Marius Gavrilescu, E<lt>marius@ieval.roE<gt>
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2015 by Marius Gavrilescu
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself, either Perl version 5.20.1 or,
+at your option, any later version of Perl 5 you may have available.
+
+
+=cut
diff --git a/t/App-Zealc.t b/t/App-Zealc.t
new file mode 100644 (file)
index 0000000..81053e0
--- /dev/null
@@ -0,0 +1,7 @@
+#!/usr/bin/perl
+use strict;
+use warnings;
+
+use Test::More tests => 1;
+BEGIN { use_ok('App::Zealc') };
+use App::Cmd::Tester;
diff --git a/zealc b/zealc
new file mode 100755 (executable)
index 0000000..62fedf6
--- /dev/null
+++ b/zealc
@@ -0,0 +1,189 @@
+#!/usr/bin/perl
+use v5.14;
+use warnings;
+
+use lib 'lib';
+use lib '../zeal/lib';
+
+use App::Zealc;
+App::Zealc->run;
+__END__
+
+=encoding utf-8
+
+=head1 NAME
+
+zealc - Browse API documentation for various projects
+
+=head1 SYNOPSIS
+
+  zealc download Perl
+  # Downloading Perl version 5.20.1 from http://sanfrancisco.kapeli.com/feeds/Perl.tgz
+
+  zealc list
+  # Perl
+
+  zealc list -l
+  # Perl perl:
+
+  zealc expand perl_os -l
+  # perl:perldos
+  # perl:perlvos
+
+  zealc query perldos
+  zealc query perldoc --elinks
+
+=head1 DESCRIPTION
+
+zealc is a command-line offline documentation browser inspired by
+L<Dash|http://kapeli.com/dash> and L<Zeal|http://zealdocs.org>. It
+uses Dash/Zeal format docsets via the L<Zeal> library.
+
+=head2 Global options
+
+=over
+
+=item B<--config>=I</path/to/file>
+
+Specify a configuration file to use. If this argument is missing,
+B<zealc> will look for files F<zealcconfig>, F<zealc.config>,
+F<zealcrc>, F<.zealcrc> in the current directory, the home directory,
+in F</etc/>, and in F</usr/local/etc/>. This behaviour is described in
+the "HOW IT WORKS" section of the L<Config::Auto> manpage.
+
+See also the L</"CONFIGURATION"> section below.
+
+=item B<--path>=I</path/to/docset/directory>
+
+The path to a directory containing docsets. Defaults to F<~/.docset>
+if the home directory is known, F<.docset> otherwise.
+
+=item B<--verbose>, B<--no-verbose>
+
+If B<--verbose> is in effect, more messages will be printed. Default
+is B<--no-verbose>.
+
+=back
+
+=head2 Commands
+
+=over
+
+=item B<zealc download>
+
+View the list of official Dash docsets. The docsets that are already
+installed will be displayed in a bold font and with a * after their
+name.
+
+=item B<zealc download> I<docset_id>
+
+Download an official Dash docset. I<docset_id> is one of the ids
+returned by B<zealc download>.
+
+=item B<zealc download> I<http://example.com/path/to/feed.xml>
+
+Download a docset from a given docset feed.
+
+=item B<zealc expand> [-f|--family] I<pattern>
+
+List all documents matching I<pattern>, where I<pattern> is a SQL LIKE
+pattern. If I<-f> or I<--family> is present, include the docset family
+of each found document. This command is mostly intended for use in
+scripts, as each line of the output can be directly passed to B<zealc
+query>.
+
+=item B<zealc list> [-l|--long]
+
+List the names of all installed docsets. If I<-l> or I<--long> is
+present, also display the family of each docset.
+
+=item B<zealc query> [-w WITH|--with=WITH] [-f FORMAT|--format FORMAT] I<pattern>
+
+Display the documentation for a given pattern. I<pattern> is a SQL
+LIKE pattern. If more than one document is found and STDOUT is a
+terminal, the user will be asked to choose one of them. If more than
+one document is found and STDOUT is not a terminal, a randomly chosen
+document will be displayed.
+
+To display the document, it will first be converted in the format
+specified by I<--format>, then it will be opened with the program
+specified by I<--with>.
+
+I<--format> can be one of:
+
+=over
+
+=item html, in which case no conversion will be done
+
+=item text, in which case it will be converted to text with L<HTML::FormatText>
+
+=item program arg1 arg2, in which case the HTML document will be
+passed as the first argument to this program
+
+=back
+
+=back
+
+=head1 CONFIGURATION
+
+B<zealc> uses L<Config::Auto> for configuration. please read its
+manpage for a detailed explanation. Command-line arguments override
+configuration directives. The available configuration directives are:
+
+=over
+
+=item B<path>
+
+Path to the directory containing the docsets. Equivalent to the
+B<--config> global option.
+
+=item B<verbose>
+
+If true, print more detailed messages. Equivalent to the B<--verbose>
+global option.
+
+If false, do not print detailed messages. Equivalent to the
+B<--no-verbose> global option, which is the default.
+
+=item B<with>
+
+The program used to open documents. Usually a web browser or a pager.
+Equivalent to the B<--with> option to B<zealc query>.
+
+=item B<format>
+
+The program used to format documents. This can also be one of the
+special values I<html> (do not format this document) or I<text>
+(convert to text via L<HTML::FormatText>). Equivalent to the
+B<--format> option to B<zealc query>.
+
+=back
+
+To get started with configuration, create a file named F<.zealcrc> in
+your home directory (or in the current directory) with keys separated
+by values using an equals sign. For example:
+
+  path=/home/mgv/docsets/
+  with=/usr/bin/lynx -color
+  format=html
+  verbose=1
+
+=head1 SEE ALSO
+
+L<http://kapeli.com/dash>, L<Zeal>
+
+=head1 AUTHOR
+
+Marius Gavrilescu, E<lt>marius@ieval.roE<gt>
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2015 by Marius Gavrilescu
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself, either Perl version 5.20.1 or,
+at your option, any later version of Perl 5 you may have available.
+
+
+
+=cut
This page took 0.027783 seconds and 4 git commands to generate.