[RFC] git-send-email: Cache generated message-ids, use them when prompting

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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@xxxxxxxxxxxxxxxxxx>
---
 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

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]