git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
From: Rasmus Villemoes <rv@rasmusvillemoes.dk>
To: gitster@pobox.com
Cc: git@vger.kernel.org, Rasmus Villemoes <rv@rasmusvillemoes.dk>
Subject: [RFC] git-send-email: Cache generated message-ids, use them when prompting
Date: Sat, 17 Aug 2013 00:58:46 +0000	[thread overview]
Message-ID: <1376701126-5759-1-git-send-email-rv@rasmusvillemoes.dk> (raw)

This is mostly a proof of concept/RFC patch. The idea is for
git-send-email to store the message-ids it generates, along with the
Subject and Date headers of the message. When prompting for which
Message-ID should be used in In-Reply-To, display a list of recent
emails (identifed using the Date/Subject pairs; the message-ids
themselves are not for human consumption). Choosing from that list
will then use the corresponding message-id; otherwise, the behaviour
is as usual.

When composing v2 or v3 of a patch or patch series, this avoids the
need to get one's MUA to display the Message-ID of the earlier email
(which is cumbersome in some MUAs) and then copy-paste that.

If this idea is accepted, I'm certain I'll get to use the feature
immediately, since the patch is not quite ready for inclusion :-)

Signed-off-by: Rasmus Villemoes <rv@rasmusvillemoes.dk>
---
 git-send-email.perl | 101 +++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 96 insertions(+), 5 deletions(-)

diff --git a/git-send-email.perl b/git-send-email.perl
index f608d9b..2e3685c 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -26,6 +26,7 @@ use Data::Dumper;
 use Term::ANSIColor;
 use File::Temp qw/ tempdir tempfile /;
 use File::Spec::Functions qw(catfile);
+use Date::Parse;
 use Error qw(:try);
 use Git;
 
@@ -203,6 +204,7 @@ my ($validate, $confirm);
 my (@suppress_cc);
 my ($auto_8bit_encoding);
 my ($compose_encoding);
+my ($msgid_cache_file, $msgid_maxprompt);
 
 my ($debug_net_smtp) = 0;		# Net::SMTP, see send_message()
 
@@ -214,7 +216,7 @@ my %config_bool_settings = (
     "signedoffcc" => [\$signed_off_by_cc, undef],      # Deprecated
     "validate" => [\$validate, 1],
     "multiedit" => [\$multiedit, undef],
-    "annotate" => [\$annotate, undef]
+    "annotate" => [\$annotate, undef],
 );
 
 my %config_settings = (
@@ -237,6 +239,7 @@ my %config_settings = (
     "from" => \$sender,
     "assume8bitencoding" => \$auto_8bit_encoding,
     "composeencoding" => \$compose_encoding,
+    "msgidcachefile" => \$msgid_cache_file,
 );
 
 my %config_path_settings = (
@@ -311,6 +314,7 @@ my $rc = GetOptions("h" => \$help,
 		    "8bit-encoding=s" => \$auto_8bit_encoding,
 		    "compose-encoding=s" => \$compose_encoding,
 		    "force" => \$force,
+		    "msgid-cache-file=s" => \$msgid_cache_file,
 	 );
 
 usage() if $help;
@@ -784,10 +788,31 @@ sub expand_one_alias {
 @bcclist = validate_address_list(sanitize_address_list(@bcclist));
 
 if ($thread && !defined $initial_reply_to) {
-	$initial_reply_to = ask(
-		"Message-ID to be used as In-Reply-To for the first email (if any)? ",
-		default => "",
-		valid_re => qr/\@.*\./, confirm_only => 1);
+	my @choices;
+	if ($msgid_cache_file) {
+		@choices = msgid_cache_getmatches();
+	}
+	if (@choices) {
+		my $prompt = '';
+		my $i = 0;
+		$prompt .= sprintf "(%d) [%s] %s\n", $i++, $_->{date}, $_->{subject}
+		    for (@choices);
+		$prompt .= sprintf "Answer 0-%d to use the Message-ID of one of the above\n", $#choices;
+		$prompt .= "Message-ID to be used as In-Reply-To for the first email (if any)? ";
+		$initial_reply_to = 
+		    ask($prompt,
+			default => "",
+			valid_re => qr/\@.*\.|^[0-9]+$/, confirm_only => 1);
+		if ($initial_reply_to =~ /^[0-9]+$/ && $initial_reply_to < @choices) {
+			$initial_reply_to = $choices[$initial_reply_to]{id};
+		}
+	}
+	else {
+		$initial_reply_to = 
+		    ask("Message-ID to be used as In-Reply-To for the first email (if any)? ",
+			default => "",
+			valid_re => qr/\@.*\./, confirm_only => 1);
+	}
 }
 if (defined $initial_reply_to) {
 	$initial_reply_to =~ s/^\s*<?//;
@@ -1282,6 +1307,8 @@ X-Mailer: git-send-email $gitversion
 		}
 	}
 
+	msgid_cache_this($message_id, $subject, $date) if ($msgid_cache_file && !$dry_run);
+
 	return 1;
 }
 
@@ -1508,6 +1535,8 @@ sub cleanup_compose_files {
 
 $smtp->quit if $smtp;
 
+msgid_cache_write() if $msgid_cache_file;
+
 sub unique_email_list {
 	my %seen;
 	my @emails;
@@ -1556,3 +1585,65 @@ sub body_or_subject_has_nonascii {
 	}
 	return 0;
 }
+
+my @msgid_new_entries;
+
+# For now, use a simple tab-separated format:
+#
+#    $id\t$date\t$subject\n
+sub msgid_cache_read {
+	my $fh;
+	my $line;
+	my @entries;
+	if (not open ($fh, '<', $msgid_cache_file)) {
+		# A non-existing cache file is ok, but should we warn if errno != ENOENT?
+		return ();
+	}
+	while ($line = <$fh>) {
+		chomp($line);
+		my ($id, $date, $subject) = split /\t/, $line;
+		my $epoch = str2time($date);
+		push @entries, {id=>$id, date=>$date, epoch=>$epoch, subject=>$subject};
+	}
+	close($fh);
+	return @entries;
+}
+sub msgid_cache_write {
+	my $fh;
+	if (not open($fh, '>>', $msgid_cache_file)) {
+	    warn "cannot open $msgid_cache_file for appending: $!";
+	    return;
+	}
+	printf $fh "%s\t%s\t%s\n", $_->{id}, $_->{date}, $_->{subject} for (@msgid_new_entries);
+	close($fh);
+}
+# Return an array of cached message-ids, ordered by "relevance". It
+# might make sense to take the Subject of the new mail as an extra
+# argument and do some kind of fuzzy matching against the old
+# subjects, but for now "more relevant" simply means "newer".
+sub msgid_cache_getmatches {
+	my ($maxentries) = @_;
+	$maxentries //= 10;
+	my @list = msgid_cache_read();
+	@list = sort {$b->{epoch} <=> $a->{epoch}} @list;
+	@list = @list[0 .. $maxentries-1] if (@list > $maxentries);
+	return @list;
+}
+
+sub msgid_cache_this {
+	my $msgid = shift;
+	my $subject = shift;
+	my $date = shift;
+	# Make sure there are no tabs which will confuse us, and save
+	# some valuable horizontal real-estate by removing redundant
+	# whitespace.
+	if ($subject) {
+		$subject =~ s/^\s+|\s+$//g;
+		$subject =~ s/\s+/ /g;
+	}
+	# Replace undef or the empty string by an actual string. Nobody uses "0" as the subject...
+	$subject ||= '(none)';
+	$date //= format_2822_time(time());
+	$date =~ s/\s+/ /g;
+	push @msgid_new_entries, {id => $msgid, subject => $subject, date => $date};
+}
-- 
1.8.4.rc3.2.gb900fc8

             reply	other threads:[~2013-08-17  0:59 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-08-17  0:58 Rasmus Villemoes [this message]
2013-08-18 21:08 ` [RFC] git-send-email: Cache generated message-ids, use them when prompting Junio C Hamano
2013-08-18 22:24   ` brian m. carlson
2013-08-21 19:04 ` [PATCH v2 0/2] git-send-email: Message-ID caching Rasmus Villemoes
2013-08-21 19:04   ` [PATCH 1/2] git-send-email: add optional 'choices' parameter to the ask sub Rasmus Villemoes
2013-08-21 19:04   ` [PATCH 2/2] git-send-email: Cache generated message-ids, use them when prompting Rasmus Villemoes
2013-08-22  0:20   ` [PATCH v2 0/2] git-send-email: Message-ID caching Junio C Hamano

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://vger.kernel.org/majordomo-info.html

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

  git send-email \
    --in-reply-to=1376701126-5759-1-git-send-email-rv@rasmusvillemoes.dk \
    --to=rv@rasmusvillemoes.dk \
    --cc=git@vger.kernel.org \
    --cc=gitster@pobox.com \
    /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/mirrors/git.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).