about summary refs log tree commit homepage
path: root/lib/PublicInbox
diff options
context:
space:
mode:
authorEric Wong <e@80x24.org>2023-03-23 21:45:45 +0000
committerEric Wong <e@80x24.org>2023-03-25 21:03:53 +0000
commit2dd3cec8783700f061a0c9b69e329918a4f5cccd (patch)
tree14eb91e32413f0006706ca0557309b4a37ff6139 /lib/PublicInbox
parent2021c73236b0c7d9f4e6ad90291c35138c9ef75e (diff)
downloadpublic-inbox-2dd3cec8783700f061a0c9b69e329918a4f5cccd.tar.gz
This fixes completions of labels (`+L:' for `lei import' and
`L:' for `lei q') so they can appear anywhere in the
command-line.

I mainly wanted this for `lei import $URL +L:label', but
this also fixes `lei forget-external' completions for URLs
(which involve colons).
Diffstat (limited to 'lib/PublicInbox')
-rw-r--r--lib/PublicInbox/LeiExternal.pm31
-rw-r--r--lib/PublicInbox/LeiForgetExternal.pm8
-rw-r--r--lib/PublicInbox/LeiImport.pm22
-rw-r--r--lib/PublicInbox/LeiQuery.pm2
4 files changed, 31 insertions, 32 deletions
diff --git a/lib/PublicInbox/LeiExternal.pm b/lib/PublicInbox/LeiExternal.pm
index 3e2a2288..31b9bd1e 100644
--- a/lib/PublicInbox/LeiExternal.pm
+++ b/lib/PublicInbox/LeiExternal.pm
@@ -86,39 +86,34 @@ sub canonicalize_excludes {
 # returns an anonymous sub which returns an array of potential results
 sub complete_url_prepare {
         my $argv = $_[-1]; # $_[0] may be $lei
-        # 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) // '';
+        # Workaround bash default COMP_WORDBREAKS splitting URLs to
+        # ['https', ':', '//', ...].  COMP_WORDBREAKS is global for all
+        # completions loaded, not just ours, so we can't change it.
+        # cf. contrib/completion/lei-completion.bash
+        my ($pfx, $cur)  = ('', pop(@$argv) // '');
         if (@$argv) {
                 my @x = @$argv;
-                if ($cur eq ':' && @x) {
+                if ($cur =~ /\A[:;=]\z/) { # COMP_WORDBREAKS + URL union
                         push @x, $cur;
                         $cur = '';
                 }
-                while (@x > 2 && $x[0] !~ /\A(?:http|nntp|imap)s?\z/i &&
-                                $x[1] ne ':') {
-                        shift @x;
+                while (@x && $pfx !~ m!\A(?: (?:[\+\-]?(?:L|kw):) |
+                                (?:(?:imap|nntp|http)s?:) |
+                                (?:--\w?\z)|(?:-\w?\z) )!x) {
+                        $pfx = pop(@x).$pfx;
                 }
-                if (@x >= 2) { # qw(https : hostname : 443) or qw(http :)
-                        $re = join('', @x);
-                } else { # just filter out the flags and hope for the best
-                        $re = join('', grep(!/^-/, @$argv));
-                }
-                $re = quotemeta($re);
         }
+        my $re = qr!\A\Q$pfx\E(\Q$cur\E.*)!;
         my $match_cb = sub {
                 # the "//;" here (for AUTH=ANONYMOUS) interacts badly with
                 # bash tab completion, strip it out for now since our commands
                 # work w/o it.  Not sure if there's a better solution...
                 $_[0] =~ s!//;AUTH=ANONYMOUS\@!//!i;
-                $_[0] =~ s!;!\\;!g;
                 # only return the part specified on the CLI
                 # don't duplicate if already 100% completed
-                $_[0] =~ /\A$re(\Q$cur\E.*)/ ? ($cur eq $1 ? () : $1) : ()
+                $_[0] =~ $re ? ($cur eq $1 ? () : $1) : ()
         };
-        wantarray ? ($re, $cur, $match_cb) : $match_cb;
+        wantarray ? ($pfx, $cur, $match_cb) : $match_cb;
 }
 
 1;
diff --git a/lib/PublicInbox/LeiForgetExternal.pm b/lib/PublicInbox/LeiForgetExternal.pm
index 07f0ac80..39bfc60b 100644
--- a/lib/PublicInbox/LeiForgetExternal.pm
+++ b/lib/PublicInbox/LeiForgetExternal.pm
@@ -32,14 +32,10 @@ sub lei_forget_external {
 sub _complete_forget_external {
         my ($lei, @argv) = @_;
         my $cfg = $lei->_lei_cfg or return ();
-        my ($cur, $re, $match_cb) = $lei->complete_url_prepare(\@argv);
-        # FIXME: bash completion off "http:" or "https:" when the last
-        # character is a colon doesn't work properly even if we're
-        # returning "//$HTTP_HOST/$PATH_INFO/", not sure why, could
-        # be a bash issue.
+        my ($pfx, $cur, $match_cb) = $lei->complete_url_prepare(\@argv);
         map {
                 $match_cb->(substr($_, length('external.')));
-        } grep(/\Aexternal\.$re\Q$cur/, @{$cfg->{-section_order}});
+        } grep(/\Aexternal\.\Q$pfx$cur/, @{$cfg->{-section_order}});
 }
 
 1;
diff --git a/lib/PublicInbox/LeiImport.pm b/lib/PublicInbox/LeiImport.pm
index 2d91e4c4..9053048a 100644
--- a/lib/PublicInbox/LeiImport.pm
+++ b/lib/PublicInbox/LeiImport.pm
@@ -115,18 +115,24 @@ sub lei_import { # the main "lei import" method
 
 sub _complete_import {
         my ($lei, @argv) = @_;
-        my ($re, $cur, $match_cb) = $lei->complete_url_prepare(\@argv);
-        my @k = $lei->url_folder_cache->keys($argv[-1] // undef, 1);
+        my $has_arg = @argv;
+        my ($pfx, $cur, $match_cb) = $lei->complete_url_prepare(\@argv);
+        my @try = $has_arg ? ($pfx.$cur, $argv[-1]) : ($argv[-1]);
+        push(@try, undef) if defined $try[-1];
+        my (@f, @k);
+        for (@try) {
+                @k = $lei->url_folder_cache->keys($_, 1) and last;
+        }
         my @L = eval { $lei->_lei_store->search->all_terms('L') };
         push(@k, map { "+L:$_" } @L);
-        my @m = map { $match_cb->($_) } @k;
-        my %f = map { $_ => 1 } (@m ? @m : @k);
         if (my $lms = $lei->lms) {
-                @k = $lms->folders($argv[-1] // undef, 1);
-                @m = map { $match_cb->($_) } @k;
-                if (@m) { @f{@m} = @m } else { @f{@k} = @k }
+                for (@try) {
+                        @f = $lms->folders($_, 1) and last;
+                }
+                push @k, @f;
         }
-        keys %f;
+        my @m = map { $match_cb->($_) } @k;
+        @m ? @m : @k;
 }
 
 no warnings 'once';
diff --git a/lib/PublicInbox/LeiQuery.pm b/lib/PublicInbox/LeiQuery.pm
index 358574ea..3337e5d4 100644
--- a/lib/PublicInbox/LeiQuery.pm
+++ b/lib/PublicInbox/LeiQuery.pm
@@ -173,6 +173,8 @@ no query allowed on command-line with --stdin
 # shell completion helper called by lei__complete
 sub _complete_q {
         my ($self, @argv) = @_;
+        join('', @argv) =~ /\bL:\S*\z/ and
+                return eval { $self->_lei_store->search->all_terms('L') };
         my @cur;
         my $cb = $self->lazy_cb(qw(forget-external _complete_));
         while (@argv) {