From c168e24174d32563ceb1a35d9bf1875c5bfeac25 Mon Sep 17 00:00:00 2001 From: Carl Worth Date: Thu, 12 Nov 2009 22:01:44 -0800 Subject: [PATCH] notmuch search: Print the number of matched/total messages for each thread. Note that we don't print the number of *unread* messages, but instead the number of messages that matched the search terms. This is in keeping with our philosophy that the inbox is nothing more than a search view. If we search for messages with an inbox tag, then that's what we'll get a count of. (And if somebody does want to see unread counts, then they can search for the "unread" tag.) Getting the number of matched messages is really nice when doing historical searches. For example in a search like: notmuch search tag:sent (where the "sent" tag has been applied to all messages originating from the user's email address)---here it's really nice to be able to see a thread where the user just mentioned one point [1/13] vs. really getting involved in the discussion [10/29]. --- lib/notmuch-private.h | 5 ++- lib/notmuch.h | 17 +++++++++ lib/query.cc | 3 +- lib/thread.cc | 87 +++++++++++++++++++++++++++++-------------- notmuch-search.c | 4 +- 5 files changed, 84 insertions(+), 32 deletions(-) diff --git a/lib/notmuch-private.h b/lib/notmuch-private.h index 190d3038..c286aa4b 100644 --- a/lib/notmuch-private.h +++ b/lib/notmuch-private.h @@ -150,9 +150,10 @@ _find_prefix (const char *name); /* thread.cc */ notmuch_thread_t * -_notmuch_thread_create (const void *ctx, +_notmuch_thread_create (void *ctx, notmuch_database_t *notmuch, - const char *thread_id); + const char *thread_id, + const char *query_string); /* message.cc */ diff --git a/lib/notmuch.h b/lib/notmuch.h index c67376eb..6469744d 100644 --- a/lib/notmuch.h +++ b/lib/notmuch.h @@ -469,6 +469,23 @@ notmuch_threads_destroy (notmuch_threads_t *threads); const char * notmuch_thread_get_thread_id (notmuch_thread_t *thread); +/* Get the total number of messages in 'thread'. + * + * This count consists of all messages in the database belonging to + * this thread. Contrast with notmuch_thread_get_matched_messages() . + */ +int +notmuch_thread_get_total_messages (notmuch_thread_t *thread); + +/* Get the number of messages in 'thread' that matched the search. + * + * This count includes only the messages in this thread that were + * matched by the search from which the thread was created. Contrast + * with notmuch_thread_get_total_messages() . + */ +int +notmuch_thread_get_matched_messages (notmuch_thread_t *thread); + /* Get the authors of 'thread' * * The returned string is a comma-separated list of the names of the diff --git a/lib/query.cc b/lib/query.cc index b5f1546a..e853d4ec 100644 --- a/lib/query.cc +++ b/lib/query.cc @@ -220,7 +220,8 @@ notmuch_query_search_threads (notmuch_query_t *query, { if (threads_seen >= first) { thread = _notmuch_thread_create (query, query->notmuch, - thread_id); + thread_id, + query->query_string); g_ptr_array_add (threads->threads, thread); } else { thread = NULL; diff --git a/lib/thread.cc b/lib/thread.cc index 4f0696b4..df1d0db7 100644 --- a/lib/thread.cc +++ b/lib/thread.cc @@ -34,7 +34,8 @@ struct _notmuch_thread { char *authors; GHashTable *tags; - notmuch_bool_t has_message; + int total_messages; + int matched_messages; time_t oldest; time_t newest; }; @@ -112,49 +113,57 @@ _thread_add_message (notmuch_thread_t *thread, date = notmuch_message_get_date (message); - if (date < thread->oldest || ! thread->has_message) + if (date < thread->oldest || ! thread->total_messages) thread->oldest = date; - if (date > thread->newest || ! thread->has_message) + if (date > thread->newest || ! thread->total_messages) thread->newest = date; - thread->has_message = 1; + thread->total_messages++; } -/* Create a new notmuch_thread_t object for the given thread ID. +/* Create a new notmuch_thread_t object for the given thread ID, + * treating any messages matching 'query_string' as "matched". * - * Creating the thread will trigger a database search for the messages - * belonging to the thread so that the thread object can return some - * details about them, (authors, subject, etc.). + * Creating the thread will trigger two database searches. The first + * is for all messages belonging to the thread, (to get the first + * subject line, the total count of messages, and all authors). The + * second search is for all messages that are in the thread and that + * also match the given query_string. This is to allow for a separate + * count of matched messages, and to allow a viewer to diplay these + * messages differently. * - * Here, 'talloc owner' is an optional talloc context to which the new - * thread will belong. This allows for the caller to not bother - * calling notmuch_thread_destroy on the thread, and know that all - * memory will be reclaimed with 'talloc_owner' is freed. The caller - * still can call notmuch_thread_destroy when finished with the - * thread if desired. - * - * The 'talloc_owner' argument can also be NULL, in which case the - * caller *is* responsible for calling notmuch_thread_destroy. + * Here, 'ctx' is talloc context for the resulting thread object. * * This function returns NULL in the case of any error. */ notmuch_thread_t * -_notmuch_thread_create (const void *ctx, +_notmuch_thread_create (void *ctx, notmuch_database_t *notmuch, - const char *thread_id) + const char *thread_id, + const char *query_string) { notmuch_thread_t *thread; - const char *query_string; - notmuch_query_t *query; + const char *thread_id_query_string, *matched_query_string; + notmuch_query_t *thread_id_query, *matched_query; notmuch_messages_t *messages; - query_string = talloc_asprintf (ctx, "thread:%s", thread_id); + thread_id_query_string = talloc_asprintf (ctx, "thread:%s", thread_id); if (unlikely (query_string == NULL)) return NULL; - query = notmuch_query_create (notmuch, query_string); - if (unlikely (query == NULL)) + matched_query_string = talloc_asprintf (ctx, "%s AND (%s)", + thread_id_query_string, + query_string); + if (unlikely (matched_query_string == NULL)) + return NULL; + + thread_id_query = notmuch_query_create (notmuch, thread_id_query_string); + if (unlikely (thread_id_query == NULL)) + return NULL; + + matched_query = notmuch_query_create (notmuch, matched_query_string); + if (unlikely (thread_id_query == NULL)) return NULL; thread = talloc (ctx, notmuch_thread_t); @@ -172,20 +181,30 @@ _notmuch_thread_create (const void *ctx, thread->tags = g_hash_table_new_full (g_str_hash, g_str_equal, free, NULL); - thread->has_message = 0; + thread->total_messages = 0; + thread->matched_messages = 0; thread->oldest = 0; thread->newest = 0; - notmuch_query_set_sort (query, NOTMUCH_SORT_DATE_OLDEST_FIRST); + notmuch_query_set_sort (thread_id_query, NOTMUCH_SORT_DATE_OLDEST_FIRST); - for (messages = notmuch_query_search_messages (query, 0, -1); + for (messages = notmuch_query_search_messages (thread_id_query, 0, -1); notmuch_messages_has_more (messages); notmuch_messages_advance (messages)) { _thread_add_message (thread, notmuch_messages_get (messages)); } - notmuch_query_destroy (query); + notmuch_query_destroy (thread_id_query); + + for (messages = notmuch_query_search_messages (matched_query, 0, -1); + notmuch_messages_has_more (messages); + notmuch_messages_advance (messages)) + { + thread->matched_messages++; + } + + notmuch_query_destroy (matched_query); return thread; } @@ -196,6 +215,18 @@ notmuch_thread_get_thread_id (notmuch_thread_t *thread) return thread->thread_id; } +int +notmuch_thread_get_total_messages (notmuch_thread_t *thread) +{ + return thread->total_messages; +} + +int +notmuch_thread_get_matched_messages (notmuch_thread_t *thread) +{ + return thread->matched_messages; +} + const char * notmuch_thread_get_authors (notmuch_thread_t *thread) { diff --git a/notmuch-search.c b/notmuch-search.c index 85f3514e..a0a71bbd 100644 --- a/notmuch-search.c +++ b/notmuch-search.c @@ -91,9 +91,11 @@ notmuch_search_command (void *ctx, int argc, char *argv[]) date = notmuch_thread_get_oldest_date (thread); relative_date = notmuch_time_relative_date (ctx, date); - printf ("thread:%s %12s %s; %s", + printf ("thread:%s %12s [%d/%d] %s; %s", notmuch_thread_get_thread_id (thread), relative_date, + notmuch_thread_get_matched_messages (thread), + notmuch_thread_get_total_messages (thread), notmuch_thread_get_authors (thread), notmuch_thread_get_subject (thread));