]> Sergey Matveev's repositories - public-inbox.git/commitdiff
lei mark: add support for (bash) completion
authorEric Wong <e@80x24.org>
Tue, 23 Mar 2021 05:02:18 +0000 (11:02 +0600)
committerEric Wong <e@80x24.org>
Wed, 24 Mar 2021 01:33:26 +0000 (01:33 +0000)
Only lightly tested, this seems to suffer from the same
problem as external completions for network URLs with
colons in them.  In any case, its usable enough for me.

The core LEI module now supports completions for lazy-loaded
commands, too, so we'll be able to do completions for other
commands more easily.

lib/PublicInbox/LEI.pm
lib/PublicInbox/LeiMark.pm

index 91c95239fe6d0fa5993c479195afede9bfdd4f82..0be417ebae524338af023c519d412e4909417782 100644 (file)
@@ -604,6 +604,19 @@ EOM
        }
 }
 
+sub lazy_cb ($$$) {
+       my ($self, $cmd, $pfx) = @_;
+       my $ucmd = $cmd;
+       $ucmd =~ tr/-/_/;
+       my $cb;
+       $cb = $self->can($pfx.$ucmd) and return $cb;
+       my $base = $ucmd;
+       $base =~ s/_([a-z])/\u$1/g;
+       my $pkg = "PublicInbox::Lei\u$base";
+       ($INC{"PublicInbox/Lei\u$base.pm"} // eval("require $pkg")) ?
+               $pkg->can($pfx.$ucmd) : undef;
+}
+
 sub dispatch {
        my ($self, $cmd, @argv) = @_;
        local $current_lei = $self; # for __WARN__
@@ -616,14 +629,7 @@ sub dispatch {
                push @{$self->{opt}->{substr($cmd, 1, 1)}}, $v;
                $cmd = shift(@argv) // return _help($self, 'no command given');
        }
-       my $func = "lei_$cmd";
-       $func =~ tr/-/_/;
-       my $cb = __PACKAGE__->can($func) // ($CMD{$cmd} ? do {
-               my $mod = "PublicInbox::Lei\u$cmd";
-               ($INC{"PublicInbox/Lei\u$cmd.pm"} //
-                       eval("require $mod")) ? $mod->can($func) : undef;
-       } : undef);
-       if ($cb) {
+       if (my $cb = lazy_cb(__PACKAGE__, $cmd, 'lei_')) {
                optparse($self, $cmd, \@argv) or return;
                $self->{opt}->{c} and (_tmp_cfg($self) // return);
                if (my $chdir = $self->{opt}->{C}) {
@@ -808,9 +814,8 @@ sub lei__complete {
                        @v;
                } grep(/\A(?:[\w-]+\|)*$opt\b.*?(?:\t$cmd)?\z/, keys %OPTDESC);
        }
-       $cmd =~ tr/-/_/;
-       if (my $sub = $self->can("_complete_$cmd")) {
-               puts $self, $sub->($self, @argv, $cur ? ($cur) : ());
+       if (my $cb = lazy_cb($self, $cmd, '_complete_')) {
+               puts $self, $cb->($self, @argv, $cur ? ($cur) : ());
        }
        # TODO: URLs, pathnames, OIDs, MIDs, etc...  See optparse() for
        # proto parsing.
index aa52ad5ae580b3cef90669c2e16bbee7f304fc58..7b50aa512a16a7acb36001033c9d95161c81e836 100644 (file)
@@ -174,4 +174,47 @@ sub ipc_atfork_child {
        PublicInbox::OnDestroy->new($$, \&note_missing, $self);
 }
 
+# Workaround bash word-splitting s to ['kw', ':', 'keyword' ...]
+# Maybe there's a better way to go about this in
+# contrib/completion/lei-completion.bash
+sub _complete_mark_common ($) {
+       my ($argv) = @_;
+       # Workaround bash word-splitting URLs to ['https', ':', '//' ...]
+       # Maybe there's a better way to go about this in
+       # contrib/completion/lei-completion.bash
+       my $re = '';
+       my $cur = pop(@$argv) // '';
+       if (@$argv) {
+               my @x = @$argv;
+               if ($cur eq ':' && @x) {
+                       push @x, $cur;
+                       $cur = '';
+               }
+               while (@x > 2 && $x[0] !~ /\A[+\-](?:kw|L)\z/ &&
+                                       $x[1] ne ':') {
+                       shift @x;
+               }
+               if (@x >= 2) { # qw(kw : $KEYWORD) or qw(kw :)
+                       $re = join('', @x);
+               } else { # just return everything and hope for the best
+                       $re = join('', @$argv);
+               }
+               $re = quotemeta($re);
+       }
+       ($cur, $re);
+}
+
+# FIXME: same problems as _complete_forget_external and similar
+sub _complete_mark {
+       my ($self, @argv) = @_;
+       my @all = map { ("+kw:$_", "-kw:$_") } @KW;
+       return @all if !@argv;
+       my ($cur, $re) = _complete_mark_common(\@argv);
+       map {
+               # only return the part specified on the CLI
+               # don't duplicate if already 100% completed
+               /\A$re(\Q$cur\E.*)/ ? ($cur eq $1 ? () : $1) : ();
+       } grep(/$re\Q$cur/, @all);
+}
+
 1;