[notmuch] Using notmuch as an address book for tab-completion
Normally, I wouldn't respond to myself to fix a typo, but this seemed important. > Remember, neither of these will do you much good with the shared lib and > cnotmuch installed. I meant, of course, that neither would do you much good *WITHOUT* the shared lib and cnotmuch installed. Apologies, Jesse
[notmuch] Using notmuch as an address book for tab-completion
Dear All, There was some talk on IRC ages ago about using notmuch as an address-book for tab-completion in emacs message mode. Thanks to some great recent work (Ingmar Vanhassel's shared lib and Sebastians's cnotmuch python lib) I have been able to take a first step in that direction. I've written a python script (with some help and suggestions from spaetz) which can perform the address-book functionality, and a backend for emacs's EUDC address-lookup functionality to access the script. They are available by the following commands: git clone http://jkr.acm.jhu.edu/git/notmuch_addresses.git git clone http://jkr.acm.jhu.edu/git/notmuch_eudc.git Remember, neither of these will do you much good with the shared lib and cnotmuch installed. At the moment, the script works by search addresses that you have written to (or CC'd or BCC'd) in the past. This seems like a good utility-speed tradeoff, but it would be easy to hack the script to search a different set of messages. Give three letters (it looks through first names, last names, and email addresses) it returns results from my 12K messages in well under a second. The responses are sorted by frequency, and each email address is associated with the most frequently used real name (null real-names are avoided, unless they're the only option). The script can be run from the command line by: $ python notmuch_addresses.py query To get tab completion from emacs, you have to install the script into your path, make it executable, and then put my eudcb-notmuch.el file into your load path (you should byte-compile it too). DON'T CHANGE THE TITLE OF THE .EL FILE! EUDC looks for a specific title based on protocol. Then add the following to your .emacs: (eudc-set-server "localhost" 'notmuch t) (setq eudc-server-hotlist '(("localhost" . notmuch))) (setq eudc-inline-expansion-servers 'hotlist) if you wish to use BBDB too (likely before you use notmuch), then you should use something like this: (eudc-set-server "localhost" 'bbdb t) (eudc-protocol-set 'eudc-inline-expansion-format '("%s %s <%s>" firstname lastname net) 'bbdb) (eudc-set-server "localhost" 'notmuch t) (setq eudc-server-hotlist '(("localhost" . bbdb) ("localhost" . notmuch))) (setq eudc-inline-expansion-servers 'hotlist) That should do it. Please let me know if it works for you. (For those of you who care, eudcb-notmuch.el has a few hacky bits to hide the fact that notmuch really isn't an address book. That is, it doesn't know the difference between names and email addresses. So everything you enter just goes in as one string, which I call "name." Back-end stuff, but if you're looking through the code, that might make a few things clearer.) Best, Jesse
[notmuch] Tag search peculiarities
On Thu, 18 Mar 2010 15:27:12 +0100, Sandra Snan wrote: > Hey, Ben. > Ben Gamari wrote: > > notmuch tag -new tag:new and tag:list notmuch tag -new +inbox tag:new > > Is there a new line between the calls? Like: > notmuch tag -new tag:new and tag:list # removes new from list > notmuch tag -new +inbox tag:new # replaces those that still are new with inbox > Eh? They are two separate notmuch invocations. > > However, I found that mailing list traffic was still getting through. > > What do you mean by ???through Do you mean that there still are > messages tagged both inbox and list? Even though you can???t search for > them? > Yeah, poor choice of words. After the two commands above ran, my mailing list messages were tagged with new, inbox. > If a message is tagged both inbox and list, but not new then the two > lines of your script that you posted so far wouldn???t change it, and it > would still bo both inbox and list. > > It???s risky being so dependent on the new tag. > Eh? I fail to see why. It's no more risky than depending on the inbox tag. > > After investigating further, I found that any query in the form of > > "tag:inbox > > and tag:$TAG" would return no results. Strangely, all other combinations of > > tag > > searches (i.e. "tag:lkml and tag:unread") seem to work just fine. > > > > Has anyone else noticed this sort of behavior? Does the inbox tag have some > > special signifigance that I should know of? > > Yes, many versions of the reading client (for example, the version of > notmuch.el that ships with the notmuch package in debian) remove the > inbox tag from messages once you scroll past them or when you press > the key that???s bound to notmuch-show-archive-thread (default is ???a???). > I guess I should have been more explicit. I meant in notmuch itself, not the clients. > > Is my index just FUBAR? (the ladder would be very strange > > considering it's only a few days old and I can't think of any > > crashes, etc. that might have corrupted it) Any ideas for debugging? > > Add the tags manually to a few messages, search for them again, and be > sure to not run your tagging script while looking at this problem. > > Michal???s tip, looking at a few lines of notmuch dump, is a good idea > too. Notmuch dump is fast, so don???t be afraid (notmuch restore on the > other hand??? but even that completes fast enough.) > > I???ve often been surprised at weird tag situations then realized that > it was old versions of my own scripts that had ran in the background > and I???ve forgotten about it. > Indeed. Hopefully it will be something so simple. I'm currently blissfully unaware of the internals of Xapian, and would really like to remain that way. Thanks, - Ben
[notmuch] [PATCH 5/5] Added backwards iterator to tags
Added the functions notmuch_tags_move_to_prevoius, notmuch_tags_move_to_last and notmuch_tags_move_to_first to notmuch library. With them is possible to iterate backwards on tags. * notmuch_tags_move_to_prevoius do the opposite than notmuch_tags_move_to_next, getting the tags iterator one position backwards. * notmuch_tags_move_to_last move the iterator to the first last tag. * notmuch_tags_move_to_first move the iterator to the first valid tag. --- lib/notmuch.h | 28 lib/tags.c| 21 + 2 files changed, 49 insertions(+), 0 deletions(-) diff --git a/lib/notmuch.h b/lib/notmuch.h index b96b624..dc668dc 100644 --- a/lib/notmuch.h +++ b/lib/notmuch.h @@ -1022,6 +1022,15 @@ notmuch_tags_valid (notmuch_tags_t *tags); const char * notmuch_tags_get (notmuch_tags_t *tags); +/* Move the 'tags' iterator to the first tag. + * + * After that the 'tags' iterator will be set to the first valid + * tag, so it can be use to iterate with + * notmuch_tags_move_to_next. + */ +void +notmuch_tags_move_to_first (notmuch_tags_t *tags); + /* Move the 'tags' iterator to the next tag. * * If 'tags' is already pointing at the last tag then the iterator @@ -1035,6 +1044,25 @@ notmuch_tags_get (notmuch_tags_t *tags); void notmuch_tags_move_to_next (notmuch_tags_t *tags); +/* Move the 'tags' iterator to the last tag. + * + * After that the 'tags' iterator will be set to the last valid + * tag, so it can be use to iterate with + * notmuch_tags_move_to_previous. + */ +void +notmuch_tags_move_to_last (notmuch_tags_t *tags); + +/* Move the 'tags' iterator to the previous tag. + * + * If 'tags' is already pointing at the first tag then the + * iterator will be moved to a point just beyond that first tag, + * (where notmuch_tags_valid will return FALSE and + * notmuch_tags_get will return NULL). + */ +void +notmuch_tags_move_to_previous (notmuch_tags_t *tags); + /* Destroy a notmuch_tags_t object. * * It's not strictly necessary to call this function. All memory from diff --git a/lib/tags.c b/lib/tags.c index 8fe4a3f..9c9a897 100644 --- a/lib/tags.c +++ b/lib/tags.c @@ -105,6 +105,12 @@ notmuch_tags_get (notmuch_tags_t *tags) } void +notmuch_tags_move_to_first (notmuch_tags_t *tags) +{ +tags->iterator = g_list_first (tags->tags); +} + +void notmuch_tags_move_to_next (notmuch_tags_t *tags) { if (tags->iterator == NULL) @@ -114,6 +120,21 @@ notmuch_tags_move_to_next (notmuch_tags_t *tags) } void +notmuch_tags_move_to_last (notmuch_tags_t *tags) +{ +tags->iterator = g_list_last (tags->tags); +} + +void +notmuch_tags_move_to_previous (notmuch_tags_t *tags) +{ +if (tags->iterator == NULL) + return; + +tags->iterator = tags->iterator->prev; +} + +void notmuch_tags_destroy (notmuch_tags_t *tags) { talloc_free (tags); -- 1.7.0
[notmuch] [PATCH 4/5] Added backwards iterator to threads
Added the functions notmuch_threads_move_to_prevoius, notmuch_threads_move_to_last and notmuch_threads_move_to_first to notmuch library. With them is possible to iterate backwards on threads. * notmuch_threads_move_to_prevoius do the opposite than notmuch_threads_move_to_next, getting the threads iterator one position backwards. * notmuch_threads_move_to_last move the iterator to the first last thread. * notmuch_threads_move_to_first move the iterator to the first valid thread. For it has been implemented notmuch_thread_list_t structur that stores the thread_ids so the backwards iteration gets the thread_id in the same order that was show on forward iteration. --- lib/notmuch.h | 28 +++ lib/query.cc | 143 - 2 files changed, 159 insertions(+), 12 deletions(-) diff --git a/lib/notmuch.h b/lib/notmuch.h index 753f3bb..b96b624 100644 --- a/lib/notmuch.h +++ b/lib/notmuch.h @@ -466,6 +466,15 @@ notmuch_threads_valid (notmuch_threads_t *threads); notmuch_thread_t * notmuch_threads_get (notmuch_threads_t *threads); +/* Move the 'threads' iterator to the first thread. + * + * After that the 'threads' iterator will be set to the first valid + * thread, so it can be use to iterate with + * notmuch_threads_move_to_next. + */ +void +notmuch_threads_move_to_first (notmuch_threads_t *threads); + /* Move the 'threads' iterator to the next thread. * * If 'threads' is already pointing at the last thread then the @@ -479,6 +488,25 @@ notmuch_threads_get (notmuch_threads_t *threads); void notmuch_threads_move_to_next (notmuch_threads_t *threads); +/* Move the 'threads' iterator to the last thread. + * + * After that the 'threads' iterator will be set to the last valid + * thread, so it can be use to iterate with + * notmuch_threads_move_to_previous. + */ +void +notmuch_threads_move_to_last (notmuch_threads_t *threads); + +/* Move the 'threads' iterator to the previous thread. + * + * If 'threads' is already pointing at the first thread then the + * iterator will be moved to a point just beyond that first thread, + * (where notmuch_threads_valid will return FALSE and + * notmuch_threads_get will return NULL). + */ +void +notmuch_threads_move_to_previous (notmuch_threads_t *threads); + /* Destroy a notmuch_threads_t object. * * It's not strictly necessary to call this function. All memory from diff --git a/lib/query.cc b/lib/query.cc index 44950c1..39985e7 100644 --- a/lib/query.cc +++ b/lib/query.cc @@ -39,13 +39,25 @@ typedef struct _notmuch_mset_messages { Xapian::MSetIterator iterator_end; } notmuch_mset_messages_t; +typedef struct _notmuch_thread_node { +const char *thread_id; +struct _notmuch_thread_node *next; +struct _notmuch_thread_node *prev; +} notmuch_thread_node_t; + +typedef struct _notmuch_thread_list { +notmuch_thread_node_t *head; +notmuch_thread_node_t *tail; +notmuch_thread_node_t *iterator; +} notmuch_thread_list_t; + struct _notmuch_threads { notmuch_query_t *query; GHashTable *threads; notmuch_messages_t *messages; -/* This thread ID is our iterator state. */ -const char *thread_id; +/* thread list with the thread_id of the showed messages */ +notmuch_thread_list_t *list; }; notmuch_query_t * @@ -269,6 +281,64 @@ _notmuch_mset_messages_move_to_previous (notmuch_messages_t *messages) } } +static void +_notmuch_thread_list_create (notmuch_thread_list_t *list, const char *thread_id) +{ +list->head = talloc (list, notmuch_thread_node_t); +list->tail = list->head; +list->iterator = list->head; +list->iterator->thread_id = thread_id; +list->iterator->next = NULL; +list->iterator->prev = NULL; +} + +static void +_notmuch_thread_list_append (notmuch_thread_list_t *list, const char *thread_id) +{ +list->tail->next = talloc (list, notmuch_thread_node_t); +list->iterator = list->tail->next; +list->iterator->thread_id = thread_id; +list->iterator->next = NULL; +list->iterator->prev = list->tail; +list->tail = list->iterator; +} + +static const char * +_notmuch_thread_list_get_id (notmuch_thread_list_t *list) +{ +return list->iterator->thread_id; +} + +static notmuch_bool_t +_notmuch_thread_list_valid (notmuch_thread_list_t *list) +{ +return (list->iterator != NULL); +} + +static void +_notmuch_thread_list_move_to_first (notmuch_thread_list_t *list) +{ +list->iterator = list->head; +} + +static void +_notmuch_thread_list_move_to_next (notmuch_thread_list_t *list) +{ +list->iterator = list->iterator->next; +} + +static void +_notmuch_thread_list_move_to_last (notmuch_thread_list_t *list) +{ +list->iterator = list->tail; +} + +static void +_notmuch_thread_list_move_to_previous (notmuch_thread_list_t *list) +{ +list->iterator = list->iterator->prev; +} + /* Glib objects force use to use a talloc destructor as well, (but not * nearly as ugly as the for messages due to
[notmuch] [PATCH 3/5] Move the logic of threads iterator out of 'valid'
The logic of notmuch_threads_move_to_next iterator was on notmuch_threads_valid function. Now notmuch_threads_valid just check if the iterator is valid and is notmuch_threads_move_to_next wich actually update the iterator. --- lib/query.cc | 47 --- 1 files changed, 24 insertions(+), 23 deletions(-) diff --git a/lib/query.cc b/lib/query.cc index 970c35a..44950c1 100644 --- a/lib/query.cc +++ b/lib/query.cc @@ -285,6 +285,7 @@ notmuch_threads_t * notmuch_query_search_threads (notmuch_query_t *query) { notmuch_threads_t *threads; +notmuch_message_t *message; threads = talloc (query, notmuch_threads_t); if (threads == NULL) @@ -296,7 +297,10 @@ notmuch_query_search_threads (notmuch_query_t *query) threads->messages = notmuch_query_search_messages (query); -threads->thread_id = NULL; +message = notmuch_messages_get (threads->messages); +threads->thread_id = notmuch_message_get_thread_id (message); +g_hash_table_insert (threads->threads, + xstrdup (threads->thread_id), NULL); talloc_set_destructor (threads, _notmuch_threads_destructor); @@ -312,10 +316,25 @@ notmuch_query_destroy (notmuch_query_t *query) notmuch_bool_t notmuch_threads_valid (notmuch_threads_t *threads) { -notmuch_message_t *message; +return (threads->thread_id != NULL); +} -if (threads->thread_id) - return TRUE; +notmuch_thread_t * +notmuch_threads_get (notmuch_threads_t *threads) +{ +if (! notmuch_threads_valid (threads)) + return NULL; + +return _notmuch_thread_create (threads->query, + threads->query->notmuch, + threads->thread_id, + threads->query->query_string); +} + +void +notmuch_threads_move_to_next (notmuch_threads_t *threads) +{ +notmuch_message_t *message; while (notmuch_messages_valid (threads->messages)) { @@ -330,33 +349,15 @@ notmuch_threads_valid (notmuch_threads_t *threads) g_hash_table_insert (threads->threads, xstrdup (threads->thread_id), NULL); notmuch_messages_move_to_next (threads->messages); - return TRUE; + return; } notmuch_messages_move_to_next (threads->messages); } threads->thread_id = NULL; -return FALSE; -} - -notmuch_thread_t * -notmuch_threads_get (notmuch_threads_t *threads) -{ -if (! notmuch_threads_valid (threads)) - return NULL; - -return _notmuch_thread_create (threads->query, - threads->query->notmuch, - threads->thread_id, - threads->query->query_string); } -void -notmuch_threads_move_to_next (notmuch_threads_t *threads) -{ -threads->thread_id = NULL; -} void notmuch_threads_destroy (notmuch_threads_t *threads) -- 1.7.0
[notmuch] [PATCH 2/5] Added backwards iterator to messages
Added the functions notmuch_messages_move_to_prevoius, notmuch_messages_move_to_last and notmuch_messages_move_to_first to notmuch library. With them is possible to iterate backwards on messages. * notmuch_messages_move_to_prevoius do the opposite than notmuch_messages_move_to_next, getting the messages iterator one position backwards. * notmuch_messages_move_to_last move the iterator to the first last message. * notmuch_messages_move_to_first move the iterator to the first valid message. --- lib/messages.c| 31 + lib/notmuch-private.h | 10 + lib/notmuch.h | 28 ++ lib/query.cc | 52 + 4 files changed, 121 insertions(+), 0 deletions(-) diff --git a/lib/messages.c b/lib/messages.c index 2a85774..975e4b1 100644 --- a/lib/messages.c +++ b/lib/messages.c @@ -90,6 +90,7 @@ _notmuch_messages_create (notmuch_message_list_t *list) messages->is_of_list_type = TRUE; messages->iterator = list->head; +messages->list = list; return messages; } @@ -134,6 +135,15 @@ notmuch_messages_get (notmuch_messages_t *messages) } void +notmuch_messages_move_to_first (notmuch_messages_t *messages) +{ +if (! messages->is_of_list_type) + return _notmuch_mset_messages_move_to_first (messages); + +messages->iterator = messages->list->head; +} + +void notmuch_messages_move_to_next (notmuch_messages_t *messages) { if (! messages->is_of_list_type) @@ -146,6 +156,27 @@ notmuch_messages_move_to_next (notmuch_messages_t *messages) } void +notmuch_messages_move_to_last (notmuch_messages_t *messages) +{ +if (! messages->is_of_list_type) + return _notmuch_mset_messages_move_to_last (messages); + +messages->iterator = messages->list->tail; +} + +void +notmuch_messages_move_to_previous (notmuch_messages_t *messages) +{ +if (! messages->is_of_list_type) + return _notmuch_mset_messages_move_to_previous (messages); + +if (messages->iterator == NULL) + return; + +messages->iterator = messages->iterator->prev; +} + +void notmuch_messages_destroy (notmuch_messages_t *messages) { talloc_free (messages); diff --git a/lib/notmuch-private.h b/lib/notmuch-private.h index 3b3f0eb..2269d2b 100644 --- a/lib/notmuch-private.h +++ b/lib/notmuch-private.h @@ -364,6 +364,7 @@ typedef struct _notmuch_message_list { struct _notmuch_messages { notmuch_bool_t is_of_list_type; notmuch_message_node_t *iterator; +notmuch_message_list_t *list; }; notmuch_message_list_t * @@ -389,8 +390,17 @@ notmuch_message_t * _notmuch_mset_messages_get (notmuch_messages_t *messages); void +_notmuch_mset_messages_move_to_first (notmuch_messages_t *messages); + +void _notmuch_mset_messages_move_to_next (notmuch_messages_t *messages); +void +_notmuch_mset_messages_move_to_last (notmuch_messages_t *messages); + +void +_notmuch_mset_messages_move_to_previous (notmuch_messages_t *messages); + /* message.cc */ void diff --git a/lib/notmuch.h b/lib/notmuch.h index 0d9cb0f..753f3bb 100644 --- a/lib/notmuch.h +++ b/lib/notmuch.h @@ -645,6 +645,15 @@ notmuch_messages_valid (notmuch_messages_t *messages); notmuch_message_t * notmuch_messages_get (notmuch_messages_t *messages); +/* Move the 'messages' iterator to the first message. + * + * After that the 'messages' iterator will be set to the first valid + * message, so it can be use to iterate with + * notmuch_messages_move_to_next. + */ +void +notmuch_messages_move_to_first (notmuch_messages_t *messages); + /* Move the 'messages' iterator to the next message. * * If 'messages' is already pointing at the last message then the @@ -658,6 +667,25 @@ notmuch_messages_get (notmuch_messages_t *messages); void notmuch_messages_move_to_next (notmuch_messages_t *messages); +/* Move the 'messages' iterator to the last message. + * + * After that the 'messages' iterator will be set to the last valid + * message, so it can be use to iterate with + * notmuch_messages_move_to_previous. + */ +void +notmuch_messages_move_to_last (notmuch_messages_t *messages); + +/* Move the 'messages' iterator to the previous message. + * + * If 'messages' is already pointing at the first message then the + * iterator will be moved to a point just beyond that first message, + * (where notmuch_messages_valid will return FALSE and + * notmuch_messages_get will return NULL). + */ +void +notmuch_messages_move_to_previous (notmuch_messages_t *messages); + /* Destroy a notmuch_messages_t object. * * It's not strictly necessary to call this function. All memory from diff --git a/lib/query.cc b/lib/query.cc index 9266d35..970c35a 100644 --- a/lib/query.cc +++ b/lib/query.cc @@ -35,6 +35,7 @@ typedef struct _notmuch_mset_messages { notmuch_messages_t base; notmuch_database_t *notmuch; Xapian::MSetIterator iterator; +Xapian::MSetIterator iterator_begin; Xapian::MSetIterator
[notmuch] [PATCH 1/5] Convert notmuch_message_list_t in a doubly linked
The messages list now have pointers to previous nodes, so it is possible to iterate backwards. --- lib/messages.c| 18 +- lib/notmuch-private.h |3 ++- lib/thread.cc |4 ++-- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/lib/messages.c b/lib/messages.c index db2b7a1..2a85774 100644 --- a/lib/messages.c +++ b/lib/messages.c @@ -37,20 +37,28 @@ _notmuch_message_list_create (const void *ctx) return NULL; list->head = NULL; -list->tail = >head; +list->tail = NULL; return list; } -/* Append 'node' (which can of course point to an arbitrarily long - * list of nodes) to the end of 'list'. +/* Append 'node' to the end of 'list'. */ void _notmuch_message_list_append (notmuch_message_list_t *list, notmuch_message_node_t *node) { -*(list->tail) = node; -list->tail = >next; +node->prev = list->tail; +if (list->head) +{ +list->tail->next = node; +} +else +{ +list->head = node; +list->tail = node; +} +list->tail = node; } /* Allocate a new node for 'message' and append it to the end of diff --git a/lib/notmuch-private.h b/lib/notmuch-private.h index d52d84d..3b3f0eb 100644 --- a/lib/notmuch-private.h +++ b/lib/notmuch-private.h @@ -349,11 +349,12 @@ notmuch_message_file_get_header (notmuch_message_file_t *message, typedef struct _notmuch_message_node { notmuch_message_t *message; struct _notmuch_message_node *next; +struct _notmuch_message_node *prev; } notmuch_message_node_t; typedef struct _notmuch_message_list { notmuch_message_node_t *head; -notmuch_message_node_t **tail; +notmuch_message_node_t *tail; } notmuch_message_list_t; /* There's a rumor that there's an alternate struct _notmuch_messages diff --git a/lib/thread.cc b/lib/thread.cc index ec80f85..05d2c39 100644 --- a/lib/thread.cc +++ b/lib/thread.cc @@ -169,8 +169,8 @@ _resolve_thread_relationships (unused (notmuch_thread_t *thread)) (void **) )) { *prev = node->next; - if (thread->message_list->tail == >next) - thread->message_list->tail = prev; + if (thread->message_list->tail == node) + thread->message_list->tail = node->prev; node->next = NULL; _notmuch_message_add_reply (parent, node); } else { -- 1.7.0
[notmuch] reverse iterators
Adds support to reverse iteration on messages, threads and tags. To revew and think if makes sense to include them on notmuch or wait until they have a real use. The patch 3 "Move the logic of threads iterator out of 'valid'" is just a reorganization of the code, I think it makes sense to include it in notmuch even if we decide that the reverse iterators are not included.
[notmuch] reverse iterators
Adds support to reverse iteration on messages, threads and tags. To revew and think if makes sense to include them on notmuch or wait until they have a real use. The patch 3 Move the logic of threads iterator out of 'valid' is just a reorganization of the code, I think it makes sense to include it in notmuch even if we decide that the reverse iterators are not included. ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
[notmuch] [PATCH 1/5] Convert notmuch_message_list_t in a doubly linked
The messages list now have pointers to previous nodes, so it is possible to iterate backwards. --- lib/messages.c| 18 +- lib/notmuch-private.h |3 ++- lib/thread.cc |4 ++-- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/lib/messages.c b/lib/messages.c index db2b7a1..2a85774 100644 --- a/lib/messages.c +++ b/lib/messages.c @@ -37,20 +37,28 @@ _notmuch_message_list_create (const void *ctx) return NULL; list-head = NULL; -list-tail = list-head; +list-tail = NULL; return list; } -/* Append 'node' (which can of course point to an arbitrarily long - * list of nodes) to the end of 'list'. +/* Append 'node' to the end of 'list'. */ void _notmuch_message_list_append (notmuch_message_list_t *list, notmuch_message_node_t *node) { -*(list-tail) = node; -list-tail = node-next; +node-prev = list-tail; +if (list-head) +{ +list-tail-next = node; +} +else +{ +list-head = node; +list-tail = node; +} +list-tail = node; } /* Allocate a new node for 'message' and append it to the end of diff --git a/lib/notmuch-private.h b/lib/notmuch-private.h index d52d84d..3b3f0eb 100644 --- a/lib/notmuch-private.h +++ b/lib/notmuch-private.h @@ -349,11 +349,12 @@ notmuch_message_file_get_header (notmuch_message_file_t *message, typedef struct _notmuch_message_node { notmuch_message_t *message; struct _notmuch_message_node *next; +struct _notmuch_message_node *prev; } notmuch_message_node_t; typedef struct _notmuch_message_list { notmuch_message_node_t *head; -notmuch_message_node_t **tail; +notmuch_message_node_t *tail; } notmuch_message_list_t; /* There's a rumor that there's an alternate struct _notmuch_messages diff --git a/lib/thread.cc b/lib/thread.cc index ec80f85..05d2c39 100644 --- a/lib/thread.cc +++ b/lib/thread.cc @@ -169,8 +169,8 @@ _resolve_thread_relationships (unused (notmuch_thread_t *thread)) (void **) parent)) { *prev = node-next; - if (thread-message_list-tail == node-next) - thread-message_list-tail = prev; + if (thread-message_list-tail == node) + thread-message_list-tail = node-prev; node-next = NULL; _notmuch_message_add_reply (parent, node); } else { -- 1.7.0 ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
[notmuch] [PATCH 2/5] Added backwards iterator to messages
Added the functions notmuch_messages_move_to_prevoius, notmuch_messages_move_to_last and notmuch_messages_move_to_first to notmuch library. With them is possible to iterate backwards on messages. * notmuch_messages_move_to_prevoius do the opposite than notmuch_messages_move_to_next, getting the messages iterator one position backwards. * notmuch_messages_move_to_last move the iterator to the first last message. * notmuch_messages_move_to_first move the iterator to the first valid message. --- lib/messages.c| 31 + lib/notmuch-private.h | 10 + lib/notmuch.h | 28 ++ lib/query.cc | 52 + 4 files changed, 121 insertions(+), 0 deletions(-) diff --git a/lib/messages.c b/lib/messages.c index 2a85774..975e4b1 100644 --- a/lib/messages.c +++ b/lib/messages.c @@ -90,6 +90,7 @@ _notmuch_messages_create (notmuch_message_list_t *list) messages-is_of_list_type = TRUE; messages-iterator = list-head; +messages-list = list; return messages; } @@ -134,6 +135,15 @@ notmuch_messages_get (notmuch_messages_t *messages) } void +notmuch_messages_move_to_first (notmuch_messages_t *messages) +{ +if (! messages-is_of_list_type) + return _notmuch_mset_messages_move_to_first (messages); + +messages-iterator = messages-list-head; +} + +void notmuch_messages_move_to_next (notmuch_messages_t *messages) { if (! messages-is_of_list_type) @@ -146,6 +156,27 @@ notmuch_messages_move_to_next (notmuch_messages_t *messages) } void +notmuch_messages_move_to_last (notmuch_messages_t *messages) +{ +if (! messages-is_of_list_type) + return _notmuch_mset_messages_move_to_last (messages); + +messages-iterator = messages-list-tail; +} + +void +notmuch_messages_move_to_previous (notmuch_messages_t *messages) +{ +if (! messages-is_of_list_type) + return _notmuch_mset_messages_move_to_previous (messages); + +if (messages-iterator == NULL) + return; + +messages-iterator = messages-iterator-prev; +} + +void notmuch_messages_destroy (notmuch_messages_t *messages) { talloc_free (messages); diff --git a/lib/notmuch-private.h b/lib/notmuch-private.h index 3b3f0eb..2269d2b 100644 --- a/lib/notmuch-private.h +++ b/lib/notmuch-private.h @@ -364,6 +364,7 @@ typedef struct _notmuch_message_list { struct _notmuch_messages { notmuch_bool_t is_of_list_type; notmuch_message_node_t *iterator; +notmuch_message_list_t *list; }; notmuch_message_list_t * @@ -389,8 +390,17 @@ notmuch_message_t * _notmuch_mset_messages_get (notmuch_messages_t *messages); void +_notmuch_mset_messages_move_to_first (notmuch_messages_t *messages); + +void _notmuch_mset_messages_move_to_next (notmuch_messages_t *messages); +void +_notmuch_mset_messages_move_to_last (notmuch_messages_t *messages); + +void +_notmuch_mset_messages_move_to_previous (notmuch_messages_t *messages); + /* message.cc */ void diff --git a/lib/notmuch.h b/lib/notmuch.h index 0d9cb0f..753f3bb 100644 --- a/lib/notmuch.h +++ b/lib/notmuch.h @@ -645,6 +645,15 @@ notmuch_messages_valid (notmuch_messages_t *messages); notmuch_message_t * notmuch_messages_get (notmuch_messages_t *messages); +/* Move the 'messages' iterator to the first message. + * + * After that the 'messages' iterator will be set to the first valid + * message, so it can be use to iterate with + * notmuch_messages_move_to_next. + */ +void +notmuch_messages_move_to_first (notmuch_messages_t *messages); + /* Move the 'messages' iterator to the next message. * * If 'messages' is already pointing at the last message then the @@ -658,6 +667,25 @@ notmuch_messages_get (notmuch_messages_t *messages); void notmuch_messages_move_to_next (notmuch_messages_t *messages); +/* Move the 'messages' iterator to the last message. + * + * After that the 'messages' iterator will be set to the last valid + * message, so it can be use to iterate with + * notmuch_messages_move_to_previous. + */ +void +notmuch_messages_move_to_last (notmuch_messages_t *messages); + +/* Move the 'messages' iterator to the previous message. + * + * If 'messages' is already pointing at the first message then the + * iterator will be moved to a point just beyond that first message, + * (where notmuch_messages_valid will return FALSE and + * notmuch_messages_get will return NULL). + */ +void +notmuch_messages_move_to_previous (notmuch_messages_t *messages); + /* Destroy a notmuch_messages_t object. * * It's not strictly necessary to call this function. All memory from diff --git a/lib/query.cc b/lib/query.cc index 9266d35..970c35a 100644 --- a/lib/query.cc +++ b/lib/query.cc @@ -35,6 +35,7 @@ typedef struct _notmuch_mset_messages { notmuch_messages_t base; notmuch_database_t *notmuch; Xapian::MSetIterator iterator; +Xapian::MSetIterator iterator_begin; Xapian::MSetIterator
[notmuch] [PATCH 4/5] Added backwards iterator to threads
Added the functions notmuch_threads_move_to_prevoius, notmuch_threads_move_to_last and notmuch_threads_move_to_first to notmuch library. With them is possible to iterate backwards on threads. * notmuch_threads_move_to_prevoius do the opposite than notmuch_threads_move_to_next, getting the threads iterator one position backwards. * notmuch_threads_move_to_last move the iterator to the first last thread. * notmuch_threads_move_to_first move the iterator to the first valid thread. For it has been implemented notmuch_thread_list_t structur that stores the thread_ids so the backwards iteration gets the thread_id in the same order that was show on forward iteration. --- lib/notmuch.h | 28 +++ lib/query.cc | 143 - 2 files changed, 159 insertions(+), 12 deletions(-) diff --git a/lib/notmuch.h b/lib/notmuch.h index 753f3bb..b96b624 100644 --- a/lib/notmuch.h +++ b/lib/notmuch.h @@ -466,6 +466,15 @@ notmuch_threads_valid (notmuch_threads_t *threads); notmuch_thread_t * notmuch_threads_get (notmuch_threads_t *threads); +/* Move the 'threads' iterator to the first thread. + * + * After that the 'threads' iterator will be set to the first valid + * thread, so it can be use to iterate with + * notmuch_threads_move_to_next. + */ +void +notmuch_threads_move_to_first (notmuch_threads_t *threads); + /* Move the 'threads' iterator to the next thread. * * If 'threads' is already pointing at the last thread then the @@ -479,6 +488,25 @@ notmuch_threads_get (notmuch_threads_t *threads); void notmuch_threads_move_to_next (notmuch_threads_t *threads); +/* Move the 'threads' iterator to the last thread. + * + * After that the 'threads' iterator will be set to the last valid + * thread, so it can be use to iterate with + * notmuch_threads_move_to_previous. + */ +void +notmuch_threads_move_to_last (notmuch_threads_t *threads); + +/* Move the 'threads' iterator to the previous thread. + * + * If 'threads' is already pointing at the first thread then the + * iterator will be moved to a point just beyond that first thread, + * (where notmuch_threads_valid will return FALSE and + * notmuch_threads_get will return NULL). + */ +void +notmuch_threads_move_to_previous (notmuch_threads_t *threads); + /* Destroy a notmuch_threads_t object. * * It's not strictly necessary to call this function. All memory from diff --git a/lib/query.cc b/lib/query.cc index 44950c1..39985e7 100644 --- a/lib/query.cc +++ b/lib/query.cc @@ -39,13 +39,25 @@ typedef struct _notmuch_mset_messages { Xapian::MSetIterator iterator_end; } notmuch_mset_messages_t; +typedef struct _notmuch_thread_node { +const char *thread_id; +struct _notmuch_thread_node *next; +struct _notmuch_thread_node *prev; +} notmuch_thread_node_t; + +typedef struct _notmuch_thread_list { +notmuch_thread_node_t *head; +notmuch_thread_node_t *tail; +notmuch_thread_node_t *iterator; +} notmuch_thread_list_t; + struct _notmuch_threads { notmuch_query_t *query; GHashTable *threads; notmuch_messages_t *messages; -/* This thread ID is our iterator state. */ -const char *thread_id; +/* thread list with the thread_id of the showed messages */ +notmuch_thread_list_t *list; }; notmuch_query_t * @@ -269,6 +281,64 @@ _notmuch_mset_messages_move_to_previous (notmuch_messages_t *messages) } } +static void +_notmuch_thread_list_create (notmuch_thread_list_t *list, const char *thread_id) +{ +list-head = talloc (list, notmuch_thread_node_t); +list-tail = list-head; +list-iterator = list-head; +list-iterator-thread_id = thread_id; +list-iterator-next = NULL; +list-iterator-prev = NULL; +} + +static void +_notmuch_thread_list_append (notmuch_thread_list_t *list, const char *thread_id) +{ +list-tail-next = talloc (list, notmuch_thread_node_t); +list-iterator = list-tail-next; +list-iterator-thread_id = thread_id; +list-iterator-next = NULL; +list-iterator-prev = list-tail; +list-tail = list-iterator; +} + +static const char * +_notmuch_thread_list_get_id (notmuch_thread_list_t *list) +{ +return list-iterator-thread_id; +} + +static notmuch_bool_t +_notmuch_thread_list_valid (notmuch_thread_list_t *list) +{ +return (list-iterator != NULL); +} + +static void +_notmuch_thread_list_move_to_first (notmuch_thread_list_t *list) +{ +list-iterator = list-head; +} + +static void +_notmuch_thread_list_move_to_next (notmuch_thread_list_t *list) +{ +list-iterator = list-iterator-next; +} + +static void +_notmuch_thread_list_move_to_last (notmuch_thread_list_t *list) +{ +list-iterator = list-tail; +} + +static void +_notmuch_thread_list_move_to_previous (notmuch_thread_list_t *list) +{ +list-iterator = list-iterator-prev; +} + /* Glib objects force use to use a talloc destructor as well, (but not * nearly as ugly as the for messages due to C++ objects). At * this point,
[notmuch] [PATCH 3/5] Move the logic of threads iterator out of 'valid'
The logic of notmuch_threads_move_to_next iterator was on notmuch_threads_valid function. Now notmuch_threads_valid just check if the iterator is valid and is notmuch_threads_move_to_next wich actually update the iterator. --- lib/query.cc | 47 --- 1 files changed, 24 insertions(+), 23 deletions(-) diff --git a/lib/query.cc b/lib/query.cc index 970c35a..44950c1 100644 --- a/lib/query.cc +++ b/lib/query.cc @@ -285,6 +285,7 @@ notmuch_threads_t * notmuch_query_search_threads (notmuch_query_t *query) { notmuch_threads_t *threads; +notmuch_message_t *message; threads = talloc (query, notmuch_threads_t); if (threads == NULL) @@ -296,7 +297,10 @@ notmuch_query_search_threads (notmuch_query_t *query) threads-messages = notmuch_query_search_messages (query); -threads-thread_id = NULL; +message = notmuch_messages_get (threads-messages); +threads-thread_id = notmuch_message_get_thread_id (message); +g_hash_table_insert (threads-threads, + xstrdup (threads-thread_id), NULL); talloc_set_destructor (threads, _notmuch_threads_destructor); @@ -312,10 +316,25 @@ notmuch_query_destroy (notmuch_query_t *query) notmuch_bool_t notmuch_threads_valid (notmuch_threads_t *threads) { -notmuch_message_t *message; +return (threads-thread_id != NULL); +} -if (threads-thread_id) - return TRUE; +notmuch_thread_t * +notmuch_threads_get (notmuch_threads_t *threads) +{ +if (! notmuch_threads_valid (threads)) + return NULL; + +return _notmuch_thread_create (threads-query, + threads-query-notmuch, + threads-thread_id, + threads-query-query_string); +} + +void +notmuch_threads_move_to_next (notmuch_threads_t *threads) +{ +notmuch_message_t *message; while (notmuch_messages_valid (threads-messages)) { @@ -330,33 +349,15 @@ notmuch_threads_valid (notmuch_threads_t *threads) g_hash_table_insert (threads-threads, xstrdup (threads-thread_id), NULL); notmuch_messages_move_to_next (threads-messages); - return TRUE; + return; } notmuch_messages_move_to_next (threads-messages); } threads-thread_id = NULL; -return FALSE; -} - -notmuch_thread_t * -notmuch_threads_get (notmuch_threads_t *threads) -{ -if (! notmuch_threads_valid (threads)) - return NULL; - -return _notmuch_thread_create (threads-query, - threads-query-notmuch, - threads-thread_id, - threads-query-query_string); } -void -notmuch_threads_move_to_next (notmuch_threads_t *threads) -{ -threads-thread_id = NULL; -} void notmuch_threads_destroy (notmuch_threads_t *threads) -- 1.7.0 ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
[notmuch] [PATCH 5/5] Added backwards iterator to tags
Added the functions notmuch_tags_move_to_prevoius, notmuch_tags_move_to_last and notmuch_tags_move_to_first to notmuch library. With them is possible to iterate backwards on tags. * notmuch_tags_move_to_prevoius do the opposite than notmuch_tags_move_to_next, getting the tags iterator one position backwards. * notmuch_tags_move_to_last move the iterator to the first last tag. * notmuch_tags_move_to_first move the iterator to the first valid tag. --- lib/notmuch.h | 28 lib/tags.c| 21 + 2 files changed, 49 insertions(+), 0 deletions(-) diff --git a/lib/notmuch.h b/lib/notmuch.h index b96b624..dc668dc 100644 --- a/lib/notmuch.h +++ b/lib/notmuch.h @@ -1022,6 +1022,15 @@ notmuch_tags_valid (notmuch_tags_t *tags); const char * notmuch_tags_get (notmuch_tags_t *tags); +/* Move the 'tags' iterator to the first tag. + * + * After that the 'tags' iterator will be set to the first valid + * tag, so it can be use to iterate with + * notmuch_tags_move_to_next. + */ +void +notmuch_tags_move_to_first (notmuch_tags_t *tags); + /* Move the 'tags' iterator to the next tag. * * If 'tags' is already pointing at the last tag then the iterator @@ -1035,6 +1044,25 @@ notmuch_tags_get (notmuch_tags_t *tags); void notmuch_tags_move_to_next (notmuch_tags_t *tags); +/* Move the 'tags' iterator to the last tag. + * + * After that the 'tags' iterator will be set to the last valid + * tag, so it can be use to iterate with + * notmuch_tags_move_to_previous. + */ +void +notmuch_tags_move_to_last (notmuch_tags_t *tags); + +/* Move the 'tags' iterator to the previous tag. + * + * If 'tags' is already pointing at the first tag then the + * iterator will be moved to a point just beyond that first tag, + * (where notmuch_tags_valid will return FALSE and + * notmuch_tags_get will return NULL). + */ +void +notmuch_tags_move_to_previous (notmuch_tags_t *tags); + /* Destroy a notmuch_tags_t object. * * It's not strictly necessary to call this function. All memory from diff --git a/lib/tags.c b/lib/tags.c index 8fe4a3f..9c9a897 100644 --- a/lib/tags.c +++ b/lib/tags.c @@ -105,6 +105,12 @@ notmuch_tags_get (notmuch_tags_t *tags) } void +notmuch_tags_move_to_first (notmuch_tags_t *tags) +{ +tags-iterator = g_list_first (tags-tags); +} + +void notmuch_tags_move_to_next (notmuch_tags_t *tags) { if (tags-iterator == NULL) @@ -114,6 +120,21 @@ notmuch_tags_move_to_next (notmuch_tags_t *tags) } void +notmuch_tags_move_to_last (notmuch_tags_t *tags) +{ +tags-iterator = g_list_last (tags-tags); +} + +void +notmuch_tags_move_to_previous (notmuch_tags_t *tags) +{ +if (tags-iterator == NULL) + return; + +tags-iterator = tags-iterator-prev; +} + +void notmuch_tags_destroy (notmuch_tags_t *tags) { talloc_free (tags); -- 1.7.0 ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
Re: [notmuch] Tag search peculiarities
On Thu, 18 Mar 2010 15:27:12 +0100, Sandra Snan sandra.s...@handgranat.org wrote: Hey, Ben. Ben Gamari bgamari.f...@gmail.com wrote: notmuch tag -new tag:new and tag:list notmuch tag -new +inbox tag:new Is there a new line between the calls? Like: notmuch tag -new tag:new and tag:list # removes new from list notmuch tag -new +inbox tag:new # replaces those that still are new with inbox Eh? They are two separate notmuch invocations. However, I found that mailing list traffic was still getting through. What do you mean by âthroughâ? Do you mean that there still are messages tagged both inbox and list? Even though you canât search for them? Yeah, poor choice of words. After the two commands above ran, my mailing list messages were tagged with new, inbox. If a message is tagged both inbox and list, but not new then the two lines of your script that you posted so far wouldnât change it, and it would still bo both inbox and list. Itâs risky being so dependent on the new tag. Eh? I fail to see why. It's no more risky than depending on the inbox tag. After investigating further, I found that any query in the form of tag:inbox and tag:$TAG would return no results. Strangely, all other combinations of tag searches (i.e. tag:lkml and tag:unread) seem to work just fine. Has anyone else noticed this sort of behavior? Does the inbox tag have some special signifigance that I should know of? Yes, many versions of the reading client (for example, the version of notmuch.el that ships with the notmuch package in debian) remove the inbox tag from messages once you scroll past them or when you press the key thatâs bound to notmuch-show-archive-thread (default is âaâ). I guess I should have been more explicit. I meant in notmuch itself, not the clients. Is my index just FUBAR? (the ladder would be very strange considering it's only a few days old and I can't think of any crashes, etc. that might have corrupted it) Any ideas for debugging? Add the tags manually to a few messages, search for them again, and be sure to not run your tagging script while looking at this problem. Michalâs tip, looking at a few lines of notmuch dump, is a good idea too. Notmuch dump is fast, so donât be afraid (notmuch restore on the other hand⦠but even that completes fast enough.) Iâve often been surprised at weird tag situations then realized that it was old versions of my own scripts that had ran in the background and Iâve forgotten about it. Indeed. Hopefully it will be something so simple. I'm currently blissfully unaware of the internals of Xapian, and would really like to remain that way. Thanks, - Ben ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
Re: [notmuch] Tag search peculiarities
On Sat, 20 Mar 2010 16:09:00 -0700 (PDT), Ben Gamari bgamari.f...@gmail.com wrote: On Thu, 18 Mar 2010 15:27:12 +0100, Sandra Snan sandra.s...@handgranat.org wrote: Hey, Ben. Ben Gamari bgamari.f...@gmail.com wrote: notmuch tag -new tag:new and tag:list notmuch tag -new +inbox tag:new Is there a new line between the calls? Like: notmuch tag -new tag:new and tag:list # removes new from list notmuch tag -new +inbox tag:new # replaces those that still are new with inbox Eh? They are two separate notmuch invocations. In my mail (quoted above) it showed up as one single line, a single invocation. Guess there was mail problem somewhere. Thanks for the clarification. Yeah, poor choice of words. After the two commands above ran, my mailing list messages were tagged with new, inbox. And not list? Huh. Does seem weird that after explicitly replacing new with inbox, as you did, you still have them new. ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
[notmuch] Using notmuch as an address book for tab-completion
Dear All, There was some talk on IRC ages ago about using notmuch as an address-book for tab-completion in emacs message mode. Thanks to some great recent work (Ingmar Vanhassel's shared lib and Sebastians's cnotmuch python lib) I have been able to take a first step in that direction. I've written a python script (with some help and suggestions from spaetz) which can perform the address-book functionality, and a backend for emacs's EUDC address-lookup functionality to access the script. They are available by the following commands: git clone http://jkr.acm.jhu.edu/git/notmuch_addresses.git git clone http://jkr.acm.jhu.edu/git/notmuch_eudc.git Remember, neither of these will do you much good with the shared lib and cnotmuch installed. At the moment, the script works by search addresses that you have written to (or CC'd or BCC'd) in the past. This seems like a good utility-speed tradeoff, but it would be easy to hack the script to search a different set of messages. Give three letters (it looks through first names, last names, and email addresses) it returns results from my 12K messages in well under a second. The responses are sorted by frequency, and each email address is associated with the most frequently used real name (null real-names are avoided, unless they're the only option). The script can be run from the command line by: $ python notmuch_addresses.py query To get tab completion from emacs, you have to install the script into your path, make it executable, and then put my eudcb-notmuch.el file into your load path (you should byte-compile it too). DON'T CHANGE THE TITLE OF THE .EL FILE! EUDC looks for a specific title based on protocol. Then add the following to your .emacs: (eudc-set-server localhost 'notmuch t) (setq eudc-server-hotlist '((localhost . notmuch))) (setq eudc-inline-expansion-servers 'hotlist) if you wish to use BBDB too (likely before you use notmuch), then you should use something like this: (eudc-set-server localhost 'bbdb t) (eudc-protocol-set 'eudc-inline-expansion-format '(%s %s %s firstname lastname net) 'bbdb) (eudc-set-server localhost 'notmuch t) (setq eudc-server-hotlist '((localhost . bbdb) (localhost . notmuch))) (setq eudc-inline-expansion-servers 'hotlist) That should do it. Please let me know if it works for you. (For those of you who care, eudcb-notmuch.el has a few hacky bits to hide the fact that notmuch really isn't an address book. That is, it doesn't know the difference between names and email addresses. So everything you enter just goes in as one string, which I call name. Back-end stuff, but if you're looking through the code, that might make a few things clearer.) Best, Jesse ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
Re: [notmuch] Using notmuch as an address book for tab-completion
Normally, I wouldn't respond to myself to fix a typo, but this seemed important. Remember, neither of these will do you much good with the shared lib and cnotmuch installed. I meant, of course, that neither would do you much good *WITHOUT* the shared lib and cnotmuch installed. Apologies, Jesse ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch