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].
This commit is contained in:
Carl Worth 2009-11-12 22:01:44 -08:00
parent 184c327692
commit c168e24174
5 changed files with 84 additions and 32 deletions

View file

@ -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 */

View file

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

View file

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

View file

@ -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)
{

View file

@ -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));