notmuch show: Add a one-line summary of the message before the header.
authorCarl Worth <cworth@cworth.org>
Thu, 29 Oct 2009 23:06:27 +0000 (16:06 -0700)
committerCarl Worth <cworth@cworth.org>
Fri, 30 Oct 2009 00:30:56 +0000 (17:30 -0700)
The idea here is that a client could usefully display just this one
line while optionally hiding the other header fields.

database.cc
message.cc
notmuch.c
notmuch.h

index 3e00aa59754c0f69b610cf369441020a057dcb55..604062835427f0c539dd16791b24d84aab7d1da0 100644 (file)
@@ -84,7 +84,7 @@ typedef struct {
  *
  * and has a single value:
  *
- *     TIMETAMPS:      The time_t value from the user.
+ *     TIMESTAMP:      The time_t value from the user.
  */
 
 /* With these prefix values we follow the conventions published here:
index e2f1cd31843541f43002cd77eb0bc4576ca7ade4..2a9001493721dc5493d643659c36afde4f74028b 100644 (file)
@@ -370,6 +370,21 @@ notmuch_message_get_filename (notmuch_message_t *message)
     return message->filename;
 }
 
+time_t
+notmuch_message_get_date (notmuch_message_t *message)
+{
+    std::string value;
+
+    try {
+       value = message->doc.get_value (NOTMUCH_VALUE_TIMESTAMP);
+    } catch (Xapian::Error &error) {
+       INTERNAL_ERROR ("Failed to read timestamp value from document.");
+       return 0;
+    }
+
+    return Xapian::sortable_unserialise (value);
+}
+
 notmuch_tags_t *
 notmuch_message_get_tags (notmuch_message_t *message)
 {
index 4ac5531ae42a14c8216e3977cfc7dc8a495fbb29..c6807e832af2fef868e346630321bdd3e8d94aaa 100644 (file)
--- a/notmuch.c
+++ b/notmuch.c
@@ -797,6 +797,97 @@ search_command (int argc, char *argv[])
     return ret;
 }
 
+/* Format a nice representation of 'time' relative to the current time.
+ *
+ * Examples include:
+ *
+ *     5 minutes ago   (For times less than 60 minutes ago)
+ *     12:30           (For times >60 minutes but still today)
+ *     Yesterday
+ *     Monday          (Before yesterday but fewer than 7 days ago)
+ *     Oct. 12         (Between 7 and 180 days ago (about 6 months))
+ *     2008-06-30      (More than 180 days ago)
+ */
+#define MINUTE (60)
+#define HOUR (60 * MINUTE)
+#define DAY (24 * HOUR)
+#define RELATIVE_DATE_MAX 20
+static const char *
+_format_relative_date (void *ctx, time_t then)
+{
+    struct tm tm_now, tm_then;
+    time_t now = time(NULL);
+    time_t delta;
+    char *result;
+
+    localtime_r (&now, &tm_now);
+    localtime_r (&then, &tm_then);
+
+    result = talloc_zero_size (ctx, RELATIVE_DATE_MAX);
+    if (result == NULL)
+       return "when?";
+
+    if (then > now)
+       return "the future";
+
+    delta = now - then;
+
+    if (delta > 180 * DAY) {
+       strftime (result, RELATIVE_DATE_MAX,
+                 "%F", &tm_then);
+       return result;
+    }
+
+    if (delta < 3600) {
+       snprintf (result, RELATIVE_DATE_MAX,
+                 "%d minutes ago", (int) (delta / 60));
+       return result;
+    }
+
+    if (delta <= 6 * DAY) {
+       if (tm_then.tm_wday == tm_now.tm_wday &&
+           delta < DAY)
+       {
+           strftime (result, RELATIVE_DATE_MAX,
+                     "%R", &tm_then);
+           return result;
+       } else if ((tm_now.tm_wday + 7 - tm_then.tm_wday) % 7 == 1) {
+           return "Yesterday";
+       } else {
+           strftime (result, RELATIVE_DATE_MAX,
+                     "%A", &tm_then);
+           return result;
+       }
+    }
+
+    strftime (result, RELATIVE_DATE_MAX,
+             "%b %d", &tm_then);
+    return result;
+}
+#undef MINUTE
+#undef HOUR
+#undef DAY
+
+/* Get a nice, single-line summary of message. */
+static const char *
+_get_one_line_summary (void *ctx, notmuch_message_t *message)
+{
+    const char *from;
+    time_t date;
+    const char *relative_date;
+    const char *subject;
+
+    from = notmuch_message_get_header (message, "from");
+
+    date = notmuch_message_get_date (message);
+    relative_date = _format_relative_date (ctx, date);
+
+    subject = notmuch_message_get_header (message, "subject");
+
+    return talloc_asprintf (ctx, "%s (%s) %s",
+                           from, relative_date, subject);
+}
+
 static int
 show_command (unused (int argc), unused (char *argv[]))
 {
@@ -853,6 +944,8 @@ show_command (unused (int argc), unused (char *argv[]))
 
        printf ("%%header{\n");
 
+       printf ("%s\n", _get_one_line_summary (local, message));
+
        for (i = 0; i < ARRAY_SIZE (headers); i++) {
            name = headers[i];
            value = notmuch_message_get_header (message, name);
index d25f277c87776028411f783b6bec40142d2322d8..3f59709a579542db6eeaa1d00baa7022eff9396f 100644 (file)
--- a/notmuch.h
+++ b/notmuch.h
@@ -617,6 +617,14 @@ notmuch_message_get_thread_id (notmuch_message_t *message);
 const char *
 notmuch_message_get_filename (notmuch_message_t *message);
 
+/* Get the date of 'message' as a time_t value.
+ *
+ * For the original textual representation of the Date header from the
+ * message call notmuch_message_get_header() with a header value of
+ * "date". */
+time_t
+notmuch_message_get_date  (notmuch_message_t *message);
+
 /* Get the size in bytes of the full header section of 'message'.
  *
  * This is useful in conjunction with notmuch_message_get_filename