unofficial mirror of meta@public-inbox.org
 help / color / mirror / Atom feed
From: Eric Wong <e@80x24.org>
To: meta@public-inbox.org
Subject: [PATCH] lei q: add --mua-cmd switch
Date: Sat, 16 Jan 2021 20:52:27 -1200	[thread overview]
Message-ID: <20210117085227.23448-1-e@80x24.org> (raw)

It can be convenient to invoke an MUA as search results
are being written to it, as an eager person may want to
start seeing results ASAP.  This lets Maildir users
see results in the MUA as we are writing them.  Users
of IMAP will eventually be able to take advantage of
them, too.

Since we don't support mbox locking (yet?), we'll only invoke
the MUA after results are done for mbox formats.
---
 lib/PublicInbox/LEI.pm        | 45 ++++++++++++++++++++++++++++-------
 lib/PublicInbox/LeiToMail.pm  |  4 ++++
 lib/PublicInbox/LeiXSearch.pm |  4 ++++
 3 files changed, 45 insertions(+), 8 deletions(-)

diff --git a/lib/PublicInbox/LEI.pm b/lib/PublicInbox/LEI.pm
index 56254c45..ee5c26a8 100644
--- a/lib/PublicInbox/LEI.pm
+++ b/lib/PublicInbox/LEI.pm
@@ -83,7 +83,7 @@ sub _config_path ($) {
 our %CMD = ( # sorted in order of importance/use:
 'q' => [ 'SEARCH_TERMS...', 'search for messages matching terms', qw(
 	save-as=s output|mfolder|o=s format|f=s dedupe|d=s thread|t augment|a
-	sort|s=s reverse|r offset=i remote local! external! pretty
+	sort|s=s reverse|r offset=i remote local! external! pretty mua-cmd=s
 	since|after=s until|before=s), opt_dash('limit|n=i', '[0-9]+') ],
 
 'show' => [ 'MID|OID', 'show a given object (Message-ID or object ID)',
@@ -192,6 +192,8 @@ my %OPTDESC = (
 
 'output|o=s' => [ 'DEST',
 	"destination (e.g. `/path/to/Maildir', or `-' for stdout)" ],
+'mua-cmd|mua=s' => [ 'COMMAND',
+	"MUA to run on --output Maildir or mbox (e.g. `mutt -f %f'" ],
 
 'show	format|f=s' => [ 'OUT|plain|raw|html|mboxrd|mboxcl2|mboxcl',
 			'message/object output format' ],
@@ -635,6 +637,32 @@ sub lei_git { # support passing through random git commands
 	dwaitpid($pid, \&reap_exec, $self);
 }
 
+sub exec_buf ($$) {
+	my ($argv, $env) = @_;
+	my $argc = scalar @$argv;
+	my $buf = 'exec '.join("\0", scalar(@$argv), @$argv);
+	while (my ($k, $v) = each %$env) { $buf .= "\0$k=$v" };
+	$buf;
+}
+
+sub start_mua {
+	my ($self, $sock) = @_;
+	my $mua = $self->{opt}->{'mua-cmd'} // return;
+	my $mfolder = $self->{ovv}->{dst};
+	require Text::ParseWords;
+	my $replaced;
+	my @cmd = Text::ParseWords::shellwords($mua);
+	# mutt uses '%f' for open-hook with compressed folders, so we use %f
+	@cmd = map { $_ eq '%f' ? ($replaced = $mfolder) : $_ } @cmd;
+	push @cmd, $mfolder unless defined($replaced);
+	$sock //= $self->{sock};
+	if ($sock) { # lei(1) client process runs it
+		send($sock, exec_buf(\@cmd, {}), MSG_EOR);
+	} else { # oneshot
+		$self->{"mua.pid.$self.$$"} = spawn(\@cmd);
+	}
+}
+
 # caller needs to "-t $self->{1}" to check if tty
 sub start_pager {
 	my ($self) = @_;
@@ -644,19 +672,17 @@ sub start_pager {
 	close($fh) or warn "`git var PAGER' error: \$?=$?";
 	return if $pager eq 'cat' || $pager eq '';
 	# TODO TIOCGWINSZ
-	my %new_env = (LESS => 'FRX', LV => '-c', COLUMNS => 80);
-	$new_env{MORE} = 'FRX' if $^O eq 'freebsd';
+	my $new_env = { LESS => 'FRX', LV => '-c', COLUMNS => 80 };
+	$new_env->{MORE} = 'FRX' if $^O eq 'freebsd';
 	pipe(my ($r, $wpager)) or return warn "pipe: $!";
 	my $rdr = { 0 => $r, 1 => $self->{1}, 2 => $self->{2} };
 	my $pgr = [ undef, @$rdr{1, 2}, $$ ];
 	if (my $sock = $self->{sock}) { # lei(1) process runs it
-		delete @new_env{keys %$env}; # only set iff unset
-		my $buf = "exec 1\0".$pager;
-		while (my ($k, $v) = each %new_env) { $buf .= "\0$k=$v" };
+		delete @$new_env{keys %$env}; # only set iff unset
 		my $fds = [ map { fileno($_) } @$rdr{0..2} ];
-		$send_cmd->($sock, $fds, $buf, MSG_EOR);
+		$send_cmd->($sock, $fds, exec_buf([$pager], $new_env), MSG_EOR);
 	} else {
-		$pgr->[0] = spawn([$pager], \%new_env, $rdr);
+		$pgr->[0] = spawn([$pager], $new_env, $rdr);
 	}
 	$self->{1} = $wpager;
 	$self->{2} = $wpager if -t $self->{2};
@@ -892,6 +918,9 @@ sub DESTROY {
 	my ($self) = @_;
 	$self->{1}->autoflush(1) if $self->{1};
 	stop_pager($self);
+	if (my $mua_pid = delete $self->{"mua.pid.$self.$$"}) {
+		waitpid($mua_pid, 0);
+	}
 }
 
 1;
diff --git a/lib/PublicInbox/LeiToMail.pm b/lib/PublicInbox/LeiToMail.pm
index 744f331d..0e23b8da 100644
--- a/lib/PublicInbox/LeiToMail.pm
+++ b/lib/PublicInbox/LeiToMail.pm
@@ -418,4 +418,8 @@ sub post_augment { # fast (spawn compressor or mkdir), runs in main daemon
 	$self->$m($lei);
 }
 
+sub lock_free {
+	$_[0]->{base_type} =~ /\A(?:maildir|mh|imap|jmap)\z/ ? 1 : 0;
+}
+
 1;
diff --git a/lib/PublicInbox/LeiXSearch.pm b/lib/PublicInbox/LeiXSearch.pm
index 9563ad63..91864cd0 100644
--- a/lib/PublicInbox/LeiXSearch.pm
+++ b/lib/PublicInbox/LeiXSearch.pm
@@ -172,6 +172,9 @@ sub git {
 sub query_done { # EOF callback
 	my ($lei) = @_;
 	$lei->{ovv}->ovv_end($lei);
+	if (my $l2m = $lei->{l2m}) {
+		$lei->start_mua unless $l2m->lock_free;
+	}
 	$lei->dclose;
 }
 
@@ -181,6 +184,7 @@ sub start_query { # always runs in main (lei-daemon) process
 		$lei->{1} = $io->[1];
 		$l2m->post_augment($lei);
 		$io->[1] = delete $lei->{1};
+		$lei->start_mua($io->[3]) if $l2m->lock_free;
 	}
 	my $remotes = $self->{remotes} // [];
 	if ($lei->{opt}->{thread}) {

             reply	other threads:[~2021-01-17  8:52 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-01-17  8:52 Eric Wong [this message]
2021-01-17 10:19 ` [PATCH] lei q: add --mua-cmd switch Eric Wong
2021-01-17 10:28   ` Eric Wong

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: https://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=20210117085227.23448-1-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.
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).