user/dev discussion of public-inbox itself
 help / color / mirror / code / Atom feed
From: Eric Wong <e@80x24.org>
To: meta@public-inbox.org
Subject: [PATCH 2/2] lei mark: add support for (bash) completion
Date: Tue, 23 Mar 2021 11:02:18 +0600	[thread overview]
Message-ID: <20210323050218.28873-3-e@80x24.org> (raw)
In-Reply-To: <20210323050218.28873-1-e@80x24.org>

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     | 27 ++++++++++++++----------
 lib/PublicInbox/LeiMark.pm | 43 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 59 insertions(+), 11 deletions(-)

diff --git a/lib/PublicInbox/LEI.pm b/lib/PublicInbox/LEI.pm
index 91c95239..0be417eb 100644
--- a/lib/PublicInbox/LEI.pm
+++ b/lib/PublicInbox/LEI.pm
@@ -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.
diff --git a/lib/PublicInbox/LeiMark.pm b/lib/PublicInbox/LeiMark.pm
index aa52ad5a..7b50aa51 100644
--- a/lib/PublicInbox/LeiMark.pm
+++ b/lib/PublicInbox/LeiMark.pm
@@ -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;

      parent reply	other threads:[~2021-03-23  5:02 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-03-23  5:02 [PATCH 0/2] lei mark: volatile metadata tagging Eric Wong
2021-03-23  5:02 ` [PATCH 1/2] lei mark: command for (un)setting keywords and labels Eric Wong
2021-03-23  5:02 ` Eric Wong [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: http://public-inbox.org/README

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210323050218.28873-3-e@80x24.org \
    --to=e@80x24.org \
    --cc=meta@public-inbox.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://80x24.org/public-inbox.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).