#!perl

our $DATE = '2014-11-07'; # DATE
our $VERSION = '0.01'; # VERSION

use 5.010;
use strict;
use warnings;

use App::BashCompletionProg;
use Perinci::CmdLine::Any -prefer_lite=>1;

our %SPEC;

sub _all_exec_in_PATH {
    my @res;
    for my $dir (split /:/, $ENV{PATH}) {
        opendir my($dh), $dir or next;
        for my $f (readdir $dh) {
            next if $f eq '.' || $f eq '..';
            next unless ((-f "$dir/$f") && (-x _));
            push @res, "$dir/$f";
        }
    }
    \@res;
}

$SPEC{prog} = {
    v => 1.1,
    summary => 'Add appropriate bash completion command for a program',
    args => {
        file => {
            summary => 'Specify alternate location for bash-completion-prog file',
            description => <<'_',

The default is `/etc/bash-completion-prog` (if running as root), or
`~/.bash-completion-prog` (if running as normal user).

_
            schema  => 'str*',
        },
        action => {
            schema => 'str*',
            cmdline_aliases => {
                list       => { is_flag=>1, code=>sub { $_[0]{action} = 'list' } },
                l          => { is_flag=>1, code=>sub { $_[0]{action} = 'list' } },
                clean      => { is_flag=>1, code=>sub { $_[0]{action} = 'clean' } },
                remove     => { is_flag=>1, code=>sub { $_[0]{action} = 'remove' } },
                remove_all => { is_flag=>1, code=>sub { $_[0]{action} = 'remove_all' } },
            },
            default => 'add',
        },
        detail => {
            schema => 'bool*',
        },
        replace => {
            schema => 'bool*',
        },
       args => {
            schema => ['array*' => of => 'str*'],
            pos    => 0,
            greedy => 1,
        },
    },
};
sub prog {
    my %args = @_;

    my $action = $args{action};
    my $args   = $args{args};

    if ($action eq 'add') {
        $args = _all_exec_in_PATH() unless $args;
        return App::BashCompletionProg::_add(
            file    => $args{file},
            progs   => $args,
            replace => $args{replace},
        );
    } elsif ($action eq 'list') {
        return App::BashCompletionProg::_list(
            file   => $args{file},
            detail => $args{detail},
        );
    } elsif ($action eq 'clean') {
        return App::BashCompletionProg::_clean(
            file     => $args{file},
        );
    } elsif ($action eq 'remove') {
        return [400, "Please specify one or more programs"] unless $args;
        return App::BashCompletionProg::_remove(
            file   => $args{file},
            progs  => $args,
        );
    } elsif ($action eq 'remove_all') {
        return App::BashCompletionProg::_remove(
            file     => $args{file},
            criteria => sub {1},
        );
    }
}

Perinci::CmdLine::Any->new(
    url => '/main/prog',
    log => 1,
)->run;

# ABSTRACT: Add appropriate bash completion command for a program
# PODNAME: bash-completion-prog

__END__

=pod

=encoding UTF-8

=head1 NAME

bash-completion-prog - Add appropriate bash completion command for a program

=head1 VERSION

This document describes version 0.01 of bash-completion-prog (from Perl distribution App-BashCompletionProg), released on 2014-11-07.

=head1 SYNOPSIS

Detect completion for all programs found in C<PATH>:

 % bash-completion-prog

Detect completion for some programs (replace if already listed before):

 % bash-completion-prog --replace prog1 prog2 ./bin/prog3

List completions:

 % bash-completion-prog --list

Remove some programs:

 % bash-completion-prog --remove prog1 prog2

Remove all:

 % bash-completion-prog --remove-all

=head1 DESCRIPTION

B<bash-completion-prog> is a script to make it easy to add completion for
programs. It tries to detect programs/scripts in PATH and add C<complete> bash
commands for programs that it recognizes. Currently it recognizes:

=over

=item * Scripts which are tagged with hints

You can put this in a script, e.g. in a script called C<foo>:

 # FRAGMENT id=bash-completion-prog-hints command=bar

The above line tells C<bash-completion-prog> that the script should be completed
using an external program called C<bar>. This will add this line to
C</etc/bash-completion-prog> (or C<~/.bash-completion-prog>):

 complete -C bar foo # FRAGMENT id=foo

Ignore the C<# FRAGMENT ...> or C<# BEGIN FRAGMENT ... # END FRAGMENT> part, it
is just used to aid in adding or removing the fragment.

=item * Perinci::CmdLine-based CLI scripts

If a script like C<foo> is detected as a Perl script using L<Perinci::CmdLine>
(or its variant like L<Perinci::CmdLine::Lite> or L<Perinci::CmdLine::Any>) we
know that it can complete itself. Thus, C<bash-completion-prog> will add this
line:

 complete -C foo foo # FRAGMENT id=foo

Note: this is the original reason why C<bash-completion-prog> came into being:
to easily add completion for Perinci::CmdLine-based scripts, which I write a
lot.

=item * Other methods

Other methods will be added in the future, e.g. using C<.
/etc/bash_completion.d/foo> if it exists, etc.

=back

=head2 Installation

To install system-wide:

 % touch /etc/bash-completion-prog

and put this line (notice the dot):

 . /etc/bash-completion-prog

in C</etc/bash.bashrc> or C</etc/profile>.

To install for a single user:

 % touch ~/.bash-completion-prog

and put this line (notice the dot):

 . ~/.bash-completion-prog

in C<~/.bashrc> or C<~/.bash_profile>.

=head1 Usage

The simplest usage would be to call the program without any argument, which will
scan all programs found in C<PATH> and add completion for all recognizable
commands. This will fill C</etc/bash-completion-prog> (if you're root) or
C<~/.bash-completion-prog> (if you're a normal user):

 % bash-completion-prog

Or you can add individual programs. Program names without directory (without
C</>) will be searched in C<PATH>:

 % bash-completion-prog foo ./bar/baz

If a program's completion cannot be determined, it will simply be ignored. If a
program's completion command is already listed, it will also be ignored, unless
C<--replace> is specified.

=head1 COMMAND-LINE OPTIONS

=head2 --file, -f

Specify an alternate location for the C<bash-completion-prog> file. By default
it's C</etc/bash-completion-prog> for root, or C<~/.bash-completion-prog> for
normal users.

=head2 --list, -l

List all programs which are listed in the C<bash-completion-prog> file.

=head2 --remove

Remove all programs in C<bash-completion-prog> file that are not in C<PATH>.

=head2 --remove

Remove specified programs from C<bash-completion-prog> file.

=head2 --remove-all

Remove all entries in C<bash-completion-prog> file.

=head2 --replace

When adding a program that already exists in C<bash-completion-prog> file,
replace it without warning. The default behavior is to ignore the program.

=head1 ENVIRONMENT

=head2 DEBUG => bool

Set to true to enable debugging messages.

=head1 TODO

C<--disable> and C<--enable> options.

=head1 SEE ALSO

B<bash-completion> package, http://bash-completion.alioth.debian.org/

L<Dist::Zilla::Plugin::Rinci::InstallCompletion>

=head1 HOMEPAGE

Please visit the project's homepage at L<https://metacpan.org/release/App-BashCompletionProg>.

=head1 SOURCE

Source repository is at L<https://github.com/perlancar/perl-App-BashCompletionProg>.

=head1 BUGS

Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=App-BashCompletionProg>

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
feature.

=head1 AUTHOR

perlancar <perlancar@cpan.org>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2014 by perlancar@cpan.org.

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

=cut
