[PATCH v2 11/13] emacs: code cleanup in `notmuch-show-operate-all', no functional changes
notmuch-show-tag-all, in the first line of the commit message. As in the previous patch, if the previous patch comes earlier in the series, notmuch-show-tag-all could be written this way initially. Quoth Dmitry Kurochkin on Jan 30 at 6:26 am: > Use `notmuch-show-mapc' function instead of a custom `loop'. > --- > emacs/notmuch-show.el | 13 ++--- > 1 files changed, 6 insertions(+), 7 deletions(-) > > diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el > index b115a8f..69381ac 100644 > --- a/emacs/notmuch-show.el > +++ b/emacs/notmuch-show.el > @@ -1516,13 +1516,12 @@ TAG-CHANGES is a list of tag operations for > `notmuch-tag'." > TAG-CHANGES is a list of tag operations for `notmuch-tag'." >(interactive (notmuch-read-tag-changes nil notmuch-show-thread-id)) >(apply 'notmuch-tag (notmuch-show-get-messages-ids-search) tag-changes) > - (save-excursion > -(goto-char (point-min)) > -(loop do (let* ((current-tags (notmuch-show-get-tags)) > - (new-tags (notmuch-update-tags current-tags tag-changes))) > -(unless (equal current-tags new-tags) > - (notmuch-show-set-tags new-tags))) > - while (notmuch-show-goto-message-next > + (notmuch-show-mapc > + (lambda () > + (let* ((current-tags (notmuch-show-get-tags)) > + (new-tags (notmuch-update-tags current-tags tag-changes))) > + (unless (equal current-tags new-tags) > + (notmuch-show-set-tags new-tags)) > > (defun notmuch-show-add-tag () >"Same as `notmuch-show-tag' but sets initial input to '+'." -- Austin Clements MIT/'06/PhD/CSAIL amdragon at mit.edu http://web.mit.edu/amdragon Somewhere in the dream we call reality you will find me, searching for the reality we call dreams.
[PATCH v2 10/13] emacs: use message ids instead of thread id in `notmuch-show-operate-all'
Quoth Dmitry Kurochkin on Jan 30 at 6:26 am: > Before the change, `notmuch-show-operate-all' used thread id for notmuch-show-tag-all? > "notmuch tag" search. This could result in tagging unexpected > messages that were added to the thread after the notmuch-show buffer > was created. The patch changes `notmuch-show-operate-all' to use ids > of shown messages to fix this. > --- If you move this patch before the one that introduces notmuch-show-tag-all, you could do it this way from the beginning. > emacs/notmuch-show.el | 23 ++- > 1 files changed, 22 insertions(+), 1 deletions(-) > > diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el > index 0d90c1e..b115a8f 100644 > --- a/emacs/notmuch-show.el > +++ b/emacs/notmuch-show.el > @@ -1170,6 +1170,15 @@ All currently available key bindings: > (notmuch-show-move-to-message-top) > t)) > > +(defun notmuch-show-mapc (function) > + "Iterate through all messages in the current thread with > +`notmuch-show-goto-message-next' and call FUNCTION for side > +effects." > + (save-excursion > +(goto-char (point-min)) > +(loop do (funcall function) > + while (notmuch-show-goto-message-next > + > ;; Functions relating to the visibility of messages and their > ;; components. > > @@ -1222,6 +1231,18 @@ Some useful entries are: >"Return the message id of the current message." >(concat "id:\"" (notmuch-show-get-prop :id) "\"")) > > +(defun notmuch-show-get-messages-ids () > + "Return all message ids of messages in the current thread." > + (let ((message-ids)) > +(notmuch-show-mapc > + (lambda () (push (notmuch-show-get-message-id) message-ids))) > +message-ids)) > + > +(defun notmuch-show-get-messages-ids-search () > + "Return a search string for all message ids of messages in the > +current thread." > + (mapconcat 'identity (notmuch-show-get-messages-ids) " or ")) > + > ;; dme: Would it make sense to use a macro for many of these? > > (defun notmuch-show-get-filename () > @@ -1494,7 +1515,7 @@ TAG-CHANGES is a list of tag operations for > `notmuch-tag'." > > TAG-CHANGES is a list of tag operations for `notmuch-tag'." >(interactive (notmuch-read-tag-changes nil notmuch-show-thread-id)) > - (apply 'notmuch-tag notmuch-show-thread-id tag-changes) > + (apply 'notmuch-tag (notmuch-show-get-messages-ids-search) tag-changes) >(save-excursion > (goto-char (point-min)) > (loop do (let* ((current-tags (notmuch-show-get-tags))
[PATCH v2 03/13] emacs: make "+" and "-" tagging operations in notmuch-search more robust
Looking good. Just a few small points below. Quoth Dmitry Kurochkin on Jan 30 at 6:26 am: > Before the change, "+" and "-" tagging operations in notmuch-search > view accepted only a single tag. The patch makes them use the > recently added `notmuch-read-tag-changes' function (renamed > `notmuch-select-tags-with-completion'), which allows to enter multiple > tags with "+" and "-" prefixes. So after the change, "+" and "-" > bindings in notmuch-search view allow to both add and remove multiple > tags. The only difference between "+" and "-" is the minibuffer > initial input ("+" and "-" respectively). > --- > emacs/notmuch.el | 164 > +++--- > 1 files changed, 82 insertions(+), 82 deletions(-) > > diff --git a/emacs/notmuch.el b/emacs/notmuch.el > index ff46617..90b594c 100644 > --- a/emacs/notmuch.el > +++ b/emacs/notmuch.el > @@ -76,38 +76,57 @@ For example: > (defvar notmuch-query-history nil >"Variable to store minibuffer history for notmuch queries") > > -(defun notmuch-tag-completions ( prefixes search-terms) > - (let ((tag-list > - (split-string > - (with-output-to-string > - (with-current-buffer standard-output > - (apply 'call-process notmuch-command nil t > - nil "search-tags" search-terms))) > - "\n+" t))) > -(if (null prefixes) > - tag-list > - (apply #'append > - (mapcar (lambda (tag) > -(mapcar (lambda (prefix) > - (concat prefix tag)) prefixes)) > - tag-list) > +(defun notmuch-tag-completions ( search-terms) > + (split-string > + (with-output-to-string > + (with-current-buffer standard-output > + (apply 'call-process notmuch-command nil t > + nil "search-tags" search-terms))) > + "\n+" t)) > > (defun notmuch-select-tag-with-completion (prompt search-terms) > - (let ((tag-list (notmuch-tag-completions nil search-terms))) > + (let ((tag-list (notmuch-tag-completions search-terms))) > (completing-read prompt tag-list))) > > -(defun notmuch-select-tags-with-completion (prompt prefixes > search-terms) > - (let ((tag-list (notmuch-tag-completions prefixes search-terms)) > - (crm-separator " ") > - ;; By default, space is bound to "complete word" function. > - ;; Re-bind it to insert a space instead. Note that > - ;; still does the completion. > - (crm-local-completion-map > - (let ((map (make-sparse-keymap))) > -(set-keymap-parent map crm-local-completion-map) > -(define-key map " " 'self-insert-command) > -map))) > -(delete "" (completing-read-multiple prompt tag-list > +(defun notmuch-read-tag-changes ( initial-input search-terms) > + (let* ((all-tag-list (notmuch-tag-completions)) > + (add-tag-list (mapcar (apply-partially 'concat "+") all-tag-list)) > + (remove-tag-list (mapcar (apply-partially 'concat "-") > + (if (null search-terms) > + all-tag-list > + (notmuch-tag-completions search-terms > + (tag-list (append add-tag-list remove-tag-list)) > + (crm-separator " ") > + ;; By default, space is bound to "complete word" function. > + ;; Re-bind it to insert a space instead. Note that > + ;; still does the completion. > + (crm-local-completion-map > + (let ((map (make-sparse-keymap))) > + (set-keymap-parent map crm-local-completion-map) > + (define-key map " " 'self-insert-command) > + map))) > +(delete "" (completing-read-multiple "Tags (+add -drop): " > + tag-list nil nil initial-input > + > +(defun notmuch-update-tags (tags tag-changes) > + "Return a copy of TAGS with additions and removals from TAG-CHANGES. > + > +TAG-CHANGES must be a list of tags names, each prefixed with > +either a \"+\" to indicate the tag should be added to TAGS if not > +present or a \"-\" to indicate that the tag should be removed > +from TAGS if present." > + (let ((result-tags (copy-sequence tags))) > +(dolist (tag-change tag-changes) > + (unless (string= tag-change "") This function should give the "must be of the form" error for empty strings, rather than silently ignoring them. It turns out `string-to-char' on an empty string is fine (it returns 0, which will trigger the error), but `substring' isn't. Perhaps move the unless into the let before, like (let ((op (string-to-char tag-change)) (tag (unless (string= tag-change "") (substring tag-change 1 > + (let ((op (string-to-char tag-change)) > + (tag (substring tag-change 1))) > + (case op > + (?+ (unless (member tag result-tags) > + (push tag result-tags))) > + (?- (setq result-tags (delete tag result-tags))) > + (otherwise > + (error "Changed tag must be of the form
Bug: emacs 23.2 doesn't like ido-completing-read
Hello I have been experimenting with notmuch-always-prompt-for-sender on my debian stable setup (emacs 23.2.1) and it doesn't like ido-completing-read. It goes to the minibuffer and then it seems to be impossible to exit the minibuffer. I can find an emacs bug report #3274 and some discussion http://comments.gmane.org/gmane.emacs.bugs/27856 which indicates that it is a problem with ido initialisation. Unfortunately I can't get from there to a solution (except upgrade emacs). Many thanks Mark
[PATCH 7/7] emacs: show: recognize the exclude flag.
Show mode will recognize the exclude flag by not opening excluding messages by default, and will start at the first matching non-excluded message. If there are no matching non-excluded messages it will go to the first matching (necessarily excluded) message. --- emacs/notmuch-show.el | 18 +- 1 files changed, 17 insertions(+), 1 deletions(-) diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el index 84ac624..8efadf6 100644 --- a/emacs/notmuch-show.el +++ b/emacs/notmuch-show.el @@ -905,7 +905,8 @@ current buffer, if possible." ;; Message visibility depends on whether it matched the search ;; criteria. -(notmuch-show-message-visible msg (plist-get msg :match +(notmuch-show-message-visible msg (and (plist-get msg :match) + (not (plist-get msg :excluded)) (defun notmuch-show-insert-tree (tree depth) "Insert the message tree TREE at depth DEPTH in the current thread." @@ -1015,6 +1016,9 @@ buffer." ;; Move straight to the first open message (unless (notmuch-show-message-visible-p) (notmuch-show-next-open-message)) +(when (eq (point) (point-max)) + (goto-char (point-min)) + (notmuch-show-next-matching-message)) ;; Set the header line to the subject of the first open message. (setq header-line-format (notmuch-show-strip-re (notmuch-show-get-subject))) @@ -1417,6 +1421,18 @@ any effects from previous calls to (notmuch-show-message-adjust)) (goto-char (point-max) +(defun notmuch-show-next-matching-message () + "Show the next matching message." + (interactive) + (let (r) +(while (and (setq r (notmuch-show-goto-message-next)) + (not (notmuch-show-get-prop :match +(if r + (progn + (notmuch-show-mark-read) + (notmuch-show-message-adjust)) + (goto-char (point-max) + (defun notmuch-show-previous-open-message () "Show the previous message." (interactive) -- 1.7.2.3
[PATCH 6/7] cli: omit excluded messages in results where appropriate.
In all cases of notmuch count/search/show where the results returned cannot reflect the exclude flag return just the matched not-excluded results. If the caller wishes to have all the matched results (i.e., including the excluded ones) they should call with the --do-not-exclude option. The relevant cases are count: both threads and messages search: all cases except the summary view show: mbox format --- notmuch-count.c |2 ++ notmuch-search.c |9 + notmuch-show.c |5 + 3 files changed, 16 insertions(+), 0 deletions(-) diff --git a/notmuch-count.c b/notmuch-count.c index c88975e..1aa3f1a 100644 --- a/notmuch-count.c +++ b/notmuch-count.c @@ -87,6 +87,8 @@ notmuch_count_command (void *ctx, int argc, char *argv[]) notmuch_query_add_tag_exclude (query, search_exclude_tags[i]); } +notmuch_query_set_omit_excluded_messages (query, TRUE); + switch (output) { case OUTPUT_MESSAGES: printf ("%u\n", notmuch_query_count_messages (query)); diff --git a/notmuch-search.c b/notmuch-search.c index 084dd05..339ce82 100644 --- a/notmuch-search.c +++ b/notmuch-search.c @@ -207,6 +207,9 @@ do_search_threads (const search_format_t *format, int first_thread = 1; int i; +if (output == OUTPUT_THREADS) + notmuch_query_set_omit_excluded_messages (query, TRUE); + if (offset < 0) { offset += notmuch_query_count_threads (query); if (offset < 0) @@ -297,6 +300,8 @@ do_search_messages (const search_format_t *format, int first_message = 1; int i; +notmuch_query_set_omit_excluded_messages (query, TRUE); + if (offset < 0) { offset += notmuch_query_count_messages (query); if (offset < 0) @@ -368,6 +373,10 @@ do_search_tags (notmuch_database_t *notmuch, const char *tag; int first_tag = 1; +notmuch_query_set_omit_excluded_messages (query, TRUE); +/* should the following only special case if no excluded terms + * specified? */ + /* Special-case query of "*" for better performance. */ if (strcmp (notmuch_query_get_query_string (query), "*") == 0) { tags = notmuch_database_get_all_tags (notmuch); diff --git a/notmuch-show.c b/notmuch-show.c index 681827f..5d98724 100644 --- a/notmuch-show.c +++ b/notmuch-show.c @@ -1167,6 +1167,11 @@ notmuch_show_command (void *ctx, unused (int argc), unused (char *argv[])) return 1; } +/* if format=mbox then we can not output excluded messages as + * there is no way to make the exclude flag available */ +if (mbox) + notmuch_query_set_omit_excluded_messages (query, TRUE); + /* if part was requested and format was not specified, use format=raw */ if (params.part >= 0 && !format_specified) format = _raw; -- 1.7.2.3
[PATCH 5/7] cli: Make notmuch-show respect excludes.
This adds the excludes to notmuch-show.c. We do not exclude when only a single message (or part) is requested. notmuch-show will output the exclude information when either text or json format is requested. As this changes the output from notmuch-show it breaks many tests (in a trivial and expected fashion). --- notmuch-show.c | 26 +- 1 files changed, 21 insertions(+), 5 deletions(-) diff --git a/notmuch-show.c b/notmuch-show.c index dec799c..681827f 100644 --- a/notmuch-show.c +++ b/notmuch-show.c @@ -193,10 +193,12 @@ _get_one_line_summary (const void *ctx, notmuch_message_t *message) static void format_message_text (unused (const void *ctx), notmuch_message_t *message, int indent) { -printf ("id:%s depth:%d match:%d filename:%s\n", +/* Could changing this could break users ? */ +printf ("id:%s depth:%d match:%d excluded:%d filename:%s\n", notmuch_message_get_message_id (message), indent, - notmuch_message_get_flag (message, NOTMUCH_MESSAGE_FLAG_MATCH), + notmuch_message_get_flag (message, NOTMUCH_MESSAGE_FLAG_MATCH) ? 1 : 0, + notmuch_message_get_flag (message, NOTMUCH_MESSAGE_FLAG_EXCLUDED) ? 1 : 0, notmuch_message_get_filename (message)); } @@ -212,9 +214,10 @@ format_message_json (const void *ctx, notmuch_message_t *message, unused (int in date = notmuch_message_get_date (message); relative_date = notmuch_time_relative_date (ctx, date); -printf ("\"id\": %s, \"match\": %s, \"filename\": %s, \"timestamp\": %ld, \"date_relative\": \"%s\", \"tags\": [", +printf ("\"id\": %s, \"match\": %s, \"excluded\": %s, \"filename\": %s, \"timestamp\": %ld, \"date_relative\": \"%s\", \"tags\": [", json_quote_str (ctx_quote, notmuch_message_get_message_id (message)), notmuch_message_get_flag (message, NOTMUCH_MESSAGE_FLAG_MATCH) ? "true" : "false", + notmuch_message_get_flag (message, NOTMUCH_MESSAGE_FLAG_EXCLUDED) ? "true" : "false", json_quote_str (ctx_quote, notmuch_message_get_filename (message)), date, relative_date); @@ -1059,9 +1062,13 @@ notmuch_show_command (void *ctx, unused (int argc), unused (char *argv[])) char *opt; const notmuch_show_format_t *format = _text; notmuch_show_params_t params; +const char **search_exclude_tags; +size_t search_exclude_tags_length; int mbox = 0; int format_specified = 0; int i; +notmuch_bool_t do_not_exclude = FALSE; +unsigned int j; params.entire_thread = 0; params.raw = 0; @@ -1098,6 +1105,8 @@ notmuch_show_command (void *ctx, unused (int argc), unused (char *argv[])) params.part = atoi(argv[i] + sizeof ("--part=") - 1); } else if (STRNCMP_LITERAL (argv[i], "--entire-thread") == 0) { params.entire_thread = 1; + } else if (STRNCMP_LITERAL (argv[i], "--do-not-exclude") == 0) { + do_not_exclude = TRUE; } else if ((STRNCMP_LITERAL (argv[i], "--verify") == 0) || (STRNCMP_LITERAL (argv[i], "--decrypt") == 0)) { if (params.cryptoctx == NULL) { @@ -1105,7 +1114,7 @@ notmuch_show_command (void *ctx, unused (int argc), unused (char *argv[])) /* TODO: GMimePasswordRequestFunc */ if (NULL == (params.cryptoctx = g_mime_gpg_context_new(NULL, "gpg"))) #else - GMimeSession* session = g_object_new(g_mime_session_get_type(), NULL); + GMimeSession* session = g_object_new(g_mime_session_get_type(), NULL); if (NULL == (params.cryptoctx = g_mime_gpg_context_new(session, "gpg"))) #endif fprintf (stderr, "Failed to construct gpg context.\n"); @@ -1167,10 +1176,17 @@ notmuch_show_command (void *ctx, unused (int argc), unused (char *argv[])) if (params.raw && params.part < 0) params.part = 0; +/* if a single message is requested we do not use search_excludes */ if (params.part >= 0) return do_show_single (ctx, query, format, ); else - return do_show (ctx, query, format, ); + if (!do_not_exclude) { + search_exclude_tags = notmuch_config_get_search_exclude_tags + (config, _exclude_tags_length); + for (j = 0; j < search_exclude_tags_length; j++) + notmuch_query_add_tag_exclude (query, search_exclude_tags[j]); + return do_show (ctx, query, format, ); + } notmuch_query_destroy (query); notmuch_database_close (notmuch); -- 1.7.2.3
[PATCH 4/7] lib: Add the exclude flag to notmuch_query_search_threads
Add the NOTMUCH_MESSAGE_FLAG_EXCLUDED flag to notmuch_query_search_threads. Implemented by inspecting the tags directly in _notmuch_thread_create/_thread_add_message rather than as a Xapian query for speed reasons. --- lib/notmuch-private.h | 16 ++-- lib/query.cc |1 + lib/thread.cc | 18 +++--- 3 files changed, 26 insertions(+), 9 deletions(-) diff --git a/lib/notmuch-private.h b/lib/notmuch-private.h index e791bb0..56b87c6 100644 --- a/lib/notmuch-private.h +++ b/lib/notmuch-private.h @@ -211,12 +211,8 @@ _notmuch_directory_get_document_id (notmuch_directory_t *directory); /* thread.cc */ -notmuch_thread_t * -_notmuch_thread_create (void *ctx, - notmuch_database_t *notmuch, - unsigned int seed_doc_id, - notmuch_doc_id_set_t *match_set, - notmuch_sort_t sort); +/* Definition of _notmuch_thread_create moved later since now uses + * string_list_t */ /* message.cc */ @@ -492,6 +488,14 @@ notmuch_filenames_t * _notmuch_filenames_create (const void *ctx, notmuch_string_list_t *list); +notmuch_thread_t * +_notmuch_thread_create (void *ctx, + notmuch_database_t *notmuch, + unsigned int seed_doc_id, + notmuch_doc_id_set_t *match_set, + notmuch_string_list_t *excluded_terms, + notmuch_sort_t sort); + #pragma GCC visibility pop NOTMUCH_END_DECLS diff --git a/lib/query.cc b/lib/query.cc index 7d165d2..dee7ec0 100644 --- a/lib/query.cc +++ b/lib/query.cc @@ -472,6 +472,7 @@ notmuch_threads_get (notmuch_threads_t *threads) threads->query->notmuch, doc_id, >match_set, + threads->query->exclude_terms, threads->query->sort); } diff --git a/lib/thread.cc b/lib/thread.cc index 0435ee6..6d65d52 100644 --- a/lib/thread.cc +++ b/lib/thread.cc @@ -214,7 +214,8 @@ _thread_cleanup_author (notmuch_thread_t *thread, */ static void _thread_add_message (notmuch_thread_t *thread, -notmuch_message_t *message) +notmuch_message_t *message, +notmuch_string_list_t *exclude_terms) { notmuch_tags_t *tags; const char *tag; @@ -262,6 +263,15 @@ _thread_add_message (notmuch_thread_t *thread, notmuch_tags_move_to_next (tags)) { tag = notmuch_tags_get (tags); + /* mark excluded messages */ + for (notmuch_string_node_t *term = exclude_terms->head; term; +term = term->next) { + /* we ignore initial 'K' */ + if (strcmp(tag, (term->string + 1)) == 0) { + notmuch_message_set_flag (message, NOTMUCH_MESSAGE_FLAG_EXCLUDED, TRUE); + break; + } + } g_hash_table_insert (thread->tags, xstrdup (tag), NULL); } } @@ -321,7 +331,8 @@ _thread_add_matched_message (notmuch_thread_t *thread, _thread_set_subject_from_message (thread, message); } -thread->matched_messages++; +if (!notmuch_message_get_flag (message, NOTMUCH_MESSAGE_FLAG_EXCLUDED)) + thread->matched_messages++; if (g_hash_table_lookup_extended (thread->message_hash, notmuch_message_get_message_id (message), NULL, @@ -392,6 +403,7 @@ _notmuch_thread_create (void *ctx, notmuch_database_t *notmuch, unsigned int seed_doc_id, notmuch_doc_id_set_t *match_set, + notmuch_string_list_t *exclude_terms, notmuch_sort_t sort) { notmuch_thread_t *thread; @@ -467,7 +479,7 @@ _notmuch_thread_create (void *ctx, if (doc_id == seed_doc_id) message = seed_message; - _thread_add_message (thread, message); + _thread_add_message (thread, message, exclude_terms); if ( _notmuch_doc_id_set_contains (match_set, doc_id)) { _notmuch_doc_id_set_remove (match_set, doc_id); -- 1.7.2.3
[PATCH 2/7] lib: Rearrange the exclude code in query.cc
Slightly refactor the exclude code to give the callers access to the exclude query itself. There should be no functional change. --- lib/query.cc | 29 +++-- 1 files changed, 19 insertions(+), 10 deletions(-) diff --git a/lib/query.cc b/lib/query.cc index 0b36602..c25b301 100644 --- a/lib/query.cc +++ b/lib/query.cc @@ -122,12 +122,15 @@ _notmuch_messages_destructor (notmuch_mset_messages_t *messages) return 0; } -/* Return a query that does not match messages with the excluded tags - * registered with the query. Any tags that explicitly appear in - * xquery will not be excluded. */ +/* Return a query that matches messages with the excluded tags + * registered with query. Any tags that explicitly appear in xquery + * will not be excluded. The caller of this function has to combine + * the returned query appropriately.*/ static Xapian::Query _notmuch_exclude_tags (notmuch_query_t *query, Xapian::Query xquery) { +Xapian::Query exclude_query = Xapian::Query::MatchNothing; + for (notmuch_string_node_t *term = query->exclude_terms->head; term; term = term->next) { Xapian::TermIterator it = xquery.get_terms_begin (); @@ -137,10 +140,10 @@ _notmuch_exclude_tags (notmuch_query_t *query, Xapian::Query xquery) break; } if (it == end) - xquery = Xapian::Query (Xapian::Query::OP_AND_NOT, - xquery, Xapian::Query (term->string)); + exclude_query = Xapian::Query (Xapian::Query::OP_OR, + exclude_query, Xapian::Query (term->string)); } -return xquery; +return exclude_query; } notmuch_messages_t * @@ -168,7 +171,7 @@ notmuch_query_search_messages (notmuch_query_t *query) Xapian::Query mail_query (talloc_asprintf (query, "%s%s", _find_prefix ("type"), "mail")); - Xapian::Query string_query, final_query; + Xapian::Query string_query, final_query, exclude_query; Xapian::MSet mset; unsigned int flags = (Xapian::QueryParser::FLAG_BOOLEAN | Xapian::QueryParser::FLAG_PHRASE | @@ -188,7 +191,10 @@ notmuch_query_search_messages (notmuch_query_t *query) mail_query, string_query); } - final_query = _notmuch_exclude_tags (query, final_query); + exclude_query = _notmuch_exclude_tags (query, final_query); + + final_query = Xapian::Query (Xapian::Query::OP_AND_NOT, +final_query, exclude_query); enquire.set_weighting_scheme (Xapian::BoolWeight()); @@ -449,7 +455,7 @@ notmuch_query_count_messages (notmuch_query_t *query) Xapian::Query mail_query (talloc_asprintf (query, "%s%s", _find_prefix ("type"), "mail")); - Xapian::Query string_query, final_query; + Xapian::Query string_query, final_query, exclude_query; Xapian::MSet mset; unsigned int flags = (Xapian::QueryParser::FLAG_BOOLEAN | Xapian::QueryParser::FLAG_PHRASE | @@ -469,7 +475,10 @@ notmuch_query_count_messages (notmuch_query_t *query) mail_query, string_query); } - final_query = _notmuch_exclude_tags (query, final_query); + exclude_query = _notmuch_exclude_tags (query, final_query); + + final_query = Xapian::Query (Xapian::Query::OP_AND_NOT, +final_query, exclude_query); enquire.set_weighting_scheme(Xapian::BoolWeight()); enquire.set_docid_order(Xapian::Enquire::ASCENDING); -- 1.7.2.3
[PATCH 1/7] cli: add --do-not-exclude option to count and search.
This option turns off the exclusion so all matching messages are returned. We do not need to add this to show as notmuch-show does not (yet) exclude. --- notmuch-count.c | 12 notmuch-search.c | 12 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/notmuch-count.c b/notmuch-count.c index 63459fb..c88975e 100644 --- a/notmuch-count.c +++ b/notmuch-count.c @@ -37,6 +37,7 @@ notmuch_count_command (void *ctx, int argc, char *argv[]) int output = OUTPUT_MESSAGES; const char **search_exclude_tags; size_t search_exclude_tags_length; +notmuch_bool_t do_not_exclude = FALSE; unsigned int i; notmuch_opt_desc_t options[] = { @@ -44,6 +45,7 @@ notmuch_count_command (void *ctx, int argc, char *argv[]) (notmuch_keyword_t []){ { "threads", OUTPUT_THREADS }, { "messages", OUTPUT_MESSAGES }, { 0, 0 } } }, + { NOTMUCH_OPT_BOOLEAN, _not_exclude, "do-not-exclude", 'd', 0 }, { 0, 0, 0, 0, 0 } }; @@ -78,10 +80,12 @@ notmuch_count_command (void *ctx, int argc, char *argv[]) return 1; } -search_exclude_tags = notmuch_config_get_search_exclude_tags - (config, _exclude_tags_length); -for (i = 0; i < search_exclude_tags_length; i++) - notmuch_query_add_tag_exclude (query, search_exclude_tags[i]); +if (!do_not_exclude) { + search_exclude_tags = notmuch_config_get_search_exclude_tags + (config, _exclude_tags_length); + for (i = 0; i < search_exclude_tags_length; i++) + notmuch_query_add_tag_exclude (query, search_exclude_tags[i]); +} switch (output) { case OUTPUT_MESSAGES: diff --git a/notmuch-search.c b/notmuch-search.c index d504051..084dd05 100644 --- a/notmuch-search.c +++ b/notmuch-search.c @@ -425,6 +425,7 @@ notmuch_search_command (void *ctx, int argc, char *argv[]) int limit = -1; /* unlimited */ const char **search_exclude_tags; size_t search_exclude_tags_length; +notmuch_bool_t do_not_exclude = FALSE; unsigned int i; enum { NOTMUCH_FORMAT_JSON, NOTMUCH_FORMAT_TEXT } @@ -446,6 +447,7 @@ notmuch_search_command (void *ctx, int argc, char *argv[]) { "files", OUTPUT_FILES }, { "tags", OUTPUT_TAGS }, { 0, 0 } } }, +{ NOTMUCH_OPT_BOOLEAN, _not_exclude, "do-not-exclude", 'd', 0 }, { NOTMUCH_OPT_INT, , "offset", 'O', 0 }, { NOTMUCH_OPT_INT, , "limit", 'L', 0 }, { 0, 0, 0, 0, 0 } @@ -493,10 +495,12 @@ notmuch_search_command (void *ctx, int argc, char *argv[]) notmuch_query_set_sort (query, sort); -search_exclude_tags = notmuch_config_get_search_exclude_tags - (config, _exclude_tags_length); -for (i = 0; i < search_exclude_tags_length; i++) - notmuch_query_add_tag_exclude (query, search_exclude_tags[i]); +if (!do_not_exclude) { + search_exclude_tags = notmuch_config_get_search_exclude_tags + (config, _exclude_tags_length); + for (i = 0; i < search_exclude_tags_length; i++) + notmuch_query_add_tag_exclude (query, search_exclude_tags[i]); +} switch (output) { default: -- 1.7.2.3
[RFC PATCH 2/4] Add NOTMUCH_MESSAGE_FLAG_EXCLUDED flag
Ok I now have a patch set which might be complete enough to be worth reviewing. It is essentially complete and appears to work. Things that still need doing: updating the test suite. The series changes notmuch-show to output the exclude flag so several tests need updating. Of course, the new functionality needs some tests too. emacs/notmuch.el I think it would be nice to hide (make invisible) threads with no matching non-excluded messages (with a toggle for visibility) but that is definitely beyond my elisp skills. The first patch of the series is not really part of the series: it adds a --do-not-exclude option to tell the command not to exclude. I think this is useful anyway, but it also simplifies behaviour decisions with the excludes. For example notmuch count will only count matching non-excluded messages but notmuch count --do-not-exclude will count all matching messages excluded or not. One outstanding issue is that raised in id:"20120124025331.GZ16740 at mit.edu". I will need to think about that. Best wishes Mark
[PATCH 1/6] emacs: move tag format validation to `notmuch-tag' function
Quoth Dmitry Kurochkin on Jan 30 at 2:54 am: > Hi Austin. > > On Sun, 29 Jan 2012 16:34:27 -0500, Austin Clements > wrote: > > One philosophical nit below, but not enough to hold this up. > > > > Quoth Dmitry Kurochkin on Jan 28 at 8:41 am: > > > Before the change, tag format validation was done in > > > `notmuch-search-operate-all' function only. The patch moves it down > > > to `notmuch-tag', so that all users of that function get input > > > validation. > > > --- > > > emacs/notmuch.el | 12 ++-- > > > 1 files changed, 6 insertions(+), 6 deletions(-) > > > > > > diff --git a/emacs/notmuch.el b/emacs/notmuch.el > > > index 72f78ed..84d7d0a 100644 > > > --- a/emacs/notmuch.el > > > +++ b/emacs/notmuch.el > > > @@ -522,6 +522,12 @@ Note: Other code should always use this function > > > alter tags of > > > messages instead of running (notmuch-call-notmuch-process \"tag\" ..) > > > directly, so that hooks specified in notmuch-before-tag-hook and > > > notmuch-after-tag-hook will be run." > > > + ;; Perform some validation > > > + (when (null tags) (error "No tags given")) > > > > Since this is a non-interactive function and hence is meant to be > > invoked programmatically, I would expect it to accept zero tags. > > Unlike the following check, this is a UI-level check and thus, I > > believe, belongs in interactive functions (even if that requires a > > little duplication). > > > > Agreed. Though I would hate to add the same check to each tag > operation. Perhaps this check can go to > `notmuch-select-tags-with-completion'? > > This is not the main patch in the series. So I think I would prefer not > to make v2 because of this issue. If we come up with a good (i.e. no > duplication) solution, I will prepare a separate patch for it. What about not giving any error for no tags? As a user, if I delete the whole tags prompt including the +/- operator, that's a very explicit action and it's very clear what it should do (nothing). I don't need Emacs wagging its finger at me for doing something with a clear meaning.
[PATCH 8/6] emacs: use message ids instead of thread id in `notmuch-show-operate-all'
Eighth in the increasingly inaccurately named six patch series... Quoth Dmitry Kurochkin on Jan 28 at 9:59 am: > Before the change, `notmuch-show-operate-all' used thread id for > "notmuch tag" search. This could result in tagging unexpected > messages that were added to the thread after the notmuch-show buffer > was created. The patch changes `notmuch-show-operate-all' to use ids > of shown messages to fix this. Are you planning to roll this into your earlier patch? > --- > emacs/notmuch-show.el | 23 ++- > 1 files changed, 22 insertions(+), 1 deletions(-) > > diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el > index 2ca4d92..e606224 100644 > --- a/emacs/notmuch-show.el > +++ b/emacs/notmuch-show.el > @@ -1170,6 +1170,15 @@ All currently available key bindings: > (notmuch-show-move-to-message-top) > t)) > > +(defun notmuch-show-mapc (function) > + "Iterate through all messages with > +`notmuch-show-goto-message-next' and call `function' for side > +effects." `function' should be FUNCTION. > + (save-excursion > +(goto-char (point-min)) > +(loop do (funcall function) > + while (notmuch-show-goto-message-next > + > ;; Functions relating to the visibility of messages and their > ;; components. > > @@ -1222,6 +1231,18 @@ Some useful entries are: >"Return the message id of the current message." >(concat "id:\"" (notmuch-show-get-prop :id) "\"")) > > +(defun notmuch-show-get-messages-ids () > + "Return all message ids of currently shown messages." "currently shown" could mean visible on the screen, which is not what you mean. You also don't mean "open messages". Maybe "Return all message ids of messages in this show buffer"? > + (let ((message-ids)) > +(notmuch-show-mapc > + (lambda () (push (notmuch-show-get-message-id) message-ids))) > +message-ids)) > + > +(defun notmuch-show-get-messages-ids-search () > + "Return a search string for all message ids of currently shown > +messages." Same. > + (mapconcat 'identity (notmuch-show-get-messages-ids) " or ")) > + > ;; dme: Would it make sense to use a macro for many of these? > > (defun notmuch-show-get-filename () > @@ -1496,7 +1517,7 @@ i.e. a list of tags to change with '+' and '-' > prefixes." > `Changed-tags' is a list of tag operations for \"notmuch tag\", > i.e. a list of tags to change with '+' and '-' prefixes." >(interactive (notmuch-select-tags-with-completion nil > notmuch-show-thread-id)) > - (apply 'notmuch-tag notmuch-show-thread-id changed-tags) > + (apply 'notmuch-tag (notmuch-show-get-messages-ids-search) changed-tags) >(save-excursion > (goto-char (point-min)) > (loop do (let* ((current-tags (notmuch-show-get-tags))
[PATCH 3/3] NEWS: add entry for the improved unicode handling in the python bindings
Signed-off-by: Justus Winter <4winter at informatik.uni-hamburg.de> --- NEWS |6 ++ 1 files changed, 6 insertions(+), 0 deletions(-) diff --git a/NEWS b/NEWS index 71644ff..132efe8 100644 --- a/NEWS +++ b/NEWS @@ -61,6 +61,12 @@ Python 3.2 compatibility The python bindings are now compatible with both python 2.x and 3.2. +Added missing unicode conversions + + Python strings have to be encoded to and decoded from utf-8 when + calling libnotmuch functions. Porting the bindings to python 3.2 + revealed a few function calls that were missing these conversions. + Build fixes --- -- 1.7.8.3
[PATCH 2/3] NEWS: add entry for python 3.2 compatibility
Signed-off-by: Justus Winter <4winter at informatik.uni-hamburg.de> --- NEWS |4 1 files changed, 4 insertions(+), 0 deletions(-) diff --git a/NEWS b/NEWS index bee6f2e..71644ff 100644 --- a/NEWS +++ b/NEWS @@ -57,6 +57,10 @@ Fix error handling in python bindings. exceptions to indicate the error condition. Any subsequent calls into libnotmuch caused segmentation faults. +Python 3.2 compatibility + + The python bindings are now compatible with both python 2.x and 3.2. + Build fixes --- -- 1.7.8.3
[PATCH 1/3] NEWS: add entry for python error handling fix
Signed-off-by: Justus Winter <4winter at informatik.uni-hamburg.de> --- NEWS | 10 ++ 1 files changed, 10 insertions(+), 0 deletions(-) diff --git a/NEWS b/NEWS index 2acdce5..bee6f2e 100644 --- a/NEWS +++ b/NEWS @@ -47,6 +47,16 @@ New functions notmuch_query_add_tag_exclude supports the new tag exclusion feature. +Python bindings changes +--- + +Fix error handling in python bindings. + + The python bindings in 0.11 failed to detect NULL pointers being + returned from libnotmuch functions and thus failed to raise + exceptions to indicate the error condition. Any subsequent calls + into libnotmuch caused segmentation faults. + Build fixes --- -- 1.7.8.3
NEWS: add entries for the changes in the python bindings
This patch series adds a section for the python binding changes to the NEWS file. Cheers, Justus
[PATCH 6/6] emacs: separate history for operations which accept single and multiple tags
Quoth Dmitry Kurochkin on Jan 28 at 8:41 am: > Some tag-related operations accept a single tag without prefix > (`notmuch-select-tag-with-completion'), others accept multiple tags > prefixed with '+' or '-' (`notmuch-select-tags-with-completion'). > Before the change, both functions used a single default minibuffer > history. This is inconvenient because you have to skip options with > incompatible format when going through the history. The patch adds > separate history lists for the two functions. Note that functions > that accept the same input format (e.g. "+", "-", "*") share the > history list as before. > --- > emacs/notmuch.el | 12 ++-- > 1 files changed, 10 insertions(+), 2 deletions(-) > > diff --git a/emacs/notmuch.el b/emacs/notmuch.el > index 24b0ea3..9813e0a 100644 > --- a/emacs/notmuch.el > +++ b/emacs/notmuch.el > @@ -76,6 +76,14 @@ For example: > (defvar notmuch-query-history nil >"Variable to store minibuffer history for notmuch queries") > > +(defvar notmuch-select-tag-history nil > + "Variable to store notmuch tag history for > + `notmuch-select-tag-with-completion'.") > + > +(defvar notmuch-select-tags-history nil > + "Variable to store notmuch tags history for > + `notmuch-select-tags-with-completion'.") > + Really these are minibuffer or input histories, not "notmuch tag history". Also, the second line shouldn't be indented. (Definitely nits, but if you roll a new version, you might as well fix these.) > (defun notmuch-tag-completions ( search-terms) >(split-string > (with-output-to-string > @@ -86,7 +94,7 @@ For example: > > (defun notmuch-select-tag-with-completion (prompt search-terms) >(let ((tag-list (notmuch-tag-completions search-terms))) > -(completing-read prompt tag-list))) > +(completing-read prompt tag-list nil nil nil > 'notmuch-select-tag-history))) > > (defun notmuch-select-tags-with-completion ( initial-input > search-terms) >(let* ((add-tag-list (mapcar (apply-partially 'concat "+") > @@ -105,7 +113,7 @@ For example: > map))) > (delete "" (completing-read-multiple > "Operations (+add -drop): notmuch tag " tag-list nil > - nil initial-input > + nil initial-input 'notmuch-select-tags-history > > (defun notmuch-update-tags (current-tags changed-tags) >"Update `current-tags' with `changed-tags' and return the result.
error handling and stderr
Hi notmuch developers, currently there is no way to determine why opening a database using notmuch_database_open fails. I suppose that this is a problem for all functions returning a pointer, but it is especially problematic for this function since one cannot distinguish between a temporary failure (someone else opened the db read/write) and a configuration problem (wrong path). This is a real problem for providing sensible feedback to the user. And writing an error message to stderr is a sensible thing to do if it is done in a command line utility but doing so within a library is a severe problem for any curses frontends and is generally considered a bad practice. For the record, libabcs README[0] agrees with me on both aspects. Since fixing this means breaking the api we need to discuss this thoroughly and identify all the functions involved. Users of the python bindings won't be affected by an api change like this since we're converting any error code to exceptions anyway. Cheers, Justus 0: https://git.kernel.org/?p=linux/kernel/git/kay/libabc.git;a=blob_plain;f=README
[PATCH 4/6] test: fix emacs tests after tagging operations changes
Quoth Dmitry Kurochkin on Jan 28 at 8:41 am: > After the recent tagging operations changes, functions bound to "+" > and "-" in notmuch-search and notmuch-show views always read input > from the minibuffer. Use kbd macros instead of calling them directly. Should this be folded into the previous patch so these tests aren't temporarily broken?
[PATCH 3/6] emacs: make "+" and "-" tagging operations more robust
I'm looking forward to having this. I think it'll streamline tagging operations. Quoth Dmitry Kurochkin on Jan 28 at 8:41 am: > Before the change, "+" and "-" tagging operations in notmuch-search > and notmuch-show views accepted only a single tag. The patch makes > them use the recently added `notmuch-select-tags-with-completion' > function, which allows to enter multiple tags with "+" and "-" > prefixes. So after the change, "+" and "-" bindings allow to both add > and remove multiple tags. The only difference between "+" and "-" is > the minibuffer initial input ("+" and "-" respectively). This patch was a little difficult to review because it was largish and the diff happened to contain a bunch of forward references. If it's convenient (don't bother if it's not), could you divide up the next version a little? Something simple like sending the show changes as a separate patch would probably make it a lot easier. > --- > emacs/notmuch-show.el | 65 +++ > emacs/notmuch.el | 165 > + > 2 files changed, 107 insertions(+), 123 deletions(-) > > diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el > index 84ac624..03eadfb 100644 > --- a/emacs/notmuch-show.el > +++ b/emacs/notmuch-show.el > @@ -38,8 +38,9 @@ > > (declare-function notmuch-call-notmuch-process "notmuch" ( args)) > (declare-function notmuch-fontify-headers "notmuch" nil) > -(declare-function notmuch-select-tag-with-completion "notmuch" (prompt > search-terms)) > +(declare-function notmuch-select-tags-with-completion "notmuch" ( > initial-input search-terms)) > (declare-function notmuch-search-show-thread "notmuch" nil) > +(declare-function notmuch-update-tags "notmuch" (current-tags changed-tags)) > > (defcustom notmuch-message-headers '("Subject" "To" "Cc" "Date") >"Headers that should be shown in a message, in this order. > @@ -1267,7 +1268,7 @@ Some useful entries are: > > (defun notmuch-show-mark-read () >"Mark the current message as read." > - (notmuch-show-remove-tag "unread")) > + (notmuch-show-tag-message "-unread")) > > ;; Functions for getting attributes of several messages in the current > ;; thread. > @@ -1470,51 +1471,33 @@ than only the current message." > (message (format "Command '%s' exited abnormally with code %d" >shell-command exit-code > > -(defun notmuch-show-add-tags-worker (current-tags add-tags) > - "Add to `current-tags' with any tags from `add-tags' not > -currently present and return the result." > - (let ((result-tags (copy-sequence current-tags))) > -(mapc (lambda (add-tag) > - (unless (member add-tag current-tags) > - (setq result-tags (push add-tag result-tags > - add-tags) > -(sort result-tags 'string<))) > - > -(defun notmuch-show-del-tags-worker (current-tags del-tags) > - "Remove any tags in `del-tags' from `current-tags' and return > -the result." > - (let ((result-tags (copy-sequence current-tags))) > -(mapc (lambda (del-tag) > - (setq result-tags (delete del-tag result-tags))) > - del-tags) > -result-tags)) > - > -(defun notmuch-show-add-tag ( toadd) > - "Add a tag to the current message." > - (interactive > - (list (notmuch-select-tag-with-completion "Tag to add: "))) > +(defun notmuch-show-tag-message ( changed-tags) > + "Change tags for the current message. > > +`Changed-tags' is a list of tag operations for \"notmuch tag\", > +i.e. a list of tags to change with '+' and '-' prefixes." Ticks in a docstring indicate functions (and will be hyperlinked as such by describe-function). Typically, argument names are indicated by writing them in all caps. Also, it probably makes more sense to reference `notmuch-tag' than "notmuch tag", since this is Lisp land (and, since that will be helpfully hyperlinked, you probably don't need to explain changed-tags here). >(let* ((current-tags (notmuch-show-get-tags)) > - (new-tags (notmuch-show-add-tags-worker current-tags toadd))) > - > + (new-tags (notmuch-update-tags current-tags changed-tags))) > (unless (equal current-tags new-tags) > - (apply 'notmuch-tag (notmuch-show-get-message-id) > - (mapcar (lambda (s) (concat "+" s)) toadd)) > + (apply 'notmuch-tag (notmuch-show-get-message-id) changed-tags) >(notmuch-show-set-tags new-tags > > -(defun notmuch-show-remove-tag ( toremove) > - "Remove a tag from the current message." > - (interactive > - (list (notmuch-select-tag-with-completion > - "Tag to remove: " (notmuch-show-get-message-id > +(defun notmuch-show-tag ( initial-input) > + "Change tags for the current message, read input from the minibuffer." > + (interactive) > + (let ((changed-tags (notmuch-select-tags-with-completion > +initial-input (notmuch-show-get-message-id > +(apply 'notmuch-show-tag-message changed-tags))) > > -
bugfix release (was: heads up from the python front)
Hey David, Quoting David Bremner (2012-01-22 13:30:35) >On Sun, 22 Jan 2012 06:01:41 -, Justus Winter <4winter at >informatik.uni-hamburg.de> wrote: >> >> I feel kind of bad since I severely broke the error handling for all >> pythonic notmuch users out there, is there any chance of a bugfix >> release? The patch[3] is really simple and I'd say it's trivial to >> backport it to the last release. What do you think? >> > >I'm not opposed in principle; I tentatively plan on a bugfix release for >Aaron's mml quoting patch, so we can have the two fixes in one release. What about that bugfix release? Cheers, Justus
[PATCH 1/6] emacs: move tag format validation to `notmuch-tag' function
One philosophical nit below, but not enough to hold this up. Quoth Dmitry Kurochkin on Jan 28 at 8:41 am: > Before the change, tag format validation was done in > `notmuch-search-operate-all' function only. The patch moves it down > to `notmuch-tag', so that all users of that function get input > validation. > --- > emacs/notmuch.el | 12 ++-- > 1 files changed, 6 insertions(+), 6 deletions(-) > > diff --git a/emacs/notmuch.el b/emacs/notmuch.el > index 72f78ed..84d7d0a 100644 > --- a/emacs/notmuch.el > +++ b/emacs/notmuch.el > @@ -522,6 +522,12 @@ Note: Other code should always use this function alter > tags of > messages instead of running (notmuch-call-notmuch-process \"tag\" ..) > directly, so that hooks specified in notmuch-before-tag-hook and > notmuch-after-tag-hook will be run." > + ;; Perform some validation > + (when (null tags) (error "No tags given")) Since this is a non-interactive function and hence is meant to be invoked programmatically, I would expect it to accept zero tags. Unlike the following check, this is a UI-level check and thus, I believe, belongs in interactive functions (even if that requires a little duplication). > + (mapc (lambda (tag) > + (unless (string-match-p "^[-+][-+_.[:word:]]+$" tag) > + (error "Tag must be of the form `+this_tag' or `-that_tag'"))) > + tags) >(run-hooks 'notmuch-before-tag-hook) >(apply 'notmuch-call-notmuch-process >(append (list "tag") tags (list "--" query))) > @@ -890,12 +896,6 @@ characters as well as `_.+-'. >(interactive (notmuch-select-tags-with-completion > "Operations (+add -drop): notmuch tag " > '("+" "-"))) > - ;; Perform some validation > - (when (null actions) (error "No operations given")) > - (mapc (lambda (action) > - (unless (string-match-p "^[-+][-+_.[:word:]]+$" action) > - (error "Action must be of the form `+this_tag' or `-that_tag'"))) > - actions) >(apply 'notmuch-tag notmuch-search-query-string actions)) > > (defun notmuch-search-buffer-title (query)
[PATCH 0/3] reworked crypto toggle, plus a couple of other toggles
On Wed, 25 Jan 2012 10:18:46 +, David Edmondson wrote: > The crypto toggle previously worked using an argument to > `notmuch-show' and various other functions and relied on killing and > re-creating the notmuch-show-mode buffer. Various other > pseudo-buffer-local variables were present based on an ad-hoc scheme. > > Replace the ad-hoc scheme with real buffer-local variables and then > update `notmuch-show-refresh-view' to erase and re-paint rather than > kill and re-create. Update the crypto switch accordingly. Hey, David. Thank you so much for this! I was really hoping someone would eventually pick this up, and your solution is great! This new behavior is *much* nicer. I really like it. I haven't done a full code review, though, just tested it out. I may not be able to get to it for a while, so please don't hold this patch up on my account). > Add two other toggles: > - whether non-matching messages are available, > - the indentation of message contents. > Both of these default to the current behaviour. These new features enabled by this are very cool! I love them both. I bet there are other interesting toggle features that could be enabled by this. > My inclination is to remove `notmuch-crypto-process-mime' altogether > (declared it an obsolete variable) and allow users to set a default > for `notmuch-show-process-crypto' directly, but that is not done in > this patchset while awaiting feedback. I'm not sure I understand this. `notmuch-show-process-crypto' *is* what sets the default for the `notmuch-show-process-crypto' buffer-local variable. How would you change the current behavior or settings (beyond just a variable rename)? > `notmuch-crypto-process-mime' is used only in notmuch-show.el, so the > setting really belongs there with an appropriate name. I intentionally put this in a separate section in case there were eventually other needs for this setting beyond just show mode. I personally think we should just leave it where it is, particularly since it's been there for a while. jamie. -- next part -- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 835 bytes Desc: not available URL: <http://notmuchmail.org/pipermail/notmuch/attachments/20120129/e55fff04/attachment.pgp>
[PATCH 1/2] test: emacs mailto: URI handling
This adds a test for proposed rfc6068 "mailto:; URI handling. The proposed function would be called 'notmuch-mua-mailto'. The test provides an example mailto: string that should test some subset of the rfc6068 specification: http://tools.ietf.org/html/rfc6068 --- test/emacs | 29 + 1 files changed, 29 insertions(+), 0 deletions(-) diff --git a/test/emacs b/test/emacs index 8ca4c8a..c6afa14 100755 --- a/test/emacs +++ b/test/emacs @@ -273,6 +273,35 @@ On 01 Jan 2000 12:00:00 -, Notmuch Test Suite w EOF test_expect_equal_file OUTPUT EXPECTED +test_begin_subtest "Compose to \"mailto:\; URI" +test_subtest_known_broken +# This *should* test the ability to parse rfc6068 "mailto:; URIs: +# http://tools.ietf.org/html/rfc6068 +# this test is based on: +# http://shadow2531.com/opera/testcases/mailto/rfc2368-0.html +# which is itself based on the precursor rfc2368, so it could probably +# be updated. +test_emacs "(let ((mailto \"mailto:to1%40example.net%2C%20to2%40example.net?to=to3%40example.net%2C%20to4%40example.netsubject=last%20call%20for%20cats%20%26%20dogs%2Esubject=You%20should%20not%20see%20me%2Ebody=line1%0D%0Aline2body=line3body=line4%0D%0AColumn1A%09Column1B%09Column1C%09Column1D%0D%0A%E2%88%9Acc=cc1%40example.net%2C%20cc2%40example.netto=to5%40example.net%2C%20to6%40example.netfoo=IGNOREbcc=bcc1%40example.net%2C%20bcc2%40example.netbcc=bcc3%40example.net%2C%20bcc4%40example.netin-reply-to=\") + (notmuch-fcc-dirs nil)) + (notmuch-mua-mailto mailto) + (test-output))" +cat
[RFC PATCH 2/4] Add NOTMUCH_MESSAGE_FLAG_EXCLUDED flag
> The cli stuff needs thought (about what it should do rather than > how to do it). Ok I have thought about the cli interface. My thoughts are as follows: count/search/show should all have a --do-not-exclude option. notmuch count: messages: just output count of matching not-excluded threads: count threads matching in a non-excluded message notmuch search: default/summary should output line as in the current patch with number matching being number non-excluded matching (so some will be zero) messages/files/tags should be matching not-excluded threads: show thread ids of messages matching in a non-excluded message notmuch show: raw and part both deal with a single message so should output it regardless of exclude flags. text/json can give out the results including the exclude flag mbox only include matching not-excluded The rationale is that all formats which can return an exclude flag do; those that cannot omit the excluded results since the caller can just call without setting the excludes if they want the full results. Does that seem reasonable? Best wishes Mark
[PATCH] lib: update notmuch_tags_get examle to reflect api change
The function notmuch_database_find_message_by_filename now requires a notmuch_message_t and returns a notmuch_status_t. This change was introduced with 02a3076711, LIBNOTMUCH_VERSION_MAJOR = 2, version 0.9. --- lib/notmuch.h | 21 +++-- 1 files changed, 11 insertions(+), 10 deletions(-) diff --git a/lib/notmuch.h b/lib/notmuch.h index 7929fe7..5e6e449 100644 --- a/lib/notmuch.h +++ b/lib/notmuch.h @@ -941,21 +941,22 @@ notmuch_message_get_header (notmuch_message_t *message, const char *header); * Typical usage might be: * * notmuch_message_t *message; + * notmuch_status_t status; * notmuch_tags_t *tags; * const char *tag; * - * message = notmuch_database_find_message (database, message_id); - * - * for (tags = notmuch_message_get_tags (message); - * notmuch_tags_valid (tags); - * notmuch_result_move_to_next (tags)) - * { - * tag = notmuch_tags_get (tags); - * + * status = notmuch_database_find_message (database, message_id, ); + * if(!status && message) { + * for (tags = notmuch_message_get_tags (message); + * notmuch_tags_valid (tags); + * notmuch_result_move_to_next (tags)) + * { + * tag = notmuch_tags_get (tags); + * + * } + * notmuch_message_destroy (message); * } * - * notmuch_message_destroy (message); - * * Note that there's no explicit destructor needed for the * notmuch_tags_t object. (For consistency, we do provide a * notmuch_tags_destroy function, but there's no good reason to call -- 1.7.2.5
[PATCH] lib: notmuch_tags_get example was not updated to reflect api change
The subject should be about what this patch does, like "lib: update notmuch_tags_get example to reflect api change" On Jan 29, 2012 12:46 AM, "Allan Wind" wrote: > And preferably you would describe here what the api change was. > --- > lib/notmuch.h | 21 +++-- > 1 files changed, 11 insertions(+), 10 deletions(-) > > diff --git a/lib/notmuch.h b/lib/notmuch.h > index 7929fe7..5e6e449 100644 > --- a/lib/notmuch.h > +++ b/lib/notmuch.h > @@ -941,21 +941,22 @@ notmuch_message_get_header (notmuch_message_t *message, const char *header); > * Typical usage might be: > * > * notmuch_message_t *message; > + * notmuch_status_t status; > * notmuch_tags_t *tags; > * const char *tag; > * > - * message = notmuch_database_find_message (database, message_id); > - * > - * for (tags = notmuch_message_get_tags (message); > - * notmuch_tags_valid (tags); > - * notmuch_result_move_to_next (tags)) > - * { > - * tag = notmuch_tags_get (tags); > - * > + * status = notmuch_database_find_message (database, message_id, ); > + * if(!status && message) { > + * for (tags = notmuch_message_get_tags (message); > + * notmuch_tags_valid (tags); > + * notmuch_result_move_to_next (tags)) > + * { > + * tag = notmuch_tags_get (tags); > + * > + * } > + * notmuch_message_destroy (message); > * } > * > - * notmuch_message_destroy (message); > - * > * Note that there's no explicit destructor needed for the > * notmuch_tags_t object. (For consistency, we do provide a > * notmuch_tags_destroy function, but there's no good reason to call > -- > 1.7.2.5 > > ___ > notmuch mailing list > notmuch at notmuchmail.org > http://notmuchmail.org/mailman/listinfo/notmuch -- next part -- An HTML attachment was scrubbed... URL: <http://notmuchmail.org/pipermail/notmuch/attachments/20120129/efaed20e/attachment.html>
[PATCH 2/2] test: remove explicit loading of elisp tests in emacs-address-cleaning
It is no longer needed, since elisp tests files are auto loaded now. --- test/emacs-address-cleaning |9 +++-- 1 files changed, 3 insertions(+), 6 deletions(-) diff --git a/test/emacs-address-cleaning b/test/emacs-address-cleaning index 51018fe..6ddde5c 100755 --- a/test/emacs-address-cleaning +++ b/test/emacs-address-cleaning @@ -4,15 +4,12 @@ test_description="emacs address cleaning" . test-lib.sh test_begin_subtest "notmuch-test-address-clean part 1" -test_emacs_expect_t \ -'(load "emacs-address-cleaning.el") (notmuch-test-address-cleaning-1)' +test_emacs_expect_t '(notmuch-test-address-cleaning-1)' test_begin_subtest "notmuch-test-address-clean part 2" -test_emacs_expect_t \ -'(load "emacs-address-cleaning.el") (notmuch-test-address-cleaning-2)' +test_emacs_expect_t '(notmuch-test-address-cleaning-2)' test_begin_subtest "notmuch-test-address-clean part 3" -test_emacs_expect_t \ -'(load "emacs-address-cleaning.el") (notmuch-test-address-cleaning-3)' +test_emacs_expect_t '(notmuch-test-address-cleaning-3)' test_done -- 1.7.8.3
[PATCH 1/2] test: auto load elisp tests file in test_emacs if available
This allows us to simplify shell part of tests written in elisp. --- test/test-lib.sh |7 +++ 1 files changed, 7 insertions(+), 0 deletions(-) diff --git a/test/test-lib.sh b/test/test-lib.sh index 8158328..0174e93 100644 --- a/test/test-lib.sh +++ b/test/test-lib.sh @@ -943,6 +943,12 @@ test_emacs () { test -z "$missing_dependencies" || return if [ -z "$EMACS_SERVER" ]; then + emacs_tests="$(basename $0).el" + if [ -f "$TEST_DIRECTORY/$emacs_tests" ]; then + load_emacs_tests="--eval '(load \"$emacs_tests\")'" + else + load_emacs_tests= + fi server_name="notmuch-test-suite-$$" # start a detached session with an emacs server # user's TERM is given to dtach which assumes a minimally @@ -950,6 +956,7 @@ test_emacs () { TERM=$ORIGINAL_TERM dtach -n "$TEST_TMPDIR/emacs-dtach-socket.$$" \ sh -c "stty rows 24 cols 80; exec '$TMP_DIRECTORY/run_emacs' \ --no-window-system \ + $load_emacs_tests \ --eval '(setq server-name \"$server_name\")' \ --eval '(server-start)' \ --eval '(orphan-watchdog $$)'" || return -- 1.7.8.3
[PATCH v7 2/2] emacs: Tests for user-defined sections
Hi Daniel. On Sat, 28 Jan 2012 22:30:57 +0100, Daniel Schoepe wrote: > Hi Dmitry, > > On Tue, 24 Jan 2012 03:07, Dmitry Kurochkin > wrote: > > There are some trailing whitespaces in the tests. > > those are also produced by the various notmuch-hello functions, and are > also in the existing tests. If someone is bothered by this, it should be > fixed in a separate patch. > I only meant trailing whitespaces in test/emacs file in the lines added by the patch. Trailing whitespaces in expected results are obviously fine. > > > > Also, please consider moving the hello sections tests to a separate file > > (emacs-hello-sections, perhaps?). I am worried that test/emacs file > > becomes too big. And we will probably add more notmuch-hello > > section-related tests in the future. > > I think it's better to split it up into more than just > emacs-hello-sections and emacs, as there are also quite a few tests > relating solely to, e.g., -show or -search. > I think splitting emacs tests based on -hello, -show and -search views is a good idea. Splitting existing tests is out of scope of this patch. But I think it may be a good opportunity to add a new file with -hello tests. > Anyhow, I'll send another rebased version fixing conflicts with the > search-interface changes. > Thanks, I will try to review it soon. Regards, Dmitry > Cheers, > Daniel
[PATCH 2/2] emacs: Quote MML tags in replies
Emacs message-mode uses certain text strings to indicate how to attach files to outgoing mail. If these are present in the text of an email, and a user is tricked into replying to the message, the user?s files could be exposed. --- NEWS | 18 ++ emacs/notmuch-mua.el |3 ++- test/emacs |1 - 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index 2acdce5..c8b90c7 100644 --- a/NEWS +++ b/NEWS @@ -56,6 +56,24 @@ Compatibility with GMime 2.6 However, a bug in current GMime 2.6 causes notmuch not to report signatures where the signer key is unavailable (GNOME bug 668085). +Notmuch 0.11.1 (2012-xx-xx) +=== + +Emacs Interface +--- + +Quote MML tags in replies + + MML tags are text codes that Emacs uses to indicate attachments + (among other things) in messages being composed. The Emacs + interface did not quote MML tags in the quoted text of a reply. If + a user could be tricked into replying to a maliciously formatted + message and not editing out the MML tags from the quoted text, this + could lead to files from the user's machine being attached to the + outgoing message. The Emacs interface now quotes these tags in + reply text, so that they cannot have an effect on the outgoing + message. + Notmuch 0.11 (2012-01-13) = diff --git a/emacs/notmuch-mua.el b/emacs/notmuch-mua.el index 023645e..32c376d 100644 --- a/emacs/notmuch-mua.el +++ b/emacs/notmuch-mua.el @@ -116,7 +116,8 @@ list." (push-mark)) (set-buffer-modified-p nil) - (message-goto-body)) + (message-goto-body) + (mml-quote-region (point) (mark))) (defun notmuch-mua-forward-message () (message-forward) diff --git a/test/emacs b/test/emacs index a57513a..affcca4 100755 --- a/test/emacs +++ b/test/emacs @@ -274,7 +274,6 @@ EOF test_expect_equal_file OUTPUT EXPECTED test_begin_subtest "Quote MML tags on reply" -test_subtest_known_broken add_message '[from]="1337 h4xor "' \ '[to]="Unsuspecting rube "' \ '[subject]="hackety hack hack"' \ -- 1.7.9
[PATCH 3/3] lib: Use talloc to simplify cleanup in notmuch_database_open
Previously, we manually "free"d various pointers in notmuch_database_open. Use a local talloc context instead to simplify cleanup and eliminate various NULL pointer initializations and conditionals. --- lib/database.cc | 14 +- 1 files changed, 5 insertions(+), 9 deletions(-) diff --git a/lib/database.cc b/lib/database.cc index 94022d7..c928d02 100644 --- a/lib/database.cc +++ b/lib/database.cc @@ -582,15 +582,15 @@ notmuch_database_t * notmuch_database_open (const char *path, notmuch_database_mode_t mode) { +void *local = talloc_new (NULL); notmuch_database_t *notmuch = NULL; -char *notmuch_path = NULL, *xapian_path = NULL; +char *notmuch_path, *xapian_path; struct stat st; int err; unsigned int i, version; static int initialized = 0; -if (asprintf (_path, "%s/%s", path, ".notmuch") == -1) { - notmuch_path = NULL; +if (! (notmuch_path = talloc_asprintf (local, "%s/%s", path, ".notmuch"))) { fprintf (stderr, "Out of memory\n"); goto DONE; } @@ -602,8 +602,7 @@ notmuch_database_open (const char *path, goto DONE; } -if (asprintf (_path, "%s/%s", notmuch_path, "xapian") == -1) { - xapian_path = NULL; +if (! (xapian_path = talloc_asprintf (local, "%s/%s", notmuch_path, "xapian"))) { fprintf (stderr, "Out of memory\n"); goto DONE; } @@ -708,10 +707,7 @@ notmuch_database_open (const char *path, } DONE: -if (notmuch_path) - free (notmuch_path); -if (xapian_path) - free (xapian_path); +talloc_free (local); return notmuch; } -- 1.7.7.3
[PATCH 2/3] lib: Release resources if notmuch_database_open fails
Previously, if a Xapian exception occurred in notmuch_database_open, we failed to clean up the allocated notmuch_database_t object. --- lib/database.cc |1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/lib/database.cc b/lib/database.cc index a6d15a1..94022d7 100644 --- a/lib/database.cc +++ b/lib/database.cc @@ -703,6 +703,7 @@ notmuch_database_open (const char *path, } catch (const Xapian::Error ) { fprintf (stderr, "A Xapian exception occurred opening database: %s\n", error.get_msg().c_str()); + notmuch_database_close (notmuch); notmuch = NULL; } -- 1.7.7.3
[PATCH 1/3] lib: Don't delete uninitialized pointers
In the error-handling paths of notmuch_database_open, we call notmuch_database_close, which "delete"s several objects referenced by the notmuch_database_t object. However, some of these pointers may be uninitialized, resulting in undefined behavior. Hence, allocate the notmuch_database_t with talloc_zero to make sure these pointers are NULL so that "delete"ing them is harmless. --- lib/database.cc |2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/lib/database.cc b/lib/database.cc index 8103bd9..a6d15a1 100644 --- a/lib/database.cc +++ b/lib/database.cc @@ -617,7 +617,7 @@ notmuch_database_open (const char *path, initialized = 1; } -notmuch = talloc (NULL, notmuch_database_t); +notmuch = talloc_zero (NULL, notmuch_database_t); notmuch->exception_reported = FALSE; notmuch->path = talloc_strdup (notmuch, path); -- 1.7.7.3
[PATCH 4/4] Add exclude flag
Make notmuch-show.c respect the EXCLUDE flag. --- notmuch-show.c | 20 +--- 1 files changed, 17 insertions(+), 3 deletions(-) diff --git a/notmuch-show.c b/notmuch-show.c index dec799c..b55d2ba 100644 --- a/notmuch-show.c +++ b/notmuch-show.c @@ -193,10 +193,12 @@ _get_one_line_summary (const void *ctx, notmuch_message_t *message) static void format_message_text (unused (const void *ctx), notmuch_message_t *message, int indent) { -printf ("id:%s depth:%d match:%d filename:%s\n", +/* Could changing this could break users ? */ +printf ("id:%s depth:%d match:%d excluded:%d filename:%s\n", notmuch_message_get_message_id (message), indent, notmuch_message_get_flag (message, NOTMUCH_MESSAGE_FLAG_MATCH), + notmuch_message_get_flag (message, NOTMUCH_MESSAGE_FLAG_EXCLUDED), notmuch_message_get_filename (message)); } @@ -212,9 +214,10 @@ format_message_json (const void *ctx, notmuch_message_t *message, unused (int in date = notmuch_message_get_date (message); relative_date = notmuch_time_relative_date (ctx, date); -printf ("\"id\": %s, \"match\": %s, \"filename\": %s, \"timestamp\": %ld, \"date_relative\": \"%s\", \"tags\": [", +printf ("\"id\": %s, \"match\": %s, \"excluded\": %s, \"filename\": %s, \"timestamp\": %ld, \"date_relative\": \"%s\", \"tags\": [", json_quote_str (ctx_quote, notmuch_message_get_message_id (message)), notmuch_message_get_flag (message, NOTMUCH_MESSAGE_FLAG_MATCH) ? "true" : "false", + notmuch_message_get_flag (message, NOTMUCH_MESSAGE_FLAG_EXCLUDED) ? "true" : "false", json_quote_str (ctx_quote, notmuch_message_get_filename (message)), date, relative_date); @@ -293,6 +296,7 @@ _is_from_line (const char *line) * * http://qmail.org/qmail-manual-html/man5/mbox.html */ +/* should this do something with the exclude flag? */ static void format_message_mbox (const void *ctx, notmuch_message_t *message, @@ -947,9 +951,11 @@ do_show_single (void *ctx, notmuch_messages_t *messages; notmuch_message_t *message; +/* we need to fix something in notmuch_query_count for now just + * comment this out*/ if (notmuch_query_count_messages (query) != 1) { fprintf (stderr, "Error: search term did not match precisely one message.\n"); - return 1; + /* return 1; */ } messages = notmuch_query_search_messages (query); @@ -1059,9 +1065,12 @@ notmuch_show_command (void *ctx, unused (int argc), unused (char *argv[])) char *opt; const notmuch_show_format_t *format = _text; notmuch_show_params_t params; +const char **search_exclude_tags; +size_t search_exclude_tags_length; int mbox = 0; int format_specified = 0; int i; +unsigned int j; params.entire_thread = 0; params.raw = 0; @@ -1158,6 +1167,11 @@ notmuch_show_command (void *ctx, unused (int argc), unused (char *argv[])) return 1; } +search_exclude_tags = notmuch_config_get_search_exclude_tags +(config, _exclude_tags_length); +for (j = 0; j < search_exclude_tags_length; j++) +notmuch_query_add_tag_exclude (query, search_exclude_tags[j]); + /* if part was requested and format was not specified, use format=raw */ if (params.part >= 0 && !format_specified) format = _raw; -- 1.7.2.3
[PATCH 3/4] Add exclude flag
Add the exclude flag to notmuch_query_search_threads --- lib/notmuch-private.h | 17 +++-- lib/query.cc |1 + lib/thread.cc | 18 +++--- 3 files changed, 27 insertions(+), 9 deletions(-) diff --git a/lib/notmuch-private.h b/lib/notmuch-private.h index 7bf153e..56b87c6 100644 --- a/lib/notmuch-private.h +++ b/lib/notmuch-private.h @@ -211,12 +211,8 @@ _notmuch_directory_get_document_id (notmuch_directory_t *directory); /* thread.cc */ -notmuch_thread_t * -_notmuch_thread_create (void *ctx, - notmuch_database_t *notmuch, - unsigned int seed_doc_id, - notmuch_doc_id_set_t *match_set, - notmuch_sort_t sort); +/* Definition of _notmuch_thread_create moved later since now uses + * string_list_t */ /* message.cc */ @@ -401,6 +397,7 @@ typedef struct _notmuch_message_list { */ struct visible _notmuch_messages { notmuch_bool_t is_of_list_type; +notmuch_doc_id_set_t *excluded_doc_ids; notmuch_message_node_t *iterator; }; @@ -491,6 +488,14 @@ notmuch_filenames_t * _notmuch_filenames_create (const void *ctx, notmuch_string_list_t *list); +notmuch_thread_t * +_notmuch_thread_create (void *ctx, + notmuch_database_t *notmuch, + unsigned int seed_doc_id, + notmuch_doc_id_set_t *match_set, + notmuch_string_list_t *excluded_terms, + notmuch_sort_t sort); + #pragma GCC visibility pop NOTMUCH_END_DECLS diff --git a/lib/query.cc b/lib/query.cc index 8ffafe5..de95745 100644 --- a/lib/query.cc +++ b/lib/query.cc @@ -456,6 +456,7 @@ notmuch_threads_get (notmuch_threads_t *threads) threads->query->notmuch, doc_id, >match_set, + threads->query->exclude_terms, threads->query->sort); } diff --git a/lib/thread.cc b/lib/thread.cc index 0435ee6..6d65d52 100644 --- a/lib/thread.cc +++ b/lib/thread.cc @@ -214,7 +214,8 @@ _thread_cleanup_author (notmuch_thread_t *thread, */ static void _thread_add_message (notmuch_thread_t *thread, -notmuch_message_t *message) +notmuch_message_t *message, +notmuch_string_list_t *exclude_terms) { notmuch_tags_t *tags; const char *tag; @@ -262,6 +263,15 @@ _thread_add_message (notmuch_thread_t *thread, notmuch_tags_move_to_next (tags)) { tag = notmuch_tags_get (tags); + /* mark excluded messages */ + for (notmuch_string_node_t *term = exclude_terms->head; term; +term = term->next) { + /* we ignore initial 'K' */ + if (strcmp(tag, (term->string + 1)) == 0) { + notmuch_message_set_flag (message, NOTMUCH_MESSAGE_FLAG_EXCLUDED, TRUE); + break; + } + } g_hash_table_insert (thread->tags, xstrdup (tag), NULL); } } @@ -321,7 +331,8 @@ _thread_add_matched_message (notmuch_thread_t *thread, _thread_set_subject_from_message (thread, message); } -thread->matched_messages++; +if (!notmuch_message_get_flag (message, NOTMUCH_MESSAGE_FLAG_EXCLUDED)) + thread->matched_messages++; if (g_hash_table_lookup_extended (thread->message_hash, notmuch_message_get_message_id (message), NULL, @@ -392,6 +403,7 @@ _notmuch_thread_create (void *ctx, notmuch_database_t *notmuch, unsigned int seed_doc_id, notmuch_doc_id_set_t *match_set, + notmuch_string_list_t *exclude_terms, notmuch_sort_t sort) { notmuch_thread_t *thread; @@ -467,7 +479,7 @@ _notmuch_thread_create (void *ctx, if (doc_id == seed_doc_id) message = seed_message; - _thread_add_message (thread, message); + _thread_add_message (thread, message, exclude_terms); if ( _notmuch_doc_id_set_contains (match_set, doc_id)) { _notmuch_doc_id_set_remove (match_set, doc_id); -- 1.7.2.3
[PATCH 2/4] Add exclude flag
Make notmuch_query_search_messages set the exclude flag Exclude flag will be added to notmuch_query_search threads later. --- lib/notmuch.h |3 ++- lib/query.cc | 34 +++--- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/lib/notmuch.h b/lib/notmuch.h index 7929fe7..cf0d45d 100644 --- a/lib/notmuch.h +++ b/lib/notmuch.h @@ -895,7 +895,8 @@ notmuch_message_get_filenames (notmuch_message_t *message); /* Message flags */ typedef enum _notmuch_message_flag { -NOTMUCH_MESSAGE_FLAG_MATCH +NOTMUCH_MESSAGE_FLAG_MATCH, +NOTMUCH_MESSAGE_FLAG_EXCLUDED } notmuch_message_flag_t; /* Get a value of a flag for the email corresponding to 'message'. */ diff --git a/lib/query.cc b/lib/query.cc index c25b301..8ffafe5 100644 --- a/lib/query.cc +++ b/lib/query.cc @@ -57,6 +57,12 @@ struct visible _notmuch_threads { notmuch_doc_id_set_t match_set; }; +/* we need this in the message functions so forward declare */ +static notmuch_bool_t +_notmuch_doc_id_set_init (void *ctx, + notmuch_doc_id_set_t *doc_ids, + GArray *arr); + notmuch_query_t * notmuch_query_create (notmuch_database_t *notmuch, const char *query_string) @@ -173,6 +179,7 @@ notmuch_query_search_messages (notmuch_query_t *query) "mail")); Xapian::Query string_query, final_query, exclude_query; Xapian::MSet mset; + Xapian::MSetIterator iterator; unsigned int flags = (Xapian::QueryParser::FLAG_BOOLEAN | Xapian::QueryParser::FLAG_PHRASE | Xapian::QueryParser::FLAG_LOVEHATE | @@ -190,11 +197,28 @@ notmuch_query_search_messages (notmuch_query_t *query) final_query = Xapian::Query (Xapian::Query::OP_AND, mail_query, string_query); } + if (query->exclude_terms) { + exclude_query = _notmuch_exclude_tags (query, final_query); + exclude_query = Xapian::Query (Xapian::Query::OP_AND, + exclude_query, final_query); - exclude_query = _notmuch_exclude_tags (query, final_query); + enquire.set_weighting_scheme (Xapian::BoolWeight()); + enquire.set_query (exclude_query); - final_query = Xapian::Query (Xapian::Query::OP_AND_NOT, -final_query, exclude_query); + mset = enquire.get_mset (0, notmuch->xapian_db->get_doccount ()); + + GArray *excluded_doc_ids = g_array_new (FALSE, FALSE, sizeof (unsigned int)); + + for (iterator = mset.begin (); iterator != mset.end (); iterator++) + { + unsigned int doc_id = *iterator; + g_array_append_val (excluded_doc_ids, doc_id); + } + messages->base.excluded_doc_ids = talloc (query, _notmuch_doc_id_set); + _notmuch_doc_id_set_init (query, messages->base.excluded_doc_ids, + excluded_doc_ids); + } else + messages->base.excluded_doc_ids = NULL; enquire.set_weighting_scheme (Xapian::BoolWeight()); @@ -283,6 +307,10 @@ _notmuch_mset_messages_get (notmuch_messages_t *messages) INTERNAL_ERROR ("a messages iterator contains a non-existent document ID.\n"); } +if ((messages->excluded_doc_ids) && + (_notmuch_doc_id_set_contains (messages->excluded_doc_ids, doc_id))) + notmuch_message_set_flag (message, NOTMUCH_MESSAGE_FLAG_EXCLUDED, TRUE); + return message; } -- 1.7.2.3
[PATCH 1/4] Add exclude flag
Slightly refactor the exclude code to give the callers access to the exclude query itself. There should be no functional change. --- lib/query.cc | 29 +++-- 1 files changed, 19 insertions(+), 10 deletions(-) diff --git a/lib/query.cc b/lib/query.cc index 0b36602..c25b301 100644 --- a/lib/query.cc +++ b/lib/query.cc @@ -122,12 +122,15 @@ _notmuch_messages_destructor (notmuch_mset_messages_t *messages) return 0; } -/* Return a query that does not match messages with the excluded tags - * registered with the query. Any tags that explicitly appear in - * xquery will not be excluded. */ +/* Return a query that matches messages with the excluded tags + * registered with query. Any tags that explicitly appear in xquery + * will not be excluded. The caller of this function has to combine + * the returned query appropriately.*/ static Xapian::Query _notmuch_exclude_tags (notmuch_query_t *query, Xapian::Query xquery) { +Xapian::Query exclude_query = Xapian::Query::MatchNothing; + for (notmuch_string_node_t *term = query->exclude_terms->head; term; term = term->next) { Xapian::TermIterator it = xquery.get_terms_begin (); @@ -137,10 +140,10 @@ _notmuch_exclude_tags (notmuch_query_t *query, Xapian::Query xquery) break; } if (it == end) - xquery = Xapian::Query (Xapian::Query::OP_AND_NOT, - xquery, Xapian::Query (term->string)); + exclude_query = Xapian::Query (Xapian::Query::OP_OR, + exclude_query, Xapian::Query (term->string)); } -return xquery; +return exclude_query; } notmuch_messages_t * @@ -168,7 +171,7 @@ notmuch_query_search_messages (notmuch_query_t *query) Xapian::Query mail_query (talloc_asprintf (query, "%s%s", _find_prefix ("type"), "mail")); - Xapian::Query string_query, final_query; + Xapian::Query string_query, final_query, exclude_query; Xapian::MSet mset; unsigned int flags = (Xapian::QueryParser::FLAG_BOOLEAN | Xapian::QueryParser::FLAG_PHRASE | @@ -188,7 +191,10 @@ notmuch_query_search_messages (notmuch_query_t *query) mail_query, string_query); } - final_query = _notmuch_exclude_tags (query, final_query); + exclude_query = _notmuch_exclude_tags (query, final_query); + + final_query = Xapian::Query (Xapian::Query::OP_AND_NOT, +final_query, exclude_query); enquire.set_weighting_scheme (Xapian::BoolWeight()); @@ -449,7 +455,7 @@ notmuch_query_count_messages (notmuch_query_t *query) Xapian::Query mail_query (talloc_asprintf (query, "%s%s", _find_prefix ("type"), "mail")); - Xapian::Query string_query, final_query; + Xapian::Query string_query, final_query, exclude_query; Xapian::MSet mset; unsigned int flags = (Xapian::QueryParser::FLAG_BOOLEAN | Xapian::QueryParser::FLAG_PHRASE | @@ -469,7 +475,10 @@ notmuch_query_count_messages (notmuch_query_t *query) mail_query, string_query); } - final_query = _notmuch_exclude_tags (query, final_query); + exclude_query = _notmuch_exclude_tags (query, final_query); + + final_query = Xapian::Query (Xapian::Query::OP_AND_NOT, +final_query, exclude_query); enquire.set_weighting_scheme(Xapian::BoolWeight()); enquire.set_docid_order(Xapian::Enquire::ASCENDING); -- 1.7.2.3
[PATCH 1/3] NEWS: add entry for python error handling fix
Signed-off-by: Justus Winter 4win...@informatik.uni-hamburg.de --- NEWS | 10 ++ 1 files changed, 10 insertions(+), 0 deletions(-) diff --git a/NEWS b/NEWS index 2acdce5..bee6f2e 100644 --- a/NEWS +++ b/NEWS @@ -47,6 +47,16 @@ New functions notmuch_query_add_tag_exclude supports the new tag exclusion feature. +Python bindings changes +--- + +Fix error handling in python bindings. + + The python bindings in 0.11 failed to detect NULL pointers being + returned from libnotmuch functions and thus failed to raise + exceptions to indicate the error condition. Any subsequent calls + into libnotmuch caused segmentation faults. + Build fixes --- -- 1.7.8.3 ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
[PATCH 2/3] NEWS: add entry for python 3.2 compatibility
Signed-off-by: Justus Winter 4win...@informatik.uni-hamburg.de --- NEWS |4 1 files changed, 4 insertions(+), 0 deletions(-) diff --git a/NEWS b/NEWS index bee6f2e..71644ff 100644 --- a/NEWS +++ b/NEWS @@ -57,6 +57,10 @@ Fix error handling in python bindings. exceptions to indicate the error condition. Any subsequent calls into libnotmuch caused segmentation faults. +Python 3.2 compatibility + + The python bindings are now compatible with both python 2.x and 3.2. + Build fixes --- -- 1.7.8.3 ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
error handling and stderr
Hi notmuch developers, currently there is no way to determine why opening a database using notmuch_database_open fails. I suppose that this is a problem for all functions returning a pointer, but it is especially problematic for this function since one cannot distinguish between a temporary failure (someone else opened the db read/write) and a configuration problem (wrong path). This is a real problem for providing sensible feedback to the user. And writing an error message to stderr is a sensible thing to do if it is done in a command line utility but doing so within a library is a severe problem for any curses frontends and is generally considered a bad practice. For the record, libabcs README[0] agrees with me on both aspects. Since fixing this means breaking the api we need to discuss this thoroughly and identify all the functions involved. Users of the python bindings won't be affected by an api change like this since we're converting any error code to exceptions anyway. Cheers, Justus 0: https://git.kernel.org/?p=linux/kernel/git/kay/libabc.git;a=blob_plain;f=README ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
[PATCH 1/7] cli: add --do-not-exclude option to count and search.
This option turns off the exclusion so all matching messages are returned. We do not need to add this to show as notmuch-show does not (yet) exclude. --- notmuch-count.c | 12 notmuch-search.c | 12 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/notmuch-count.c b/notmuch-count.c index 63459fb..c88975e 100644 --- a/notmuch-count.c +++ b/notmuch-count.c @@ -37,6 +37,7 @@ notmuch_count_command (void *ctx, int argc, char *argv[]) int output = OUTPUT_MESSAGES; const char **search_exclude_tags; size_t search_exclude_tags_length; +notmuch_bool_t do_not_exclude = FALSE; unsigned int i; notmuch_opt_desc_t options[] = { @@ -44,6 +45,7 @@ notmuch_count_command (void *ctx, int argc, char *argv[]) (notmuch_keyword_t []){ { threads, OUTPUT_THREADS }, { messages, OUTPUT_MESSAGES }, { 0, 0 } } }, + { NOTMUCH_OPT_BOOLEAN, do_not_exclude, do-not-exclude, 'd', 0 }, { 0, 0, 0, 0, 0 } }; @@ -78,10 +80,12 @@ notmuch_count_command (void *ctx, int argc, char *argv[]) return 1; } -search_exclude_tags = notmuch_config_get_search_exclude_tags - (config, search_exclude_tags_length); -for (i = 0; i search_exclude_tags_length; i++) - notmuch_query_add_tag_exclude (query, search_exclude_tags[i]); +if (!do_not_exclude) { + search_exclude_tags = notmuch_config_get_search_exclude_tags + (config, search_exclude_tags_length); + for (i = 0; i search_exclude_tags_length; i++) + notmuch_query_add_tag_exclude (query, search_exclude_tags[i]); +} switch (output) { case OUTPUT_MESSAGES: diff --git a/notmuch-search.c b/notmuch-search.c index d504051..084dd05 100644 --- a/notmuch-search.c +++ b/notmuch-search.c @@ -425,6 +425,7 @@ notmuch_search_command (void *ctx, int argc, char *argv[]) int limit = -1; /* unlimited */ const char **search_exclude_tags; size_t search_exclude_tags_length; +notmuch_bool_t do_not_exclude = FALSE; unsigned int i; enum { NOTMUCH_FORMAT_JSON, NOTMUCH_FORMAT_TEXT } @@ -446,6 +447,7 @@ notmuch_search_command (void *ctx, int argc, char *argv[]) { files, OUTPUT_FILES }, { tags, OUTPUT_TAGS }, { 0, 0 } } }, +{ NOTMUCH_OPT_BOOLEAN, do_not_exclude, do-not-exclude, 'd', 0 }, { NOTMUCH_OPT_INT, offset, offset, 'O', 0 }, { NOTMUCH_OPT_INT, limit, limit, 'L', 0 }, { 0, 0, 0, 0, 0 } @@ -493,10 +495,12 @@ notmuch_search_command (void *ctx, int argc, char *argv[]) notmuch_query_set_sort (query, sort); -search_exclude_tags = notmuch_config_get_search_exclude_tags - (config, search_exclude_tags_length); -for (i = 0; i search_exclude_tags_length; i++) - notmuch_query_add_tag_exclude (query, search_exclude_tags[i]); +if (!do_not_exclude) { + search_exclude_tags = notmuch_config_get_search_exclude_tags + (config, search_exclude_tags_length); + for (i = 0; i search_exclude_tags_length; i++) + notmuch_query_add_tag_exclude (query, search_exclude_tags[i]); +} switch (output) { default: -- 1.7.2.3 ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
[PATCH 2/7] lib: Rearrange the exclude code in query.cc
Slightly refactor the exclude code to give the callers access to the exclude query itself. There should be no functional change. --- lib/query.cc | 29 +++-- 1 files changed, 19 insertions(+), 10 deletions(-) diff --git a/lib/query.cc b/lib/query.cc index 0b36602..c25b301 100644 --- a/lib/query.cc +++ b/lib/query.cc @@ -122,12 +122,15 @@ _notmuch_messages_destructor (notmuch_mset_messages_t *messages) return 0; } -/* Return a query that does not match messages with the excluded tags - * registered with the query. Any tags that explicitly appear in - * xquery will not be excluded. */ +/* Return a query that matches messages with the excluded tags + * registered with query. Any tags that explicitly appear in xquery + * will not be excluded. The caller of this function has to combine + * the returned query appropriately.*/ static Xapian::Query _notmuch_exclude_tags (notmuch_query_t *query, Xapian::Query xquery) { +Xapian::Query exclude_query = Xapian::Query::MatchNothing; + for (notmuch_string_node_t *term = query-exclude_terms-head; term; term = term-next) { Xapian::TermIterator it = xquery.get_terms_begin (); @@ -137,10 +140,10 @@ _notmuch_exclude_tags (notmuch_query_t *query, Xapian::Query xquery) break; } if (it == end) - xquery = Xapian::Query (Xapian::Query::OP_AND_NOT, - xquery, Xapian::Query (term-string)); + exclude_query = Xapian::Query (Xapian::Query::OP_OR, + exclude_query, Xapian::Query (term-string)); } -return xquery; +return exclude_query; } notmuch_messages_t * @@ -168,7 +171,7 @@ notmuch_query_search_messages (notmuch_query_t *query) Xapian::Query mail_query (talloc_asprintf (query, %s%s, _find_prefix (type), mail)); - Xapian::Query string_query, final_query; + Xapian::Query string_query, final_query, exclude_query; Xapian::MSet mset; unsigned int flags = (Xapian::QueryParser::FLAG_BOOLEAN | Xapian::QueryParser::FLAG_PHRASE | @@ -188,7 +191,10 @@ notmuch_query_search_messages (notmuch_query_t *query) mail_query, string_query); } - final_query = _notmuch_exclude_tags (query, final_query); + exclude_query = _notmuch_exclude_tags (query, final_query); + + final_query = Xapian::Query (Xapian::Query::OP_AND_NOT, +final_query, exclude_query); enquire.set_weighting_scheme (Xapian::BoolWeight()); @@ -449,7 +455,7 @@ notmuch_query_count_messages (notmuch_query_t *query) Xapian::Query mail_query (talloc_asprintf (query, %s%s, _find_prefix (type), mail)); - Xapian::Query string_query, final_query; + Xapian::Query string_query, final_query, exclude_query; Xapian::MSet mset; unsigned int flags = (Xapian::QueryParser::FLAG_BOOLEAN | Xapian::QueryParser::FLAG_PHRASE | @@ -469,7 +475,10 @@ notmuch_query_count_messages (notmuch_query_t *query) mail_query, string_query); } - final_query = _notmuch_exclude_tags (query, final_query); + exclude_query = _notmuch_exclude_tags (query, final_query); + + final_query = Xapian::Query (Xapian::Query::OP_AND_NOT, +final_query, exclude_query); enquire.set_weighting_scheme(Xapian::BoolWeight()); enquire.set_docid_order(Xapian::Enquire::ASCENDING); -- 1.7.2.3 ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
[PATCH 3/7] lib: Make notmuch_query_search_messages set the exclude flag
Add a flag NOTMUCH_MESSAGE_FLAG_EXCLUDED which is set by notmuch_query_search_messages for excluded messages. Also add an option omit_excluded_messages to the search that we do not want the excludes at all. This exclude flag will be added to notmuch_query_search threads in the next patch. --- lib/notmuch-private.h |1 + lib/notmuch.h |8 ++- lib/query.cc | 52 +--- 3 files changed, 56 insertions(+), 5 deletions(-) diff --git a/lib/notmuch-private.h b/lib/notmuch-private.h index 7bf153e..e791bb0 100644 --- a/lib/notmuch-private.h +++ b/lib/notmuch-private.h @@ -401,6 +401,7 @@ typedef struct _notmuch_message_list { */ struct visible _notmuch_messages { notmuch_bool_t is_of_list_type; +notmuch_doc_id_set_t *excluded_doc_ids; notmuch_message_node_t *iterator; }; diff --git a/lib/notmuch.h b/lib/notmuch.h index 7929fe7..740d005 100644 --- a/lib/notmuch.h +++ b/lib/notmuch.h @@ -449,6 +449,11 @@ typedef enum { const char * notmuch_query_get_query_string (notmuch_query_t *query); +/* specify whether to results should omit the excluded results rather + * than just marking them excluded */ +void +notmuch_query_set_omit_excluded_messages (notmuch_query_t *query, notmuch_bool_t omit); + /* Specify the sorting desired for this query. */ void notmuch_query_set_sort (notmuch_query_t *query, notmuch_sort_t sort); @@ -895,7 +900,8 @@ notmuch_message_get_filenames (notmuch_message_t *message); /* Message flags */ typedef enum _notmuch_message_flag { -NOTMUCH_MESSAGE_FLAG_MATCH +NOTMUCH_MESSAGE_FLAG_MATCH, +NOTMUCH_MESSAGE_FLAG_EXCLUDED } notmuch_message_flag_t; /* Get a value of a flag for the email corresponding to 'message'. */ diff --git a/lib/query.cc b/lib/query.cc index c25b301..7d165d2 100644 --- a/lib/query.cc +++ b/lib/query.cc @@ -28,6 +28,7 @@ struct _notmuch_query { const char *query_string; notmuch_sort_t sort; notmuch_string_list_t *exclude_terms; +notmuch_bool_t omit_excluded_messages; }; typedef struct _notmuch_mset_messages { @@ -57,6 +58,12 @@ struct visible _notmuch_threads { notmuch_doc_id_set_t match_set; }; +/* we need this in the message functions so forward declare */ +static notmuch_bool_t +_notmuch_doc_id_set_init (void *ctx, + notmuch_doc_id_set_t *doc_ids, + GArray *arr); + notmuch_query_t * notmuch_query_create (notmuch_database_t *notmuch, const char *query_string) @@ -79,6 +86,8 @@ notmuch_query_create (notmuch_database_t *notmuch, query-exclude_terms = _notmuch_string_list_create (query); +query-omit_excluded_messages = FALSE; + return query; } @@ -89,6 +98,12 @@ notmuch_query_get_query_string (notmuch_query_t *query) } void +notmuch_query_set_omit_excluded_messages (notmuch_query_t *query, notmuch_bool_t omit) +{ +query-omit_excluded_messages = omit; +} + +void notmuch_query_set_sort (notmuch_query_t *query, notmuch_sort_t sort) { query-sort = sort; @@ -173,6 +188,7 @@ notmuch_query_search_messages (notmuch_query_t *query) mail)); Xapian::Query string_query, final_query, exclude_query; Xapian::MSet mset; + Xapian::MSetIterator iterator; unsigned int flags = (Xapian::QueryParser::FLAG_BOOLEAN | Xapian::QueryParser::FLAG_PHRASE | Xapian::QueryParser::FLAG_LOVEHATE | @@ -190,11 +206,35 @@ notmuch_query_search_messages (notmuch_query_t *query) final_query = Xapian::Query (Xapian::Query::OP_AND, mail_query, string_query); } + messages-base.excluded_doc_ids = NULL; + + if (query-exclude_terms) { + exclude_query = _notmuch_exclude_tags (query, final_query); + exclude_query = Xapian::Query (Xapian::Query::OP_AND, + exclude_query, final_query); + + if (query-omit_excluded_messages) + final_query = Xapian::Query (Xapian::Query::OP_AND_NOT, +final_query, exclude_query); + else { + enquire.set_weighting_scheme (Xapian::BoolWeight()); + enquire.set_query (exclude_query); + + mset = enquire.get_mset (0, notmuch-xapian_db-get_doccount ()); + + GArray *excluded_doc_ids = g_array_new (FALSE, FALSE, sizeof (unsigned int)); + + for (iterator = mset.begin (); iterator != mset.end (); iterator++) + { + unsigned int doc_id = *iterator; + g_array_append_val (excluded_doc_ids, doc_id); + } + messages-base.excluded_doc_ids = talloc (query, _notmuch_doc_id_set); + _notmuch_doc_id_set_init (query, messages-base.excluded_doc_ids, +
[PATCH 4/7] lib: Add the exclude flag to notmuch_query_search_threads
Add the NOTMUCH_MESSAGE_FLAG_EXCLUDED flag to notmuch_query_search_threads. Implemented by inspecting the tags directly in _notmuch_thread_create/_thread_add_message rather than as a Xapian query for speed reasons. --- lib/notmuch-private.h | 16 ++-- lib/query.cc |1 + lib/thread.cc | 18 +++--- 3 files changed, 26 insertions(+), 9 deletions(-) diff --git a/lib/notmuch-private.h b/lib/notmuch-private.h index e791bb0..56b87c6 100644 --- a/lib/notmuch-private.h +++ b/lib/notmuch-private.h @@ -211,12 +211,8 @@ _notmuch_directory_get_document_id (notmuch_directory_t *directory); /* thread.cc */ -notmuch_thread_t * -_notmuch_thread_create (void *ctx, - notmuch_database_t *notmuch, - unsigned int seed_doc_id, - notmuch_doc_id_set_t *match_set, - notmuch_sort_t sort); +/* Definition of _notmuch_thread_create moved later since now uses + * string_list_t */ /* message.cc */ @@ -492,6 +488,14 @@ notmuch_filenames_t * _notmuch_filenames_create (const void *ctx, notmuch_string_list_t *list); +notmuch_thread_t * +_notmuch_thread_create (void *ctx, + notmuch_database_t *notmuch, + unsigned int seed_doc_id, + notmuch_doc_id_set_t *match_set, + notmuch_string_list_t *excluded_terms, + notmuch_sort_t sort); + #pragma GCC visibility pop NOTMUCH_END_DECLS diff --git a/lib/query.cc b/lib/query.cc index 7d165d2..dee7ec0 100644 --- a/lib/query.cc +++ b/lib/query.cc @@ -472,6 +472,7 @@ notmuch_threads_get (notmuch_threads_t *threads) threads-query-notmuch, doc_id, threads-match_set, + threads-query-exclude_terms, threads-query-sort); } diff --git a/lib/thread.cc b/lib/thread.cc index 0435ee6..6d65d52 100644 --- a/lib/thread.cc +++ b/lib/thread.cc @@ -214,7 +214,8 @@ _thread_cleanup_author (notmuch_thread_t *thread, */ static void _thread_add_message (notmuch_thread_t *thread, -notmuch_message_t *message) +notmuch_message_t *message, +notmuch_string_list_t *exclude_terms) { notmuch_tags_t *tags; const char *tag; @@ -262,6 +263,15 @@ _thread_add_message (notmuch_thread_t *thread, notmuch_tags_move_to_next (tags)) { tag = notmuch_tags_get (tags); + /* mark excluded messages */ + for (notmuch_string_node_t *term = exclude_terms-head; term; +term = term-next) { + /* we ignore initial 'K' */ + if (strcmp(tag, (term-string + 1)) == 0) { + notmuch_message_set_flag (message, NOTMUCH_MESSAGE_FLAG_EXCLUDED, TRUE); + break; + } + } g_hash_table_insert (thread-tags, xstrdup (tag), NULL); } } @@ -321,7 +331,8 @@ _thread_add_matched_message (notmuch_thread_t *thread, _thread_set_subject_from_message (thread, message); } -thread-matched_messages++; +if (!notmuch_message_get_flag (message, NOTMUCH_MESSAGE_FLAG_EXCLUDED)) + thread-matched_messages++; if (g_hash_table_lookup_extended (thread-message_hash, notmuch_message_get_message_id (message), NULL, @@ -392,6 +403,7 @@ _notmuch_thread_create (void *ctx, notmuch_database_t *notmuch, unsigned int seed_doc_id, notmuch_doc_id_set_t *match_set, + notmuch_string_list_t *exclude_terms, notmuch_sort_t sort) { notmuch_thread_t *thread; @@ -467,7 +479,7 @@ _notmuch_thread_create (void *ctx, if (doc_id == seed_doc_id) message = seed_message; - _thread_add_message (thread, message); + _thread_add_message (thread, message, exclude_terms); if ( _notmuch_doc_id_set_contains (match_set, doc_id)) { _notmuch_doc_id_set_remove (match_set, doc_id); -- 1.7.2.3 ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
[PATCH 5/7] cli: Make notmuch-show respect excludes.
This adds the excludes to notmuch-show.c. We do not exclude when only a single message (or part) is requested. notmuch-show will output the exclude information when either text or json format is requested. As this changes the output from notmuch-show it breaks many tests (in a trivial and expected fashion). --- notmuch-show.c | 26 +- 1 files changed, 21 insertions(+), 5 deletions(-) diff --git a/notmuch-show.c b/notmuch-show.c index dec799c..681827f 100644 --- a/notmuch-show.c +++ b/notmuch-show.c @@ -193,10 +193,12 @@ _get_one_line_summary (const void *ctx, notmuch_message_t *message) static void format_message_text (unused (const void *ctx), notmuch_message_t *message, int indent) { -printf (id:%s depth:%d match:%d filename:%s\n, +/* Could changing this could break users ? */ +printf (id:%s depth:%d match:%d excluded:%d filename:%s\n, notmuch_message_get_message_id (message), indent, - notmuch_message_get_flag (message, NOTMUCH_MESSAGE_FLAG_MATCH), + notmuch_message_get_flag (message, NOTMUCH_MESSAGE_FLAG_MATCH) ? 1 : 0, + notmuch_message_get_flag (message, NOTMUCH_MESSAGE_FLAG_EXCLUDED) ? 1 : 0, notmuch_message_get_filename (message)); } @@ -212,9 +214,10 @@ format_message_json (const void *ctx, notmuch_message_t *message, unused (int in date = notmuch_message_get_date (message); relative_date = notmuch_time_relative_date (ctx, date); -printf (\id\: %s, \match\: %s, \filename\: %s, \timestamp\: %ld, \date_relative\: \%s\, \tags\: [, +printf (\id\: %s, \match\: %s, \excluded\: %s, \filename\: %s, \timestamp\: %ld, \date_relative\: \%s\, \tags\: [, json_quote_str (ctx_quote, notmuch_message_get_message_id (message)), notmuch_message_get_flag (message, NOTMUCH_MESSAGE_FLAG_MATCH) ? true : false, + notmuch_message_get_flag (message, NOTMUCH_MESSAGE_FLAG_EXCLUDED) ? true : false, json_quote_str (ctx_quote, notmuch_message_get_filename (message)), date, relative_date); @@ -1059,9 +1062,13 @@ notmuch_show_command (void *ctx, unused (int argc), unused (char *argv[])) char *opt; const notmuch_show_format_t *format = format_text; notmuch_show_params_t params; +const char **search_exclude_tags; +size_t search_exclude_tags_length; int mbox = 0; int format_specified = 0; int i; +notmuch_bool_t do_not_exclude = FALSE; +unsigned int j; params.entire_thread = 0; params.raw = 0; @@ -1098,6 +1105,8 @@ notmuch_show_command (void *ctx, unused (int argc), unused (char *argv[])) params.part = atoi(argv[i] + sizeof (--part=) - 1); } else if (STRNCMP_LITERAL (argv[i], --entire-thread) == 0) { params.entire_thread = 1; + } else if (STRNCMP_LITERAL (argv[i], --do-not-exclude) == 0) { + do_not_exclude = TRUE; } else if ((STRNCMP_LITERAL (argv[i], --verify) == 0) || (STRNCMP_LITERAL (argv[i], --decrypt) == 0)) { if (params.cryptoctx == NULL) { @@ -1105,7 +1114,7 @@ notmuch_show_command (void *ctx, unused (int argc), unused (char *argv[])) /* TODO: GMimePasswordRequestFunc */ if (NULL == (params.cryptoctx = g_mime_gpg_context_new(NULL, gpg))) #else - GMimeSession* session = g_object_new(g_mime_session_get_type(), NULL); + GMimeSession* session = g_object_new(g_mime_session_get_type(), NULL); if (NULL == (params.cryptoctx = g_mime_gpg_context_new(session, gpg))) #endif fprintf (stderr, Failed to construct gpg context.\n); @@ -1167,10 +1176,17 @@ notmuch_show_command (void *ctx, unused (int argc), unused (char *argv[])) if (params.raw params.part 0) params.part = 0; +/* if a single message is requested we do not use search_excludes */ if (params.part = 0) return do_show_single (ctx, query, format, params); else - return do_show (ctx, query, format, params); + if (!do_not_exclude) { + search_exclude_tags = notmuch_config_get_search_exclude_tags + (config, search_exclude_tags_length); + for (j = 0; j search_exclude_tags_length; j++) + notmuch_query_add_tag_exclude (query, search_exclude_tags[j]); + return do_show (ctx, query, format, params); + } notmuch_query_destroy (query); notmuch_database_close (notmuch); -- 1.7.2.3 ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
[PATCH 6/7] cli: omit excluded messages in results where appropriate.
In all cases of notmuch count/search/show where the results returned cannot reflect the exclude flag return just the matched not-excluded results. If the caller wishes to have all the matched results (i.e., including the excluded ones) they should call with the --do-not-exclude option. The relevant cases are count: both threads and messages search: all cases except the summary view show: mbox format --- notmuch-count.c |2 ++ notmuch-search.c |9 + notmuch-show.c |5 + 3 files changed, 16 insertions(+), 0 deletions(-) diff --git a/notmuch-count.c b/notmuch-count.c index c88975e..1aa3f1a 100644 --- a/notmuch-count.c +++ b/notmuch-count.c @@ -87,6 +87,8 @@ notmuch_count_command (void *ctx, int argc, char *argv[]) notmuch_query_add_tag_exclude (query, search_exclude_tags[i]); } +notmuch_query_set_omit_excluded_messages (query, TRUE); + switch (output) { case OUTPUT_MESSAGES: printf (%u\n, notmuch_query_count_messages (query)); diff --git a/notmuch-search.c b/notmuch-search.c index 084dd05..339ce82 100644 --- a/notmuch-search.c +++ b/notmuch-search.c @@ -207,6 +207,9 @@ do_search_threads (const search_format_t *format, int first_thread = 1; int i; +if (output == OUTPUT_THREADS) + notmuch_query_set_omit_excluded_messages (query, TRUE); + if (offset 0) { offset += notmuch_query_count_threads (query); if (offset 0) @@ -297,6 +300,8 @@ do_search_messages (const search_format_t *format, int first_message = 1; int i; +notmuch_query_set_omit_excluded_messages (query, TRUE); + if (offset 0) { offset += notmuch_query_count_messages (query); if (offset 0) @@ -368,6 +373,10 @@ do_search_tags (notmuch_database_t *notmuch, const char *tag; int first_tag = 1; +notmuch_query_set_omit_excluded_messages (query, TRUE); +/* should the following only special case if no excluded terms + * specified? */ + /* Special-case query of * for better performance. */ if (strcmp (notmuch_query_get_query_string (query), *) == 0) { tags = notmuch_database_get_all_tags (notmuch); diff --git a/notmuch-show.c b/notmuch-show.c index 681827f..5d98724 100644 --- a/notmuch-show.c +++ b/notmuch-show.c @@ -1167,6 +1167,11 @@ notmuch_show_command (void *ctx, unused (int argc), unused (char *argv[])) return 1; } +/* if format=mbox then we can not output excluded messages as + * there is no way to make the exclude flag available */ +if (mbox) + notmuch_query_set_omit_excluded_messages (query, TRUE); + /* if part was requested and format was not specified, use format=raw */ if (params.part = 0 !format_specified) format = format_raw; -- 1.7.2.3 ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
[PATCH 7/7] emacs: show: recognize the exclude flag.
Show mode will recognize the exclude flag by not opening excluding messages by default, and will start at the first matching non-excluded message. If there are no matching non-excluded messages it will go to the first matching (necessarily excluded) message. --- emacs/notmuch-show.el | 18 +- 1 files changed, 17 insertions(+), 1 deletions(-) diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el index 84ac624..8efadf6 100644 --- a/emacs/notmuch-show.el +++ b/emacs/notmuch-show.el @@ -905,7 +905,8 @@ current buffer, if possible. ;; Message visibility depends on whether it matched the search ;; criteria. -(notmuch-show-message-visible msg (plist-get msg :match +(notmuch-show-message-visible msg (and (plist-get msg :match) + (not (plist-get msg :excluded)) (defun notmuch-show-insert-tree (tree depth) Insert the message tree TREE at depth DEPTH in the current thread. @@ -1015,6 +1016,9 @@ buffer. ;; Move straight to the first open message (unless (notmuch-show-message-visible-p) (notmuch-show-next-open-message)) +(when (eq (point) (point-max)) + (goto-char (point-min)) + (notmuch-show-next-matching-message)) ;; Set the header line to the subject of the first open message. (setq header-line-format (notmuch-show-strip-re (notmuch-show-get-subject))) @@ -1417,6 +1421,18 @@ any effects from previous calls to (notmuch-show-message-adjust)) (goto-char (point-max) +(defun notmuch-show-next-matching-message () + Show the next matching message. + (interactive) + (let (r) +(while (and (setq r (notmuch-show-goto-message-next)) + (not (notmuch-show-get-prop :match +(if r + (progn + (notmuch-show-mark-read) + (notmuch-show-message-adjust)) + (goto-char (point-max) + (defun notmuch-show-previous-open-message () Show the previous message. (interactive) -- 1.7.2.3 ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
[PATCH 1/2] test: emacs mailto: URI handling
This adds a test for proposed rfc6068 mailto:; URI handling. The proposed function would be called 'notmuch-mua-mailto'. The test provides an example mailto: string that should test some subset of the rfc6068 specification: http://tools.ietf.org/html/rfc6068 --- test/emacs | 29 + 1 files changed, 29 insertions(+), 0 deletions(-) diff --git a/test/emacs b/test/emacs index 8ca4c8a..c6afa14 100755 --- a/test/emacs +++ b/test/emacs @@ -273,6 +273,35 @@ On 01 Jan 2000 12:00:00 -, Notmuch Test Suite test_su...@notmuchmail.org w EOF test_expect_equal_file OUTPUT EXPECTED +test_begin_subtest Compose to \mailto:\; URI +test_subtest_known_broken +# This *should* test the ability to parse rfc6068 mailto:; URIs: +# http://tools.ietf.org/html/rfc6068 +# this test is based on: +# http://shadow2531.com/opera/testcases/mailto/rfc2368-0.html +# which is itself based on the precursor rfc2368, so it could probably +# be updated. +test_emacs (let ((mailto \mailto:to1%40example.net%2C%20to2%40example.net?to=to3%40example.net%2C%20to4%40example.netamp;subject=last%20call%20for%20cats%20%26%20dogs%2Eamp;subject=You%20should%20not%20see%20me%2Eamp;body=line1%0D%0Aline2amp;body=line3amp;body=line4%0D%0AColumn1A%09Column1B%09Column1C%09Column1D%0D%0A%E2%88%9Aamp;cc=cc1%40example.net%2C%20cc2%40example.netamp;to=to5%40example.net%2C%20to6%40example.netamp;foo=IGNOREamp;bcc=bcc1%40example.net%2C%20bcc2%40example.netamp;bcc=bcc3%40example.net%2C%20bcc4%40example.netamp;in-reply-to=or...@example.net\) + (notmuch-fcc-dirs nil)) + (notmuch-mua-mailto mailto) + (test-output)) +cat EOF EXPECTED +From: Notmuch Test Suite test_su...@notmuchmail.org +To: t...@example.net, t...@example.net, t...@example.net, t...@example.net +Cc: c...@example.net, c...@example.net +Subject: last call for cats dogs. +In-Reply-To: or...@example.net +Bcc: b...@example.net, b...@example.net +--text follows this line-- +line1 +line2 +line3 +line4 +Column1A Column1BColumn1CColumn1D +√ +EOF +test_expect_equal_file OUTPUT EXPECTED + test_begin_subtest Save attachment from within emacs using notmuch-show-save-attachments # save as archive to test that Emacs does not re-compress .gz test_emacs '(let ((standard-input \attachment1.gz\)) -- 1.7.8.3 ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
[PATCH 2/2] emacs: new mua mailto: URI handler
The new function 'notmuch-mua-mailto' provides an interactive handler for rfc6068 mailto:; URIs. It attempts to implement the rfc6068 specification: http://tools.ietf.org/html/rfc6068 More decoding of the mailto string needs to be done, as is evident by the fact that the mailto test remains broken. --- Unfortunately I'm not sure how best to do the URI decoding, so I've left a FIXME in the code, and the test as known_broken. I'm hoping an elisp/encodings expert out there will pick this up. emacs/notmuch-mua.el | 62 ++ 1 files changed, 62 insertions(+), 0 deletions(-) diff --git a/emacs/notmuch-mua.el b/emacs/notmuch-mua.el index 023645e..750e8d6 100644 --- a/emacs/notmuch-mua.el +++ b/emacs/notmuch-mua.el @@ -24,6 +24,10 @@ (require 'notmuch-lib) (require 'notmuch-address) +(require 'rfc2368) +(require 'rfc2047) +(require 'mailheader) + ;; (defcustom notmuch-mua-send-hook '(notmuch-mua-message-send-hook) @@ -131,6 +135,64 @@ list. (message-goto-to)) +(defun notmuch-mua-mailto (mailto) + Invoke the notmuch mail composition window for a `mailto:' URI. + ;; this should implement implement rfc6068: http://tools.ietf.org/html/rfc6068 + ;; which obsoleted: http://tools.ietf.org/html/rfc2368 + ;; this function is based on previous work: http://www.emacswiki.org/emacs/MailtoHandler + (interactive) + (when (and (stringp mailto) +(string-match \\`mailto:; mailto)) +(let* ( + ;; FIXME: need to decode all html encodings in uri. + (mailto (replace-regexp-in-string amp; mailto)) + (hdr-alist (rfc2368-parse-mailto-url mailto)) + to subject other-headers body + (allowed-xtra-hdrs '(cc bcc in-reply-to))) + + (with-temp-buffer + ;; extract body if it's defined + (when (assoc Body hdr-alist) + (dolist (hdr hdr-alist) + (when (equal Body (car hdr)) + (insert (format %s\n (cdr hdr) + (rfc2047-decode-region (point-min) (point-max)) + (setq body (buffer-substring-no-properties + (point-min) (point-max))) + (erase-buffer)) + + ;; extract headers + (dolist (hdr hdr-alist) + (unless (equal Body (car hdr)) + (insert (format %s: %s\n (car hdr) (cdr hdr) + (rfc2047-decode-region (point-min) (point-max)) + (goto-char (point-min)) + (setq hdr-alist (mail-header-extract-no-properties))) + + (setq to (cdr (assoc 'to hdr-alist))) + (setq subject (cdr (assoc 'subject hdr-alist))) + + ;; extract allowed other headers, taking only first defined + ;; value + (dolist (hdr hdr-alist) + (if (and (member (car hdr) allowed-xtra-hdrs) +(not (assoc (car hdr) other-headers))) + (add-to-list 'other-headers hdr))) + + (notmuch-mua-mail to subject other-headers) + + ;; insert the message body - but put it in front of the signature + ;; if one is present + (goto-char (point-max)) + (if (re-search-backward message-signature-separator nil t) + (forward-line -1) + (goto-char (point-max))) + (insert body) + (push-mark)) +(set-buffer-modified-p nil) + +(message-goto-body))) + (defun notmuch-mua-mail (optional to subject other-headers rest other-args) Invoke the notmuch mail composition window. -- 1.7.8.3 ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
Re: [PATCH 4/6] test: fix emacs tests after tagging operations changes
Quoth Dmitry Kurochkin on Jan 28 at 8:41 am: After the recent tagging operations changes, functions bound to + and - in notmuch-search and notmuch-show views always read input from the minibuffer. Use kbd macros instead of calling them directly. Should this be folded into the previous patch so these tests aren't temporarily broken? ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
Re: [PATCH 6/6] emacs: separate history for operations which accept single and multiple tags
Quoth Dmitry Kurochkin on Jan 28 at 8:41 am: Some tag-related operations accept a single tag without prefix (`notmuch-select-tag-with-completion'), others accept multiple tags prefixed with '+' or '-' (`notmuch-select-tags-with-completion'). Before the change, both functions used a single default minibuffer history. This is inconvenient because you have to skip options with incompatible format when going through the history. The patch adds separate history lists for the two functions. Note that functions that accept the same input format (e.g. +, -, *) share the history list as before. --- emacs/notmuch.el | 12 ++-- 1 files changed, 10 insertions(+), 2 deletions(-) diff --git a/emacs/notmuch.el b/emacs/notmuch.el index 24b0ea3..9813e0a 100644 --- a/emacs/notmuch.el +++ b/emacs/notmuch.el @@ -76,6 +76,14 @@ For example: (defvar notmuch-query-history nil Variable to store minibuffer history for notmuch queries) +(defvar notmuch-select-tag-history nil + Variable to store notmuch tag history for + `notmuch-select-tag-with-completion'.) + +(defvar notmuch-select-tags-history nil + Variable to store notmuch tags history for + `notmuch-select-tags-with-completion'.) + Really these are minibuffer or input histories, not notmuch tag history. Also, the second line shouldn't be indented. (Definitely nits, but if you roll a new version, you might as well fix these.) (defun notmuch-tag-completions (optional search-terms) (split-string (with-output-to-string @@ -86,7 +94,7 @@ For example: (defun notmuch-select-tag-with-completion (prompt rest search-terms) (let ((tag-list (notmuch-tag-completions search-terms))) -(completing-read prompt tag-list))) +(completing-read prompt tag-list nil nil nil 'notmuch-select-tag-history))) (defun notmuch-select-tags-with-completion (optional initial-input rest search-terms) (let* ((add-tag-list (mapcar (apply-partially 'concat +) @@ -105,7 +113,7 @@ For example: map))) (delete (completing-read-multiple Operations (+add -drop): notmuch tag tag-list nil - nil initial-input + nil initial-input 'notmuch-select-tags-history (defun notmuch-update-tags (current-tags changed-tags) Update `current-tags' with `changed-tags' and return the result. ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
Re: [PATCH 4/6] test: fix emacs tests after tagging operations changes
On Sun, 29 Jan 2012 17:58:41 -0500, Austin Clements amdra...@mit.edu wrote: Quoth Dmitry Kurochkin on Jan 28 at 8:41 am: After the recent tagging operations changes, functions bound to + and - in notmuch-search and notmuch-show views always read input from the minibuffer. Use kbd macros instead of calling them directly. Should this be folded into the previous patch so these tests aren't temporarily broken? I think it is a common approach for notmuch. IIRC I sent patches which changes both code and tests, and I was asked to move the tests to a separate patch. So I will leave it as is for now. Though if you point me to a relevant discussion or policy, which says that the tests should be merged, I would be happy to do it. Regards, Dmitry ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
Re: [PATCH 8/6] emacs: use message ids instead of thread id in `notmuch-show-operate-all'
Eighth in the increasingly inaccurately named six patch series... Quoth Dmitry Kurochkin on Jan 28 at 9:59 am: Before the change, `notmuch-show-operate-all' used thread id for notmuch tag search. This could result in tagging unexpected messages that were added to the thread after the notmuch-show buffer was created. The patch changes `notmuch-show-operate-all' to use ids of shown messages to fix this. Are you planning to roll this into your earlier patch? --- emacs/notmuch-show.el | 23 ++- 1 files changed, 22 insertions(+), 1 deletions(-) diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el index 2ca4d92..e606224 100644 --- a/emacs/notmuch-show.el +++ b/emacs/notmuch-show.el @@ -1170,6 +1170,15 @@ All currently available key bindings: (notmuch-show-move-to-message-top) t)) +(defun notmuch-show-mapc (function) + Iterate through all messages with +`notmuch-show-goto-message-next' and call `function' for side +effects. `function' should be FUNCTION. + (save-excursion +(goto-char (point-min)) +(loop do (funcall function) + while (notmuch-show-goto-message-next + ;; Functions relating to the visibility of messages and their ;; components. @@ -1222,6 +1231,18 @@ Some useful entries are: Return the message id of the current message. (concat id:\ (notmuch-show-get-prop :id) \)) +(defun notmuch-show-get-messages-ids () + Return all message ids of currently shown messages. currently shown could mean visible on the screen, which is not what you mean. You also don't mean open messages. Maybe Return all message ids of messages in this show buffer? + (let ((message-ids)) +(notmuch-show-mapc + (lambda () (push (notmuch-show-get-message-id) message-ids))) +message-ids)) + +(defun notmuch-show-get-messages-ids-search () + Return a search string for all message ids of currently shown +messages. Same. + (mapconcat 'identity (notmuch-show-get-messages-ids) or )) + ;; dme: Would it make sense to use a macro for many of these? (defun notmuch-show-get-filename () @@ -1496,7 +1517,7 @@ i.e. a list of tags to change with '+' and '-' prefixes. `Changed-tags' is a list of tag operations for \notmuch tag\, i.e. a list of tags to change with '+' and '-' prefixes. (interactive (notmuch-select-tags-with-completion nil notmuch-show-thread-id)) - (apply 'notmuch-tag notmuch-show-thread-id changed-tags) + (apply 'notmuch-tag (notmuch-show-get-messages-ids-search) changed-tags) (save-excursion (goto-char (point-min)) (loop do (let* ((current-tags (notmuch-show-get-tags)) ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
Bug: emacs 23.2 doesn't like ido-completing-read
Hello I have been experimenting with notmuch-always-prompt-for-sender on my debian stable setup (emacs 23.2.1) and it doesn't like ido-completing-read. It goes to the minibuffer and then it seems to be impossible to exit the minibuffer. I can find an emacs bug report #3274 and some discussion http://comments.gmane.org/gmane.emacs.bugs/27856 which indicates that it is a problem with ido initialisation. Unfortunately I can't get from there to a solution (except upgrade emacs). Many thanks Mark ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
Re: [PATCH 1/6] emacs: move tag format validation to `notmuch-tag' function
Quoth Dmitry Kurochkin on Jan 30 at 2:54 am: Hi Austin. On Sun, 29 Jan 2012 16:34:27 -0500, Austin Clements amdra...@mit.edu wrote: One philosophical nit below, but not enough to hold this up. Quoth Dmitry Kurochkin on Jan 28 at 8:41 am: Before the change, tag format validation was done in `notmuch-search-operate-all' function only. The patch moves it down to `notmuch-tag', so that all users of that function get input validation. --- emacs/notmuch.el | 12 ++-- 1 files changed, 6 insertions(+), 6 deletions(-) diff --git a/emacs/notmuch.el b/emacs/notmuch.el index 72f78ed..84d7d0a 100644 --- a/emacs/notmuch.el +++ b/emacs/notmuch.el @@ -522,6 +522,12 @@ Note: Other code should always use this function alter tags of messages instead of running (notmuch-call-notmuch-process \tag\ ..) directly, so that hooks specified in notmuch-before-tag-hook and notmuch-after-tag-hook will be run. + ;; Perform some validation + (when (null tags) (error No tags given)) Since this is a non-interactive function and hence is meant to be invoked programmatically, I would expect it to accept zero tags. Unlike the following check, this is a UI-level check and thus, I believe, belongs in interactive functions (even if that requires a little duplication). Agreed. Though I would hate to add the same check to each tag operation. Perhaps this check can go to `notmuch-select-tags-with-completion'? This is not the main patch in the series. So I think I would prefer not to make v2 because of this issue. If we come up with a good (i.e. no duplication) solution, I will prepare a separate patch for it. What about not giving any error for no tags? As a user, if I delete the whole tags prompt including the +/- operator, that's a very explicit action and it's very clear what it should do (nothing). I don't need Emacs wagging its finger at me for doing something with a clear meaning. ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
Re: [PATCH 1/6] emacs: move tag format validation to `notmuch-tag' function
On Sun, 29 Jan 2012 18:16:50 -0500, Austin Clements amdra...@mit.edu wrote: Quoth Dmitry Kurochkin on Jan 30 at 2:54 am: Hi Austin. On Sun, 29 Jan 2012 16:34:27 -0500, Austin Clements amdra...@mit.edu wrote: One philosophical nit below, but not enough to hold this up. Quoth Dmitry Kurochkin on Jan 28 at 8:41 am: Before the change, tag format validation was done in `notmuch-search-operate-all' function only. The patch moves it down to `notmuch-tag', so that all users of that function get input validation. --- emacs/notmuch.el | 12 ++-- 1 files changed, 6 insertions(+), 6 deletions(-) diff --git a/emacs/notmuch.el b/emacs/notmuch.el index 72f78ed..84d7d0a 100644 --- a/emacs/notmuch.el +++ b/emacs/notmuch.el @@ -522,6 +522,12 @@ Note: Other code should always use this function alter tags of messages instead of running (notmuch-call-notmuch-process \tag\ ..) directly, so that hooks specified in notmuch-before-tag-hook and notmuch-after-tag-hook will be run. + ;; Perform some validation + (when (null tags) (error No tags given)) Since this is a non-interactive function and hence is meant to be invoked programmatically, I would expect it to accept zero tags. Unlike the following check, this is a UI-level check and thus, I believe, belongs in interactive functions (even if that requires a little duplication). Agreed. Though I would hate to add the same check to each tag operation. Perhaps this check can go to `notmuch-select-tags-with-completion'? This is not the main patch in the series. So I think I would prefer not to make v2 because of this issue. If we come up with a good (i.e. no duplication) solution, I will prepare a separate patch for it. What about not giving any error for no tags? As a user, if I delete the whole tags prompt including the +/- operator, that's a very explicit action and it's very clear what it should do (nothing). I don't need Emacs wagging its finger at me for doing something with a clear meaning. Sure, let's try it. I am always hesitant to do changes like this to avoid boring discussions on what is better. I hope nobody would argue with this change :) Regards, Dmitry ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
Re: Bug?: notmuch-search-show-thread shows several threads; only one containing matching messages
Hi Jani, notmuch developers, executive summary: notmuch almangamates several e-mail threads into one notmuch-thread, I consider this a bug: * Jani Nikula j...@nikula.org [26. Jan. 2012]: On Thu, 26 Jan 2012 13:44:50 +0100, Gregor Zattler telegr...@gmx.net wrote: * Jameson Graef Rollins jroll...@finestructure.net [25. Jan. 2012]: On Wed, 25 Jan 2012 20:19:03 -0500, Austin Clements amdra...@mit.edu wrote: One very common cause of this is someone using reply to get an initial set of recipients, but then replacing the entire message and subject (presumably without realizing that the mail is still tracking what it was a reply to). This can also happen if someone intentionally replies to multiple messages (though few mail clients support this), or if there was a message ID collision. This is a very common occurrence for me as well. I would put money down that this is what you're seeing. I thought about this too and this is why I checked for any occurrence of Message-IDs in the other emails: | I isolated the thread I was interested in, | extracted the message ids of its messages and greped the rest of | the messages for this message ids: no matches.[2] Therefore no of | the rests messages are part of the thread I was interested in perhaps there was a logic error in how I did this: | [2] grep -I ^Message-Id: /tmp/thread-I-m-interested-in.mbox |sed -e s/Message-Id: //I -e s/$// really.mid | grep -I -F really.mid rest.mbox | -- no match /tmp/thread-I-m-interested-in.mbox is a mbox with messages I'minterested in, the real ones. really.mid is a list of Message-IDs of these real emails. rest.mbox is a mbox with the other emails, Emacs showed in his notmuch show buffer but are other threads. Since there is no match I concluded, the threads are not linked. Perhaps I made a mistake. I'l retest it and report again. But right now I don't have the time to do this. I re-did it. This time I used the Emacs interface, searched for folder:orgmode date 64 bit 32 and in the notmuch-search -buffer I used notmuch-search-stash-thread-id to get the internal thread-number. I then did a notmuch show --format=mbox thread:000108e0 thread.mbox opened this mbox with mutt, saved the one thread about dates before 1970 in one maildir `date64bit32-I-am-interested-in.mailbox' and the rest in a maildir `other-e-mails.mailbox'. I produced a list of all Message-Ids of the interesting thread by doing rgrep -E -i ^Message-Id:[[:space:]] date64bit32-I-am-interested-in.mailbox|egrep -o [^]+@[^]+ date64bit32-I-am-interested-in.mid and searched for this strings in the other e-mails: rgrep -F date64bit32-I-am-interested-in.mid other-e-mails.mailbox No hits. I also did it the other way around: rgrep -E -i ^Message-Id:[[:space:]] other-e-mails.mailbox|egrep -o [^]+@[^]+ other-e-mails.mid rgrep -F other-e-mails.mid date64bit32-I-am-interested-in.mailbox No hits. (I spared me the hassle to search for the Message-Ids in correct headers only, there are simply no hits anywhere in this other e-mails. Thus I conclude that notmuch amalgamates different e-mail-threads into one as represented by one thread-id. I consider this a bug. If anybody is interested I can email her/him the mbox file with the relevant thread (minus privacy relevant headers / 300 KiB gzipped). Do you have an mbox file in the maildir indexed by notmuch? That seems like the issue. I don't think so: I rgreped for files with more than 1 line beginning with Message-Id. I got 38 hits. I looked at all of them, they are no mbox files (at least no valid ones) but e-mails with other e-mails attached, or cited or in one case a multipart/mixed message with plain text part and html part. Nonetheless I isolated all Message-Ids from these 38 files, eliminated some html artefacts and greped for this in date64bit32-I-am-interested-in.mailbox and other-e-mails.mailbox: No hits with either file. I also did it the other way around: Searching for the Message-ids of the two sets in the 38 potential mbox files: No hit. Ciao, Gregor -- -... --- .-. . -.. ..--.. ...-.- ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
Re: [PATCH 3/6] emacs: make + and - tagging operations more robust
Hi Austin. The below changes will be send as v2 soon. On Sun, 29 Jan 2012 17:57:10 -0500, Austin Clements amdra...@mit.edu wrote: I'm looking forward to having this. I think it'll streamline tagging operations. Quoth Dmitry Kurochkin on Jan 28 at 8:41 am: Before the change, + and - tagging operations in notmuch-search and notmuch-show views accepted only a single tag. The patch makes them use the recently added `notmuch-select-tags-with-completion' function, which allows to enter multiple tags with + and - prefixes. So after the change, + and - bindings allow to both add and remove multiple tags. The only difference between + and - is the minibuffer initial input (+ and - respectively). This patch was a little difficult to review because it was largish and the diff happened to contain a bunch of forward references. If it's convenient (don't bother if it's not), could you divide up the next version a little? Something simple like sending the show changes as a separate patch would probably make it a lot easier. done --- emacs/notmuch-show.el | 65 +++ emacs/notmuch.el | 165 + 2 files changed, 107 insertions(+), 123 deletions(-) diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el index 84ac624..03eadfb 100644 --- a/emacs/notmuch-show.el +++ b/emacs/notmuch-show.el @@ -38,8 +38,9 @@ (declare-function notmuch-call-notmuch-process notmuch (rest args)) (declare-function notmuch-fontify-headers notmuch nil) -(declare-function notmuch-select-tag-with-completion notmuch (prompt rest search-terms)) +(declare-function notmuch-select-tags-with-completion notmuch (optional initial-input rest search-terms)) (declare-function notmuch-search-show-thread notmuch nil) +(declare-function notmuch-update-tags notmuch (current-tags changed-tags)) (defcustom notmuch-message-headers '(Subject To Cc Date) Headers that should be shown in a message, in this order. @@ -1267,7 +1268,7 @@ Some useful entries are: (defun notmuch-show-mark-read () Mark the current message as read. - (notmuch-show-remove-tag unread)) + (notmuch-show-tag-message -unread)) ;; Functions for getting attributes of several messages in the current ;; thread. @@ -1470,51 +1471,33 @@ than only the current message. (message (format Command '%s' exited abnormally with code %d shell-command exit-code -(defun notmuch-show-add-tags-worker (current-tags add-tags) - Add to `current-tags' with any tags from `add-tags' not -currently present and return the result. - (let ((result-tags (copy-sequence current-tags))) -(mapc (lambda (add-tag) - (unless (member add-tag current-tags) - (setq result-tags (push add-tag result-tags - add-tags) -(sort result-tags 'string))) - -(defun notmuch-show-del-tags-worker (current-tags del-tags) - Remove any tags in `del-tags' from `current-tags' and return -the result. - (let ((result-tags (copy-sequence current-tags))) -(mapc (lambda (del-tag) - (setq result-tags (delete del-tag result-tags))) - del-tags) -result-tags)) - -(defun notmuch-show-add-tag (rest toadd) - Add a tag to the current message. - (interactive - (list (notmuch-select-tag-with-completion Tag to add: ))) +(defun notmuch-show-tag-message (rest changed-tags) + Change tags for the current message. +`Changed-tags' is a list of tag operations for \notmuch tag\, +i.e. a list of tags to change with '+' and '-' prefixes. Ticks in a docstring indicate functions (and will be hyperlinked as such by describe-function). Typically, argument names are indicated by writing them in all caps. Thanks for the explanation. Fixed. Also, it probably makes more sense to reference `notmuch-tag' than notmuch tag, since this is Lisp land (and, since that will be helpfully hyperlinked, you probably don't need to explain changed-tags here). Makes sense, done. (let* ((current-tags (notmuch-show-get-tags)) -(new-tags (notmuch-show-add-tags-worker current-tags toadd))) - +(new-tags (notmuch-update-tags current-tags changed-tags))) (unless (equal current-tags new-tags) - (apply 'notmuch-tag (notmuch-show-get-message-id) -(mapcar (lambda (s) (concat + s)) toadd)) + (apply 'notmuch-tag (notmuch-show-get-message-id) changed-tags) (notmuch-show-set-tags new-tags -(defun notmuch-show-remove-tag (rest toremove) - Remove a tag from the current message. - (interactive - (list (notmuch-select-tag-with-completion - Tag to remove: (notmuch-show-get-message-id +(defun notmuch-show-tag (optional initial-input) + Change tags for the current message, read input from the minibuffer. + (interactive) + (let ((changed-tags
Re: [PATCH 6/6] emacs: separate history for operations which accept single and multiple tags
On Sun, 29 Jan 2012 18:02:29 -0500, Austin Clements amdra...@mit.edu wrote: Quoth Dmitry Kurochkin on Jan 28 at 8:41 am: Some tag-related operations accept a single tag without prefix (`notmuch-select-tag-with-completion'), others accept multiple tags prefixed with '+' or '-' (`notmuch-select-tags-with-completion'). Before the change, both functions used a single default minibuffer history. This is inconvenient because you have to skip options with incompatible format when going through the history. The patch adds separate history lists for the two functions. Note that functions that accept the same input format (e.g. +, -, *) share the history list as before. --- emacs/notmuch.el | 12 ++-- 1 files changed, 10 insertions(+), 2 deletions(-) diff --git a/emacs/notmuch.el b/emacs/notmuch.el index 24b0ea3..9813e0a 100644 --- a/emacs/notmuch.el +++ b/emacs/notmuch.el @@ -76,6 +76,14 @@ For example: (defvar notmuch-query-history nil Variable to store minibuffer history for notmuch queries) +(defvar notmuch-select-tag-history nil + Variable to store notmuch tag history for + `notmuch-select-tag-with-completion'.) + +(defvar notmuch-select-tags-history nil + Variable to store notmuch tags history for + `notmuch-select-tags-with-completion'.) + Really these are minibuffer or input histories, not notmuch tag history. Also, the second line shouldn't be indented. (Definitely nits, but if you roll a new version, you might as well fix these.) fixed Regards, Dmitry (defun notmuch-tag-completions (optional search-terms) (split-string (with-output-to-string @@ -86,7 +94,7 @@ For example: (defun notmuch-select-tag-with-completion (prompt rest search-terms) (let ((tag-list (notmuch-tag-completions search-terms))) -(completing-read prompt tag-list))) +(completing-read prompt tag-list nil nil nil 'notmuch-select-tag-history))) (defun notmuch-select-tags-with-completion (optional initial-input rest search-terms) (let* ((add-tag-list (mapcar (apply-partially 'concat +) @@ -105,7 +113,7 @@ For example: map))) (delete (completing-read-multiple Operations (+add -drop): notmuch tag tag-list nil - nil initial-input + nil initial-input 'notmuch-select-tags-history (defun notmuch-update-tags (current-tags changed-tags) Update `current-tags' with `changed-tags' and return the result. ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
Re: [PATCH 8/6] emacs: use message ids instead of thread id in `notmuch-show-operate-all'
EOn Sun, 29 Jan 2012 18:11:20 -0500, Austin Clements amdra...@mit.edu wrote: Eighth in the increasingly inaccurately named six patch series... Quoth Dmitry Kurochkin on Jan 28 at 9:59 am: Before the change, `notmuch-show-operate-all' used thread id for notmuch tag search. This could result in tagging unexpected messages that were added to the thread after the notmuch-show buffer was created. The patch changes `notmuch-show-operate-all' to use ids of shown messages to fix this. Are you planning to roll this into your earlier patch? I would prefer to leave it separate. --- emacs/notmuch-show.el | 23 ++- 1 files changed, 22 insertions(+), 1 deletions(-) diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el index 2ca4d92..e606224 100644 --- a/emacs/notmuch-show.el +++ b/emacs/notmuch-show.el @@ -1170,6 +1170,15 @@ All currently available key bindings: (notmuch-show-move-to-message-top) t)) +(defun notmuch-show-mapc (function) + Iterate through all messages with +`notmuch-show-goto-message-next' and call `function' for side +effects. `function' should be FUNCTION. done + (save-excursion +(goto-char (point-min)) +(loop do (funcall function) + while (notmuch-show-goto-message-next + ;; Functions relating to the visibility of messages and their ;; components. @@ -1222,6 +1231,18 @@ Some useful entries are: Return the message id of the current message. (concat id:\ (notmuch-show-get-prop :id) \)) +(defun notmuch-show-get-messages-ids () + Return all message ids of currently shown messages. currently shown could mean visible on the screen, which is not what you mean. You also don't mean open messages. Maybe Return all message ids of messages in this show buffer? Changed to messages in the current thread. That is consistent with other docstrings in notmuch-show.el. + (let ((message-ids)) +(notmuch-show-mapc + (lambda () (push (notmuch-show-get-message-id) message-ids))) +message-ids)) + +(defun notmuch-show-get-messages-ids-search () + Return a search string for all message ids of currently shown +messages. Same. fixed Regards, Dmitry + (mapconcat 'identity (notmuch-show-get-messages-ids) or )) + ;; dme: Would it make sense to use a macro for many of these? (defun notmuch-show-get-filename () @@ -1496,7 +1517,7 @@ i.e. a list of tags to change with '+' and '-' prefixes. `Changed-tags' is a list of tag operations for \notmuch tag\, i.e. a list of tags to change with '+' and '-' prefixes. (interactive (notmuch-select-tags-with-completion nil notmuch-show-thread-id)) - (apply 'notmuch-tag notmuch-show-thread-id changed-tags) + (apply 'notmuch-tag (notmuch-show-get-messages-ids-search) changed-tags) (save-excursion (goto-char (point-min)) (loop do (let* ((current-tags (notmuch-show-get-tags)) ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
[PATCH v2 00/13] emacs: more robust and consistent tagging operations
Changes in v2: * add patch to remove No tags given error from `notmuch-tag' as suggested by Austin in [1] * split patch 3 in two (search and show) for easier review * add patch with NEWS entry * rename `notmuch-{search,show}-operate-all' to `notmuch-{search,show}-tag-all' * fix other comments from Austin's reviews [2,3,4] Regards, Dmitry [1] id:20120129231650.gk17...@mit.edu [2] id:20120129225710.gg17...@mit.edu [3] id:20120129230229.gi17...@mit.edu [4] id:20120129231120.gj17...@mit.edu ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
[PATCH v2 02/13] emacs: remove text properties from `notmuch-search-get-tags' result
--- emacs/notmuch.el |2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/emacs/notmuch.el b/emacs/notmuch.el index 84d7d0a..ff46617 100644 --- a/emacs/notmuch.el +++ b/emacs/notmuch.el @@ -577,7 +577,7 @@ the messages that were tagged (let ((beg (+ (point) 1))) (re-search-forward )) (let ((end (- (point) 1))) - (split-string (buffer-substring beg end)) + (split-string (buffer-substring-no-properties beg end)) (defun notmuch-search-get-tags-region (beg end) (save-excursion -- 1.7.8.3 ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
[PATCH v2 05/13] test: fix emacs tests after tagging operations changes
After the recent tagging operations changes, functions bound to + and - in notmuch-search and notmuch-show views always read input from the minibuffer. Use kbd macros instead of calling them directly. --- test/emacs | 20 ++-- 1 files changed, 10 insertions(+), 10 deletions(-) diff --git a/test/emacs b/test/emacs index 8ca4c8a..b9c0e02 100755 --- a/test/emacs +++ b/test/emacs @@ -101,26 +101,26 @@ test_begin_subtest Add tag from search view os_x_darwin_thread=$(notmuch search --output=threads id:ddd65cda0911171950o4eea4389v86de9525e4605...@mail.gmail.com) test_emacs (notmuch-search \$os_x_darwin_thread\) (notmuch-test-wait) - (notmuch-search-add-tag \tag-from-search-view\) + (execute-kbd-macro \+tag-from-search-view\) output=$(notmuch search $os_x_darwin_thread | notmuch_search_sanitize) test_expect_equal $output thread:XXX 2009-11-18 [4/4] Jjgod Jiang, Alexander Botero-Lowry; [notmuch] Mac OS X/Darwin compatibility issues (inbox tag-from-search-view unread) test_begin_subtest Remove tag from search view test_emacs (notmuch-search \$os_x_darwin_thread\) (notmuch-test-wait) - (notmuch-search-remove-tag \tag-from-search-view\) + (execute-kbd-macro \-tag-from-search-view\) output=$(notmuch search $os_x_darwin_thread | notmuch_search_sanitize) test_expect_equal $output thread:XXX 2009-11-18 [4/4] Jjgod Jiang, Alexander Botero-Lowry; [notmuch] Mac OS X/Darwin compatibility issues (inbox unread) test_begin_subtest Add tag from notmuch-show view test_emacs (notmuch-show \$os_x_darwin_thread\) - (notmuch-show-add-tag \tag-from-show-view\) + (execute-kbd-macro \+tag-from-show-view\) output=$(notmuch search $os_x_darwin_thread | notmuch_search_sanitize) test_expect_equal $output thread:XXX 2009-11-18 [4/4] Jjgod Jiang, Alexander Botero-Lowry; [notmuch] Mac OS X/Darwin compatibility issues (inbox tag-from-show-view unread) test_begin_subtest Remove tag from notmuch-show view test_emacs (notmuch-show \$os_x_darwin_thread\) - (notmuch-show-remove-tag \tag-from-show-view\) + (execute-kbd-macro \-tag-from-show-view\) output=$(notmuch search $os_x_darwin_thread | notmuch_search_sanitize) test_expect_equal $output thread:XXX 2009-11-18 [4/4] Jjgod Jiang, Alexander Botero-Lowry; [notmuch] Mac OS X/Darwin compatibility issues (inbox unread) @@ -128,14 +128,14 @@ test_begin_subtest Message with .. in Message-Id: add_message [id]=123..456@example '[subject]=Message with .. in Message-Id' test_emacs '(notmuch-search id:\123..456@example\) (notmuch-test-wait) - (notmuch-search-add-tag search-add) - (notmuch-search-add-tag search-remove) - (notmuch-search-remove-tag search-remove) + (execute-kbd-macro +search-add) + (execute-kbd-macro +search-remove) + (execute-kbd-macro -search-remove) (notmuch-show id:\123..456@example\) (notmuch-test-wait) - (notmuch-show-add-tag show-add) - (notmuch-show-add-tag show-remove) - (notmuch-show-remove-tag show-remove)' + (execute-kbd-macro +show-add) + (execute-kbd-macro +show-remove) + (execute-kbd-macro -show-remove)' output=$(notmuch search 'id:123..456@example' | notmuch_search_sanitize) test_expect_equal $output thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Message with .. in Message-Id (inbox search-add show-add) -- 1.7.8.3 ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
[PATCH v2 07/13] emacs: add * binding for notmuch-show view
The patch adds `notmuch-show-tag-all' function bound to * in notmuch-show view. The function is similar to the `notmuch-search-tag-all' function for the notmuch-search view: it changes tags for all messages in the current thread. --- emacs/notmuch-show.el | 15 +++ 1 files changed, 15 insertions(+), 0 deletions(-) diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el index 11dab2d..0d90c1e 100644 --- a/emacs/notmuch-show.el +++ b/emacs/notmuch-show.el @@ -1073,6 +1073,7 @@ thread id. If a prefix is given, crypto processing is toggled. (define-key map c 'notmuch-show-stash-map) (define-key map = 'notmuch-show-refresh-view) (define-key map h 'notmuch-show-toggle-headers) + (define-key map * 'notmuch-show-tag-all) (define-key map - 'notmuch-show-remove-tag) (define-key map + 'notmuch-show-add-tag) (define-key map x 'notmuch-show-archive-thread-then-exit) @@ -1488,6 +1489,20 @@ TAG-CHANGES is a list of tag operations for `notmuch-tag'. initial-input (notmuch-show-get-message-id (apply 'notmuch-show-tag-message tag-changes))) +(defun notmuch-show-tag-all (rest tag-changes) + Change tags for all messages in the current thread. + +TAG-CHANGES is a list of tag operations for `notmuch-tag'. + (interactive (notmuch-read-tag-changes nil notmuch-show-thread-id)) + (apply 'notmuch-tag notmuch-show-thread-id tag-changes) + (save-excursion +(goto-char (point-min)) +(loop do (let* ((current-tags (notmuch-show-get-tags)) + (new-tags (notmuch-update-tags current-tags tag-changes))) + (unless (equal current-tags new-tags) +(notmuch-show-set-tags new-tags))) + while (notmuch-show-goto-message-next + (defun notmuch-show-add-tag () Same as `notmuch-show-tag' but sets initial input to '+'. (interactive) -- 1.7.8.3 ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
[PATCH v2 09/13] emacs: relax tag syntax check in `notmuch-tag' function
The tag syntax check in `notmuch-tag' function was too strict and did not allow nmbug tags with ::. Since the check is done for all tagging operations in Emacs UI, this basically means that no nmbug tags can be changed. The patch relaxes the tag syntax check to allow any tag names that do not include whitespace characters. --- emacs/notmuch.el |2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/emacs/notmuch.el b/emacs/notmuch.el index 5adcac5..7e8f185 100644 --- a/emacs/notmuch.el +++ b/emacs/notmuch.el @@ -557,7 +557,7 @@ notmuch-after-tag-hook will be run. ;; Perform some validation (when (null tags) (error No tags given)) (mapc (lambda (tag) - (unless (string-match-p ^[-+][-+_.[:word:]]+$ tag) + (unless (string-match-p ^[-+]\\S-+$ tag) (error Tag must be of the form `+this_tag' or `-that_tag'))) tags) (run-hooks 'notmuch-before-tag-hook) -- 1.7.8.3 ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
[PATCH v2 10/13] emacs: use message ids instead of thread id in `notmuch-show-operate-all'
Before the change, `notmuch-show-operate-all' used thread id for notmuch tag search. This could result in tagging unexpected messages that were added to the thread after the notmuch-show buffer was created. The patch changes `notmuch-show-operate-all' to use ids of shown messages to fix this. --- emacs/notmuch-show.el | 23 ++- 1 files changed, 22 insertions(+), 1 deletions(-) diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el index 0d90c1e..b115a8f 100644 --- a/emacs/notmuch-show.el +++ b/emacs/notmuch-show.el @@ -1170,6 +1170,15 @@ All currently available key bindings: (notmuch-show-move-to-message-top) t)) +(defun notmuch-show-mapc (function) + Iterate through all messages in the current thread with +`notmuch-show-goto-message-next' and call FUNCTION for side +effects. + (save-excursion +(goto-char (point-min)) +(loop do (funcall function) + while (notmuch-show-goto-message-next + ;; Functions relating to the visibility of messages and their ;; components. @@ -1222,6 +1231,18 @@ Some useful entries are: Return the message id of the current message. (concat id:\ (notmuch-show-get-prop :id) \)) +(defun notmuch-show-get-messages-ids () + Return all message ids of messages in the current thread. + (let ((message-ids)) +(notmuch-show-mapc + (lambda () (push (notmuch-show-get-message-id) message-ids))) +message-ids)) + +(defun notmuch-show-get-messages-ids-search () + Return a search string for all message ids of messages in the +current thread. + (mapconcat 'identity (notmuch-show-get-messages-ids) or )) + ;; dme: Would it make sense to use a macro for many of these? (defun notmuch-show-get-filename () @@ -1494,7 +1515,7 @@ TAG-CHANGES is a list of tag operations for `notmuch-tag'. TAG-CHANGES is a list of tag operations for `notmuch-tag'. (interactive (notmuch-read-tag-changes nil notmuch-show-thread-id)) - (apply 'notmuch-tag notmuch-show-thread-id tag-changes) + (apply 'notmuch-tag (notmuch-show-get-messages-ids-search) tag-changes) (save-excursion (goto-char (point-min)) (loop do (let* ((current-tags (notmuch-show-get-tags)) -- 1.7.8.3 ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
[PATCH v2 12/13] emacs: accept empty tag list in `notmuch-tag'
Since `notmuch-tag' is a non-interactive function and hence is meant to be invoked programmatically, it should accept zero tags. Also, the tagging operations (bound to *, +, -) would accept empty input without an error. --- emacs/notmuch.el | 10 +- 1 files changed, 5 insertions(+), 5 deletions(-) diff --git a/emacs/notmuch.el b/emacs/notmuch.el index 7e8f185..1b7a835 100644 --- a/emacs/notmuch.el +++ b/emacs/notmuch.el @@ -555,15 +555,15 @@ messages instead of running (notmuch-call-notmuch-process \tag\ ..) directly, so that hooks specified in notmuch-before-tag-hook and notmuch-after-tag-hook will be run. ;; Perform some validation - (when (null tags) (error No tags given)) (mapc (lambda (tag) (unless (string-match-p ^[-+]\\S-+$ tag) (error Tag must be of the form `+this_tag' or `-that_tag'))) tags) - (run-hooks 'notmuch-before-tag-hook) - (apply 'notmuch-call-notmuch-process -(append (list tag) tags (list -- query))) - (run-hooks 'notmuch-after-tag-hook)) + (unless (null tags) +(run-hooks 'notmuch-before-tag-hook) +(apply 'notmuch-call-notmuch-process tag + (append tags (list -- query))) +(run-hooks 'notmuch-after-tag-hook))) (defcustom notmuch-before-tag-hook nil Hooks that are run before tags of a message are modified. -- 1.7.8.3 ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
Re: [PATCH v2 10/13] emacs: use message ids instead of thread id in `notmuch-show-operate-all'
Quoth Dmitry Kurochkin on Jan 30 at 6:26 am: Before the change, `notmuch-show-operate-all' used thread id for notmuch-show-tag-all? notmuch tag search. This could result in tagging unexpected messages that were added to the thread after the notmuch-show buffer was created. The patch changes `notmuch-show-operate-all' to use ids of shown messages to fix this. --- If you move this patch before the one that introduces notmuch-show-tag-all, you could do it this way from the beginning. emacs/notmuch-show.el | 23 ++- 1 files changed, 22 insertions(+), 1 deletions(-) diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el index 0d90c1e..b115a8f 100644 --- a/emacs/notmuch-show.el +++ b/emacs/notmuch-show.el @@ -1170,6 +1170,15 @@ All currently available key bindings: (notmuch-show-move-to-message-top) t)) +(defun notmuch-show-mapc (function) + Iterate through all messages in the current thread with +`notmuch-show-goto-message-next' and call FUNCTION for side +effects. + (save-excursion +(goto-char (point-min)) +(loop do (funcall function) + while (notmuch-show-goto-message-next + ;; Functions relating to the visibility of messages and their ;; components. @@ -1222,6 +1231,18 @@ Some useful entries are: Return the message id of the current message. (concat id:\ (notmuch-show-get-prop :id) \)) +(defun notmuch-show-get-messages-ids () + Return all message ids of messages in the current thread. + (let ((message-ids)) +(notmuch-show-mapc + (lambda () (push (notmuch-show-get-message-id) message-ids))) +message-ids)) + +(defun notmuch-show-get-messages-ids-search () + Return a search string for all message ids of messages in the +current thread. + (mapconcat 'identity (notmuch-show-get-messages-ids) or )) + ;; dme: Would it make sense to use a macro for many of these? (defun notmuch-show-get-filename () @@ -1494,7 +1515,7 @@ TAG-CHANGES is a list of tag operations for `notmuch-tag'. TAG-CHANGES is a list of tag operations for `notmuch-tag'. (interactive (notmuch-read-tag-changes nil notmuch-show-thread-id)) - (apply 'notmuch-tag notmuch-show-thread-id tag-changes) + (apply 'notmuch-tag (notmuch-show-get-messages-ids-search) tag-changes) (save-excursion (goto-char (point-min)) (loop do (let* ((current-tags (notmuch-show-get-tags)) ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
Re: [PATCH v2 11/13] emacs: code cleanup in `notmuch-show-operate-all', no functional changes
notmuch-show-tag-all, in the first line of the commit message. As in the previous patch, if the previous patch comes earlier in the series, notmuch-show-tag-all could be written this way initially. Quoth Dmitry Kurochkin on Jan 30 at 6:26 am: Use `notmuch-show-mapc' function instead of a custom `loop'. --- emacs/notmuch-show.el | 13 ++--- 1 files changed, 6 insertions(+), 7 deletions(-) diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el index b115a8f..69381ac 100644 --- a/emacs/notmuch-show.el +++ b/emacs/notmuch-show.el @@ -1516,13 +1516,12 @@ TAG-CHANGES is a list of tag operations for `notmuch-tag'. TAG-CHANGES is a list of tag operations for `notmuch-tag'. (interactive (notmuch-read-tag-changes nil notmuch-show-thread-id)) (apply 'notmuch-tag (notmuch-show-get-messages-ids-search) tag-changes) - (save-excursion -(goto-char (point-min)) -(loop do (let* ((current-tags (notmuch-show-get-tags)) - (new-tags (notmuch-update-tags current-tags tag-changes))) -(unless (equal current-tags new-tags) - (notmuch-show-set-tags new-tags))) - while (notmuch-show-goto-message-next + (notmuch-show-mapc + (lambda () + (let* ((current-tags (notmuch-show-get-tags)) + (new-tags (notmuch-update-tags current-tags tag-changes))) + (unless (equal current-tags new-tags) + (notmuch-show-set-tags new-tags)) (defun notmuch-show-add-tag () Same as `notmuch-show-tag' but sets initial input to '+'. -- Austin Clements MIT/'06/PhD/CSAIL amdra...@mit.edu http://web.mit.edu/amdragon Somewhere in the dream we call reality you will find me, searching for the reality we call dreams. ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
Re: [PATCH v2 13/13] NEWS: document Emacs UI tagging operations changes
Quoth Dmitry Kurochkin on Jan 30 at 6:26 am: --- NEWS | 18 ++ 1 files changed, 18 insertions(+), 0 deletions(-) diff --git a/NEWS b/NEWS index 2acdce5..dc3acc4 100644 --- a/NEWS +++ b/NEWS @@ -39,6 +39,24 @@ Reply to sender and search modes, 'r' has been bound to reply to sender, replacing reply to all, which now has key binding 'R'. +More robust and consistent tagging operations I don't think robust is the word you're looking for (same thing with some of the commit messages). In this context, I interpret robust as meaning the tagging operations could do incorrect things and have been fixed. Maybe flexible or capable? + + All tagging operations (+, -, *) now accept multiple tags with + + or - prefix, like * operation in notmuch-search view before. Isn't this functionality of * also new in 0.12? + + * operation (`notmuch-show-tag-all`) is now available in Did you mean ' instead of ` at the end? + notmuch-show view. + + `Notmuch-show-{add,remove}-tag' functions no longer accept tag + argument, `notmuch-show-tag-message' should be used instead. Custom + bindings using these functions should be updated, e.g.: + +(notmuch-show-remove-tag unread) + + should be changed to: + +(notmuch-show-tag-message -unread) + Library changes --- ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
Re: [PATCH v2 13/13] NEWS: document Emacs UI tagging operations changes
On Mon, 30 Jan 2012 00:04:02 -0500, Austin Clements amdra...@mit.edu wrote: Quoth Dmitry Kurochkin on Jan 30 at 6:26 am: --- NEWS | 18 ++ 1 files changed, 18 insertions(+), 0 deletions(-) diff --git a/NEWS b/NEWS index 2acdce5..dc3acc4 100644 --- a/NEWS +++ b/NEWS @@ -39,6 +39,24 @@ Reply to sender and search modes, 'r' has been bound to reply to sender, replacing reply to all, which now has key binding 'R'. +More robust and consistent tagging operations I don't think robust is the word you're looking for (same thing with some of the commit messages). In this context, I interpret robust as meaning the tagging operations could do incorrect things and have been fixed. Maybe flexible or capable? Changed to flexible. + + All tagging operations (+, -, *) now accept multiple tags with + + or - prefix, like * operation in notmuch-search view before. Isn't this functionality of * also new in 0.12? No, * in notmuch-search was always working this way. + + * operation (`notmuch-show-tag-all`) is now available in Did you mean ' instead of ` at the end? No. Regards, Dmitry + notmuch-show view. + + `Notmuch-show-{add,remove}-tag' functions no longer accept tag + argument, `notmuch-show-tag-message' should be used instead. Custom + bindings using these functions should be updated, e.g.: + +(notmuch-show-remove-tag unread) + + should be changed to: + +(notmuch-show-tag-message -unread) + Library changes --- ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
[PATCH v3 04/12] emacs: make + and - tagging operations in notmuch-show more flexible
Before the change, + and - tagging operations in notmuch-show view accepted only a single tag. The patch makes them use the recently added `notmuch-read-tag-changes' function, which allows to enter multiple tags with + and - prefixes. So after the change, + and - bindings in notmuch-show view allow to both add and remove multiple tags. The only difference between + and - is the minibuffer initial input (+ and - respectively). --- emacs/notmuch-show.el | 64 +--- 1 files changed, 23 insertions(+), 41 deletions(-) diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el index 84ac624..11dab2d 100644 --- a/emacs/notmuch-show.el +++ b/emacs/notmuch-show.el @@ -38,8 +38,9 @@ (declare-function notmuch-call-notmuch-process notmuch (rest args)) (declare-function notmuch-fontify-headers notmuch nil) -(declare-function notmuch-select-tag-with-completion notmuch (prompt rest search-terms)) +(declare-function notmuch-read-tag-changes notmuch (optional initial-input rest search-terms)) (declare-function notmuch-search-show-thread notmuch nil) +(declare-function notmuch-update-tags notmuch (current-tags tag-changes)) (defcustom notmuch-message-headers '(Subject To Cc Date) Headers that should be shown in a message, in this order. @@ -1267,7 +1268,7 @@ Some useful entries are: (defun notmuch-show-mark-read () Mark the current message as read. - (notmuch-show-remove-tag unread)) + (notmuch-show-tag-message -unread)) ;; Functions for getting attributes of several messages in the current ;; thread. @@ -1470,51 +1471,32 @@ than only the current message. (message (format Command '%s' exited abnormally with code %d shell-command exit-code -(defun notmuch-show-add-tags-worker (current-tags add-tags) - Add to `current-tags' with any tags from `add-tags' not -currently present and return the result. - (let ((result-tags (copy-sequence current-tags))) -(mapc (lambda (add-tag) - (unless (member add-tag current-tags) - (setq result-tags (push add-tag result-tags - add-tags) -(sort result-tags 'string))) - -(defun notmuch-show-del-tags-worker (current-tags del-tags) - Remove any tags in `del-tags' from `current-tags' and return -the result. - (let ((result-tags (copy-sequence current-tags))) -(mapc (lambda (del-tag) - (setq result-tags (delete del-tag result-tags))) - del-tags) -result-tags)) - -(defun notmuch-show-add-tag (rest toadd) - Add a tag to the current message. - (interactive - (list (notmuch-select-tag-with-completion Tag to add: ))) +(defun notmuch-show-tag-message (rest tag-changes) + Change tags for the current message. +TAG-CHANGES is a list of tag operations for `notmuch-tag'. (let* ((current-tags (notmuch-show-get-tags)) -(new-tags (notmuch-show-add-tags-worker current-tags toadd))) - +(new-tags (notmuch-update-tags current-tags tag-changes))) (unless (equal current-tags new-tags) - (apply 'notmuch-tag (notmuch-show-get-message-id) -(mapcar (lambda (s) (concat + s)) toadd)) + (apply 'notmuch-tag (notmuch-show-get-message-id) tag-changes) (notmuch-show-set-tags new-tags -(defun notmuch-show-remove-tag (rest toremove) - Remove a tag from the current message. - (interactive - (list (notmuch-select-tag-with-completion - Tag to remove: (notmuch-show-get-message-id +(defun notmuch-show-tag (optional initial-input) + Change tags for the current message, read input from the minibuffer. + (interactive) + (let ((tag-changes (notmuch-read-tag-changes + initial-input (notmuch-show-get-message-id +(apply 'notmuch-show-tag-message tag-changes))) - (let* ((current-tags (notmuch-show-get-tags)) -(new-tags (notmuch-show-del-tags-worker current-tags toremove))) +(defun notmuch-show-add-tag () + Same as `notmuch-show-tag' but sets initial input to '+'. + (interactive) + (notmuch-show-tag +)) -(unless (equal current-tags new-tags) - (apply 'notmuch-tag (notmuch-show-get-message-id) -(mapcar (lambda (s) (concat - s)) toremove)) - (notmuch-show-set-tags new-tags +(defun notmuch-show-remove-tag () + Same as `notmuch-show-tag' but sets initial input to '-'. + (interactive) + (notmuch-show-tag -)) (defun notmuch-show-toggle-headers () Toggle the visibility of the current message headers. @@ -1559,7 +1541,7 @@ argument, hide all of the messages. (defun notmuch-show-archive-thread-internal (show-next) ;; Remove the tag from the current set of messages. (goto-char (point-min)) - (loop do (notmuch-show-remove-tag inbox) + (loop do (notmuch-show-tag-message -inbox) until (not (notmuch-show-goto-message-next))) ;; Move to the next item in the search results, if any. (let ((parent-buffer notmuch-show-parent-buffer)) -- 1.7.8.3
[PATCH v2 2/2] emacs: add `notmuch-show-stash-mlarchive-link{, -and-go}'
* emacs/notmuch-show.el (notmuch-show-stash-mlarchive-link-alist): New defcustom of type `alist' (key = name, value = URI), containing Mailing List Archive URI's for searching by Message-Id. (notmuch-show-stash-mlarchive-link-default): New defcustom, default MLA to use when `notmuch-show-stash-mlarchive-link' received no user input whatsoever. Available choices are generated using the contents of `notmuch-show-stash-mlarchive-link-alist'. (notmuch-show-stash-map): Added keybinds l and L for `notmuch-show-stash-mlarchive-link' respectively `notmuch-show-stash-mlarchive-link-and-go'. (notmuch-show-stash-mlarchive-link): New function, stashes a URI pointing to the current message at one of the MLAs configured in `notmuch-show-stash-mlarchive-link-alist'. Prompts user with `completing-read' if not provided with an MLA key. (notmuch-show-stash-mlarchive-link-and-go): New function, uses `notmuch-show-stash-mlarchive-link' to stash a URI, and then visits it using the browser configured in `browse-url-browser-function'. * test/emacs Expanded subtest Stashing in notmuch-show wrt new functions `notmuch-show-stash-mlarchive-link{,-and-go}'. Based on original work [1] by David Edmondson d...@dme.org. [1] id:1327397873-20596-1-git-send-email-...@dme.org --- Addressed comments by David Edmondson [2] and Dmitry Kurochkin [3]. [2] id:cunsjj1jyfj@hotblack-desiato.hh.sledj.net [3] id:87zkd9je5j@gmail.com emacs/notmuch-show.el | 61 + test/emacs|8 +- 2 files changed, 68 insertions(+), 1 deletions(-) diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el index b13d088..3d1312c 100644 --- a/emacs/notmuch-show.el +++ b/emacs/notmuch-show.el @@ -124,6 +124,35 @@ indentation. (const :tag View interactively notmuch-show-interactively-view-part))) +(defcustom notmuch-show-stash-mlarchive-link-alist + '((Gmane . http://mid.gmane.org/;) +(MARC . http://marc.info/?i=;) +(Mail Archive, The . http://mail-archive.com/search?l=midq=;) +;; FIXME: can these services be searched by `Message-Id' ? +;; (MarkMail . http://markmail.org/;) +;; (Nabble . http://nabble.com/;) +;; (opensubscriber . http://opensubscriber.com/;) +) + List of Mailing List Archives to use when stashing links. + +These URIs are concatenated with the current message's +Message-Id in `notmuch-show-stash-mlarchive-link'. + :type '(alist :key-type (string :tag Name) + :value-type (string :tag URL)) + :group 'notmuch-show) + +(defcustom notmuch-show-stash-mlarchive-link-default Gmane + Default Mailing List Archive to use when stashing links. + +This is used when `notmuch-show-stash-mlarchive-link' isn't +provided with an MLA argument nor `completing-read' input. + :type `(choice + ,@(mapcar +(lambda (mla) + (list 'const :tag (car mla) :value (car mla))) +notmuch-show-stash-mlarchive-link-alist)) + :group 'notmuch-show) + (defmacro with-current-notmuch-show-message (rest body) Evaluate body with current buffer set to the text of current message `(save-excursion @@ -1048,6 +1077,8 @@ thread id. If a prefix is given, crypto processing is toggled. (define-key map s 'notmuch-show-stash-subject) (define-key map T 'notmuch-show-stash-tags) (define-key map t 'notmuch-show-stash-to) +(define-key map l 'notmuch-show-stash-mlarchive-link) +(define-key map L 'notmuch-show-stash-mlarchive-link-and-go) map) Submap for stash commands) (fset 'notmuch-show-stash-map notmuch-show-stash-map) @@ -1640,6 +1671,36 @@ buffer. (interactive) (notmuch-common-do-stash (notmuch-show-get-to))) +(defun notmuch-show-stash-mlarchive-link (optional mla) + Copy an ML Archive URI for the current message to the kill-ring. + +This presumes that the message is available at the selected Mailing List Archive. + +If optional argument MLA is non-nil, use the provided key instead of prompting +the user (see `notmuch-show-stash-mlarchive-link-alist'). + (interactive) + (notmuch-common-do-stash + (concat (cdr (assoc +(or mla +(let ((completion-ignore-case t)) + (completing-read + Mailing List Archive: + notmuch-show-stash-mlarchive-link-alist + nil t nil nil notmuch-show-stash-mlarchive-link-default))) +notmuch-show-stash-mlarchive-link-alist)) + (notmuch-show-get-message-id t + +(defun notmuch-show-stash-mlarchive-link-and-go (optional mla) + Copy an ML Archive URI for the current message to the kill-ring and visit it. + +This presumes that the message is available at the selected Mailing List Archive. + +If optional argument MLA is non-nil, use the provided key instead of prompting +the user (see
Re: [RFC] Re: [PATCH] emacs: Add `notmuch-show-stash-gmane' and `notmuch-show-stash-gmane-and-go'.
On Fri, 27 Jan 2012 20:36:40 +0400, Dmitry Kurochkin dmitry.kuroch...@gmail.com wrote: On Fri, 27 Jan 2012 09:42:23 +0100, Pieter Praet pie...@praet.org wrote: On Thu, 26 Jan 2012 14:40:26 +, David Edmondson d...@dme.org wrote: In general, I like this. - I think that the stash function(s) should take an optional argument specifying the archive to use. That will make testing simpler and also allow people to produce preferred bindings more easily. Agreed. In fact, apparently that last patch [1] of mine made the test suite hang @ emacs:Stashing in notmuch-show due to it waiting for `completing-read' to finish... Sorry for that. - Message archive: feels better than ML Archive: , but I don't really care. Agreed. FWIW I believe Mailing list archive would be better. Agreed. Regards, Dmitry - Don't base the patch on the thing that I posted, just on master from the repository - no need to make David's life harder. Seeing as how it was only a minor improvement to your idea (and further discussion/correction was probably appropriate), I intended for you to squash it into your original patch. Anyways, patch (relative to master) follows... Peace -- Pieter [1] id:1327583610-30085-1-git-send-email-pie...@praet.org ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch Peace -- Pieter ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch