[PATCH v2 11/13] emacs: code cleanup in `notmuch-show-operate-all', no functional changes

2012-01-29 Thread Austin Clements
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'

2012-01-29 Thread Austin Clements
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

2012-01-29 Thread Austin Clements
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

2012-01-29 Thread Mark Walters

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.

2012-01-29 Thread Mark Walters
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.

2012-01-29 Thread Mark Walters
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.

2012-01-29 Thread Mark Walters
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

2012-01-29 Thread Mark Walters
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

2012-01-29 Thread Mark Walters
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.

2012-01-29 Thread Mark Walters
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

2012-01-29 Thread Mark Walters

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

2012-01-29 Thread Austin Clements
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'

2012-01-29 Thread Austin Clements
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

2012-01-29 Thread Justus Winter
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

2012-01-29 Thread Justus Winter
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

2012-01-29 Thread Justus Winter
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

2012-01-29 Thread Justus Winter
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

2012-01-29 Thread Austin Clements
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

2012-01-29 Thread Justus Winter
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

2012-01-29 Thread Austin Clements
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

2012-01-29 Thread Austin Clements
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)

2012-01-29 Thread Justus Winter
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

2012-01-29 Thread Austin Clements
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

2012-01-29 Thread Jameson Graef Rollins
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

2012-01-29 Thread Jameson Graef Rollins
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

2012-01-29 Thread Mark Walters

> 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

2012-01-29 Thread Allan Wind
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

2012-01-29 Thread Jani Nikula
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

2012-01-29 Thread Dmitry Kurochkin
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

2012-01-29 Thread Dmitry Kurochkin
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

2012-01-29 Thread Dmitry Kurochkin
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

2012-01-29 Thread Aaron Ecay
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

2012-01-29 Thread Austin Clements
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

2012-01-29 Thread Austin Clements
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

2012-01-29 Thread Austin Clements
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

2012-01-29 Thread Mark Walters
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

2012-01-29 Thread Mark Walters
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

2012-01-29 Thread Mark Walters
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

2012-01-29 Thread Mark Walters
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

2012-01-29 Thread Justus Winter
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

2012-01-29 Thread Justus Winter
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

2012-01-29 Thread Justus Winter
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.

2012-01-29 Thread Mark Walters
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

2012-01-29 Thread Mark Walters
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

2012-01-29 Thread Mark Walters
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

2012-01-29 Thread Mark Walters
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.

2012-01-29 Thread Mark Walters
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.

2012-01-29 Thread Mark Walters
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.

2012-01-29 Thread Mark Walters
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

2012-01-29 Thread Jameson Graef Rollins
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

2012-01-29 Thread Jameson Graef Rollins
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

2012-01-29 Thread Austin Clements
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

2012-01-29 Thread Austin Clements
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

2012-01-29 Thread Dmitry Kurochkin
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'

2012-01-29 Thread Austin Clements
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

2012-01-29 Thread Mark Walters

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

2012-01-29 Thread Austin Clements
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

2012-01-29 Thread Dmitry Kurochkin
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

2012-01-29 Thread Gregor Zattler
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

2012-01-29 Thread Dmitry Kurochkin
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

2012-01-29 Thread Dmitry Kurochkin
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'

2012-01-29 Thread Dmitry Kurochkin
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

2012-01-29 Thread Dmitry Kurochkin
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

2012-01-29 Thread Dmitry Kurochkin
---
 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

2012-01-29 Thread Dmitry Kurochkin
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

2012-01-29 Thread Dmitry Kurochkin
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

2012-01-29 Thread Dmitry Kurochkin
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'

2012-01-29 Thread Dmitry Kurochkin
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'

2012-01-29 Thread Dmitry Kurochkin
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'

2012-01-29 Thread Austin Clements
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

2012-01-29 Thread Austin Clements
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

2012-01-29 Thread Austin Clements
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

2012-01-29 Thread Dmitry Kurochkin
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

2012-01-29 Thread Dmitry Kurochkin
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}'

2012-01-29 Thread Pieter Praet
* 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'.

2012-01-29 Thread Pieter Praet
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