package Bash::Completion::Plugins::VimTag;
use strict;
use warnings;
use Path::Iterator::Rule;
use parent 'Bash::Completion::Plugin';
our $VERSION = '2.00';
sub should_activate { [ qw(vit) ] }

sub generate_bash_setup {
    q{complete -C 'bash-complete complete VimTag' -o nospace -o default vit};
}

sub complete {
    my ($self, $r) = @_;
    my $CTAGSDIR = $ENV{CTAGSDIR} // "$ENV{HOME}/.ctagsdir";
    my $word = $r->word;
    my @candidates;
    my $rule = Path::Iterator::Rule->new->name('tags');
    for my $file ($rule->all($CTAGSDIR)) {
        open my $fh, '<', $file or next;    # fail silently

      # The tags file is sorted alphabetically, so if we've found something,
      # then from that point on, if a line doesn't match, we don't need to
      # search any further - we can't match anything that comes later in the
      # file either.
      #
      # Compared to slurping the whole file, then checking every line, this is a
      # lot faster, so the bash completion feels a lot more responsive.
        my $has_hits = 0;
        while (<$fh>) {
            if (index($_, $word) == 0) {
                push @candidates, (split)[0];
                $has_hits++;
            } else {
                last if $has_hits;
            }
        }
        close $fh or next;
    }

    # Special case if the word contains one or more colons: Only return the
    # part of each completion that comes after the last colon. This has to do
    # with bash using the colon as a delimiter, I guess.
    if ($word =~ /^(.+::?)/) {
        my $prefix_length = length $1;
        substr($_, 0, $prefix_length) = '' for @candidates;
    }
    $r->candidates(@candidates);
}
1;

=head1 NAME

Bash::Completion::Plugins::VimTag - Bash completion plugin for vim tags

=head1 DESCRIPTION

This is a L<Bash::Completion> plugin that can complete on tags
generated by C<ctags>. My setup places all C<tags> files from
different projects in a C<~/.ctagsdir> directory so vim can know about
them regardless of the current directory:

    ~/.ctagsdir
    ├── project1
    │   └── tags
    ├── project2
    │   └── tags
    └── perlbrew
        └── tags

My <.vimrc> then contains:

    set tags+=~/.ctagsdir/*/tags

And <.bashrc> contains:

    alias vit='vi -t'

If you keep your tags in a different directory - for example, your
main repository directory -, you can set the C<CTAGSDIR> environment
variable to that directory and this plugin will scan the C<tags> files
in that directory.

The reason for the C<perlbrew/tags> file shown in the tree above is
that I want to have tags for all installed modules, so I generate them
with:

    find $PERLBREW_ROOT/perls/$PERLBREW_PERL/lib -name \*.pm | \
        ctags -f ~/.ctagsdir/perlbrew/tags --recurse --languages=Perl -L -;

=cut
