package Dist::Zilla::Plugin::GenShellCompletion;

our $DATE = '2016-04-20'; # DATE
our $VERSION = '0.11'; # VERSION

use 5.010001;
use strict;
use warnings;
use utf8;

use Moose;
use namespace::autoclean;

use Data::Dmp;
use List::Util qw(first);
use Perl::osnames;

with (
    'Dist::Zilla::Role::FileFinderUser' => {
        default_finders => [':ExecFiles'],

sub setup_installer {
  my ($self) = @_;

  unless (@{ $self->found_files }) {
      $self->log_debug('No scripts in this distribution, skipped');

  # first, try MakeMaker
  my $build_script = first { $_->name eq 'Makefile.PL' }
      @{ $self->zilla->files };
  $self->log_fatal('No Makefile.PL found. Using [MakeMaker] is required')
      unless $build_script;

  my $content = $build_script->content;

  no strict 'refs';
  my $header = "
# modify generated Makefile to generate shell completion scripts. this piece\n".
"# is generated by " . __PACKAGE__ . " version " .
    (${__PACKAGE__ ."::VERSION"} // 'dev').".\n";

  my @posix_oses = map { $_->[0] } grep {
      my $rec = $_;
      grep { $_ eq 'posix' } @{ $rec->[1] }
  } @$Perl::osnames::data;

  my $body = <<'_';
  $body .= '    last unless grep { $^O eq $_ } '.dmp(@posix_oses).";\n\n";
  $body .= <<'_';
    print "Modifying Makefile to generate shell completion on install\n";
    open my($fh), "<", "Makefile" or die "Can't open generated Makefile: $!";
    my $content = do { local $/; ~~<$fh> };

    $content =~ s/^(install :: pure_install doc_install)/$1 comp_install/m
        or die "Can't find pattern in Makefile (1)";

    $content =~ s/^(uninstall :: .+)/$1 comp_uninstall/m
        or die "Can't find pattern in Makefile (2)";

    $content .= qq|\ncomp_install :\n\t| .
        q|$(PERLRUN) -E'if(eval { require App::shcompgen; 1 }) { system "shcompgen", "--verbose", "generate", "--replace", ($$App::shcompgen::VERSION >= 0.15 ? ("--remove"):()), @ARGV }' -- $(EXE_FILES)| .

    $content .= qq|\ncomp_uninstall :\n\t| .
        q|$(PERLRUN) -E'if(eval { require App::shcompgen; 1 }) { system "shcompgen", "--verbose", "remove", @ARGV }' -- $(EXE_FILES)| .

    open $fh, ">", "Makefile" or die "Can't write modified Makefile: $!";
    print $fh $content;

  $content .= $header . $body;

  return $build_script->content($content);

no Moose;
# ABSTRACT: Generate shell completion scripts when distribution is installed



=encoding UTF-8

=head1 NAME

Dist::Zilla::Plugin::GenShellCompletion - Generate shell completion scripts when distribution is installed

=head1 VERSION

This document describes version 0.11 of Dist::Zilla::Plugin::GenShellCompletion (from Perl distribution Dist-Zilla-Plugin-GenShellCompletion), released on 2016-04-20.


In your dist.ini:



This plugin modifies C<Makefile.PL> so that when a user installs your
distribution with C<make install>, L<shcompgen> is invoked to generate shell
completion scripts for your scripts. This is convenient because immediately
after the user installs your distribution, shell tab completion is already
activated for your scripts.

L<shcompgen> recognizes several ways/hints to generate completion to your
scripts. Please see its documentation for more details.

Some notes:

First, user must already install and setup L<shcompgen> prior to installing your
distribution. But if C<shcompgen> is installed after your distribution is
installed, she can simply run C<shcompgen generate> to scan PATH and generate
completion for all recognized programs, including yours.

Second, this plugin's implementation strategy is currently as follow (probably
hackish): insert some code in the generated C<Makefile.PL> after
C<WriteMakefile()> to insert some targets in the C<Makefile> generated by

Third, currently only MakeMaker is supported, L<Module::Build> is not.

=for Pod::Coverage setup_installer register_prereqs


Please visit the project's homepage at L<>.

=head1 SOURCE

Source repository is at L<>.

=head1 BUGS

Please report any bugs or feature requests on the bugtracker website L<>

When submitting a bug or request, please include a test-file or a
patch to an existing test-file that illustrates the bug or desired

=head1 SEE ALSO


CLI scripts using the L<Perinci::CmdLine> framework will automatically have
shell tab completion capability. C<shcompgen> detects this.

You can also use L<Getopt::Long::Complete> or L<Getopt::Long::Subcommand>.
C<shcompgen> also detects this.

=head1 AUTHOR

perlancar <>


This software is copyright (c) 2016 by

This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.