unofficial mirror of notmuch@notmuchmail.org
 help / color / mirror / code / Atom feed
* [PATCH 1/6] emacs: move tag format validation to `notmuch-tag' function
@ 2012-01-28  4:41 Dmitry Kurochkin
  2012-01-28  4:41 ` [PATCH 2/6] emacs: remove text properties from `notmuch-search-get-tags' result Dmitry Kurochkin
                   ` (10 more replies)
  0 siblings, 11 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-01-28  4:41 UTC (permalink / raw)
  To: notmuch

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"))
+  (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)
-- 
1.7.8.3

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH 2/6] emacs: remove text properties from `notmuch-search-get-tags' result
  2012-01-28  4:41 [PATCH 1/6] emacs: move tag format validation to `notmuch-tag' function Dmitry Kurochkin
@ 2012-01-28  4:41 ` Dmitry Kurochkin
  2012-01-28  4:41 ` [PATCH 3/6] emacs: make "+" and "-" tagging operations more robust Dmitry Kurochkin
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-01-28  4:41 UTC (permalink / raw)
  To: notmuch

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

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH 3/6] emacs: make "+" and "-" tagging operations more robust
  2012-01-28  4:41 [PATCH 1/6] emacs: move tag format validation to `notmuch-tag' function Dmitry Kurochkin
  2012-01-28  4:41 ` [PATCH 2/6] emacs: remove text properties from `notmuch-search-get-tags' result Dmitry Kurochkin
@ 2012-01-28  4:41 ` Dmitry Kurochkin
  2012-01-28 16:49   ` Jeremy Nickurak
  2012-01-29 22:57   ` Austin Clements
  2012-01-28  4:41 ` [PATCH 4/6] test: fix emacs tests after tagging operations changes Dmitry Kurochkin
                   ` (8 subsequent siblings)
  10 siblings, 2 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-01-28  4:41 UTC (permalink / raw)
  To: notmuch

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).
---
 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."
   (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 (notmuch-select-tags-with-completion
+		       initial-input (notmuch-show-get-message-id))))
+    (apply 'notmuch-show-tag-message changed-tags)))
 
-  (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 +1542,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))
diff --git a/emacs/notmuch.el b/emacs/notmuch.el
index ff46617..24b0ea3 100644
--- a/emacs/notmuch.el
+++ b/emacs/notmuch.el
@@ -76,38 +76,56 @@ For example:
 (defvar notmuch-query-history nil
   "Variable to store minibuffer history for notmuch queries")
 
-(defun notmuch-tag-completions (&optional 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 (&optional 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 &rest 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 &optional prefixes &rest 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 <tab>
-	;; 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-select-tags-with-completion (&optional initial-input &rest search-terms)
+  (let* ((add-tag-list (mapcar (apply-partially 'concat "+")
+			       (notmuch-tag-completions)))
+	 (remove-tag-list (mapcar (apply-partially 'concat "-")
+				  (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 <tab>
+	 ;; 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
+		"Operations (+add -drop): notmuch tag " tag-list nil
+		nil initial-input))))
+
+(defun notmuch-update-tags (current-tags changed-tags)
+  "Update `current-tags' with `changed-tags' and return the result.
+
+`Changed-tags' is a list of tag operations given to \"notmuch
+tag\", i.e. a list of changed tags with '+' and '-' prefixes."
+  (let ((result-tags (copy-sequence current-tags)))
+    (mapc (lambda (changed-tag)
+	    (unless (string= changed-tag "")
+	      (let ((op (substring changed-tag 0 1))
+		    (tag (substring changed-tag 1)))
+		(cond ((string= op "+")
+		       (unless (member tag result-tags)
+			 (push tag result-tags)))
+		      ((string= op "-")
+		       (setq result-tags (delete tag result-tags)))
+		      (t
+		       (error "Changed tag must be of the form `+this_tag' or `-that_tag'"))))))
+       changed-tags)
+    (sort result-tags 'string<)))
 
 (defun notmuch-foreach-mime-part (function mm-handle)
   (cond ((stringp (car mm-handle))
@@ -447,6 +465,10 @@ Complete list of currently available key bindings:
   "Return a list of threads for the current region"
   (notmuch-search-properties-in-region 'notmuch-search-thread-id beg end))
 
+(defun notmuch-search-find-thread-id-region-search (beg end)
+  "Return a search string for threads for the current region"
+  (mapconcat 'identity (notmuch-search-find-thread-id-region beg end) " or "))
+
 (defun notmuch-search-find-authors ()
   "Return the authors for the current thread"
   (get-text-property (point) 'notmuch-search-authors))
@@ -590,74 +612,55 @@ the messages that were tagged"
 	(forward-line 1))
       output)))
 
-(defun notmuch-search-add-tag-thread (tag)
-  (notmuch-search-add-tag-region tag (point) (point)))
+(defun notmuch-search-tag-thread (&rest tags)
+  "Change tags for the currently selected thread.
 
-(defun notmuch-search-add-tag-region (tag beg end)
-  (let ((search-id-string (mapconcat 'identity (notmuch-search-find-thread-id-region beg end) " or ")))
-    (notmuch-tag search-id-string (concat "+" tag))
-    (save-excursion
-      (let ((last-line (line-number-at-pos end))
-	    (max-line (- (line-number-at-pos (point-max)) 2)))
-	(goto-char beg)
-	(while (<= (line-number-at-pos) (min last-line max-line))
-	  (notmuch-search-set-tags (delete-dups (sort (cons tag (notmuch-search-get-tags)) 'string<)))
-	  (forward-line))))))
+See `notmuch-search-tag-region' for details."
+  (apply 'notmuch-search-tag-region (point) (point) tags))
 
-(defun notmuch-search-remove-tag-thread (tag)
-  (notmuch-search-remove-tag-region tag (point) (point)))
+(defun notmuch-search-tag-region (beg end &rest tags)
+  "Change tags for threads in the given region.
 
-(defun notmuch-search-remove-tag-region (tag beg end)
-  (let ((search-id-string (mapconcat 'identity (notmuch-search-find-thread-id-region beg end) " or ")))
-    (notmuch-tag search-id-string (concat "-" tag))
+`Tags' is a list of tag operations for \"notmuch tag\", i.e. a
+list of tags to change with '+' and '-' prefixes.  The tags are
+added or removed for all threads in the region from `beg' to
+`end'."
+  (let ((search-string (notmuch-search-find-thread-id-region-search beg end)))
+    (apply 'notmuch-tag search-string tags)
     (save-excursion
       (let ((last-line (line-number-at-pos end))
 	    (max-line (- (line-number-at-pos (point-max)) 2)))
 	(goto-char beg)
 	(while (<= (line-number-at-pos) (min last-line max-line))
-	  (notmuch-search-set-tags (delete tag (notmuch-search-get-tags)))
+	  (notmuch-search-set-tags
+	   (notmuch-update-tags (notmuch-search-get-tags) tags))
 	  (forward-line))))))
 
-(defun notmuch-search-add-tag (tag)
-  "Add a tag to the currently selected thread or region.
-
-The tag is added to all messages in the currently selected thread
-or threads in the current region."
-  (interactive
-   (list (notmuch-select-tag-with-completion "Tag to add: ")))
-  (save-excursion
-    (if (region-active-p)
-	(let* ((beg (region-beginning))
-	       (end (region-end)))
-	  (notmuch-search-add-tag-region tag beg end))
-      (notmuch-search-add-tag-thread tag))))
-
-(defun notmuch-search-remove-tag (tag)
-  "Remove a tag from the currently selected thread or region.
+(defun notmuch-search-tag (&optional initial-input)
+  "Change tags for the currently selected thread or region."
+  (interactive)
+  (let* ((beg (if (region-active-p) (region-beginning) (point)))
+	 (end (if (region-active-p) (region-end) (point)))
+	 (search-string (notmuch-search-find-thread-id-region-search beg end))
+	 (tags (notmuch-select-tags-with-completion initial-input search-string)))
+    (apply 'notmuch-search-tag-region beg end tags)))
+
+(defun notmuch-search-add-tag ()
+  "Same as `notmuch-search-tag' but sets initial input to '+'."
+  (interactive)
+  (notmuch-search-tag "+"))
 
-The tag is removed from all messages in the currently selected
-thread or threads in the current region."
-  (interactive
-   (list (notmuch-select-tag-with-completion
-	  "Tag to remove: "
-	  (if (region-active-p)
-	      (mapconcat 'identity
-			 (notmuch-search-find-thread-id-region (region-beginning) (region-end))
-			 " ")
-	    (notmuch-search-find-thread-id)))))
-  (save-excursion
-    (if (region-active-p)
-	(let* ((beg (region-beginning))
-	       (end (region-end)))
-	  (notmuch-search-remove-tag-region tag beg end))
-      (notmuch-search-remove-tag-thread tag))))
+(defun notmuch-search-remove-tag ()
+  "Same as `notmuch-search-tag' but sets initial input to '-'."
+  (interactive)
+  (notmuch-search-tag "-"))
 
 (defun notmuch-search-archive-thread ()
   "Archive the currently selected thread (remove its \"inbox\" tag).
 
 This function advances the next thread when finished."
   (interactive)
-  (notmuch-search-remove-tag-thread "inbox")
+  (notmuch-search-tag-thread "-inbox")
   (notmuch-search-next-thread))
 
 (defvar notmuch-search-process-filter-data nil
@@ -893,9 +896,7 @@ will prompt for tags to be added or removed. Tags prefixed with
 Each character of the tag name may consist of alphanumeric
 characters as well as `_.+-'.
 "
-  (interactive (notmuch-select-tags-with-completion
-		"Operations (+add -drop): notmuch tag "
-		'("+" "-")))
+  (interactive (notmuch-select-tags-with-completion))
   (apply 'notmuch-tag notmuch-search-query-string actions))
 
 (defun notmuch-search-buffer-title (query)
-- 
1.7.8.3

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH 4/6] test: fix emacs tests after tagging operations changes
  2012-01-28  4:41 [PATCH 1/6] emacs: move tag format validation to `notmuch-tag' function Dmitry Kurochkin
  2012-01-28  4:41 ` [PATCH 2/6] emacs: remove text properties from `notmuch-search-get-tags' result Dmitry Kurochkin
  2012-01-28  4:41 ` [PATCH 3/6] emacs: make "+" and "-" tagging operations more robust Dmitry Kurochkin
@ 2012-01-28  4:41 ` Dmitry Kurochkin
  2012-01-29 22:58   ` Austin Clements
  2012-01-28  4:41 ` [PATCH 5/6] emacs: add "*" binding for notmuch-show view Dmitry Kurochkin
                   ` (7 subsequent siblings)
  10 siblings, 1 reply; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-01-28  4:41 UTC (permalink / raw)
  To: notmuch

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

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH 5/6] emacs: add "*" binding for notmuch-show view
  2012-01-28  4:41 [PATCH 1/6] emacs: move tag format validation to `notmuch-tag' function Dmitry Kurochkin
                   ` (2 preceding siblings ...)
  2012-01-28  4:41 ` [PATCH 4/6] test: fix emacs tests after tagging operations changes Dmitry Kurochkin
@ 2012-01-28  4:41 ` Dmitry Kurochkin
  2012-01-28  4:41 ` [PATCH 6/6] emacs: separate history for operations which accept single and multiple tags Dmitry Kurochkin
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-01-28  4:41 UTC (permalink / raw)
  To: notmuch

The patch adds `notmuch-show-operate-all' function bound to "*" in
notmuch-show view.  The function is similar to the
`notmuch-search-operate-all' function for the notmuch-search view: it
changes tags for all messages in the current thread.
---
 emacs/notmuch-show.el |   16 ++++++++++++++++
 1 files changed, 16 insertions(+), 0 deletions(-)

diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
index 03eadfb..2ca4d92 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-operate-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)
@@ -1489,6 +1490,21 @@ i.e. a list of tags to change with '+' and '-' prefixes."
 		       initial-input (notmuch-show-get-message-id))))
     (apply 'notmuch-show-tag-message changed-tags)))
 
+(defun notmuch-show-operate-all (&rest changed-tags)
+  "Change tags for all messages in the current thread.
+
+`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)
+  (save-excursion
+    (goto-char (point-min))
+    (loop do (let* ((current-tags (notmuch-show-get-tags))
+		    (new-tags (notmuch-update-tags current-tags changed-tags)))
+	       (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

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH 6/6] emacs: separate history for operations which accept single and multiple tags
  2012-01-28  4:41 [PATCH 1/6] emacs: move tag format validation to `notmuch-tag' function Dmitry Kurochkin
                   ` (3 preceding siblings ...)
  2012-01-28  4:41 ` [PATCH 5/6] emacs: add "*" binding for notmuch-show view Dmitry Kurochkin
@ 2012-01-28  4:41 ` Dmitry Kurochkin
  2012-01-29 23:02   ` Austin Clements
  2012-01-28  5:05 ` [PATCH 7/6] emacs: relax tag syntax check in `notmuch-tag' function Dmitry Kurochkin
                   ` (5 subsequent siblings)
  10 siblings, 1 reply; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-01-28  4:41 UTC (permalink / raw)
  To: notmuch

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'.")
+
 (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.
-- 
1.7.8.3

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH 7/6] emacs: relax tag syntax check in `notmuch-tag' function
  2012-01-28  4:41 [PATCH 1/6] emacs: move tag format validation to `notmuch-tag' function Dmitry Kurochkin
                   ` (4 preceding siblings ...)
  2012-01-28  4:41 ` [PATCH 6/6] emacs: separate history for operations which accept single and multiple tags Dmitry Kurochkin
@ 2012-01-28  5:05 ` Dmitry Kurochkin
  2012-01-28  8:56   ` Jani Nikula
  2012-01-28  5:59 ` [PATCH 8/6] emacs: use message ids instead of thread id in `notmuch-show-operate-all' Dmitry Kurochkin
                   ` (4 subsequent siblings)
  10 siblings, 1 reply; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-01-28  5:05 UTC (permalink / raw)
  To: notmuch

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 9813e0a..0de6123 100644
--- a/emacs/notmuch.el
+++ b/emacs/notmuch.el
@@ -555,7 +555,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

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH 8/6] emacs: use message ids instead of thread id in `notmuch-show-operate-all'
  2012-01-28  4:41 [PATCH 1/6] emacs: move tag format validation to `notmuch-tag' function Dmitry Kurochkin
                   ` (5 preceding siblings ...)
  2012-01-28  5:05 ` [PATCH 7/6] emacs: relax tag syntax check in `notmuch-tag' function Dmitry Kurochkin
@ 2012-01-28  5:59 ` Dmitry Kurochkin
  2012-01-28  5:59   ` [PATCH 9/6] emacs: code cleanup in `notmuch-show-operate-all', no functional changes Dmitry Kurochkin
                     ` (2 more replies)
  2012-01-29 21:34 ` [PATCH 1/6] emacs: move tag format validation to `notmuch-tag' function Austin Clements
                   ` (3 subsequent siblings)
  10 siblings, 3 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-01-28  5:59 UTC (permalink / raw)
  To: notmuch

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 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."
+  (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."
+  (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."
+  (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))
-- 
1.7.8.3

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH 9/6] emacs: code cleanup in `notmuch-show-operate-all', no functional changes
  2012-01-28  5:59 ` [PATCH 8/6] emacs: use message ids instead of thread id in `notmuch-show-operate-all' Dmitry Kurochkin
@ 2012-01-28  5:59   ` Dmitry Kurochkin
  2012-01-28  9:09   ` [PATCH 8/6] emacs: use message ids instead of thread id in `notmuch-show-operate-all' Jani Nikula
  2012-01-29 23:11   ` Austin Clements
  2 siblings, 0 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-01-28  5:59 UTC (permalink / raw)
  To: notmuch

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 e606224..4ec3fce 100644
--- a/emacs/notmuch-show.el
+++ b/emacs/notmuch-show.el
@@ -1518,13 +1518,12 @@ i.e. a list of tags to change with '+' and '-' prefixes."
 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-get-messages-ids-search) changed-tags)
-  (save-excursion
-    (goto-char (point-min))
-    (loop do (let* ((current-tags (notmuch-show-get-tags))
-		    (new-tags (notmuch-update-tags current-tags changed-tags)))
-	       (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 changed-tags)))
+       (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 '+'."
-- 
1.7.8.3

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* Re: [PATCH 7/6] emacs: relax tag syntax check in `notmuch-tag' function
  2012-01-28  5:05 ` [PATCH 7/6] emacs: relax tag syntax check in `notmuch-tag' function Dmitry Kurochkin
@ 2012-01-28  8:56   ` Jani Nikula
  2012-01-28  9:49     ` Dmitry Kurochkin
  2012-02-19 20:53     ` Pieter Praet
  0 siblings, 2 replies; 136+ messages in thread
From: Jani Nikula @ 2012-01-28  8:56 UTC (permalink / raw)
  To: Dmitry Kurochkin; +Cc: notmuch

[-- Attachment #1: Type: text/plain, Size: 1453 bytes --]

On Jan 28, 2012 7:06 AM, "Dmitry Kurochkin" <dmitry.kurochkin@gmail.com>
wrote:
>
> 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.

Imho the syntax check should be in cli, or lib even. I posted a patch to
cli some time ago when I realized it's possible to add tag "-" but you
can't remove it with the current cli. (On the road, can't find the message
id now.)

> ---
>  emacs/notmuch.el |    2 +-
>  1 files changed, 1 insertions(+), 1 deletions(-)
>
> diff --git a/emacs/notmuch.el b/emacs/notmuch.el
> index 9813e0a..0de6123 100644
> --- a/emacs/notmuch.el
> +++ b/emacs/notmuch.el
> @@ -555,7 +555,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

[-- Attachment #2: Type: text/html, Size: 2020 bytes --]

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH 8/6] emacs: use message ids instead of thread id in `notmuch-show-operate-all'
  2012-01-28  5:59 ` [PATCH 8/6] emacs: use message ids instead of thread id in `notmuch-show-operate-all' Dmitry Kurochkin
  2012-01-28  5:59   ` [PATCH 9/6] emacs: code cleanup in `notmuch-show-operate-all', no functional changes Dmitry Kurochkin
@ 2012-01-28  9:09   ` Jani Nikula
  2012-01-28  9:42     ` Dmitry Kurochkin
  2012-01-29 23:11   ` Austin Clements
  2 siblings, 1 reply; 136+ messages in thread
From: Jani Nikula @ 2012-01-28  9:09 UTC (permalink / raw)
  To: Dmitry Kurochkin; +Cc: notmuch

[-- Attachment #1: Type: text/plain, Size: 3075 bytes --]

I guess this now includes the optimization of doing the tagging in a single
call to notmuch tag. (As opposed to calling it once per msg like it used to
be a while back.) There was some discussion about the cmdline length for
large threads potentially growing too big when I sent such an optimization
patch, shall we just ignore that and hope for the best? I guess an idea was
to limit to, say, a few hundred msg ids per command. (Again, sorry I can't
look up the earlier thread now.)

On Jan 28, 2012 8:00 AM, "Dmitry Kurochkin" <dmitry.kurochkin@gmail.com>
wrote:
>
> 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 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."
> +  (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."
> +  (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."
> +  (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))
> --
> 1.7.8.3
>
> _______________________________________________
> notmuch mailing list
> notmuch@notmuchmail.org
> http://notmuchmail.org/mailman/listinfo/notmuch

[-- Attachment #2: Type: text/html, Size: 4018 bytes --]

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH 8/6] emacs: use message ids instead of thread id in `notmuch-show-operate-all'
  2012-01-28  9:09   ` [PATCH 8/6] emacs: use message ids instead of thread id in `notmuch-show-operate-all' Jani Nikula
@ 2012-01-28  9:42     ` Dmitry Kurochkin
  0 siblings, 0 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-01-28  9:42 UTC (permalink / raw)
  To: Jani Nikula; +Cc: notmuch

Hi Jani.

On Sat, 28 Jan 2012 11:09:45 +0200, Jani Nikula <jani@nikula.org> wrote:
> I guess this now includes the optimization of doing the tagging in a single
> call to notmuch tag. (As opposed to calling it once per msg like it used to
> be a while back.)

This patch changes the code which was added few patches earlier in the
series.  And rational for it is not an optimization but a bug fix as
described in the preamble.

> There was some discussion about the cmdline length for
> large threads potentially growing too big when I sent such an optimization
> patch, shall we just ignore that and hope for the best?

Sorry, I think I did not read that discussion in details.  I have never
hit this issue.  So, for now, I do not care about it.

Notmuch-search range tagging works in a similar way, constructing search
string of OR'ed thread ids.  So the patch is consistent with the
existing code.

> I guess an idea was
> to limit to, say, a few hundred msg ids per command. (Again, sorry I can't
> look up the earlier thread now.)
> 

That may be a solution.  Though, I think it should rely on system's
command line limit instead of magic constants.

Anyway, this problem is out of scope of this patch series.  Currently,
neither notmuch-search region tagging code nor the proposed patch try to
solve the issue.  If and when a proper solution is found, we should
implement it for both (or probably more) cases (provided this patch gets
accepted).

Regards,
  Dmitry

> On Jan 28, 2012 8:00 AM, "Dmitry Kurochkin" <dmitry.kurochkin@gmail.com>
> wrote:
> >
> > 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 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."
> > +  (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."
> > +  (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."
> > +  (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))
> > --
> > 1.7.8.3
> >
> > _______________________________________________
> > notmuch mailing list
> > notmuch@notmuchmail.org
> > http://notmuchmail.org/mailman/listinfo/notmuch
Non-text part: text/html

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH 7/6] emacs: relax tag syntax check in `notmuch-tag' function
  2012-01-28  8:56   ` Jani Nikula
@ 2012-01-28  9:49     ` Dmitry Kurochkin
  2012-02-19 20:53     ` Pieter Praet
  1 sibling, 0 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-01-28  9:49 UTC (permalink / raw)
  To: Jani Nikula; +Cc: notmuch

On Sat, 28 Jan 2012 10:56:21 +0200, Jani Nikula <jani@nikula.org> wrote:
> On Jan 28, 2012 7:06 AM, "Dmitry Kurochkin" <dmitry.kurochkin@gmail.com>
> wrote:
> >
> > 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.
> 
> Imho the syntax check should be in cli, or lib even. I posted a patch to
> cli some time ago when I realized it's possible to add tag "-" but you
> can't remove it with the current cli. (On the road, can't find the message
> id now.)
> 

I agree that this is an issue (a general issue for notmuch, not just
Emacs UI).  But it is outside of scope of this patch.  This patch
purpose is just to solve an immediate issue with a broken regexp.

Regards,
  Dmitry

> > ---
> >  emacs/notmuch.el |    2 +-
> >  1 files changed, 1 insertions(+), 1 deletions(-)
> >
> > diff --git a/emacs/notmuch.el b/emacs/notmuch.el
> > index 9813e0a..0de6123 100644
> > --- a/emacs/notmuch.el
> > +++ b/emacs/notmuch.el
> > @@ -555,7 +555,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
Non-text part: text/html

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH 3/6] emacs: make "+" and "-" tagging operations more robust
  2012-01-28  4:41 ` [PATCH 3/6] emacs: make "+" and "-" tagging operations more robust Dmitry Kurochkin
@ 2012-01-28 16:49   ` Jeremy Nickurak
  2012-01-28 17:17     ` Dmitry Kurochkin
  2012-01-29 22:57   ` Austin Clements
  1 sibling, 1 reply; 136+ messages in thread
From: Jeremy Nickurak @ 2012-01-28 16:49 UTC (permalink / raw)
  To: Dmitry Kurochkin; +Cc: notmuch

Is it safe to assume that any reasonable seperator (comma, space,
semicolon, plus or minus sign, anything) won't show up in a tag name?

On Fri, Jan 27, 2012 at 21:41, Dmitry Kurochkin
<dmitry.kurochkin@gmail.com> wrote:
> 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).
> ---
>  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."
>   (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 (notmuch-select-tags-with-completion
> +                      initial-input (notmuch-show-get-message-id))))
> +    (apply 'notmuch-show-tag-message changed-tags)))
>
> -  (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 +1542,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))
> diff --git a/emacs/notmuch.el b/emacs/notmuch.el
> index ff46617..24b0ea3 100644
> --- a/emacs/notmuch.el
> +++ b/emacs/notmuch.el
> @@ -76,38 +76,56 @@ For example:
>  (defvar notmuch-query-history nil
>   "Variable to store minibuffer history for notmuch queries")
>
> -(defun notmuch-tag-completions (&optional 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 (&optional 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 &rest 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 &optional prefixes &rest 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 <tab>
> -       ;; 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-select-tags-with-completion (&optional initial-input &rest search-terms)
> +  (let* ((add-tag-list (mapcar (apply-partially 'concat "+")
> +                              (notmuch-tag-completions)))
> +        (remove-tag-list (mapcar (apply-partially 'concat "-")
> +                                 (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 <tab>
> +        ;; 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
> +               "Operations (+add -drop): notmuch tag " tag-list nil
> +               nil initial-input))))
> +
> +(defun notmuch-update-tags (current-tags changed-tags)
> +  "Update `current-tags' with `changed-tags' and return the result.
> +
> +`Changed-tags' is a list of tag operations given to \"notmuch
> +tag\", i.e. a list of changed tags with '+' and '-' prefixes."
> +  (let ((result-tags (copy-sequence current-tags)))
> +    (mapc (lambda (changed-tag)
> +           (unless (string= changed-tag "")
> +             (let ((op (substring changed-tag 0 1))
> +                   (tag (substring changed-tag 1)))
> +               (cond ((string= op "+")
> +                      (unless (member tag result-tags)
> +                        (push tag result-tags)))
> +                     ((string= op "-")
> +                      (setq result-tags (delete tag result-tags)))
> +                     (t
> +                      (error "Changed tag must be of the form `+this_tag' or `-that_tag'"))))))
> +       changed-tags)
> +    (sort result-tags 'string<)))
>
>  (defun notmuch-foreach-mime-part (function mm-handle)
>   (cond ((stringp (car mm-handle))
> @@ -447,6 +465,10 @@ Complete list of currently available key bindings:
>   "Return a list of threads for the current region"
>   (notmuch-search-properties-in-region 'notmuch-search-thread-id beg end))
>
> +(defun notmuch-search-find-thread-id-region-search (beg end)
> +  "Return a search string for threads for the current region"
> +  (mapconcat 'identity (notmuch-search-find-thread-id-region beg end) " or "))
> +
>  (defun notmuch-search-find-authors ()
>   "Return the authors for the current thread"
>   (get-text-property (point) 'notmuch-search-authors))
> @@ -590,74 +612,55 @@ the messages that were tagged"
>        (forward-line 1))
>       output)))
>
> -(defun notmuch-search-add-tag-thread (tag)
> -  (notmuch-search-add-tag-region tag (point) (point)))
> +(defun notmuch-search-tag-thread (&rest tags)
> +  "Change tags for the currently selected thread.
>
> -(defun notmuch-search-add-tag-region (tag beg end)
> -  (let ((search-id-string (mapconcat 'identity (notmuch-search-find-thread-id-region beg end) " or ")))
> -    (notmuch-tag search-id-string (concat "+" tag))
> -    (save-excursion
> -      (let ((last-line (line-number-at-pos end))
> -           (max-line (- (line-number-at-pos (point-max)) 2)))
> -       (goto-char beg)
> -       (while (<= (line-number-at-pos) (min last-line max-line))
> -         (notmuch-search-set-tags (delete-dups (sort (cons tag (notmuch-search-get-tags)) 'string<)))
> -         (forward-line))))))
> +See `notmuch-search-tag-region' for details."
> +  (apply 'notmuch-search-tag-region (point) (point) tags))
>
> -(defun notmuch-search-remove-tag-thread (tag)
> -  (notmuch-search-remove-tag-region tag (point) (point)))
> +(defun notmuch-search-tag-region (beg end &rest tags)
> +  "Change tags for threads in the given region.
>
> -(defun notmuch-search-remove-tag-region (tag beg end)
> -  (let ((search-id-string (mapconcat 'identity (notmuch-search-find-thread-id-region beg end) " or ")))
> -    (notmuch-tag search-id-string (concat "-" tag))
> +`Tags' is a list of tag operations for \"notmuch tag\", i.e. a
> +list of tags to change with '+' and '-' prefixes.  The tags are
> +added or removed for all threads in the region from `beg' to
> +`end'."
> +  (let ((search-string (notmuch-search-find-thread-id-region-search beg end)))
> +    (apply 'notmuch-tag search-string tags)
>     (save-excursion
>       (let ((last-line (line-number-at-pos end))
>            (max-line (- (line-number-at-pos (point-max)) 2)))
>        (goto-char beg)
>        (while (<= (line-number-at-pos) (min last-line max-line))
> -         (notmuch-search-set-tags (delete tag (notmuch-search-get-tags)))
> +         (notmuch-search-set-tags
> +          (notmuch-update-tags (notmuch-search-get-tags) tags))
>          (forward-line))))))
>
> -(defun notmuch-search-add-tag (tag)
> -  "Add a tag to the currently selected thread or region.
> -
> -The tag is added to all messages in the currently selected thread
> -or threads in the current region."
> -  (interactive
> -   (list (notmuch-select-tag-with-completion "Tag to add: ")))
> -  (save-excursion
> -    (if (region-active-p)
> -       (let* ((beg (region-beginning))
> -              (end (region-end)))
> -         (notmuch-search-add-tag-region tag beg end))
> -      (notmuch-search-add-tag-thread tag))))
> -
> -(defun notmuch-search-remove-tag (tag)
> -  "Remove a tag from the currently selected thread or region.
> +(defun notmuch-search-tag (&optional initial-input)
> +  "Change tags for the currently selected thread or region."
> +  (interactive)
> +  (let* ((beg (if (region-active-p) (region-beginning) (point)))
> +        (end (if (region-active-p) (region-end) (point)))
> +        (search-string (notmuch-search-find-thread-id-region-search beg end))
> +        (tags (notmuch-select-tags-with-completion initial-input search-string)))
> +    (apply 'notmuch-search-tag-region beg end tags)))
> +
> +(defun notmuch-search-add-tag ()
> +  "Same as `notmuch-search-tag' but sets initial input to '+'."
> +  (interactive)
> +  (notmuch-search-tag "+"))
>
> -The tag is removed from all messages in the currently selected
> -thread or threads in the current region."
> -  (interactive
> -   (list (notmuch-select-tag-with-completion
> -         "Tag to remove: "
> -         (if (region-active-p)
> -             (mapconcat 'identity
> -                        (notmuch-search-find-thread-id-region (region-beginning) (region-end))
> -                        " ")
> -           (notmuch-search-find-thread-id)))))
> -  (save-excursion
> -    (if (region-active-p)
> -       (let* ((beg (region-beginning))
> -              (end (region-end)))
> -         (notmuch-search-remove-tag-region tag beg end))
> -      (notmuch-search-remove-tag-thread tag))))
> +(defun notmuch-search-remove-tag ()
> +  "Same as `notmuch-search-tag' but sets initial input to '-'."
> +  (interactive)
> +  (notmuch-search-tag "-"))
>
>  (defun notmuch-search-archive-thread ()
>   "Archive the currently selected thread (remove its \"inbox\" tag).
>
>  This function advances the next thread when finished."
>   (interactive)
> -  (notmuch-search-remove-tag-thread "inbox")
> +  (notmuch-search-tag-thread "-inbox")
>   (notmuch-search-next-thread))
>
>  (defvar notmuch-search-process-filter-data nil
> @@ -893,9 +896,7 @@ will prompt for tags to be added or removed. Tags prefixed with
>  Each character of the tag name may consist of alphanumeric
>  characters as well as `_.+-'.
>  "
> -  (interactive (notmuch-select-tags-with-completion
> -               "Operations (+add -drop): notmuch tag "
> -               '("+" "-")))
> +  (interactive (notmuch-select-tags-with-completion))
>   (apply 'notmuch-tag notmuch-search-query-string actions))
>
>  (defun notmuch-search-buffer-title (query)
> --
> 1.7.8.3
>
> _______________________________________________
> notmuch mailing list
> notmuch@notmuchmail.org
> http://notmuchmail.org/mailman/listinfo/notmuch

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH 3/6] emacs: make "+" and "-" tagging operations more robust
  2012-01-28 16:49   ` Jeremy Nickurak
@ 2012-01-28 17:17     ` Dmitry Kurochkin
  0 siblings, 0 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-01-28 17:17 UTC (permalink / raw)
  To: Jeremy Nickurak; +Cc: notmuch

On Sat, 28 Jan 2012 09:49:33 -0700, Jeremy Nickurak <not-much@trk.nickurak.ca> wrote:
> Is it safe to assume that any reasonable seperator (comma, space,
> semicolon, plus or minus sign, anything) won't show up in a tag name?
> 

No.  Threre are existing issues with tag names that contain "unexpected"
characters.  This series does not aim to resolve them and not make it
worse.  Also see Jani's reply to another patch in the series.

Regards,
  Dmitry

[1] id:"CAB+hUn834oJ+XGx-YyYSGxSnzrBYCMvcu4Vd73ws28qTS2riuA@mail.gmail.com"

> On Fri, Jan 27, 2012 at 21:41, Dmitry Kurochkin
> <dmitry.kurochkin@gmail.com> wrote:
> > 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).
> > ---
> >  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."
> >   (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 (notmuch-select-tags-with-completion
> > +                      initial-input (notmuch-show-get-message-id))))
> > +    (apply 'notmuch-show-tag-message changed-tags)))
> >
> > -  (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 +1542,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))
> > diff --git a/emacs/notmuch.el b/emacs/notmuch.el
> > index ff46617..24b0ea3 100644
> > --- a/emacs/notmuch.el
> > +++ b/emacs/notmuch.el
> > @@ -76,38 +76,56 @@ For example:
> >  (defvar notmuch-query-history nil
> >   "Variable to store minibuffer history for notmuch queries")
> >
> > -(defun notmuch-tag-completions (&optional 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 (&optional 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 &rest 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 &optional prefixes &rest 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 <tab>
> > -       ;; 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-select-tags-with-completion (&optional initial-input &rest search-terms)
> > +  (let* ((add-tag-list (mapcar (apply-partially 'concat "+")
> > +                              (notmuch-tag-completions)))
> > +        (remove-tag-list (mapcar (apply-partially 'concat "-")
> > +                                 (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 <tab>
> > +        ;; 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
> > +               "Operations (+add -drop): notmuch tag " tag-list nil
> > +               nil initial-input))))
> > +
> > +(defun notmuch-update-tags (current-tags changed-tags)
> > +  "Update `current-tags' with `changed-tags' and return the result.
> > +
> > +`Changed-tags' is a list of tag operations given to \"notmuch
> > +tag\", i.e. a list of changed tags with '+' and '-' prefixes."
> > +  (let ((result-tags (copy-sequence current-tags)))
> > +    (mapc (lambda (changed-tag)
> > +           (unless (string= changed-tag "")
> > +             (let ((op (substring changed-tag 0 1))
> > +                   (tag (substring changed-tag 1)))
> > +               (cond ((string= op "+")
> > +                      (unless (member tag result-tags)
> > +                        (push tag result-tags)))
> > +                     ((string= op "-")
> > +                      (setq result-tags (delete tag result-tags)))
> > +                     (t
> > +                      (error "Changed tag must be of the form `+this_tag' or `-that_tag'"))))))
> > +       changed-tags)
> > +    (sort result-tags 'string<)))
> >
> >  (defun notmuch-foreach-mime-part (function mm-handle)
> >   (cond ((stringp (car mm-handle))
> > @@ -447,6 +465,10 @@ Complete list of currently available key bindings:
> >   "Return a list of threads for the current region"
> >   (notmuch-search-properties-in-region 'notmuch-search-thread-id beg end))
> >
> > +(defun notmuch-search-find-thread-id-region-search (beg end)
> > +  "Return a search string for threads for the current region"
> > +  (mapconcat 'identity (notmuch-search-find-thread-id-region beg end) " or "))
> > +
> >  (defun notmuch-search-find-authors ()
> >   "Return the authors for the current thread"
> >   (get-text-property (point) 'notmuch-search-authors))
> > @@ -590,74 +612,55 @@ the messages that were tagged"
> >        (forward-line 1))
> >       output)))
> >
> > -(defun notmuch-search-add-tag-thread (tag)
> > -  (notmuch-search-add-tag-region tag (point) (point)))
> > +(defun notmuch-search-tag-thread (&rest tags)
> > +  "Change tags for the currently selected thread.
> >
> > -(defun notmuch-search-add-tag-region (tag beg end)
> > -  (let ((search-id-string (mapconcat 'identity (notmuch-search-find-thread-id-region beg end) " or ")))
> > -    (notmuch-tag search-id-string (concat "+" tag))
> > -    (save-excursion
> > -      (let ((last-line (line-number-at-pos end))
> > -           (max-line (- (line-number-at-pos (point-max)) 2)))
> > -       (goto-char beg)
> > -       (while (<= (line-number-at-pos) (min last-line max-line))
> > -         (notmuch-search-set-tags (delete-dups (sort (cons tag (notmuch-search-get-tags)) 'string<)))
> > -         (forward-line))))))
> > +See `notmuch-search-tag-region' for details."
> > +  (apply 'notmuch-search-tag-region (point) (point) tags))
> >
> > -(defun notmuch-search-remove-tag-thread (tag)
> > -  (notmuch-search-remove-tag-region tag (point) (point)))
> > +(defun notmuch-search-tag-region (beg end &rest tags)
> > +  "Change tags for threads in the given region.
> >
> > -(defun notmuch-search-remove-tag-region (tag beg end)
> > -  (let ((search-id-string (mapconcat 'identity (notmuch-search-find-thread-id-region beg end) " or ")))
> > -    (notmuch-tag search-id-string (concat "-" tag))
> > +`Tags' is a list of tag operations for \"notmuch tag\", i.e. a
> > +list of tags to change with '+' and '-' prefixes.  The tags are
> > +added or removed for all threads in the region from `beg' to
> > +`end'."
> > +  (let ((search-string (notmuch-search-find-thread-id-region-search beg end)))
> > +    (apply 'notmuch-tag search-string tags)
> >     (save-excursion
> >       (let ((last-line (line-number-at-pos end))
> >            (max-line (- (line-number-at-pos (point-max)) 2)))
> >        (goto-char beg)
> >        (while (<= (line-number-at-pos) (min last-line max-line))
> > -         (notmuch-search-set-tags (delete tag (notmuch-search-get-tags)))
> > +         (notmuch-search-set-tags
> > +          (notmuch-update-tags (notmuch-search-get-tags) tags))
> >          (forward-line))))))
> >
> > -(defun notmuch-search-add-tag (tag)
> > -  "Add a tag to the currently selected thread or region.
> > -
> > -The tag is added to all messages in the currently selected thread
> > -or threads in the current region."
> > -  (interactive
> > -   (list (notmuch-select-tag-with-completion "Tag to add: ")))
> > -  (save-excursion
> > -    (if (region-active-p)
> > -       (let* ((beg (region-beginning))
> > -              (end (region-end)))
> > -         (notmuch-search-add-tag-region tag beg end))
> > -      (notmuch-search-add-tag-thread tag))))
> > -
> > -(defun notmuch-search-remove-tag (tag)
> > -  "Remove a tag from the currently selected thread or region.
> > +(defun notmuch-search-tag (&optional initial-input)
> > +  "Change tags for the currently selected thread or region."
> > +  (interactive)
> > +  (let* ((beg (if (region-active-p) (region-beginning) (point)))
> > +        (end (if (region-active-p) (region-end) (point)))
> > +        (search-string (notmuch-search-find-thread-id-region-search beg end))
> > +        (tags (notmuch-select-tags-with-completion initial-input search-string)))
> > +    (apply 'notmuch-search-tag-region beg end tags)))
> > +
> > +(defun notmuch-search-add-tag ()
> > +  "Same as `notmuch-search-tag' but sets initial input to '+'."
> > +  (interactive)
> > +  (notmuch-search-tag "+"))
> >
> > -The tag is removed from all messages in the currently selected
> > -thread or threads in the current region."
> > -  (interactive
> > -   (list (notmuch-select-tag-with-completion
> > -         "Tag to remove: "
> > -         (if (region-active-p)
> > -             (mapconcat 'identity
> > -                        (notmuch-search-find-thread-id-region (region-beginning) (region-end))
> > -                        " ")
> > -           (notmuch-search-find-thread-id)))))
> > -  (save-excursion
> > -    (if (region-active-p)
> > -       (let* ((beg (region-beginning))
> > -              (end (region-end)))
> > -         (notmuch-search-remove-tag-region tag beg end))
> > -      (notmuch-search-remove-tag-thread tag))))
> > +(defun notmuch-search-remove-tag ()
> > +  "Same as `notmuch-search-tag' but sets initial input to '-'."
> > +  (interactive)
> > +  (notmuch-search-tag "-"))
> >
> >  (defun notmuch-search-archive-thread ()
> >   "Archive the currently selected thread (remove its \"inbox\" tag).
> >
> >  This function advances the next thread when finished."
> >   (interactive)
> > -  (notmuch-search-remove-tag-thread "inbox")
> > +  (notmuch-search-tag-thread "-inbox")
> >   (notmuch-search-next-thread))
> >
> >  (defvar notmuch-search-process-filter-data nil
> > @@ -893,9 +896,7 @@ will prompt for tags to be added or removed. Tags prefixed with
> >  Each character of the tag name may consist of alphanumeric
> >  characters as well as `_.+-'.
> >  "
> > -  (interactive (notmuch-select-tags-with-completion
> > -               "Operations (+add -drop): notmuch tag "
> > -               '("+" "-")))
> > +  (interactive (notmuch-select-tags-with-completion))
> >   (apply 'notmuch-tag notmuch-search-query-string actions))
> >
> >  (defun notmuch-search-buffer-title (query)
> > --
> > 1.7.8.3
> >
> > _______________________________________________
> > notmuch mailing list
> > notmuch@notmuchmail.org
> > http://notmuchmail.org/mailman/listinfo/notmuch

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH 1/6] emacs: move tag format validation to `notmuch-tag' function
  2012-01-28  4:41 [PATCH 1/6] emacs: move tag format validation to `notmuch-tag' function Dmitry Kurochkin
                   ` (6 preceding siblings ...)
  2012-01-28  5:59 ` [PATCH 8/6] emacs: use message ids instead of thread id in `notmuch-show-operate-all' Dmitry Kurochkin
@ 2012-01-29 21:34 ` Austin Clements
  2012-01-29 22:54   ` Dmitry Kurochkin
  2012-01-30  2:26 ` [PATCH v2 00/13] emacs: more robust and consistent tagging operations Dmitry Kurochkin
                   ` (2 subsequent siblings)
  10 siblings, 1 reply; 136+ messages in thread
From: Austin Clements @ 2012-01-29 21:34 UTC (permalink / raw)
  To: Dmitry Kurochkin; +Cc: notmuch

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)

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH 1/6] emacs: move tag format validation to `notmuch-tag' function
  2012-01-29 21:34 ` [PATCH 1/6] emacs: move tag format validation to `notmuch-tag' function Austin Clements
@ 2012-01-29 22:54   ` Dmitry Kurochkin
  2012-01-29 23:16     ` Austin Clements
  0 siblings, 1 reply; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-01-29 22:54 UTC (permalink / raw)
  To: Austin Clements; +Cc: notmuch

Hi Austin.

On Sun, 29 Jan 2012 16:34:27 -0500, Austin Clements <amdragon@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.

Regards,
  Dmitry

> > +  (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)

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH 3/6] emacs: make "+" and "-" tagging operations more robust
  2012-01-28  4:41 ` [PATCH 3/6] emacs: make "+" and "-" tagging operations more robust Dmitry Kurochkin
  2012-01-28 16:49   ` Jeremy Nickurak
@ 2012-01-29 22:57   ` Austin Clements
  2012-01-30  1:32     ` Dmitry Kurochkin
  1 sibling, 1 reply; 136+ messages in thread
From: Austin Clements @ 2012-01-29 22:57 UTC (permalink / raw)
  To: Dmitry Kurochkin; +Cc: notmuch

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" (&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.

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 (&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 (notmuch-select-tags-with-completion
> +		       initial-input (notmuch-show-get-message-id))))
> +    (apply 'notmuch-show-tag-message changed-tags)))
>  
> -  (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 "-"))

Should notmuch-show-{add,remove}-tag be considered public functions?
Previously, they were amenable to creating bindings for adding or
removing individual tags, and I believe people have done this.  If
we're okay with breaking backward-compatibility, there should at least
be a NEWS item explaining how to convert such custom bindings to use
notmuch-show-tag-message.

>  
>  (defun notmuch-show-toggle-headers ()
>    "Toggle the visibility of the current message headers."
> @@ -1559,7 +1542,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))
> diff --git a/emacs/notmuch.el b/emacs/notmuch.el
> index ff46617..24b0ea3 100644
> --- a/emacs/notmuch.el
> +++ b/emacs/notmuch.el
> @@ -76,38 +76,56 @@ For example:
>  (defvar notmuch-query-history nil
>    "Variable to store minibuffer history for notmuch queries")
>  
> -(defun notmuch-tag-completions (&optional 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 (&optional 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 &rest 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 &optional prefixes &rest 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 <tab>
> -	;; 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-select-tags-with-completion (&optional initial-input &rest search-terms)

I don't know if notmuch-select-tags-with-completion is the right name
for this now that it hard-codes the +/- prefixes (which seems like the
right thing to do, BTW).  Maybe notmuch-read-tags-add-remove?

> +  (let* ((add-tag-list (mapcar (apply-partially 'concat "+")
> +			       (notmuch-tag-completions)))
> +	 (remove-tag-list (mapcar (apply-partially 'concat "-")
> +				  (notmuch-tag-completions search-terms)))

This will make two calls to notmuch search, but often one will
suffice.  It's probably worth optimizing the case were search-terms is
nil.

> +	 (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 <tab>
> +	 ;; 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
> +		"Operations (+add -drop): notmuch tag " tag-list nil

I don't think the "notmuch tag" part is necessary.  From the
perspective of a person who only uses the Emacs UI, this will be
meaningless.  Maybe "Tag changes (+add -drop): " or even just "Tags
(+add -drop): " since the "+add -drop" part implies what you're doing.

> +		nil initial-input))))
> +
> +(defun notmuch-update-tags (current-tags changed-tags)

Maybe just "tags" instead of "current-tags"?  Nothing says they have
to be current.  It's just a list of tags.

Also, changed-tags makes it sound like a list of tags, which is isn't.
Maybe tag-changes?

> +  "Update `current-tags' with `changed-tags' and return the result.
> +
> +`Changed-tags' is a list of tag operations given to \"notmuch
> +tag\", i.e. a list of changed tags with '+' and '-' prefixes."

Same comment about ticks and "notmuch tag".

I found this docstring a bit confusing.  I wasn't sure exactly what it
meant to "update current-tags with changed-tags" (though replacing
changed-tags with tag-changes would probably help).  Plus, this
function does not, in fact, update current-tags.  Maybe,

  "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 current-tags)))
> +    (mapc (lambda (changed-tag)

Consider dolist instead of mapc, though this is a matter of taste.  It
leads to less indentation (and does have precedent in the notmuch
code, though mapc is more common).

Too bad Elisp doesn't have fold.

> +	    (unless (string= changed-tag "")
> +	      (let ((op (substring changed-tag 0 1))
> +		    (tag (substring changed-tag 1)))
> +		(cond ((string= op "+")
> +		       (unless (member tag result-tags)
> +			 (push tag result-tags)))
> +		      ((string= op "-")
> +		       (setq result-tags (delete tag result-tags)))
> +		      (t
> +		       (error "Changed tag must be of the form `+this_tag' or `-that_tag'"))))))

I would suggest case instead of cond, but, again, that's a matter of
taste.

> +       changed-tags)
> +    (sort result-tags 'string<)))
>  
>  (defun notmuch-foreach-mime-part (function mm-handle)
>    (cond ((stringp (car mm-handle))
> @@ -447,6 +465,10 @@ Complete list of currently available key bindings:
>    "Return a list of threads for the current region"
>    (notmuch-search-properties-in-region 'notmuch-search-thread-id beg end))
>  
> +(defun notmuch-search-find-thread-id-region-search (beg end)
> +  "Return a search string for threads for the current region"
> +  (mapconcat 'identity (notmuch-search-find-thread-id-region beg end) " or "))
> +
>  (defun notmuch-search-find-authors ()
>    "Return the authors for the current thread"
>    (get-text-property (point) 'notmuch-search-authors))
> @@ -590,74 +612,55 @@ the messages that were tagged"
>  	(forward-line 1))
>        output)))
>  
> -(defun notmuch-search-add-tag-thread (tag)
> -  (notmuch-search-add-tag-region tag (point) (point)))
> +(defun notmuch-search-tag-thread (&rest tags)
> +  "Change tags for the currently selected thread.
>  
> -(defun notmuch-search-add-tag-region (tag beg end)
> -  (let ((search-id-string (mapconcat 'identity (notmuch-search-find-thread-id-region beg end) " or ")))
> -    (notmuch-tag search-id-string (concat "+" tag))
> -    (save-excursion
> -      (let ((last-line (line-number-at-pos end))
> -	    (max-line (- (line-number-at-pos (point-max)) 2)))
> -	(goto-char beg)
> -	(while (<= (line-number-at-pos) (min last-line max-line))
> -	  (notmuch-search-set-tags (delete-dups (sort (cons tag (notmuch-search-get-tags)) 'string<)))
> -	  (forward-line))))))
> +See `notmuch-search-tag-region' for details."
> +  (apply 'notmuch-search-tag-region (point) (point) tags))
>  
> -(defun notmuch-search-remove-tag-thread (tag)
> -  (notmuch-search-remove-tag-region tag (point) (point)))
> +(defun notmuch-search-tag-region (beg end &rest tags)
> +  "Change tags for threads in the given region.
>  
> -(defun notmuch-search-remove-tag-region (tag beg end)
> -  (let ((search-id-string (mapconcat 'identity (notmuch-search-find-thread-id-region beg end) " or ")))
> -    (notmuch-tag search-id-string (concat "-" tag))
> +`Tags' is a list of tag operations for \"notmuch tag\", i.e. a
> +list of tags to change with '+' and '-' prefixes.  The tags are
> +added or removed for all threads in the region from `beg' to
> +`end'."

Same comment about ticks and "notmuch tag".

> +  (let ((search-string (notmuch-search-find-thread-id-region-search beg end)))
> +    (apply 'notmuch-tag search-string tags)
>      (save-excursion
>        (let ((last-line (line-number-at-pos end))
>  	    (max-line (- (line-number-at-pos (point-max)) 2)))
>  	(goto-char beg)
>  	(while (<= (line-number-at-pos) (min last-line max-line))
> -	  (notmuch-search-set-tags (delete tag (notmuch-search-get-tags)))
> +	  (notmuch-search-set-tags
> +	   (notmuch-update-tags (notmuch-search-get-tags) tags))
>  	  (forward-line))))))
>  
> -(defun notmuch-search-add-tag (tag)
> -  "Add a tag to the currently selected thread or region.
> -
> -The tag is added to all messages in the currently selected thread
> -or threads in the current region."
> -  (interactive
> -   (list (notmuch-select-tag-with-completion "Tag to add: ")))
> -  (save-excursion
> -    (if (region-active-p)
> -	(let* ((beg (region-beginning))
> -	       (end (region-end)))
> -	  (notmuch-search-add-tag-region tag beg end))
> -      (notmuch-search-add-tag-thread tag))))
> -
> -(defun notmuch-search-remove-tag (tag)
> -  "Remove a tag from the currently selected thread or region.
> +(defun notmuch-search-tag (&optional initial-input)
> +  "Change tags for the currently selected thread or region."
> +  (interactive)
> +  (let* ((beg (if (region-active-p) (region-beginning) (point)))
> +	 (end (if (region-active-p) (region-end) (point)))

While you're in here, these should probably be `use-region-p'.

> +	 (search-string (notmuch-search-find-thread-id-region-search beg end))
> +	 (tags (notmuch-select-tags-with-completion initial-input search-string)))
> +    (apply 'notmuch-search-tag-region beg end tags)))
> +
> +(defun notmuch-search-add-tag ()
> +  "Same as `notmuch-search-tag' but sets initial input to '+'."
> +  (interactive)
> +  (notmuch-search-tag "+"))
>  
> -The tag is removed from all messages in the currently selected
> -thread or threads in the current region."
> -  (interactive
> -   (list (notmuch-select-tag-with-completion
> -	  "Tag to remove: "
> -	  (if (region-active-p)
> -	      (mapconcat 'identity
> -			 (notmuch-search-find-thread-id-region (region-beginning) (region-end))
> -			 " ")
> -	    (notmuch-search-find-thread-id)))))
> -  (save-excursion
> -    (if (region-active-p)
> -	(let* ((beg (region-beginning))
> -	       (end (region-end)))
> -	  (notmuch-search-remove-tag-region tag beg end))
> -      (notmuch-search-remove-tag-thread tag))))
> +(defun notmuch-search-remove-tag ()
> +  "Same as `notmuch-search-tag' but sets initial input to '-'."
> +  (interactive)
> +  (notmuch-search-tag "-"))
>  
>  (defun notmuch-search-archive-thread ()
>    "Archive the currently selected thread (remove its \"inbox\" tag).
>  
>  This function advances the next thread when finished."
>    (interactive)
> -  (notmuch-search-remove-tag-thread "inbox")
> +  (notmuch-search-tag-thread "-inbox")
>    (notmuch-search-next-thread))
>  
>  (defvar notmuch-search-process-filter-data nil
> @@ -893,9 +896,7 @@ will prompt for tags to be added or removed. Tags prefixed with
>  Each character of the tag name may consist of alphanumeric
>  characters as well as `_.+-'.
>  "
> -  (interactive (notmuch-select-tags-with-completion
> -		"Operations (+add -drop): notmuch tag "
> -		'("+" "-")))
> +  (interactive (notmuch-select-tags-with-completion))
>    (apply 'notmuch-tag notmuch-search-query-string actions))
>  
>  (defun notmuch-search-buffer-title (query)

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH 4/6] test: fix emacs tests after tagging operations changes
  2012-01-28  4:41 ` [PATCH 4/6] test: fix emacs tests after tagging operations changes Dmitry Kurochkin
@ 2012-01-29 22:58   ` Austin Clements
  2012-01-29 23:09     ` Dmitry Kurochkin
  0 siblings, 1 reply; 136+ messages in thread
From: Austin Clements @ 2012-01-29 22:58 UTC (permalink / raw)
  To: Dmitry Kurochkin; +Cc: notmuch

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?

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH 6/6] emacs: separate history for operations which accept single and multiple tags
  2012-01-28  4:41 ` [PATCH 6/6] emacs: separate history for operations which accept single and multiple tags Dmitry Kurochkin
@ 2012-01-29 23:02   ` Austin Clements
  2012-01-30  1:42     ` Dmitry Kurochkin
  0 siblings, 1 reply; 136+ messages in thread
From: Austin Clements @ 2012-01-29 23:02 UTC (permalink / raw)
  To: Dmitry Kurochkin; +Cc: notmuch

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.

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH 4/6] test: fix emacs tests after tagging operations changes
  2012-01-29 22:58   ` Austin Clements
@ 2012-01-29 23:09     ` Dmitry Kurochkin
  0 siblings, 0 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-01-29 23:09 UTC (permalink / raw)
  To: Austin Clements; +Cc: notmuch

On Sun, 29 Jan 2012 17:58:41 -0500, Austin Clements <amdragon@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

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH 8/6] emacs: use message ids instead of thread id in `notmuch-show-operate-all'
  2012-01-28  5:59 ` [PATCH 8/6] emacs: use message ids instead of thread id in `notmuch-show-operate-all' Dmitry Kurochkin
  2012-01-28  5:59   ` [PATCH 9/6] emacs: code cleanup in `notmuch-show-operate-all', no functional changes Dmitry Kurochkin
  2012-01-28  9:09   ` [PATCH 8/6] emacs: use message ids instead of thread id in `notmuch-show-operate-all' Jani Nikula
@ 2012-01-29 23:11   ` Austin Clements
  2012-01-30  1:50     ` Dmitry Kurochkin
  2 siblings, 1 reply; 136+ messages in thread
From: Austin Clements @ 2012-01-29 23:11 UTC (permalink / raw)
  To: Dmitry Kurochkin; +Cc: notmuch

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

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH 1/6] emacs: move tag format validation to `notmuch-tag' function
  2012-01-29 22:54   ` Dmitry Kurochkin
@ 2012-01-29 23:16     ` Austin Clements
  2012-01-29 23:32       ` Dmitry Kurochkin
  0 siblings, 1 reply; 136+ messages in thread
From: Austin Clements @ 2012-01-29 23:16 UTC (permalink / raw)
  To: Dmitry Kurochkin; +Cc: notmuch

Quoth Dmitry Kurochkin on Jan 30 at  2:54 am:
> Hi Austin.
> 
> On Sun, 29 Jan 2012 16:34:27 -0500, Austin Clements <amdragon@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.

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH 1/6] emacs: move tag format validation to `notmuch-tag' function
  2012-01-29 23:16     ` Austin Clements
@ 2012-01-29 23:32       ` Dmitry Kurochkin
  0 siblings, 0 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-01-29 23:32 UTC (permalink / raw)
  To: Austin Clements; +Cc: notmuch

On Sun, 29 Jan 2012 18:16:50 -0500, Austin Clements <amdragon@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 <amdragon@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

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH 3/6] emacs: make "+" and "-" tagging operations more robust
  2012-01-29 22:57   ` Austin Clements
@ 2012-01-30  1:32     ` Dmitry Kurochkin
  0 siblings, 0 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-01-30  1:32 UTC (permalink / raw)
  To: Austin Clements; +Cc: notmuch

Hi Austin.

The below changes will be send as v2 soon.

On Sun, 29 Jan 2012 17:57:10 -0500, Austin Clements <amdragon@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 (notmuch-select-tags-with-completion
> > +		       initial-input (notmuch-show-get-message-id))))
> > +    (apply 'notmuch-show-tag-message changed-tags)))
> >  
> > -  (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 "-"))
> 
> Should notmuch-show-{add,remove}-tag be considered public functions?
> Previously, they were amenable to creating bindings for adding or
> removing individual tags, and I believe people have done this.  If
> we're okay with breaking backward-compatibility, there should at least
> be a NEWS item explaining how to convert such custom bindings to use
> notmuch-show-tag-message.
> 

I am definitely ok with breaking backward-compatibility here.  NEWS item
is a good idea, added.

> >  
> >  (defun notmuch-show-toggle-headers ()
> >    "Toggle the visibility of the current message headers."
> > @@ -1559,7 +1542,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))
> > diff --git a/emacs/notmuch.el b/emacs/notmuch.el
> > index ff46617..24b0ea3 100644
> > --- a/emacs/notmuch.el
> > +++ b/emacs/notmuch.el
> > @@ -76,38 +76,56 @@ For example:
> >  (defvar notmuch-query-history nil
> >    "Variable to store minibuffer history for notmuch queries")
> >  
> > -(defun notmuch-tag-completions (&optional 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 (&optional 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 &rest 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 &optional prefixes &rest 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 <tab>
> > -	;; 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-select-tags-with-completion (&optional initial-input &rest search-terms)
> 
> I don't know if notmuch-select-tags-with-completion is the right name
> for this now that it hard-codes the +/- prefixes (which seems like the
> right thing to do, BTW).  Maybe notmuch-read-tags-add-remove?
> 

How about `notmuch-read-tag-changes'?

> > +  (let* ((add-tag-list (mapcar (apply-partially 'concat "+")
> > +			       (notmuch-tag-completions)))
> > +	 (remove-tag-list (mapcar (apply-partially 'concat "-")
> > +				  (notmuch-tag-completions search-terms)))
> 
> This will make two calls to notmuch search, but often one will
> suffice.  It's probably worth optimizing the case were search-terms is
> nil.
> 

done

> > +	 (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 <tab>
> > +	 ;; 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
> > +		"Operations (+add -drop): notmuch tag " tag-list nil
> 
> I don't think the "notmuch tag" part is necessary.  From the
> perspective of a person who only uses the Emacs UI, this will be
> meaningless.  Maybe "Tag changes (+add -drop): " or even just "Tags
> (+add -drop): " since the "+add -drop" part implies what you're doing.
> 

Just "tags" looks good to me, changed.

> > +		nil initial-input))))
> > +
> > +(defun notmuch-update-tags (current-tags changed-tags)
> 
> Maybe just "tags" instead of "current-tags"?  Nothing says they have
> to be current.  It's just a list of tags.
> 

changed

> Also, changed-tags makes it sound like a list of tags, which is isn't.
> Maybe tag-changes?
> 

Replaced changed-tags with tag-changes everywhere.

> > +  "Update `current-tags' with `changed-tags' and return the result.
> > +
> > +`Changed-tags' is a list of tag operations given to \"notmuch
> > +tag\", i.e. a list of changed tags with '+' and '-' prefixes."
> 
> Same comment about ticks and "notmuch tag".
> 
> I found this docstring a bit confusing.  I wasn't sure exactly what it
> meant to "update current-tags with changed-tags" (though replacing
> changed-tags with tag-changes would probably help).  Plus, this
> function does not, in fact, update current-tags.  Maybe,
> 
>   "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."
> 

Looks good, using your docstring now.

> > +  (let ((result-tags (copy-sequence current-tags)))
> > +    (mapc (lambda (changed-tag)
> 
> Consider dolist instead of mapc, though this is a matter of taste.  It
> leads to less indentation (and does have precedent in the notmuch
> code, though mapc is more common).
> 

Dolist is definately better here, thanks for the suggestion.

> Too bad Elisp doesn't have fold.
> 

indeed

> > +	    (unless (string= changed-tag "")
> > +	      (let ((op (substring changed-tag 0 1))
> > +		    (tag (substring changed-tag 1)))
> > +		(cond ((string= op "+")
> > +		       (unless (member tag result-tags)
> > +			 (push tag result-tags)))
> > +		      ((string= op "-")
> > +		       (setq result-tags (delete tag result-tags)))
> > +		      (t
> > +		       (error "Changed tag must be of the form `+this_tag' or `-that_tag'"))))))
> 
> I would suggest case instead of cond, but, again, that's a matter of
> taste.
> 

Again, `case' is definately better here, changed.

> > +       changed-tags)
> > +    (sort result-tags 'string<)))
> >  
> >  (defun notmuch-foreach-mime-part (function mm-handle)
> >    (cond ((stringp (car mm-handle))
> > @@ -447,6 +465,10 @@ Complete list of currently available key bindings:
> >    "Return a list of threads for the current region"
> >    (notmuch-search-properties-in-region 'notmuch-search-thread-id beg end))
> >  
> > +(defun notmuch-search-find-thread-id-region-search (beg end)
> > +  "Return a search string for threads for the current region"
> > +  (mapconcat 'identity (notmuch-search-find-thread-id-region beg end) " or "))
> > +
> >  (defun notmuch-search-find-authors ()
> >    "Return the authors for the current thread"
> >    (get-text-property (point) 'notmuch-search-authors))
> > @@ -590,74 +612,55 @@ the messages that were tagged"
> >  	(forward-line 1))
> >        output)))
> >  
> > -(defun notmuch-search-add-tag-thread (tag)
> > -  (notmuch-search-add-tag-region tag (point) (point)))
> > +(defun notmuch-search-tag-thread (&rest tags)
> > +  "Change tags for the currently selected thread.
> >  
> > -(defun notmuch-search-add-tag-region (tag beg end)
> > -  (let ((search-id-string (mapconcat 'identity (notmuch-search-find-thread-id-region beg end) " or ")))
> > -    (notmuch-tag search-id-string (concat "+" tag))
> > -    (save-excursion
> > -      (let ((last-line (line-number-at-pos end))
> > -	    (max-line (- (line-number-at-pos (point-max)) 2)))
> > -	(goto-char beg)
> > -	(while (<= (line-number-at-pos) (min last-line max-line))
> > -	  (notmuch-search-set-tags (delete-dups (sort (cons tag (notmuch-search-get-tags)) 'string<)))
> > -	  (forward-line))))))
> > +See `notmuch-search-tag-region' for details."
> > +  (apply 'notmuch-search-tag-region (point) (point) tags))
> >  
> > -(defun notmuch-search-remove-tag-thread (tag)
> > -  (notmuch-search-remove-tag-region tag (point) (point)))
> > +(defun notmuch-search-tag-region (beg end &rest tags)
> > +  "Change tags for threads in the given region.
> >  
> > -(defun notmuch-search-remove-tag-region (tag beg end)
> > -  (let ((search-id-string (mapconcat 'identity (notmuch-search-find-thread-id-region beg end) " or ")))
> > -    (notmuch-tag search-id-string (concat "-" tag))
> > +`Tags' is a list of tag operations for \"notmuch tag\", i.e. a
> > +list of tags to change with '+' and '-' prefixes.  The tags are
> > +added or removed for all threads in the region from `beg' to
> > +`end'."
> 
> Same comment about ticks and "notmuch tag".
> 

fixed

> > +  (let ((search-string (notmuch-search-find-thread-id-region-search beg end)))
> > +    (apply 'notmuch-tag search-string tags)
> >      (save-excursion
> >        (let ((last-line (line-number-at-pos end))
> >  	    (max-line (- (line-number-at-pos (point-max)) 2)))
> >  	(goto-char beg)
> >  	(while (<= (line-number-at-pos) (min last-line max-line))
> > -	  (notmuch-search-set-tags (delete tag (notmuch-search-get-tags)))
> > +	  (notmuch-search-set-tags
> > +	   (notmuch-update-tags (notmuch-search-get-tags) tags))
> >  	  (forward-line))))))
> >  
> > -(defun notmuch-search-add-tag (tag)
> > -  "Add a tag to the currently selected thread or region.
> > -
> > -The tag is added to all messages in the currently selected thread
> > -or threads in the current region."
> > -  (interactive
> > -   (list (notmuch-select-tag-with-completion "Tag to add: ")))
> > -  (save-excursion
> > -    (if (region-active-p)
> > -	(let* ((beg (region-beginning))
> > -	       (end (region-end)))
> > -	  (notmuch-search-add-tag-region tag beg end))
> > -      (notmuch-search-add-tag-thread tag))))
> > -
> > -(defun notmuch-search-remove-tag (tag)
> > -  "Remove a tag from the currently selected thread or region.
> > +(defun notmuch-search-tag (&optional initial-input)
> > +  "Change tags for the currently selected thread or region."
> > +  (interactive)
> > +  (let* ((beg (if (region-active-p) (region-beginning) (point)))
> > +	 (end (if (region-active-p) (region-end) (point)))
> 
> While you're in here, these should probably be `use-region-p'.
> 

Looks like you are right.  But I think this should be a separate patch.
I will provide a patch for this after this series is pushed.

Regards,
  Dmitry

> > +	 (search-string (notmuch-search-find-thread-id-region-search beg end))
> > +	 (tags (notmuch-select-tags-with-completion initial-input search-string)))
> > +    (apply 'notmuch-search-tag-region beg end tags)))
> > +
> > +(defun notmuch-search-add-tag ()
> > +  "Same as `notmuch-search-tag' but sets initial input to '+'."
> > +  (interactive)
> > +  (notmuch-search-tag "+"))
> >  
> > -The tag is removed from all messages in the currently selected
> > -thread or threads in the current region."
> > -  (interactive
> > -   (list (notmuch-select-tag-with-completion
> > -	  "Tag to remove: "
> > -	  (if (region-active-p)
> > -	      (mapconcat 'identity
> > -			 (notmuch-search-find-thread-id-region (region-beginning) (region-end))
> > -			 " ")
> > -	    (notmuch-search-find-thread-id)))))
> > -  (save-excursion
> > -    (if (region-active-p)
> > -	(let* ((beg (region-beginning))
> > -	       (end (region-end)))
> > -	  (notmuch-search-remove-tag-region tag beg end))
> > -      (notmuch-search-remove-tag-thread tag))))
> > +(defun notmuch-search-remove-tag ()
> > +  "Same as `notmuch-search-tag' but sets initial input to '-'."
> > +  (interactive)
> > +  (notmuch-search-tag "-"))
> >  
> >  (defun notmuch-search-archive-thread ()
> >    "Archive the currently selected thread (remove its \"inbox\" tag).
> >  
> >  This function advances the next thread when finished."
> >    (interactive)
> > -  (notmuch-search-remove-tag-thread "inbox")
> > +  (notmuch-search-tag-thread "-inbox")
> >    (notmuch-search-next-thread))
> >  
> >  (defvar notmuch-search-process-filter-data nil
> > @@ -893,9 +896,7 @@ will prompt for tags to be added or removed. Tags prefixed with
> >  Each character of the tag name may consist of alphanumeric
> >  characters as well as `_.+-'.
> >  "
> > -  (interactive (notmuch-select-tags-with-completion
> > -		"Operations (+add -drop): notmuch tag "
> > -		'("+" "-")))
> > +  (interactive (notmuch-select-tags-with-completion))
> >    (apply 'notmuch-tag notmuch-search-query-string actions))
> >  
> >  (defun notmuch-search-buffer-title (query)

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH 6/6] emacs: separate history for operations which accept single and multiple tags
  2012-01-29 23:02   ` Austin Clements
@ 2012-01-30  1:42     ` Dmitry Kurochkin
  0 siblings, 0 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-01-30  1:42 UTC (permalink / raw)
  To: Austin Clements; +Cc: notmuch

On Sun, 29 Jan 2012 18:02:29 -0500, Austin Clements <amdragon@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.

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH 8/6] emacs: use message ids instead of thread id in `notmuch-show-operate-all'
  2012-01-29 23:11   ` Austin Clements
@ 2012-01-30  1:50     ` Dmitry Kurochkin
  0 siblings, 0 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-01-30  1:50 UTC (permalink / raw)
  To: Austin Clements; +Cc: notmuch

EOn Sun, 29 Jan 2012 18:11:20 -0500, Austin Clements <amdragon@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))

^ permalink raw reply	[flat|nested] 136+ messages in thread

* [PATCH v2 00/13] emacs: more robust and consistent tagging operations
  2012-01-28  4:41 [PATCH 1/6] emacs: move tag format validation to `notmuch-tag' function Dmitry Kurochkin
                   ` (7 preceding siblings ...)
  2012-01-29 21:34 ` [PATCH 1/6] emacs: move tag format validation to `notmuch-tag' function Austin Clements
@ 2012-01-30  2:26 ` Dmitry Kurochkin
  2012-01-30  2:26   ` [PATCH v2 01/13] emacs: move tag format validation to `notmuch-tag' function Dmitry Kurochkin
                     ` (12 more replies)
  2012-01-30  5:33 ` emacs: more flexible and consistent tagging operations Dmitry Kurochkin
  2012-02-05  7:13 ` [PATCH v5 00/12] emacs: more flexible and consistent tagging operations Dmitry Kurochkin
  10 siblings, 13 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-01-30  2:26 UTC (permalink / raw)
  To: notmuch

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.GK17991@mit.edu"
[2] id:"20120129225710.GG17991@mit.edu"
[3] id:"20120129230229.GI17991@mit.edu"
[4] id:"20120129231120.GJ17991@mit.edu"

^ permalink raw reply	[flat|nested] 136+ messages in thread

* [PATCH v2 01/13] emacs: move tag format validation to `notmuch-tag' function
  2012-01-30  2:26 ` [PATCH v2 00/13] emacs: more robust and consistent tagging operations Dmitry Kurochkin
@ 2012-01-30  2:26   ` Dmitry Kurochkin
  2012-01-30  2:26   ` [PATCH v2 02/13] emacs: remove text properties from `notmuch-search-get-tags' result Dmitry Kurochkin
                     ` (11 subsequent siblings)
  12 siblings, 0 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-01-30  2:26 UTC (permalink / raw)
  To: notmuch

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"))
+  (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)
-- 
1.7.8.3

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v2 02/13] emacs: remove text properties from `notmuch-search-get-tags' result
  2012-01-30  2:26 ` [PATCH v2 00/13] emacs: more robust and consistent tagging operations Dmitry Kurochkin
  2012-01-30  2:26   ` [PATCH v2 01/13] emacs: move tag format validation to `notmuch-tag' function Dmitry Kurochkin
@ 2012-01-30  2:26   ` Dmitry Kurochkin
  2012-01-30  2:26   ` [PATCH v2 03/13] emacs: make "+" and "-" tagging operations in notmuch-search more robust Dmitry Kurochkin
                     ` (10 subsequent siblings)
  12 siblings, 0 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-01-30  2:26 UTC (permalink / raw)
  To: notmuch

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

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v2 03/13] emacs: make "+" and "-" tagging operations in notmuch-search more robust
  2012-01-30  2:26 ` [PATCH v2 00/13] emacs: more robust and consistent tagging operations Dmitry Kurochkin
  2012-01-30  2:26   ` [PATCH v2 01/13] emacs: move tag format validation to `notmuch-tag' function Dmitry Kurochkin
  2012-01-30  2:26   ` [PATCH v2 02/13] emacs: remove text properties from `notmuch-search-get-tags' result Dmitry Kurochkin
@ 2012-01-30  2:26   ` Dmitry Kurochkin
  2012-01-30  4:48     ` Austin Clements
  2012-01-30  2:26   ` [PATCH v2 04/13] emacs: make "+" and "-" tagging operations in notmuch-show " Dmitry Kurochkin
                     ` (9 subsequent siblings)
  12 siblings, 1 reply; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-01-30  2:26 UTC (permalink / raw)
  To: notmuch

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 (&optional 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 (&optional 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 &rest 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 &optional prefixes &rest 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 <tab>
-	;; 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 (&optional initial-input &rest 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 <tab>
+	 ;; 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 "")
+	(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 `+this_tag' or `-that_tag'"))))))
+    (sort result-tags 'string<)))
 
 (defun notmuch-foreach-mime-part (function mm-handle)
   (cond ((stringp (car mm-handle))
@@ -447,6 +466,10 @@ Complete list of currently available key bindings:
   "Return a list of threads for the current region"
   (notmuch-search-properties-in-region 'notmuch-search-thread-id beg end))
 
+(defun notmuch-search-find-thread-id-region-search (beg end)
+  "Return a search string for threads for the current region"
+  (mapconcat 'identity (notmuch-search-find-thread-id-region beg end) " or "))
+
 (defun notmuch-search-find-authors ()
   "Return the authors for the current thread"
   (get-text-property (point) 'notmuch-search-authors))
@@ -590,74 +613,53 @@ the messages that were tagged"
 	(forward-line 1))
       output)))
 
-(defun notmuch-search-add-tag-thread (tag)
-  (notmuch-search-add-tag-region tag (point) (point)))
+(defun notmuch-search-tag-thread (&rest tags)
+  "Change tags for the currently selected thread.
 
-(defun notmuch-search-add-tag-region (tag beg end)
-  (let ((search-id-string (mapconcat 'identity (notmuch-search-find-thread-id-region beg end) " or ")))
-    (notmuch-tag search-id-string (concat "+" tag))
-    (save-excursion
-      (let ((last-line (line-number-at-pos end))
-	    (max-line (- (line-number-at-pos (point-max)) 2)))
-	(goto-char beg)
-	(while (<= (line-number-at-pos) (min last-line max-line))
-	  (notmuch-search-set-tags (delete-dups (sort (cons tag (notmuch-search-get-tags)) 'string<)))
-	  (forward-line))))))
+See `notmuch-search-tag-region' for details."
+  (apply 'notmuch-search-tag-region (point) (point) tags))
 
-(defun notmuch-search-remove-tag-thread (tag)
-  (notmuch-search-remove-tag-region tag (point) (point)))
+(defun notmuch-search-tag-region (beg end &rest tags)
+  "Change tags for threads in the given region.
 
-(defun notmuch-search-remove-tag-region (tag beg end)
-  (let ((search-id-string (mapconcat 'identity (notmuch-search-find-thread-id-region beg end) " or ")))
-    (notmuch-tag search-id-string (concat "-" tag))
+TAGS is a list of tag operations for `notmuch-tag'.  The tags are
+added or removed for all threads in the region from BEG to END."
+  (let ((search-string (notmuch-search-find-thread-id-region-search beg end)))
+    (apply 'notmuch-tag search-string tags)
     (save-excursion
       (let ((last-line (line-number-at-pos end))
 	    (max-line (- (line-number-at-pos (point-max)) 2)))
 	(goto-char beg)
 	(while (<= (line-number-at-pos) (min last-line max-line))
-	  (notmuch-search-set-tags (delete tag (notmuch-search-get-tags)))
+	  (notmuch-search-set-tags
+	   (notmuch-update-tags (notmuch-search-get-tags) tags))
 	  (forward-line))))))
 
-(defun notmuch-search-add-tag (tag)
-  "Add a tag to the currently selected thread or region.
-
-The tag is added to all messages in the currently selected thread
-or threads in the current region."
-  (interactive
-   (list (notmuch-select-tag-with-completion "Tag to add: ")))
-  (save-excursion
-    (if (region-active-p)
-	(let* ((beg (region-beginning))
-	       (end (region-end)))
-	  (notmuch-search-add-tag-region tag beg end))
-      (notmuch-search-add-tag-thread tag))))
-
-(defun notmuch-search-remove-tag (tag)
-  "Remove a tag from the currently selected thread or region.
+(defun notmuch-search-tag (&optional initial-input)
+  "Change tags for the currently selected thread or region."
+  (interactive)
+  (let* ((beg (if (region-active-p) (region-beginning) (point)))
+	 (end (if (region-active-p) (region-end) (point)))
+	 (search-string (notmuch-search-find-thread-id-region-search beg end))
+	 (tags (notmuch-read-tag-changes initial-input search-string)))
+    (apply 'notmuch-search-tag-region beg end tags)))
+
+(defun notmuch-search-add-tag ()
+  "Same as `notmuch-search-tag' but sets initial input to '+'."
+  (interactive)
+  (notmuch-search-tag "+"))
 
-The tag is removed from all messages in the currently selected
-thread or threads in the current region."
-  (interactive
-   (list (notmuch-select-tag-with-completion
-	  "Tag to remove: "
-	  (if (region-active-p)
-	      (mapconcat 'identity
-			 (notmuch-search-find-thread-id-region (region-beginning) (region-end))
-			 " ")
-	    (notmuch-search-find-thread-id)))))
-  (save-excursion
-    (if (region-active-p)
-	(let* ((beg (region-beginning))
-	       (end (region-end)))
-	  (notmuch-search-remove-tag-region tag beg end))
-      (notmuch-search-remove-tag-thread tag))))
+(defun notmuch-search-remove-tag ()
+  "Same as `notmuch-search-tag' but sets initial input to '-'."
+  (interactive)
+  (notmuch-search-tag "-"))
 
 (defun notmuch-search-archive-thread ()
   "Archive the currently selected thread (remove its \"inbox\" tag).
 
 This function advances the next thread when finished."
   (interactive)
-  (notmuch-search-remove-tag-thread "inbox")
+  (notmuch-search-tag-thread "-inbox")
   (notmuch-search-next-thread))
 
 (defvar notmuch-search-process-filter-data nil
@@ -893,9 +895,7 @@ will prompt for tags to be added or removed. Tags prefixed with
 Each character of the tag name may consist of alphanumeric
 characters as well as `_.+-'.
 "
-  (interactive (notmuch-select-tags-with-completion
-		"Operations (+add -drop): notmuch tag "
-		'("+" "-")))
+  (interactive (notmuch-read-tag-changes))
   (apply 'notmuch-tag notmuch-search-query-string actions))
 
 (defun notmuch-search-buffer-title (query)
-- 
1.7.8.3

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v2 04/13] emacs: make "+" and "-" tagging operations in notmuch-show more robust
  2012-01-30  2:26 ` [PATCH v2 00/13] emacs: more robust and consistent tagging operations Dmitry Kurochkin
                     ` (2 preceding siblings ...)
  2012-01-30  2:26   ` [PATCH v2 03/13] emacs: make "+" and "-" tagging operations in notmuch-search more robust Dmitry Kurochkin
@ 2012-01-30  2:26   ` Dmitry Kurochkin
  2012-01-30  2:26   ` [PATCH v2 05/13] test: fix emacs tests after tagging operations changes Dmitry Kurochkin
                     ` (8 subsequent siblings)
  12 siblings, 0 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-01-30  2:26 UTC (permalink / raw)
  To: notmuch

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

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v2 05/13] test: fix emacs tests after tagging operations changes
  2012-01-30  2:26 ` [PATCH v2 00/13] emacs: more robust and consistent tagging operations Dmitry Kurochkin
                     ` (3 preceding siblings ...)
  2012-01-30  2:26   ` [PATCH v2 04/13] emacs: make "+" and "-" tagging operations in notmuch-show " Dmitry Kurochkin
@ 2012-01-30  2:26   ` Dmitry Kurochkin
  2012-01-30  2:26   ` [PATCH v2 06/13] emacs: rename `notmuch-search-operate-all' to `notmuch-search-tag-all' Dmitry Kurochkin
                     ` (7 subsequent siblings)
  12 siblings, 0 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-01-30  2:26 UTC (permalink / raw)
  To: notmuch

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

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v2 06/13] emacs: rename `notmuch-search-operate-all' to `notmuch-search-tag-all'
  2012-01-30  2:26 ` [PATCH v2 00/13] emacs: more robust and consistent tagging operations Dmitry Kurochkin
                     ` (4 preceding siblings ...)
  2012-01-30  2:26   ` [PATCH v2 05/13] test: fix emacs tests after tagging operations changes Dmitry Kurochkin
@ 2012-01-30  2:26   ` Dmitry Kurochkin
  2012-01-30  2:26   ` [PATCH v2 07/13] emacs: add "*" binding for notmuch-show view Dmitry Kurochkin
                     ` (6 subsequent siblings)
  12 siblings, 0 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-01-30  2:26 UTC (permalink / raw)
  To: notmuch

`Notmuch-search-tag-all' is more clear and consistent with other
tagging function names.
---
 emacs/notmuch.el |    6 +++---
 1 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/emacs/notmuch.el b/emacs/notmuch.el
index 90b594c..90627dc 100644
--- a/emacs/notmuch.el
+++ b/emacs/notmuch.el
@@ -271,7 +271,7 @@ For a mouse binding, return nil."
     (define-key map "t" 'notmuch-search-filter-by-tag)
     (define-key map "f" 'notmuch-search-filter)
     (define-key map [mouse-1] 'notmuch-search-show-thread)
-    (define-key map "*" 'notmuch-search-operate-all)
+    (define-key map "*" 'notmuch-search-tag-all)
     (define-key map "a" 'notmuch-search-archive-thread)
     (define-key map "-" 'notmuch-search-remove-tag)
     (define-key map "+" 'notmuch-search-add-tag)
@@ -420,7 +420,7 @@ any tags).
 Pressing \\[notmuch-search-show-thread] on any line displays that thread. The '\\[notmuch-search-add-tag]' and '\\[notmuch-search-remove-tag]'
 keys can be used to add or remove tags from a thread. The '\\[notmuch-search-archive-thread]' key
 is a convenience for archiving a thread (removing the \"inbox\"
-tag). The '\\[notmuch-search-operate-all]' key can be used to add or remove a tag from all
+tag). The '\\[notmuch-search-tag-all]' key can be used to add or remove a tag from all
 threads in the current buffer.
 
 Other useful commands are '\\[notmuch-search-filter]' for filtering the current search
@@ -884,7 +884,7 @@ non-authors is found, assume that all of the authors match."
 	      (goto-char found-target)))
       (delete-process proc))))
 
-(defun notmuch-search-operate-all (&rest actions)
+(defun notmuch-search-tag-all (&rest actions)
   "Add/remove tags from all matching messages.
 
 This command adds or removes tags from all messages matching the
-- 
1.7.8.3

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v2 07/13] emacs: add "*" binding for notmuch-show view
  2012-01-30  2:26 ` [PATCH v2 00/13] emacs: more robust and consistent tagging operations Dmitry Kurochkin
                     ` (5 preceding siblings ...)
  2012-01-30  2:26   ` [PATCH v2 06/13] emacs: rename `notmuch-search-operate-all' to `notmuch-search-tag-all' Dmitry Kurochkin
@ 2012-01-30  2:26   ` Dmitry Kurochkin
  2012-01-30  2:26   ` [PATCH v2 08/13] emacs: separate history for operations which accept single and multiple tags Dmitry Kurochkin
                     ` (5 subsequent siblings)
  12 siblings, 0 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-01-30  2:26 UTC (permalink / raw)
  To: notmuch

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

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v2 08/13] emacs: separate history for operations which accept single and multiple tags
  2012-01-30  2:26 ` [PATCH v2 00/13] emacs: more robust and consistent tagging operations Dmitry Kurochkin
                     ` (6 preceding siblings ...)
  2012-01-30  2:26   ` [PATCH v2 07/13] emacs: add "*" binding for notmuch-show view Dmitry Kurochkin
@ 2012-01-30  2:26   ` Dmitry Kurochkin
  2012-01-30  2:26   ` [PATCH v2 09/13] emacs: relax tag syntax check in `notmuch-tag' function Dmitry Kurochkin
                     ` (4 subsequent siblings)
  12 siblings, 0 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-01-30  2:26 UTC (permalink / raw)
  To: notmuch

Some tag-related operations accept a single tag without prefix
(`notmuch-select-tag-with-completion'), others accept multiple tags
prefixed with '+' or '-' (`notmuch-read-tag-changes').  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 |   13 +++++++++++--
 1 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/emacs/notmuch.el b/emacs/notmuch.el
index 90627dc..5adcac5 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 minibuffer history for
+`notmuch-select-tag-with-completion' function.")
+
+(defvar notmuch-read-tag-changes-history nil
+  "Variable to store minibuffer history for
+`notmuch-read-tag-changes' function.")
+
 (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-read-tag-changes (&optional initial-input &rest search-terms)
   (let* ((all-tag-list (notmuch-tag-completions))
@@ -106,7 +114,8 @@ For example:
 	    (define-key map " " 'self-insert-command)
 	    map)))
     (delete "" (completing-read-multiple "Tags (+add -drop): "
-		tag-list nil nil initial-input))))
+		tag-list nil nil initial-input
+		'notmuch-read-tag-changes-history))))
 
 (defun notmuch-update-tags (tags tag-changes)
   "Return a copy of TAGS with additions and removals from TAG-CHANGES.
-- 
1.7.8.3

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v2 09/13] emacs: relax tag syntax check in `notmuch-tag' function
  2012-01-30  2:26 ` [PATCH v2 00/13] emacs: more robust and consistent tagging operations Dmitry Kurochkin
                     ` (7 preceding siblings ...)
  2012-01-30  2:26   ` [PATCH v2 08/13] emacs: separate history for operations which accept single and multiple tags Dmitry Kurochkin
@ 2012-01-30  2:26   ` Dmitry Kurochkin
  2012-01-30  2:26   ` [PATCH v2 10/13] emacs: use message ids instead of thread id in `notmuch-show-operate-all' Dmitry Kurochkin
                     ` (3 subsequent siblings)
  12 siblings, 0 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-01-30  2:26 UTC (permalink / raw)
  To: notmuch

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

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v2 10/13] emacs: use message ids instead of thread id in `notmuch-show-operate-all'
  2012-01-30  2:26 ` [PATCH v2 00/13] emacs: more robust and consistent tagging operations Dmitry Kurochkin
                     ` (8 preceding siblings ...)
  2012-01-30  2:26   ` [PATCH v2 09/13] emacs: relax tag syntax check in `notmuch-tag' function Dmitry Kurochkin
@ 2012-01-30  2:26   ` Dmitry Kurochkin
  2012-01-30  4:57     ` Austin Clements
  2012-01-30  2:26   ` [PATCH v2 11/13] emacs: code cleanup in `notmuch-show-operate-all', no functional changes Dmitry Kurochkin
                     ` (2 subsequent siblings)
  12 siblings, 1 reply; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-01-30  2:26 UTC (permalink / raw)
  To: notmuch

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

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v2 11/13] emacs: code cleanup in `notmuch-show-operate-all', no functional changes
  2012-01-30  2:26 ` [PATCH v2 00/13] emacs: more robust and consistent tagging operations Dmitry Kurochkin
                     ` (9 preceding siblings ...)
  2012-01-30  2:26   ` [PATCH v2 10/13] emacs: use message ids instead of thread id in `notmuch-show-operate-all' Dmitry Kurochkin
@ 2012-01-30  2:26   ` Dmitry Kurochkin
  2012-01-30  4:59     ` Austin Clements
  2012-01-30  2:26   ` [PATCH v2 12/13] emacs: accept empty tag list in `notmuch-tag' Dmitry Kurochkin
  2012-01-30  2:26   ` [PATCH v2 13/13] NEWS: document Emacs UI tagging operations changes Dmitry Kurochkin
  12 siblings, 1 reply; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-01-30  2:26 UTC (permalink / raw)
  To: notmuch

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 '+'."
-- 
1.7.8.3

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v2 12/13] emacs: accept empty tag list in `notmuch-tag'
  2012-01-30  2:26 ` [PATCH v2 00/13] emacs: more robust and consistent tagging operations Dmitry Kurochkin
                     ` (10 preceding siblings ...)
  2012-01-30  2:26   ` [PATCH v2 11/13] emacs: code cleanup in `notmuch-show-operate-all', no functional changes Dmitry Kurochkin
@ 2012-01-30  2:26   ` Dmitry Kurochkin
  2012-01-30  2:26   ` [PATCH v2 13/13] NEWS: document Emacs UI tagging operations changes Dmitry Kurochkin
  12 siblings, 0 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-01-30  2:26 UTC (permalink / raw)
  To: notmuch

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

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v2 13/13] NEWS: document Emacs UI tagging operations changes
  2012-01-30  2:26 ` [PATCH v2 00/13] emacs: more robust and consistent tagging operations Dmitry Kurochkin
                     ` (11 preceding siblings ...)
  2012-01-30  2:26   ` [PATCH v2 12/13] emacs: accept empty tag list in `notmuch-tag' Dmitry Kurochkin
@ 2012-01-30  2:26   ` Dmitry Kurochkin
  2012-01-30  5:04     ` Austin Clements
  12 siblings, 1 reply; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-01-30  2:26 UTC (permalink / raw)
  To: notmuch

---
 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
+
+  All tagging operations ("+", "-", "*") now accept multiple tags with
+  "+" or "-" prefix, like "*" operation in notmuch-search view before.
+
+  "*" operation (`notmuch-show-tag-all`) is now available in
+  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
 ---------------
 
-- 
1.7.8.3

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* Re: [PATCH v2 03/13] emacs: make "+" and "-" tagging operations in notmuch-search more robust
  2012-01-30  2:26   ` [PATCH v2 03/13] emacs: make "+" and "-" tagging operations in notmuch-search more robust Dmitry Kurochkin
@ 2012-01-30  4:48     ` Austin Clements
  2012-01-30  5:10       ` Dmitry Kurochkin
  0 siblings, 1 reply; 136+ messages in thread
From: Austin Clements @ 2012-01-30  4:48 UTC (permalink / raw)
  To: Dmitry Kurochkin; +Cc: notmuch

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 (&optional 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 (&optional 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 &rest 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 &optional prefixes &rest 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 <tab>
> -	;; 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 (&optional initial-input &rest 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 <tab>
> +	 ;; 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 `+this_tag' or `-that_tag'"))))))
> +    (sort result-tags 'string<)))
>  
>  (defun notmuch-foreach-mime-part (function mm-handle)
>    (cond ((stringp (car mm-handle))
> @@ -447,6 +466,10 @@ Complete list of currently available key bindings:
>    "Return a list of threads for the current region"
>    (notmuch-search-properties-in-region 'notmuch-search-thread-id beg end))
>  
> +(defun notmuch-search-find-thread-id-region-search (beg end)
> +  "Return a search string for threads for the current region"
> +  (mapconcat 'identity (notmuch-search-find-thread-id-region beg end) " or "))
> +
>  (defun notmuch-search-find-authors ()
>    "Return the authors for the current thread"
>    (get-text-property (point) 'notmuch-search-authors))
> @@ -590,74 +613,53 @@ the messages that were tagged"
>  	(forward-line 1))
>        output)))
>  
> -(defun notmuch-search-add-tag-thread (tag)
> -  (notmuch-search-add-tag-region tag (point) (point)))
> +(defun notmuch-search-tag-thread (&rest tags)

Maybe "tag-changes" instead of "tags" for this and
notmuch-search-tag-region?

> +  "Change tags for the currently selected thread.
>  
> -(defun notmuch-search-add-tag-region (tag beg end)
> -  (let ((search-id-string (mapconcat 'identity (notmuch-search-find-thread-id-region beg end) " or ")))
> -    (notmuch-tag search-id-string (concat "+" tag))
> -    (save-excursion
> -      (let ((last-line (line-number-at-pos end))
> -	    (max-line (- (line-number-at-pos (point-max)) 2)))
> -	(goto-char beg)
> -	(while (<= (line-number-at-pos) (min last-line max-line))
> -	  (notmuch-search-set-tags (delete-dups (sort (cons tag (notmuch-search-get-tags)) 'string<)))
> -	  (forward-line))))))
> +See `notmuch-search-tag-region' for details."
> +  (apply 'notmuch-search-tag-region (point) (point) tags))
>  
> -(defun notmuch-search-remove-tag-thread (tag)
> -  (notmuch-search-remove-tag-region tag (point) (point)))
> +(defun notmuch-search-tag-region (beg end &rest tags)
> +  "Change tags for threads in the given region.
>  
> -(defun notmuch-search-remove-tag-region (tag beg end)
> -  (let ((search-id-string (mapconcat 'identity (notmuch-search-find-thread-id-region beg end) " or ")))
> -    (notmuch-tag search-id-string (concat "-" tag))
> +TAGS is a list of tag operations for `notmuch-tag'.  The tags are
> +added or removed for all threads in the region from BEG to END."
> +  (let ((search-string (notmuch-search-find-thread-id-region-search beg end)))
> +    (apply 'notmuch-tag search-string tags)
>      (save-excursion
>        (let ((last-line (line-number-at-pos end))
>  	    (max-line (- (line-number-at-pos (point-max)) 2)))
>  	(goto-char beg)
>  	(while (<= (line-number-at-pos) (min last-line max-line))
> -	  (notmuch-search-set-tags (delete tag (notmuch-search-get-tags)))
> +	  (notmuch-search-set-tags
> +	   (notmuch-update-tags (notmuch-search-get-tags) tags))
>  	  (forward-line))))))
>  
> -(defun notmuch-search-add-tag (tag)
> -  "Add a tag to the currently selected thread or region.
> -
> -The tag is added to all messages in the currently selected thread
> -or threads in the current region."
> -  (interactive
> -   (list (notmuch-select-tag-with-completion "Tag to add: ")))
> -  (save-excursion
> -    (if (region-active-p)
> -	(let* ((beg (region-beginning))
> -	       (end (region-end)))
> -	  (notmuch-search-add-tag-region tag beg end))
> -      (notmuch-search-add-tag-thread tag))))
> -
> -(defun notmuch-search-remove-tag (tag)
> -  "Remove a tag from the currently selected thread or region.

It's great to see all of this old copy-pasted code go away!

> +(defun notmuch-search-tag (&optional initial-input)
> +  "Change tags for the currently selected thread or region."
> +  (interactive)
> +  (let* ((beg (if (region-active-p) (region-beginning) (point)))
> +	 (end (if (region-active-p) (region-end) (point)))
> +	 (search-string (notmuch-search-find-thread-id-region-search beg end))
> +	 (tags (notmuch-read-tag-changes initial-input search-string)))
> +    (apply 'notmuch-search-tag-region beg end tags)))
> +
> +(defun notmuch-search-add-tag ()
> +  "Same as `notmuch-search-tag' but sets initial input to '+'."
> +  (interactive)
> +  (notmuch-search-tag "+"))
>  
> -The tag is removed from all messages in the currently selected
> -thread or threads in the current region."
> -  (interactive
> -   (list (notmuch-select-tag-with-completion
> -	  "Tag to remove: "
> -	  (if (region-active-p)
> -	      (mapconcat 'identity
> -			 (notmuch-search-find-thread-id-region (region-beginning) (region-end))
> -			 " ")
> -	    (notmuch-search-find-thread-id)))))
> -  (save-excursion
> -    (if (region-active-p)
> -	(let* ((beg (region-beginning))
> -	       (end (region-end)))
> -	  (notmuch-search-remove-tag-region tag beg end))
> -      (notmuch-search-remove-tag-thread tag))))
> +(defun notmuch-search-remove-tag ()
> +  "Same as `notmuch-search-tag' but sets initial input to '-'."
> +  (interactive)
> +  (notmuch-search-tag "-"))
>  
>  (defun notmuch-search-archive-thread ()
>    "Archive the currently selected thread (remove its \"inbox\" tag).
>  
>  This function advances the next thread when finished."
>    (interactive)
> -  (notmuch-search-remove-tag-thread "inbox")
> +  (notmuch-search-tag-thread "-inbox")
>    (notmuch-search-next-thread))
>  
>  (defvar notmuch-search-process-filter-data nil
> @@ -893,9 +895,7 @@ will prompt for tags to be added or removed. Tags prefixed with
>  Each character of the tag name may consist of alphanumeric
>  characters as well as `_.+-'.
>  "
> -  (interactive (notmuch-select-tags-with-completion
> -		"Operations (+add -drop): notmuch tag "
> -		'("+" "-")))
> +  (interactive (notmuch-read-tag-changes))
>    (apply 'notmuch-tag notmuch-search-query-string actions))
>  
>  (defun notmuch-search-buffer-title (query)

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v2 10/13] emacs: use message ids instead of thread id in `notmuch-show-operate-all'
  2012-01-30  2:26   ` [PATCH v2 10/13] emacs: use message ids instead of thread id in `notmuch-show-operate-all' Dmitry Kurochkin
@ 2012-01-30  4:57     ` Austin Clements
  2012-01-30  5:21       ` Dmitry Kurochkin
  0 siblings, 1 reply; 136+ messages in thread
From: Austin Clements @ 2012-01-30  4:57 UTC (permalink / raw)
  To: Dmitry Kurochkin; +Cc: notmuch

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

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v2 11/13] emacs: code cleanup in `notmuch-show-operate-all', no functional changes
  2012-01-30  2:26   ` [PATCH v2 11/13] emacs: code cleanup in `notmuch-show-operate-all', no functional changes Dmitry Kurochkin
@ 2012-01-30  4:59     ` Austin Clements
  2012-01-30  5:25       ` Dmitry Kurochkin
  0 siblings, 1 reply; 136+ messages in thread
From: Austin Clements @ 2012-01-30  4:59 UTC (permalink / raw)
  To: Dmitry Kurochkin; +Cc: notmuch

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

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v2 13/13] NEWS: document Emacs UI tagging operations changes
  2012-01-30  2:26   ` [PATCH v2 13/13] NEWS: document Emacs UI tagging operations changes Dmitry Kurochkin
@ 2012-01-30  5:04     ` Austin Clements
  2012-01-30  5:16       ` Dmitry Kurochkin
  0 siblings, 1 reply; 136+ messages in thread
From: Austin Clements @ 2012-01-30  5:04 UTC (permalink / raw)
  To: Dmitry Kurochkin; +Cc: notmuch

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

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v2 03/13] emacs: make "+" and "-" tagging operations in notmuch-search more robust
  2012-01-30  4:48     ` Austin Clements
@ 2012-01-30  5:10       ` Dmitry Kurochkin
  0 siblings, 0 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-01-30  5:10 UTC (permalink / raw)
  To: Austin Clements; +Cc: notmuch

On Sun, 29 Jan 2012 23:48:06 -0500, Austin Clements <amdragon@MIT.EDU> wrote:
> 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 (&optional 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 (&optional 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 &rest 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 &optional prefixes &rest 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 <tab>
> > -	;; 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 (&optional initial-input &rest 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 <tab>
> > +	 ;; 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))))
> 

done

> > +	(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 `+this_tag' or `-that_tag'"))))))
> > +    (sort result-tags 'string<)))
> >  
> >  (defun notmuch-foreach-mime-part (function mm-handle)
> >    (cond ((stringp (car mm-handle))
> > @@ -447,6 +466,10 @@ Complete list of currently available key bindings:
> >    "Return a list of threads for the current region"
> >    (notmuch-search-properties-in-region 'notmuch-search-thread-id beg end))
> >  
> > +(defun notmuch-search-find-thread-id-region-search (beg end)
> > +  "Return a search string for threads for the current region"
> > +  (mapconcat 'identity (notmuch-search-find-thread-id-region beg end) " or "))
> > +
> >  (defun notmuch-search-find-authors ()
> >    "Return the authors for the current thread"
> >    (get-text-property (point) 'notmuch-search-authors))
> > @@ -590,74 +613,53 @@ the messages that were tagged"
> >  	(forward-line 1))
> >        output)))
> >  
> > -(defun notmuch-search-add-tag-thread (tag)
> > -  (notmuch-search-add-tag-region tag (point) (point)))
> > +(defun notmuch-search-tag-thread (&rest tags)
> 
> Maybe "tag-changes" instead of "tags" for this and
> notmuch-search-tag-region?
> 

This should also be changed in `notmuch-search-tag-all' and
`notmuch-tag' (which involved docstring changes), so I will do this in a
separate patch.

Regards,
  Dmitry

> > +  "Change tags for the currently selected thread.
> >  
> > -(defun notmuch-search-add-tag-region (tag beg end)
> > -  (let ((search-id-string (mapconcat 'identity (notmuch-search-find-thread-id-region beg end) " or ")))
> > -    (notmuch-tag search-id-string (concat "+" tag))
> > -    (save-excursion
> > -      (let ((last-line (line-number-at-pos end))
> > -	    (max-line (- (line-number-at-pos (point-max)) 2)))
> > -	(goto-char beg)
> > -	(while (<= (line-number-at-pos) (min last-line max-line))
> > -	  (notmuch-search-set-tags (delete-dups (sort (cons tag (notmuch-search-get-tags)) 'string<)))
> > -	  (forward-line))))))
> > +See `notmuch-search-tag-region' for details."
> > +  (apply 'notmuch-search-tag-region (point) (point) tags))
> >  
> > -(defun notmuch-search-remove-tag-thread (tag)
> > -  (notmuch-search-remove-tag-region tag (point) (point)))
> > +(defun notmuch-search-tag-region (beg end &rest tags)
> > +  "Change tags for threads in the given region.
> >  
> > -(defun notmuch-search-remove-tag-region (tag beg end)
> > -  (let ((search-id-string (mapconcat 'identity (notmuch-search-find-thread-id-region beg end) " or ")))
> > -    (notmuch-tag search-id-string (concat "-" tag))
> > +TAGS is a list of tag operations for `notmuch-tag'.  The tags are
> > +added or removed for all threads in the region from BEG to END."
> > +  (let ((search-string (notmuch-search-find-thread-id-region-search beg end)))
> > +    (apply 'notmuch-tag search-string tags)
> >      (save-excursion
> >        (let ((last-line (line-number-at-pos end))
> >  	    (max-line (- (line-number-at-pos (point-max)) 2)))
> >  	(goto-char beg)
> >  	(while (<= (line-number-at-pos) (min last-line max-line))
> > -	  (notmuch-search-set-tags (delete tag (notmuch-search-get-tags)))
> > +	  (notmuch-search-set-tags
> > +	   (notmuch-update-tags (notmuch-search-get-tags) tags))
> >  	  (forward-line))))))
> >  
> > -(defun notmuch-search-add-tag (tag)
> > -  "Add a tag to the currently selected thread or region.
> > -
> > -The tag is added to all messages in the currently selected thread
> > -or threads in the current region."
> > -  (interactive
> > -   (list (notmuch-select-tag-with-completion "Tag to add: ")))
> > -  (save-excursion
> > -    (if (region-active-p)
> > -	(let* ((beg (region-beginning))
> > -	       (end (region-end)))
> > -	  (notmuch-search-add-tag-region tag beg end))
> > -      (notmuch-search-add-tag-thread tag))))
> > -
> > -(defun notmuch-search-remove-tag (tag)
> > -  "Remove a tag from the currently selected thread or region.
> 
> It's great to see all of this old copy-pasted code go away!
> 
> > +(defun notmuch-search-tag (&optional initial-input)
> > +  "Change tags for the currently selected thread or region."
> > +  (interactive)
> > +  (let* ((beg (if (region-active-p) (region-beginning) (point)))
> > +	 (end (if (region-active-p) (region-end) (point)))
> > +	 (search-string (notmuch-search-find-thread-id-region-search beg end))
> > +	 (tags (notmuch-read-tag-changes initial-input search-string)))
> > +    (apply 'notmuch-search-tag-region beg end tags)))
> > +
> > +(defun notmuch-search-add-tag ()
> > +  "Same as `notmuch-search-tag' but sets initial input to '+'."
> > +  (interactive)
> > +  (notmuch-search-tag "+"))
> >  
> > -The tag is removed from all messages in the currently selected
> > -thread or threads in the current region."
> > -  (interactive
> > -   (list (notmuch-select-tag-with-completion
> > -	  "Tag to remove: "
> > -	  (if (region-active-p)
> > -	      (mapconcat 'identity
> > -			 (notmuch-search-find-thread-id-region (region-beginning) (region-end))
> > -			 " ")
> > -	    (notmuch-search-find-thread-id)))))
> > -  (save-excursion
> > -    (if (region-active-p)
> > -	(let* ((beg (region-beginning))
> > -	       (end (region-end)))
> > -	  (notmuch-search-remove-tag-region tag beg end))
> > -      (notmuch-search-remove-tag-thread tag))))
> > +(defun notmuch-search-remove-tag ()
> > +  "Same as `notmuch-search-tag' but sets initial input to '-'."
> > +  (interactive)
> > +  (notmuch-search-tag "-"))
> >  
> >  (defun notmuch-search-archive-thread ()
> >    "Archive the currently selected thread (remove its \"inbox\" tag).
> >  
> >  This function advances the next thread when finished."
> >    (interactive)
> > -  (notmuch-search-remove-tag-thread "inbox")
> > +  (notmuch-search-tag-thread "-inbox")
> >    (notmuch-search-next-thread))
> >  
> >  (defvar notmuch-search-process-filter-data nil
> > @@ -893,9 +895,7 @@ will prompt for tags to be added or removed. Tags prefixed with
> >  Each character of the tag name may consist of alphanumeric
> >  characters as well as `_.+-'.
> >  "
> > -  (interactive (notmuch-select-tags-with-completion
> > -		"Operations (+add -drop): notmuch tag "
> > -		'("+" "-")))
> > +  (interactive (notmuch-read-tag-changes))
> >    (apply 'notmuch-tag notmuch-search-query-string actions))
> >  
> >  (defun notmuch-search-buffer-title (query)

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v2 13/13] NEWS: document Emacs UI tagging operations changes
  2012-01-30  5:04     ` Austin Clements
@ 2012-01-30  5:16       ` Dmitry Kurochkin
  0 siblings, 0 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-01-30  5:16 UTC (permalink / raw)
  To: Austin Clements; +Cc: notmuch

On Mon, 30 Jan 2012 00:04:02 -0500, Austin Clements <amdragon@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
> >  ---------------
> >  

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v2 10/13] emacs: use message ids instead of thread id in `notmuch-show-operate-all'
  2012-01-30  4:57     ` Austin Clements
@ 2012-01-30  5:21       ` Dmitry Kurochkin
  0 siblings, 0 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-01-30  5:21 UTC (permalink / raw)
  To: Austin Clements; +Cc: notmuch

On Sun, 29 Jan 2012 23:57:09 -0500, Austin Clements <amdragon@MIT.EDU> wrote:
> 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?
> 

ouch

> > "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.
> 

This patch can not be moved before the one that introduces
`notmuch-show-tag-all', because it changes `notmuch-show-tag-all'.
Perhaps you meant to factor out `notmuch-show-mapc' and
`notmuch-show-get-messages-ids-search' into a separate patch(es), but I
am too lazy.

I merged this patch into the one which introduces
`notmuch-show-tag-all'.

Regards,
  Dmitry

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

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v2 11/13] emacs: code cleanup in `notmuch-show-operate-all', no functional changes
  2012-01-30  4:59     ` Austin Clements
@ 2012-01-30  5:25       ` Dmitry Kurochkin
  0 siblings, 0 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-01-30  5:25 UTC (permalink / raw)
  To: Austin Clements; +Cc: notmuch

On Sun, 29 Jan 2012 23:59:08 -0500, Austin Clements <amdragon@MIT.EDU> wrote:
> notmuch-show-tag-all, in the first line of the commit message.
> 

ouch, again

> As in the previous patch, if the previous patch comes earlier in the
> series, notmuch-show-tag-all could be written this way initially.
> 

As with the previous patch, I merged it into the patch that introduces
`notmuch-show-tag-all'.

Regards,
  Dmitry

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

^ permalink raw reply	[flat|nested] 136+ messages in thread

* emacs: more flexible and consistent tagging operations
  2012-01-28  4:41 [PATCH 1/6] emacs: move tag format validation to `notmuch-tag' function Dmitry Kurochkin
                   ` (8 preceding siblings ...)
  2012-01-30  2:26 ` [PATCH v2 00/13] emacs: more robust and consistent tagging operations Dmitry Kurochkin
@ 2012-01-30  5:33 ` Dmitry Kurochkin
  2012-01-30  5:33   ` [PATCH v3 01/12] emacs: move tag format validation to `notmuch-tag' function Dmitry Kurochkin
                     ` (14 more replies)
  2012-02-05  7:13 ` [PATCH v5 00/12] emacs: more flexible and consistent tagging operations Dmitry Kurochkin
  10 siblings, 15 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-01-30  5:33 UTC (permalink / raw)
  To: notmuch

Changes:

v3:

* merged 3 `notmuch-show-tag-all'-related patches into one

* add patch to clean up tagging function argument names

* fix other comments from Austin's reviews [5,6]

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.GK17991@mit.edu"
[2] id:"20120129225710.GG17991@mit.edu"
[3] id:"20120129230229.GI17991@mit.edu"
[4] id:"20120129231120.GJ17991@mit.edu"
[5] id:"20120130044806.GM17991@mit.edu"
[6] id:"20120130050402.GP17991@mit.edu"

^ permalink raw reply	[flat|nested] 136+ messages in thread

* [PATCH v3 01/12] emacs: move tag format validation to `notmuch-tag' function
  2012-01-30  5:33 ` emacs: more flexible and consistent tagging operations Dmitry Kurochkin
@ 2012-01-30  5:33   ` Dmitry Kurochkin
  2012-01-30  5:33   ` [PATCH v3 02/12] emacs: remove text properties from `notmuch-search-get-tags' result Dmitry Kurochkin
                     ` (13 subsequent siblings)
  14 siblings, 0 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-01-30  5:33 UTC (permalink / raw)
  To: notmuch

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"))
+  (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)
-- 
1.7.8.3

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v3 02/12] emacs: remove text properties from `notmuch-search-get-tags' result
  2012-01-30  5:33 ` emacs: more flexible and consistent tagging operations Dmitry Kurochkin
  2012-01-30  5:33   ` [PATCH v3 01/12] emacs: move tag format validation to `notmuch-tag' function Dmitry Kurochkin
@ 2012-01-30  5:33   ` Dmitry Kurochkin
  2012-01-30  5:33   ` [PATCH v3 03/12] emacs: make "+" and "-" tagging operations in notmuch-search more flexible Dmitry Kurochkin
                     ` (12 subsequent siblings)
  14 siblings, 0 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-01-30  5:33 UTC (permalink / raw)
  To: notmuch

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

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v3 03/12] emacs: make "+" and "-" tagging operations in notmuch-search more flexible
  2012-01-30  5:33 ` emacs: more flexible and consistent tagging operations Dmitry Kurochkin
  2012-01-30  5:33   ` [PATCH v3 01/12] emacs: move tag format validation to `notmuch-tag' function Dmitry Kurochkin
  2012-01-30  5:33   ` [PATCH v3 02/12] emacs: remove text properties from `notmuch-search-get-tags' result Dmitry Kurochkin
@ 2012-01-30  5:33   ` Dmitry Kurochkin
  2012-01-30  5:33   ` [PATCH v3 04/12] emacs: make "+" and "-" tagging operations in notmuch-show " Dmitry Kurochkin
                     ` (11 subsequent siblings)
  14 siblings, 0 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-01-30  5:33 UTC (permalink / raw)
  To: notmuch

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 |  163 +++++++++++++++++++++++++++---------------------------
 1 files changed, 81 insertions(+), 82 deletions(-)

diff --git a/emacs/notmuch.el b/emacs/notmuch.el
index ff46617..ce8bef6 100644
--- a/emacs/notmuch.el
+++ b/emacs/notmuch.el
@@ -76,38 +76,56 @@ For example:
 (defvar notmuch-query-history nil
   "Variable to store minibuffer history for notmuch queries")
 
-(defun notmuch-tag-completions (&optional 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 (&optional 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 &rest 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 &optional prefixes &rest 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 <tab>
-	;; 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 (&optional initial-input &rest 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 <tab>
+	 ;; 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)
+      (let ((op (string-to-char tag-change))
+	    (tag (unless (string= tag-change "") (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 `+this_tag' or `-that_tag'")))))
+    (sort result-tags 'string<)))
 
 (defun notmuch-foreach-mime-part (function mm-handle)
   (cond ((stringp (car mm-handle))
@@ -447,6 +465,10 @@ Complete list of currently available key bindings:
   "Return a list of threads for the current region"
   (notmuch-search-properties-in-region 'notmuch-search-thread-id beg end))
 
+(defun notmuch-search-find-thread-id-region-search (beg end)
+  "Return a search string for threads for the current region"
+  (mapconcat 'identity (notmuch-search-find-thread-id-region beg end) " or "))
+
 (defun notmuch-search-find-authors ()
   "Return the authors for the current thread"
   (get-text-property (point) 'notmuch-search-authors))
@@ -590,74 +612,53 @@ the messages that were tagged"
 	(forward-line 1))
       output)))
 
-(defun notmuch-search-add-tag-thread (tag)
-  (notmuch-search-add-tag-region tag (point) (point)))
+(defun notmuch-search-tag-thread (&rest tags)
+  "Change tags for the currently selected thread.
 
-(defun notmuch-search-add-tag-region (tag beg end)
-  (let ((search-id-string (mapconcat 'identity (notmuch-search-find-thread-id-region beg end) " or ")))
-    (notmuch-tag search-id-string (concat "+" tag))
-    (save-excursion
-      (let ((last-line (line-number-at-pos end))
-	    (max-line (- (line-number-at-pos (point-max)) 2)))
-	(goto-char beg)
-	(while (<= (line-number-at-pos) (min last-line max-line))
-	  (notmuch-search-set-tags (delete-dups (sort (cons tag (notmuch-search-get-tags)) 'string<)))
-	  (forward-line))))))
+See `notmuch-search-tag-region' for details."
+  (apply 'notmuch-search-tag-region (point) (point) tags))
 
-(defun notmuch-search-remove-tag-thread (tag)
-  (notmuch-search-remove-tag-region tag (point) (point)))
+(defun notmuch-search-tag-region (beg end &rest tags)
+  "Change tags for threads in the given region.
 
-(defun notmuch-search-remove-tag-region (tag beg end)
-  (let ((search-id-string (mapconcat 'identity (notmuch-search-find-thread-id-region beg end) " or ")))
-    (notmuch-tag search-id-string (concat "-" tag))
+TAGS is a list of tag operations for `notmuch-tag'.  The tags are
+added or removed for all threads in the region from BEG to END."
+  (let ((search-string (notmuch-search-find-thread-id-region-search beg end)))
+    (apply 'notmuch-tag search-string tags)
     (save-excursion
       (let ((last-line (line-number-at-pos end))
 	    (max-line (- (line-number-at-pos (point-max)) 2)))
 	(goto-char beg)
 	(while (<= (line-number-at-pos) (min last-line max-line))
-	  (notmuch-search-set-tags (delete tag (notmuch-search-get-tags)))
+	  (notmuch-search-set-tags
+	   (notmuch-update-tags (notmuch-search-get-tags) tags))
 	  (forward-line))))))
 
-(defun notmuch-search-add-tag (tag)
-  "Add a tag to the currently selected thread or region.
-
-The tag is added to all messages in the currently selected thread
-or threads in the current region."
-  (interactive
-   (list (notmuch-select-tag-with-completion "Tag to add: ")))
-  (save-excursion
-    (if (region-active-p)
-	(let* ((beg (region-beginning))
-	       (end (region-end)))
-	  (notmuch-search-add-tag-region tag beg end))
-      (notmuch-search-add-tag-thread tag))))
-
-(defun notmuch-search-remove-tag (tag)
-  "Remove a tag from the currently selected thread or region.
+(defun notmuch-search-tag (&optional initial-input)
+  "Change tags for the currently selected thread or region."
+  (interactive)
+  (let* ((beg (if (region-active-p) (region-beginning) (point)))
+	 (end (if (region-active-p) (region-end) (point)))
+	 (search-string (notmuch-search-find-thread-id-region-search beg end))
+	 (tags (notmuch-read-tag-changes initial-input search-string)))
+    (apply 'notmuch-search-tag-region beg end tags)))
+
+(defun notmuch-search-add-tag ()
+  "Same as `notmuch-search-tag' but sets initial input to '+'."
+  (interactive)
+  (notmuch-search-tag "+"))
 
-The tag is removed from all messages in the currently selected
-thread or threads in the current region."
-  (interactive
-   (list (notmuch-select-tag-with-completion
-	  "Tag to remove: "
-	  (if (region-active-p)
-	      (mapconcat 'identity
-			 (notmuch-search-find-thread-id-region (region-beginning) (region-end))
-			 " ")
-	    (notmuch-search-find-thread-id)))))
-  (save-excursion
-    (if (region-active-p)
-	(let* ((beg (region-beginning))
-	       (end (region-end)))
-	  (notmuch-search-remove-tag-region tag beg end))
-      (notmuch-search-remove-tag-thread tag))))
+(defun notmuch-search-remove-tag ()
+  "Same as `notmuch-search-tag' but sets initial input to '-'."
+  (interactive)
+  (notmuch-search-tag "-"))
 
 (defun notmuch-search-archive-thread ()
   "Archive the currently selected thread (remove its \"inbox\" tag).
 
 This function advances the next thread when finished."
   (interactive)
-  (notmuch-search-remove-tag-thread "inbox")
+  (notmuch-search-tag-thread "-inbox")
   (notmuch-search-next-thread))
 
 (defvar notmuch-search-process-filter-data nil
@@ -893,9 +894,7 @@ will prompt for tags to be added or removed. Tags prefixed with
 Each character of the tag name may consist of alphanumeric
 characters as well as `_.+-'.
 "
-  (interactive (notmuch-select-tags-with-completion
-		"Operations (+add -drop): notmuch tag "
-		'("+" "-")))
+  (interactive (notmuch-read-tag-changes))
   (apply 'notmuch-tag notmuch-search-query-string actions))
 
 (defun notmuch-search-buffer-title (query)
-- 
1.7.8.3

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v3 04/12] emacs: make "+" and "-" tagging operations in notmuch-show more flexible
  2012-01-30  5:33 ` emacs: more flexible and consistent tagging operations Dmitry Kurochkin
                     ` (2 preceding siblings ...)
  2012-01-30  5:33   ` [PATCH v3 03/12] emacs: make "+" and "-" tagging operations in notmuch-search more flexible Dmitry Kurochkin
@ 2012-01-30  5:33   ` Dmitry Kurochkin
  2012-01-30  5:33   ` [PATCH v3 05/12] test: fix emacs tests after tagging operations changes Dmitry Kurochkin
                     ` (10 subsequent siblings)
  14 siblings, 0 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-01-30  5:33 UTC (permalink / raw)
  To: notmuch

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

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v3 05/12] test: fix emacs tests after tagging operations changes
  2012-01-30  5:33 ` emacs: more flexible and consistent tagging operations Dmitry Kurochkin
                     ` (3 preceding siblings ...)
  2012-01-30  5:33   ` [PATCH v3 04/12] emacs: make "+" and "-" tagging operations in notmuch-show " Dmitry Kurochkin
@ 2012-01-30  5:33   ` Dmitry Kurochkin
  2012-01-30  5:33   ` [PATCH v3 06/12] emacs: rename `notmuch-search-operate-all' to `notmuch-search-tag-all' Dmitry Kurochkin
                     ` (9 subsequent siblings)
  14 siblings, 0 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-01-30  5:33 UTC (permalink / raw)
  To: notmuch

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

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v3 06/12] emacs: rename `notmuch-search-operate-all' to `notmuch-search-tag-all'
  2012-01-30  5:33 ` emacs: more flexible and consistent tagging operations Dmitry Kurochkin
                     ` (4 preceding siblings ...)
  2012-01-30  5:33   ` [PATCH v3 05/12] test: fix emacs tests after tagging operations changes Dmitry Kurochkin
@ 2012-01-30  5:33   ` Dmitry Kurochkin
  2012-01-30  5:33   ` [PATCH v3 07/12] emacs: add "*" binding for notmuch-show view Dmitry Kurochkin
                     ` (8 subsequent siblings)
  14 siblings, 0 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-01-30  5:33 UTC (permalink / raw)
  To: notmuch

`Notmuch-search-tag-all' is more clear and consistent with other
tagging function names.
---
 emacs/notmuch.el |    6 +++---
 1 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/emacs/notmuch.el b/emacs/notmuch.el
index ce8bef6..7d06109 100644
--- a/emacs/notmuch.el
+++ b/emacs/notmuch.el
@@ -270,7 +270,7 @@ For a mouse binding, return nil."
     (define-key map "t" 'notmuch-search-filter-by-tag)
     (define-key map "f" 'notmuch-search-filter)
     (define-key map [mouse-1] 'notmuch-search-show-thread)
-    (define-key map "*" 'notmuch-search-operate-all)
+    (define-key map "*" 'notmuch-search-tag-all)
     (define-key map "a" 'notmuch-search-archive-thread)
     (define-key map "-" 'notmuch-search-remove-tag)
     (define-key map "+" 'notmuch-search-add-tag)
@@ -419,7 +419,7 @@ any tags).
 Pressing \\[notmuch-search-show-thread] on any line displays that thread. The '\\[notmuch-search-add-tag]' and '\\[notmuch-search-remove-tag]'
 keys can be used to add or remove tags from a thread. The '\\[notmuch-search-archive-thread]' key
 is a convenience for archiving a thread (removing the \"inbox\"
-tag). The '\\[notmuch-search-operate-all]' key can be used to add or remove a tag from all
+tag). The '\\[notmuch-search-tag-all]' key can be used to add or remove a tag from all
 threads in the current buffer.
 
 Other useful commands are '\\[notmuch-search-filter]' for filtering the current search
@@ -883,7 +883,7 @@ non-authors is found, assume that all of the authors match."
 	      (goto-char found-target)))
       (delete-process proc))))
 
-(defun notmuch-search-operate-all (&rest actions)
+(defun notmuch-search-tag-all (&rest actions)
   "Add/remove tags from all matching messages.
 
 This command adds or removes tags from all messages matching the
-- 
1.7.8.3

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v3 07/12] emacs: add "*" binding for notmuch-show view
  2012-01-30  5:33 ` emacs: more flexible and consistent tagging operations Dmitry Kurochkin
                     ` (5 preceding siblings ...)
  2012-01-30  5:33   ` [PATCH v3 06/12] emacs: rename `notmuch-search-operate-all' to `notmuch-search-tag-all' Dmitry Kurochkin
@ 2012-01-30  5:33   ` Dmitry Kurochkin
  2012-01-30  5:34   ` [PATCH v3 08/12] emacs: separate history for operations which accept single and multiple tags Dmitry Kurochkin
                     ` (7 subsequent siblings)
  14 siblings, 0 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-01-30  5:33 UTC (permalink / raw)
  To: notmuch

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 |   35 +++++++++++++++++++++++++++++++++++
 1 files changed, 35 insertions(+), 0 deletions(-)

diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
index 11dab2d..69381ac 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)
@@ -1169,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.
 
@@ -1221,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 ()
@@ -1488,6 +1510,19 @@ 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-get-messages-ids-search) tag-changes)
+  (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 '+'."
   (interactive)
-- 
1.7.8.3

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v3 08/12] emacs: separate history for operations which accept single and multiple tags
  2012-01-30  5:33 ` emacs: more flexible and consistent tagging operations Dmitry Kurochkin
                     ` (6 preceding siblings ...)
  2012-01-30  5:33   ` [PATCH v3 07/12] emacs: add "*" binding for notmuch-show view Dmitry Kurochkin
@ 2012-01-30  5:34   ` Dmitry Kurochkin
  2012-01-30  5:34   ` [PATCH v3 09/12] emacs: relax tag syntax check in `notmuch-tag' function Dmitry Kurochkin
                     ` (6 subsequent siblings)
  14 siblings, 0 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-01-30  5:34 UTC (permalink / raw)
  To: notmuch

Some tag-related operations accept a single tag without prefix
(`notmuch-select-tag-with-completion'), others accept multiple tags
prefixed with '+' or '-' (`notmuch-read-tag-changes').  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 |   13 +++++++++++--
 1 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/emacs/notmuch.el b/emacs/notmuch.el
index 7d06109..0a3bd17 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 minibuffer history for
+`notmuch-select-tag-with-completion' function.")
+
+(defvar notmuch-read-tag-changes-history nil
+  "Variable to store minibuffer history for
+`notmuch-read-tag-changes' function.")
+
 (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-read-tag-changes (&optional initial-input &rest search-terms)
   (let* ((all-tag-list (notmuch-tag-completions))
@@ -106,7 +114,8 @@ For example:
 	    (define-key map " " 'self-insert-command)
 	    map)))
     (delete "" (completing-read-multiple "Tags (+add -drop): "
-		tag-list nil nil initial-input))))
+		tag-list nil nil initial-input
+		'notmuch-read-tag-changes-history))))
 
 (defun notmuch-update-tags (tags tag-changes)
   "Return a copy of TAGS with additions and removals from TAG-CHANGES.
-- 
1.7.8.3

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v3 09/12] emacs: relax tag syntax check in `notmuch-tag' function
  2012-01-30  5:33 ` emacs: more flexible and consistent tagging operations Dmitry Kurochkin
                     ` (7 preceding siblings ...)
  2012-01-30  5:34   ` [PATCH v3 08/12] emacs: separate history for operations which accept single and multiple tags Dmitry Kurochkin
@ 2012-01-30  5:34   ` Dmitry Kurochkin
  2012-01-30  5:34   ` [PATCH v3 10/12] emacs: accept empty tag list in `notmuch-tag' Dmitry Kurochkin
                     ` (5 subsequent siblings)
  14 siblings, 0 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-01-30  5:34 UTC (permalink / raw)
  To: notmuch

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 0a3bd17..2332c42 100644
--- a/emacs/notmuch.el
+++ b/emacs/notmuch.el
@@ -556,7 +556,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

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v3 10/12] emacs: accept empty tag list in `notmuch-tag'
  2012-01-30  5:33 ` emacs: more flexible and consistent tagging operations Dmitry Kurochkin
                     ` (8 preceding siblings ...)
  2012-01-30  5:34   ` [PATCH v3 09/12] emacs: relax tag syntax check in `notmuch-tag' function Dmitry Kurochkin
@ 2012-01-30  5:34   ` Dmitry Kurochkin
  2012-01-30  5:34   ` [PATCH v3 11/12] emacs: s/tags/tag-changes/ for arguments of tagging functions Dmitry Kurochkin
                     ` (4 subsequent siblings)
  14 siblings, 0 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-01-30  5:34 UTC (permalink / raw)
  To: notmuch

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 2332c42..c464c3c 100644
--- a/emacs/notmuch.el
+++ b/emacs/notmuch.el
@@ -554,15 +554,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

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v3 11/12] emacs: s/tags/tag-changes/ for arguments of tagging functions
  2012-01-30  5:33 ` emacs: more flexible and consistent tagging operations Dmitry Kurochkin
                     ` (9 preceding siblings ...)
  2012-01-30  5:34   ` [PATCH v3 10/12] emacs: accept empty tag list in `notmuch-tag' Dmitry Kurochkin
@ 2012-01-30  5:34   ` Dmitry Kurochkin
  2012-01-30  5:34   ` [PATCH v3 12/12] NEWS: document Emacs UI tagging operations changes Dmitry Kurochkin
                     ` (3 subsequent siblings)
  14 siblings, 0 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-01-30  5:34 UTC (permalink / raw)
  To: notmuch

This makes the argument names more consistent and clear.  The
following functions changed: `notmuch-tag',
`notmuch-search-tag-thread', `notmuch-search-tag-region' and
`notmuch-search-tag-all'.
---
 emacs/notmuch.el |   33 +++++++++++++++++----------------
 1 files changed, 17 insertions(+), 16 deletions(-)

diff --git a/emacs/notmuch.el b/emacs/notmuch.el
index c464c3c..fa62019 100644
--- a/emacs/notmuch.el
+++ b/emacs/notmuch.el
@@ -543,25 +543,26 @@ and will also appear in a buffer named \"*Notmuch errors*\"."
 	    (error (buffer-substring beg end))
 	    ))))))
 
-(defun notmuch-tag (query &rest tags)
-  "Add/remove tags in TAGS to messages matching QUERY.
+(defun notmuch-tag (query &rest tag-changes)
+  "Add/remove tags in TAG-CHANGES to messages matching QUERY.
 
-TAGS should be a list of strings of the form \"+TAG\" or \"-TAG\" and
-QUERY should be a string containing the search-query.
+TAG-CHANGES should be a list of strings of the form \"+tag\" or
+\"-tag\" and QUERY should be a string containing the
+search-query.
 
 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
-  (mapc (lambda (tag)
-	  (unless (string-match-p "^[-+]\\S-+$" tag)
+  (mapc (lambda (tag-change)
+	  (unless (string-match-p "^[-+]\\S-+$" tag-change)
 	    (error "Tag must be of the form `+this_tag' or `-that_tag'")))
-	tags)
-  (unless (null tags)
+	tag-changes)
+  (unless (null tag-changes)
     (run-hooks 'notmuch-before-tag-hook)
     (apply 'notmuch-call-notmuch-process "tag"
-	   (append tags (list "--" query)))
+	   (append tag-changes (list "--" query)))
     (run-hooks 'notmuch-after-tag-hook)))
 
 (defcustom notmuch-before-tag-hook nil
@@ -621,26 +622,26 @@ the messages that were tagged"
 	(forward-line 1))
       output)))
 
-(defun notmuch-search-tag-thread (&rest tags)
+(defun notmuch-search-tag-thread (&rest tag-changes)
   "Change tags for the currently selected thread.
 
 See `notmuch-search-tag-region' for details."
-  (apply 'notmuch-search-tag-region (point) (point) tags))
+  (apply 'notmuch-search-tag-region (point) (point) tag-changes))
 
-(defun notmuch-search-tag-region (beg end &rest tags)
+(defun notmuch-search-tag-region (beg end &rest tag-changes)
   "Change tags for threads in the given region.
 
 TAGS is a list of tag operations for `notmuch-tag'.  The tags are
 added or removed for all threads in the region from BEG to END."
   (let ((search-string (notmuch-search-find-thread-id-region-search beg end)))
-    (apply 'notmuch-tag search-string tags)
+    (apply 'notmuch-tag search-string tag-changes)
     (save-excursion
       (let ((last-line (line-number-at-pos end))
 	    (max-line (- (line-number-at-pos (point-max)) 2)))
 	(goto-char beg)
 	(while (<= (line-number-at-pos) (min last-line max-line))
 	  (notmuch-search-set-tags
-	   (notmuch-update-tags (notmuch-search-get-tags) tags))
+	   (notmuch-update-tags (notmuch-search-get-tags) tag-changes))
 	  (forward-line))))))
 
 (defun notmuch-search-tag (&optional initial-input)
@@ -892,7 +893,7 @@ non-authors is found, assume that all of the authors match."
 	      (goto-char found-target)))
       (delete-process proc))))
 
-(defun notmuch-search-tag-all (&rest actions)
+(defun notmuch-search-tag-all (&rest tag-changes)
   "Add/remove tags from all matching messages.
 
 This command adds or removes tags from all messages matching the
@@ -904,7 +905,7 @@ Each character of the tag name may consist of alphanumeric
 characters as well as `_.+-'.
 "
   (interactive (notmuch-read-tag-changes))
-  (apply 'notmuch-tag notmuch-search-query-string actions))
+  (apply 'notmuch-tag notmuch-search-query-string tag-changes))
 
 (defun notmuch-search-buffer-title (query)
   "Returns the title for a buffer with notmuch search results."
-- 
1.7.8.3

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v3 12/12] NEWS: document Emacs UI tagging operations changes
  2012-01-30  5:33 ` emacs: more flexible and consistent tagging operations Dmitry Kurochkin
                     ` (10 preceding siblings ...)
  2012-01-30  5:34   ` [PATCH v3 11/12] emacs: s/tags/tag-changes/ for arguments of tagging functions Dmitry Kurochkin
@ 2012-01-30  5:34   ` Dmitry Kurochkin
  2012-01-30 15:20   ` emacs: more flexible and consistent tagging operations Austin Clements
                     ` (2 subsequent siblings)
  14 siblings, 0 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-01-30  5:34 UTC (permalink / raw)
  To: notmuch

---
 NEWS |   18 ++++++++++++++++++
 1 files changed, 18 insertions(+), 0 deletions(-)

diff --git a/NEWS b/NEWS
index 2acdce5..7506d68 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 flexible and consistent tagging operations
+
+  All tagging operations ("+", "-", "*") now accept multiple tags with
+  "+" or "-" prefix, like "*" operation in notmuch-search view before.
+
+  "*" operation (`notmuch-show-tag-all') is now available in
+  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
 ---------------
 
-- 
1.7.8.3

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* Re: emacs: more flexible and consistent tagging operations
  2012-01-30  5:33 ` emacs: more flexible and consistent tagging operations Dmitry Kurochkin
                     ` (11 preceding siblings ...)
  2012-01-30  5:34   ` [PATCH v3 12/12] NEWS: document Emacs UI tagging operations changes Dmitry Kurochkin
@ 2012-01-30 15:20   ` Austin Clements
  2012-01-30 15:55   ` Tomi Ollila
  2012-01-31  4:54   ` [PATCH v4 00/12] " Dmitry Kurochkin
  14 siblings, 0 replies; 136+ messages in thread
From: Austin Clements @ 2012-01-30 15:20 UTC (permalink / raw)
  To: Dmitry Kurochkin; +Cc: notmuch

The whole series LGTM.

Quoth Dmitry Kurochkin on Jan 30 at  9:33 am:
> Changes:
> 
> v3:
> 
> * merged 3 `notmuch-show-tag-all'-related patches into one
> 
> * add patch to clean up tagging function argument names
> 
> * fix other comments from Austin's reviews [5,6]
> 
> 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.GK17991@mit.edu"
> [2] id:"20120129225710.GG17991@mit.edu"
> [3] id:"20120129230229.GI17991@mit.edu"
> [4] id:"20120129231120.GJ17991@mit.edu"
> [5] id:"20120130044806.GM17991@mit.edu"
> [6] id:"20120130050402.GP17991@mit.edu"

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: emacs: more flexible and consistent tagging operations
  2012-01-30  5:33 ` emacs: more flexible and consistent tagging operations Dmitry Kurochkin
                     ` (12 preceding siblings ...)
  2012-01-30 15:20   ` emacs: more flexible and consistent tagging operations Austin Clements
@ 2012-01-30 15:55   ` Tomi Ollila
  2012-01-31  4:54   ` [PATCH v4 00/12] " Dmitry Kurochkin
  14 siblings, 0 replies; 136+ messages in thread
From: Tomi Ollila @ 2012-01-30 15:55 UTC (permalink / raw)
  To: Dmitry Kurochkin, notmuch


Works fine. +1

Tomi

^ permalink raw reply	[flat|nested] 136+ messages in thread

* [PATCH v4 00/12] emacs: more flexible and consistent tagging operations
  2012-01-30  5:33 ` emacs: more flexible and consistent tagging operations Dmitry Kurochkin
                     ` (13 preceding siblings ...)
  2012-01-30 15:55   ` Tomi Ollila
@ 2012-01-31  4:54   ` Dmitry Kurochkin
  2012-01-31  4:54     ` [PATCH v4 01/12] emacs: move tag format validation to `notmuch-tag' function Dmitry Kurochkin
                       ` (11 more replies)
  14 siblings, 12 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-01-31  4:54 UTC (permalink / raw)
  To: notmuch

Changes:

v4:

* rebased on master after Jameson's archiving changes

v3:

* merged 3 `notmuch-show-tag-all'-related patches into one

* add patch to clean up tagging function argument names

* fix other comments from Austin's reviews [5,6]

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.GK17991@mit.edu"
[2] id:"20120129225710.GG17991@mit.edu"
[3] id:"20120129230229.GI17991@mit.edu"
[4] id:"20120129231120.GJ17991@mit.edu"
[5] id:"20120130044806.GM17991@mit.edu"
[6] id:"20120130050402.GP17991@mit.edu"

^ permalink raw reply	[flat|nested] 136+ messages in thread

* [PATCH v4 01/12] emacs: move tag format validation to `notmuch-tag' function
  2012-01-31  4:54   ` [PATCH v4 00/12] " Dmitry Kurochkin
@ 2012-01-31  4:54     ` Dmitry Kurochkin
  2012-01-31  4:54     ` [PATCH v4 02/12] emacs: remove text properties from `notmuch-search-get-tags' result Dmitry Kurochkin
                       ` (10 subsequent siblings)
  11 siblings, 0 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-01-31  4:54 UTC (permalink / raw)
  To: notmuch

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"))
+  (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)
-- 
1.7.9

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v4 02/12] emacs: remove text properties from `notmuch-search-get-tags' result
  2012-01-31  4:54   ` [PATCH v4 00/12] " Dmitry Kurochkin
  2012-01-31  4:54     ` [PATCH v4 01/12] emacs: move tag format validation to `notmuch-tag' function Dmitry Kurochkin
@ 2012-01-31  4:54     ` Dmitry Kurochkin
  2012-02-04  1:49       ` David Bremner
  2012-01-31  4:54     ` [PATCH v4 03/12] emacs: make "+" and "-" tagging operations in notmuch-search more flexible Dmitry Kurochkin
                       ` (9 subsequent siblings)
  11 siblings, 1 reply; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-01-31  4:54 UTC (permalink / raw)
  To: notmuch

---
 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.9

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v4 03/12] emacs: make "+" and "-" tagging operations in notmuch-search more flexible
  2012-01-31  4:54   ` [PATCH v4 00/12] " Dmitry Kurochkin
  2012-01-31  4:54     ` [PATCH v4 01/12] emacs: move tag format validation to `notmuch-tag' function Dmitry Kurochkin
  2012-01-31  4:54     ` [PATCH v4 02/12] emacs: remove text properties from `notmuch-search-get-tags' result Dmitry Kurochkin
@ 2012-01-31  4:54     ` Dmitry Kurochkin
  2012-01-31  4:54     ` [PATCH v4 04/12] emacs: make "+" and "-" tagging operations in notmuch-show " Dmitry Kurochkin
                       ` (8 subsequent siblings)
  11 siblings, 0 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-01-31  4:54 UTC (permalink / raw)
  To: notmuch

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 |  163 +++++++++++++++++++++++++++---------------------------
 1 files changed, 81 insertions(+), 82 deletions(-)

diff --git a/emacs/notmuch.el b/emacs/notmuch.el
index ff46617..ce8bef6 100644
--- a/emacs/notmuch.el
+++ b/emacs/notmuch.el
@@ -76,38 +76,56 @@ For example:
 (defvar notmuch-query-history nil
   "Variable to store minibuffer history for notmuch queries")
 
-(defun notmuch-tag-completions (&optional 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 (&optional 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 &rest 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 &optional prefixes &rest 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 <tab>
-	;; 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 (&optional initial-input &rest 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 <tab>
+	 ;; 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)
+      (let ((op (string-to-char tag-change))
+	    (tag (unless (string= tag-change "") (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 `+this_tag' or `-that_tag'")))))
+    (sort result-tags 'string<)))
 
 (defun notmuch-foreach-mime-part (function mm-handle)
   (cond ((stringp (car mm-handle))
@@ -447,6 +465,10 @@ Complete list of currently available key bindings:
   "Return a list of threads for the current region"
   (notmuch-search-properties-in-region 'notmuch-search-thread-id beg end))
 
+(defun notmuch-search-find-thread-id-region-search (beg end)
+  "Return a search string for threads for the current region"
+  (mapconcat 'identity (notmuch-search-find-thread-id-region beg end) " or "))
+
 (defun notmuch-search-find-authors ()
   "Return the authors for the current thread"
   (get-text-property (point) 'notmuch-search-authors))
@@ -590,74 +612,53 @@ the messages that were tagged"
 	(forward-line 1))
       output)))
 
-(defun notmuch-search-add-tag-thread (tag)
-  (notmuch-search-add-tag-region tag (point) (point)))
+(defun notmuch-search-tag-thread (&rest tags)
+  "Change tags for the currently selected thread.
 
-(defun notmuch-search-add-tag-region (tag beg end)
-  (let ((search-id-string (mapconcat 'identity (notmuch-search-find-thread-id-region beg end) " or ")))
-    (notmuch-tag search-id-string (concat "+" tag))
-    (save-excursion
-      (let ((last-line (line-number-at-pos end))
-	    (max-line (- (line-number-at-pos (point-max)) 2)))
-	(goto-char beg)
-	(while (<= (line-number-at-pos) (min last-line max-line))
-	  (notmuch-search-set-tags (delete-dups (sort (cons tag (notmuch-search-get-tags)) 'string<)))
-	  (forward-line))))))
+See `notmuch-search-tag-region' for details."
+  (apply 'notmuch-search-tag-region (point) (point) tags))
 
-(defun notmuch-search-remove-tag-thread (tag)
-  (notmuch-search-remove-tag-region tag (point) (point)))
+(defun notmuch-search-tag-region (beg end &rest tags)
+  "Change tags for threads in the given region.
 
-(defun notmuch-search-remove-tag-region (tag beg end)
-  (let ((search-id-string (mapconcat 'identity (notmuch-search-find-thread-id-region beg end) " or ")))
-    (notmuch-tag search-id-string (concat "-" tag))
+TAGS is a list of tag operations for `notmuch-tag'.  The tags are
+added or removed for all threads in the region from BEG to END."
+  (let ((search-string (notmuch-search-find-thread-id-region-search beg end)))
+    (apply 'notmuch-tag search-string tags)
     (save-excursion
       (let ((last-line (line-number-at-pos end))
 	    (max-line (- (line-number-at-pos (point-max)) 2)))
 	(goto-char beg)
 	(while (<= (line-number-at-pos) (min last-line max-line))
-	  (notmuch-search-set-tags (delete tag (notmuch-search-get-tags)))
+	  (notmuch-search-set-tags
+	   (notmuch-update-tags (notmuch-search-get-tags) tags))
 	  (forward-line))))))
 
-(defun notmuch-search-add-tag (tag)
-  "Add a tag to the currently selected thread or region.
-
-The tag is added to all messages in the currently selected thread
-or threads in the current region."
-  (interactive
-   (list (notmuch-select-tag-with-completion "Tag to add: ")))
-  (save-excursion
-    (if (region-active-p)
-	(let* ((beg (region-beginning))
-	       (end (region-end)))
-	  (notmuch-search-add-tag-region tag beg end))
-      (notmuch-search-add-tag-thread tag))))
-
-(defun notmuch-search-remove-tag (tag)
-  "Remove a tag from the currently selected thread or region.
+(defun notmuch-search-tag (&optional initial-input)
+  "Change tags for the currently selected thread or region."
+  (interactive)
+  (let* ((beg (if (region-active-p) (region-beginning) (point)))
+	 (end (if (region-active-p) (region-end) (point)))
+	 (search-string (notmuch-search-find-thread-id-region-search beg end))
+	 (tags (notmuch-read-tag-changes initial-input search-string)))
+    (apply 'notmuch-search-tag-region beg end tags)))
+
+(defun notmuch-search-add-tag ()
+  "Same as `notmuch-search-tag' but sets initial input to '+'."
+  (interactive)
+  (notmuch-search-tag "+"))
 
-The tag is removed from all messages in the currently selected
-thread or threads in the current region."
-  (interactive
-   (list (notmuch-select-tag-with-completion
-	  "Tag to remove: "
-	  (if (region-active-p)
-	      (mapconcat 'identity
-			 (notmuch-search-find-thread-id-region (region-beginning) (region-end))
-			 " ")
-	    (notmuch-search-find-thread-id)))))
-  (save-excursion
-    (if (region-active-p)
-	(let* ((beg (region-beginning))
-	       (end (region-end)))
-	  (notmuch-search-remove-tag-region tag beg end))
-      (notmuch-search-remove-tag-thread tag))))
+(defun notmuch-search-remove-tag ()
+  "Same as `notmuch-search-tag' but sets initial input to '-'."
+  (interactive)
+  (notmuch-search-tag "-"))
 
 (defun notmuch-search-archive-thread ()
   "Archive the currently selected thread (remove its \"inbox\" tag).
 
 This function advances the next thread when finished."
   (interactive)
-  (notmuch-search-remove-tag-thread "inbox")
+  (notmuch-search-tag-thread "-inbox")
   (notmuch-search-next-thread))
 
 (defvar notmuch-search-process-filter-data nil
@@ -893,9 +894,7 @@ will prompt for tags to be added or removed. Tags prefixed with
 Each character of the tag name may consist of alphanumeric
 characters as well as `_.+-'.
 "
-  (interactive (notmuch-select-tags-with-completion
-		"Operations (+add -drop): notmuch tag "
-		'("+" "-")))
+  (interactive (notmuch-read-tag-changes))
   (apply 'notmuch-tag notmuch-search-query-string actions))
 
 (defun notmuch-search-buffer-title (query)
-- 
1.7.9

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v4 04/12] emacs: make "+" and "-" tagging operations in notmuch-show more flexible
  2012-01-31  4:54   ` [PATCH v4 00/12] " Dmitry Kurochkin
                       ` (2 preceding siblings ...)
  2012-01-31  4:54     ` [PATCH v4 03/12] emacs: make "+" and "-" tagging operations in notmuch-search more flexible Dmitry Kurochkin
@ 2012-01-31  4:54     ` Dmitry Kurochkin
  2012-01-31  4:54     ` [PATCH v4 05/12] test: fix emacs tests after tagging operations changes Dmitry Kurochkin
                       ` (7 subsequent siblings)
  11 siblings, 0 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-01-31  4:54 UTC (permalink / raw)
  To: notmuch

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 |   73 +++++++++++++++++-------------------------------
 1 files changed, 26 insertions(+), 47 deletions(-)

diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
index de9421e..a0efae7 100644
--- a/emacs/notmuch-show.el
+++ b/emacs/notmuch-show.el
@@ -38,9 +38,10 @@
 
 (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-next-thread "notmuch" nil)
 (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.
@@ -1269,7 +1270,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.
@@ -1483,51 +1484,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."
@@ -1575,10 +1557,8 @@ argument, hide all of the messages."
 If the remove switch is given, tags will be removed instead of
 added."
   (goto-char (point-min))
-  (let ((tag-function (if remove
-			  'notmuch-show-remove-tag
-			'notmuch-show-add-tag)))
-    (loop do (funcall tag-function tag)
+  (let ((op (if remove "-" "+")))
+    (loop do (notmuch-show-tag-message (concat op tag))
 	  until (not (notmuch-show-goto-message-next)))))
 
 (defun notmuch-show-add-tag-thread (tag)
@@ -1641,9 +1621,8 @@ If a prefix argument is given, the message will be
 \"unarchived\" (ie. the \"inbox\" tag will be added instead of
 removed)."
   (interactive "P")
-  (if unarchive
-      (notmuch-show-add-tag "inbox")
-    (notmuch-show-remove-tag "inbox")))
+  (let ((op (if unarchive "+" "-")))
+    (notmuch-show-tag-message (concat op "inbox"))))
 
 (defun notmuch-show-archive-message-then-next ()
   "Archive the current message, then show the next open message in the current thread."
-- 
1.7.9

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v4 05/12] test: fix emacs tests after tagging operations changes
  2012-01-31  4:54   ` [PATCH v4 00/12] " Dmitry Kurochkin
                       ` (3 preceding siblings ...)
  2012-01-31  4:54     ` [PATCH v4 04/12] emacs: make "+" and "-" tagging operations in notmuch-show " Dmitry Kurochkin
@ 2012-01-31  4:54     ` Dmitry Kurochkin
  2012-01-31  4:54     ` [PATCH v4 06/12] emacs: rename `notmuch-search-operate-all' to `notmuch-search-tag-all' Dmitry Kurochkin
                       ` (6 subsequent siblings)
  11 siblings, 0 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-01-31  4:54 UTC (permalink / raw)
  To: notmuch

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:ddd65cda0911171950o4eea4389v86de9525e46052d3@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.9

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v4 06/12] emacs: rename `notmuch-search-operate-all' to `notmuch-search-tag-all'
  2012-01-31  4:54   ` [PATCH v4 00/12] " Dmitry Kurochkin
                       ` (4 preceding siblings ...)
  2012-01-31  4:54     ` [PATCH v4 05/12] test: fix emacs tests after tagging operations changes Dmitry Kurochkin
@ 2012-01-31  4:54     ` Dmitry Kurochkin
  2012-01-31  4:54     ` [PATCH v4 07/12] emacs: add "*" binding for notmuch-show view Dmitry Kurochkin
                       ` (5 subsequent siblings)
  11 siblings, 0 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-01-31  4:54 UTC (permalink / raw)
  To: notmuch

`Notmuch-search-tag-all' is more clear and consistent with other
tagging function names.
---
 emacs/notmuch.el |    6 +++---
 1 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/emacs/notmuch.el b/emacs/notmuch.el
index ce8bef6..7d06109 100644
--- a/emacs/notmuch.el
+++ b/emacs/notmuch.el
@@ -270,7 +270,7 @@ For a mouse binding, return nil."
     (define-key map "t" 'notmuch-search-filter-by-tag)
     (define-key map "f" 'notmuch-search-filter)
     (define-key map [mouse-1] 'notmuch-search-show-thread)
-    (define-key map "*" 'notmuch-search-operate-all)
+    (define-key map "*" 'notmuch-search-tag-all)
     (define-key map "a" 'notmuch-search-archive-thread)
     (define-key map "-" 'notmuch-search-remove-tag)
     (define-key map "+" 'notmuch-search-add-tag)
@@ -419,7 +419,7 @@ any tags).
 Pressing \\[notmuch-search-show-thread] on any line displays that thread. The '\\[notmuch-search-add-tag]' and '\\[notmuch-search-remove-tag]'
 keys can be used to add or remove tags from a thread. The '\\[notmuch-search-archive-thread]' key
 is a convenience for archiving a thread (removing the \"inbox\"
-tag). The '\\[notmuch-search-operate-all]' key can be used to add or remove a tag from all
+tag). The '\\[notmuch-search-tag-all]' key can be used to add or remove a tag from all
 threads in the current buffer.
 
 Other useful commands are '\\[notmuch-search-filter]' for filtering the current search
@@ -883,7 +883,7 @@ non-authors is found, assume that all of the authors match."
 	      (goto-char found-target)))
       (delete-process proc))))
 
-(defun notmuch-search-operate-all (&rest actions)
+(defun notmuch-search-tag-all (&rest actions)
   "Add/remove tags from all matching messages.
 
 This command adds or removes tags from all messages matching the
-- 
1.7.9

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v4 07/12] emacs: add "*" binding for notmuch-show view
  2012-01-31  4:54   ` [PATCH v4 00/12] " Dmitry Kurochkin
                       ` (5 preceding siblings ...)
  2012-01-31  4:54     ` [PATCH v4 06/12] emacs: rename `notmuch-search-operate-all' to `notmuch-search-tag-all' Dmitry Kurochkin
@ 2012-01-31  4:54     ` Dmitry Kurochkin
  2012-01-31  4:54     ` [PATCH v4 08/12] emacs: separate history for operations which accept single and multiple tags Dmitry Kurochkin
                       ` (4 subsequent siblings)
  11 siblings, 0 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-01-31  4:54 UTC (permalink / raw)
  To: notmuch

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 |   35 +++++++++++++++++++++++++++++++++++
 1 files changed, 35 insertions(+), 0 deletions(-)

diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
index a0efae7..1cdd23e 100644
--- a/emacs/notmuch-show.el
+++ b/emacs/notmuch-show.el
@@ -1074,6 +1074,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)
@@ -1171,6 +1172,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.
 
@@ -1223,6 +1233,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 ()
@@ -1501,6 +1523,19 @@ 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-get-messages-ids-search) tag-changes)
+  (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 '+'."
   (interactive)
-- 
1.7.9

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v4 08/12] emacs: separate history for operations which accept single and multiple tags
  2012-01-31  4:54   ` [PATCH v4 00/12] " Dmitry Kurochkin
                       ` (6 preceding siblings ...)
  2012-01-31  4:54     ` [PATCH v4 07/12] emacs: add "*" binding for notmuch-show view Dmitry Kurochkin
@ 2012-01-31  4:54     ` Dmitry Kurochkin
  2012-01-31  4:54     ` [PATCH v4 09/12] emacs: relax tag syntax check in `notmuch-tag' function Dmitry Kurochkin
                       ` (3 subsequent siblings)
  11 siblings, 0 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-01-31  4:54 UTC (permalink / raw)
  To: notmuch

Some tag-related operations accept a single tag without prefix
(`notmuch-select-tag-with-completion'), others accept multiple tags
prefixed with '+' or '-' (`notmuch-read-tag-changes').  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 |   13 +++++++++++--
 1 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/emacs/notmuch.el b/emacs/notmuch.el
index 7d06109..0a3bd17 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 minibuffer history for
+`notmuch-select-tag-with-completion' function.")
+
+(defvar notmuch-read-tag-changes-history nil
+  "Variable to store minibuffer history for
+`notmuch-read-tag-changes' function.")
+
 (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-read-tag-changes (&optional initial-input &rest search-terms)
   (let* ((all-tag-list (notmuch-tag-completions))
@@ -106,7 +114,8 @@ For example:
 	    (define-key map " " 'self-insert-command)
 	    map)))
     (delete "" (completing-read-multiple "Tags (+add -drop): "
-		tag-list nil nil initial-input))))
+		tag-list nil nil initial-input
+		'notmuch-read-tag-changes-history))))
 
 (defun notmuch-update-tags (tags tag-changes)
   "Return a copy of TAGS with additions and removals from TAG-CHANGES.
-- 
1.7.9

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v4 09/12] emacs: relax tag syntax check in `notmuch-tag' function
  2012-01-31  4:54   ` [PATCH v4 00/12] " Dmitry Kurochkin
                       ` (7 preceding siblings ...)
  2012-01-31  4:54     ` [PATCH v4 08/12] emacs: separate history for operations which accept single and multiple tags Dmitry Kurochkin
@ 2012-01-31  4:54     ` Dmitry Kurochkin
  2012-01-31  4:54     ` [PATCH v4 10/12] emacs: accept empty tag list in `notmuch-tag' Dmitry Kurochkin
                       ` (2 subsequent siblings)
  11 siblings, 0 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-01-31  4:54 UTC (permalink / raw)
  To: notmuch

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 0a3bd17..2332c42 100644
--- a/emacs/notmuch.el
+++ b/emacs/notmuch.el
@@ -556,7 +556,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.9

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v4 10/12] emacs: accept empty tag list in `notmuch-tag'
  2012-01-31  4:54   ` [PATCH v4 00/12] " Dmitry Kurochkin
                       ` (8 preceding siblings ...)
  2012-01-31  4:54     ` [PATCH v4 09/12] emacs: relax tag syntax check in `notmuch-tag' function Dmitry Kurochkin
@ 2012-01-31  4:54     ` Dmitry Kurochkin
  2012-01-31  4:54     ` [PATCH v4 11/12] emacs: s/tags/tag-changes/ for arguments of tagging functions Dmitry Kurochkin
  2012-01-31  4:54     ` [PATCH v4 12/12] NEWS: document Emacs UI tagging operations changes Dmitry Kurochkin
  11 siblings, 0 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-01-31  4:54 UTC (permalink / raw)
  To: notmuch

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 2332c42..c464c3c 100644
--- a/emacs/notmuch.el
+++ b/emacs/notmuch.el
@@ -554,15 +554,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.9

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v4 11/12] emacs: s/tags/tag-changes/ for arguments of tagging functions
  2012-01-31  4:54   ` [PATCH v4 00/12] " Dmitry Kurochkin
                       ` (9 preceding siblings ...)
  2012-01-31  4:54     ` [PATCH v4 10/12] emacs: accept empty tag list in `notmuch-tag' Dmitry Kurochkin
@ 2012-01-31  4:54     ` Dmitry Kurochkin
  2012-01-31  4:54     ` [PATCH v4 12/12] NEWS: document Emacs UI tagging operations changes Dmitry Kurochkin
  11 siblings, 0 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-01-31  4:54 UTC (permalink / raw)
  To: notmuch

This makes the argument names more consistent and clear.  The
following functions changed: `notmuch-tag',
`notmuch-search-tag-thread', `notmuch-search-tag-region' and
`notmuch-search-tag-all'.
---
 emacs/notmuch.el |   33 +++++++++++++++++----------------
 1 files changed, 17 insertions(+), 16 deletions(-)

diff --git a/emacs/notmuch.el b/emacs/notmuch.el
index c464c3c..fa62019 100644
--- a/emacs/notmuch.el
+++ b/emacs/notmuch.el
@@ -543,25 +543,26 @@ and will also appear in a buffer named \"*Notmuch errors*\"."
 	    (error (buffer-substring beg end))
 	    ))))))
 
-(defun notmuch-tag (query &rest tags)
-  "Add/remove tags in TAGS to messages matching QUERY.
+(defun notmuch-tag (query &rest tag-changes)
+  "Add/remove tags in TAG-CHANGES to messages matching QUERY.
 
-TAGS should be a list of strings of the form \"+TAG\" or \"-TAG\" and
-QUERY should be a string containing the search-query.
+TAG-CHANGES should be a list of strings of the form \"+tag\" or
+\"-tag\" and QUERY should be a string containing the
+search-query.
 
 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
-  (mapc (lambda (tag)
-	  (unless (string-match-p "^[-+]\\S-+$" tag)
+  (mapc (lambda (tag-change)
+	  (unless (string-match-p "^[-+]\\S-+$" tag-change)
 	    (error "Tag must be of the form `+this_tag' or `-that_tag'")))
-	tags)
-  (unless (null tags)
+	tag-changes)
+  (unless (null tag-changes)
     (run-hooks 'notmuch-before-tag-hook)
     (apply 'notmuch-call-notmuch-process "tag"
-	   (append tags (list "--" query)))
+	   (append tag-changes (list "--" query)))
     (run-hooks 'notmuch-after-tag-hook)))
 
 (defcustom notmuch-before-tag-hook nil
@@ -621,26 +622,26 @@ the messages that were tagged"
 	(forward-line 1))
       output)))
 
-(defun notmuch-search-tag-thread (&rest tags)
+(defun notmuch-search-tag-thread (&rest tag-changes)
   "Change tags for the currently selected thread.
 
 See `notmuch-search-tag-region' for details."
-  (apply 'notmuch-search-tag-region (point) (point) tags))
+  (apply 'notmuch-search-tag-region (point) (point) tag-changes))
 
-(defun notmuch-search-tag-region (beg end &rest tags)
+(defun notmuch-search-tag-region (beg end &rest tag-changes)
   "Change tags for threads in the given region.
 
 TAGS is a list of tag operations for `notmuch-tag'.  The tags are
 added or removed for all threads in the region from BEG to END."
   (let ((search-string (notmuch-search-find-thread-id-region-search beg end)))
-    (apply 'notmuch-tag search-string tags)
+    (apply 'notmuch-tag search-string tag-changes)
     (save-excursion
       (let ((last-line (line-number-at-pos end))
 	    (max-line (- (line-number-at-pos (point-max)) 2)))
 	(goto-char beg)
 	(while (<= (line-number-at-pos) (min last-line max-line))
 	  (notmuch-search-set-tags
-	   (notmuch-update-tags (notmuch-search-get-tags) tags))
+	   (notmuch-update-tags (notmuch-search-get-tags) tag-changes))
 	  (forward-line))))))
 
 (defun notmuch-search-tag (&optional initial-input)
@@ -892,7 +893,7 @@ non-authors is found, assume that all of the authors match."
 	      (goto-char found-target)))
       (delete-process proc))))
 
-(defun notmuch-search-tag-all (&rest actions)
+(defun notmuch-search-tag-all (&rest tag-changes)
   "Add/remove tags from all matching messages.
 
 This command adds or removes tags from all messages matching the
@@ -904,7 +905,7 @@ Each character of the tag name may consist of alphanumeric
 characters as well as `_.+-'.
 "
   (interactive (notmuch-read-tag-changes))
-  (apply 'notmuch-tag notmuch-search-query-string actions))
+  (apply 'notmuch-tag notmuch-search-query-string tag-changes))
 
 (defun notmuch-search-buffer-title (query)
   "Returns the title for a buffer with notmuch search results."
-- 
1.7.9

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v4 12/12] NEWS: document Emacs UI tagging operations changes
  2012-01-31  4:54   ` [PATCH v4 00/12] " Dmitry Kurochkin
                       ` (10 preceding siblings ...)
  2012-01-31  4:54     ` [PATCH v4 11/12] emacs: s/tags/tag-changes/ for arguments of tagging functions Dmitry Kurochkin
@ 2012-01-31  4:54     ` Dmitry Kurochkin
  11 siblings, 0 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-01-31  4:54 UTC (permalink / raw)
  To: notmuch

---
 NEWS |   18 ++++++++++++++++++
 1 files changed, 18 insertions(+), 0 deletions(-)

diff --git a/NEWS b/NEWS
index 2acdce5..7506d68 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 flexible and consistent tagging operations
+
+  All tagging operations ("+", "-", "*") now accept multiple tags with
+  "+" or "-" prefix, like "*" operation in notmuch-search view before.
+
+  "*" operation (`notmuch-show-tag-all') is now available in
+  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
 ---------------
 
-- 
1.7.9

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* Re: [PATCH v4 02/12] emacs: remove text properties from `notmuch-search-get-tags' result
  2012-01-31  4:54     ` [PATCH v4 02/12] emacs: remove text properties from `notmuch-search-get-tags' result Dmitry Kurochkin
@ 2012-02-04  1:49       ` David Bremner
  0 siblings, 0 replies; 136+ messages in thread
From: David Bremner @ 2012-02-04  1:49 UTC (permalink / raw)
  To: Dmitry Kurochkin, notmuch

On Tue, 31 Jan 2012 08:54:16 +0400, Dmitry Kurochkin <dmitry.kurochkin@gmail.com> wrote:
> ---
>  emacs/notmuch.el |    2 +-
>  1 files changed, 1 insertions(+), 1 deletions(-)
> 

Hi Dmitry.

This series stops applying at the second patch due to other changes, so
I guess I'll wait for a rebase of the full series. I've sent out several
rebase requests this evening so you might want to wait for the dust to
settle.

d

^ permalink raw reply	[flat|nested] 136+ messages in thread

* [PATCH v5 00/12] emacs: more flexible and consistent tagging operations
  2012-01-28  4:41 [PATCH 1/6] emacs: move tag format validation to `notmuch-tag' function Dmitry Kurochkin
                   ` (9 preceding siblings ...)
  2012-01-30  5:33 ` emacs: more flexible and consistent tagging operations Dmitry Kurochkin
@ 2012-02-05  7:13 ` Dmitry Kurochkin
  2012-02-05  7:13   ` [PATCH v5 01/12] emacs: move tag format validation to `notmuch-tag' function Dmitry Kurochkin
                     ` (12 more replies)
  10 siblings, 13 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-02-05  7:13 UTC (permalink / raw)
  To: notmuch

Changes:

v4:

* rebased on master, no conflicts so no need for another review

v4:

* rebased on master after Jameson's archiving changes

v3:

* merged 3 `notmuch-show-tag-all'-related patches into one

* add patch to clean up tagging function argument names

* fix other comments from Austin's reviews [5,6]

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.GK17991@mit.edu"
[2] id:"20120129225710.GG17991@mit.edu"
[3] id:"20120129230229.GI17991@mit.edu"
[4] id:"20120129231120.GJ17991@mit.edu"
[5] id:"20120130044806.GM17991@mit.edu"
[6] id:"20120130050402.GP17991@mit.edu"

^ permalink raw reply	[flat|nested] 136+ messages in thread

* [PATCH v5 01/12] emacs: move tag format validation to `notmuch-tag' function
  2012-02-05  7:13 ` [PATCH v5 00/12] emacs: more flexible and consistent tagging operations Dmitry Kurochkin
@ 2012-02-05  7:13   ` Dmitry Kurochkin
  2012-02-05  7:13   ` [PATCH v5 02/12] emacs: remove text properties from `notmuch-search-get-tags' result Dmitry Kurochkin
                     ` (11 subsequent siblings)
  12 siblings, 0 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-02-05  7:13 UTC (permalink / raw)
  To: notmuch

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 cd04ffd..19206db 100644
--- a/emacs/notmuch.el
+++ b/emacs/notmuch.el
@@ -516,6 +516,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"))
+  (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)))
@@ -883,12 +889,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)
-- 
1.7.9

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v5 02/12] emacs: remove text properties from `notmuch-search-get-tags' result
  2012-02-05  7:13 ` [PATCH v5 00/12] emacs: more flexible and consistent tagging operations Dmitry Kurochkin
  2012-02-05  7:13   ` [PATCH v5 01/12] emacs: move tag format validation to `notmuch-tag' function Dmitry Kurochkin
@ 2012-02-05  7:13   ` Dmitry Kurochkin
  2012-02-05  7:13   ` [PATCH v5 03/12] emacs: make "+" and "-" tagging operations in notmuch-search more flexible Dmitry Kurochkin
                     ` (10 subsequent siblings)
  12 siblings, 0 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-02-05  7:13 UTC (permalink / raw)
  To: notmuch

---
 emacs/notmuch.el |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/emacs/notmuch.el b/emacs/notmuch.el
index 19206db..5980fea 100644
--- a/emacs/notmuch.el
+++ b/emacs/notmuch.el
@@ -571,7 +571,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.9

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v5 03/12] emacs: make "+" and "-" tagging operations in notmuch-search more flexible
  2012-02-05  7:13 ` [PATCH v5 00/12] emacs: more flexible and consistent tagging operations Dmitry Kurochkin
  2012-02-05  7:13   ` [PATCH v5 01/12] emacs: move tag format validation to `notmuch-tag' function Dmitry Kurochkin
  2012-02-05  7:13   ` [PATCH v5 02/12] emacs: remove text properties from `notmuch-search-get-tags' result Dmitry Kurochkin
@ 2012-02-05  7:13   ` Dmitry Kurochkin
  2012-02-05  7:13   ` [PATCH v5 04/12] emacs: make "+" and "-" tagging operations in notmuch-show " Dmitry Kurochkin
                     ` (9 subsequent siblings)
  12 siblings, 0 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-02-05  7:13 UTC (permalink / raw)
  To: notmuch

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 |  163 +++++++++++++++++++++++++++---------------------------
 1 files changed, 81 insertions(+), 82 deletions(-)

diff --git a/emacs/notmuch.el b/emacs/notmuch.el
index 5980fea..1b472dd 100644
--- a/emacs/notmuch.el
+++ b/emacs/notmuch.el
@@ -76,38 +76,56 @@ For example:
 (defvar notmuch-query-history nil
   "Variable to store minibuffer history for notmuch queries")
 
-(defun notmuch-tag-completions (&optional 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 (&optional 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 &rest 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 &optional prefixes &rest 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 <tab>
-	;; 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 (&optional initial-input &rest 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 <tab>
+	 ;; 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)
+      (let ((op (string-to-char tag-change))
+	    (tag (unless (string= tag-change "") (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 `+this_tag' or `-that_tag'")))))
+    (sort result-tags 'string<)))
 
 (defun notmuch-foreach-mime-part (function mm-handle)
   (cond ((stringp (car mm-handle))
@@ -447,6 +465,10 @@ Complete list of currently available key bindings:
   "Return a list of threads for the current region"
   (notmuch-search-properties-in-region 'notmuch-search-thread-id beg end))
 
+(defun notmuch-search-find-thread-id-region-search (beg end)
+  "Return a search string for threads for the current region"
+  (mapconcat 'identity (notmuch-search-find-thread-id-region beg end) " or "))
+
 (defun notmuch-search-find-authors ()
   "Return the authors for the current thread"
   (get-text-property (point) 'notmuch-search-authors))
@@ -584,74 +606,53 @@ the messages that were tagged"
 	(forward-line 1))
       output)))
 
-(defun notmuch-search-add-tag-thread (tag)
-  (notmuch-search-add-tag-region tag (point) (point)))
+(defun notmuch-search-tag-thread (&rest tags)
+  "Change tags for the currently selected thread.
 
-(defun notmuch-search-add-tag-region (tag beg end)
-  (let ((search-id-string (mapconcat 'identity (notmuch-search-find-thread-id-region beg end) " or ")))
-    (notmuch-tag search-id-string (concat "+" tag))
-    (save-excursion
-      (let ((last-line (line-number-at-pos end))
-	    (max-line (- (line-number-at-pos (point-max)) 2)))
-	(goto-char beg)
-	(while (<= (line-number-at-pos) (min last-line max-line))
-	  (notmuch-search-set-tags (delete-dups (sort (cons tag (notmuch-search-get-tags)) 'string<)))
-	  (forward-line))))))
+See `notmuch-search-tag-region' for details."
+  (apply 'notmuch-search-tag-region (point) (point) tags))
 
-(defun notmuch-search-remove-tag-thread (tag)
-  (notmuch-search-remove-tag-region tag (point) (point)))
+(defun notmuch-search-tag-region (beg end &rest tags)
+  "Change tags for threads in the given region.
 
-(defun notmuch-search-remove-tag-region (tag beg end)
-  (let ((search-id-string (mapconcat 'identity (notmuch-search-find-thread-id-region beg end) " or ")))
-    (notmuch-tag search-id-string (concat "-" tag))
+TAGS is a list of tag operations for `notmuch-tag'.  The tags are
+added or removed for all threads in the region from BEG to END."
+  (let ((search-string (notmuch-search-find-thread-id-region-search beg end)))
+    (apply 'notmuch-tag search-string tags)
     (save-excursion
       (let ((last-line (line-number-at-pos end))
 	    (max-line (- (line-number-at-pos (point-max)) 2)))
 	(goto-char beg)
 	(while (<= (line-number-at-pos) (min last-line max-line))
-	  (notmuch-search-set-tags (delete tag (notmuch-search-get-tags)))
+	  (notmuch-search-set-tags
+	   (notmuch-update-tags (notmuch-search-get-tags) tags))
 	  (forward-line))))))
 
-(defun notmuch-search-add-tag (tag)
-  "Add a tag to the currently selected thread or region.
-
-The tag is added to all messages in the currently selected thread
-or threads in the current region."
-  (interactive
-   (list (notmuch-select-tag-with-completion "Tag to add: ")))
-  (save-excursion
-    (if (region-active-p)
-	(let* ((beg (region-beginning))
-	       (end (region-end)))
-	  (notmuch-search-add-tag-region tag beg end))
-      (notmuch-search-add-tag-thread tag))))
-
-(defun notmuch-search-remove-tag (tag)
-  "Remove a tag from the currently selected thread or region.
+(defun notmuch-search-tag (&optional initial-input)
+  "Change tags for the currently selected thread or region."
+  (interactive)
+  (let* ((beg (if (region-active-p) (region-beginning) (point)))
+	 (end (if (region-active-p) (region-end) (point)))
+	 (search-string (notmuch-search-find-thread-id-region-search beg end))
+	 (tags (notmuch-read-tag-changes initial-input search-string)))
+    (apply 'notmuch-search-tag-region beg end tags)))
+
+(defun notmuch-search-add-tag ()
+  "Same as `notmuch-search-tag' but sets initial input to '+'."
+  (interactive)
+  (notmuch-search-tag "+"))
 
-The tag is removed from all messages in the currently selected
-thread or threads in the current region."
-  (interactive
-   (list (notmuch-select-tag-with-completion
-	  "Tag to remove: "
-	  (if (region-active-p)
-	      (mapconcat 'identity
-			 (notmuch-search-find-thread-id-region (region-beginning) (region-end))
-			 " ")
-	    (notmuch-search-find-thread-id)))))
-  (save-excursion
-    (if (region-active-p)
-	(let* ((beg (region-beginning))
-	       (end (region-end)))
-	  (notmuch-search-remove-tag-region tag beg end))
-      (notmuch-search-remove-tag-thread tag))))
+(defun notmuch-search-remove-tag ()
+  "Same as `notmuch-search-tag' but sets initial input to '-'."
+  (interactive)
+  (notmuch-search-tag "-"))
 
 (defun notmuch-search-archive-thread ()
   "Archive the currently selected thread (remove its \"inbox\" tag).
 
 This function advances the next thread when finished."
   (interactive)
-  (notmuch-search-remove-tag-thread "inbox")
+  (notmuch-search-tag-thread "-inbox")
   (notmuch-search-next-thread))
 
 (defvar notmuch-search-process-filter-data nil
@@ -886,9 +887,7 @@ will prompt for tags to be added or removed. Tags prefixed with
 Each character of the tag name may consist of alphanumeric
 characters as well as `_.+-'.
 "
-  (interactive (notmuch-select-tags-with-completion
-		"Operations (+add -drop): notmuch tag "
-		'("+" "-")))
+  (interactive (notmuch-read-tag-changes))
   (apply 'notmuch-tag notmuch-search-query-string actions))
 
 (defun notmuch-search-buffer-title (query)
-- 
1.7.9

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v5 04/12] emacs: make "+" and "-" tagging operations in notmuch-show more flexible
  2012-02-05  7:13 ` [PATCH v5 00/12] emacs: more flexible and consistent tagging operations Dmitry Kurochkin
                     ` (2 preceding siblings ...)
  2012-02-05  7:13   ` [PATCH v5 03/12] emacs: make "+" and "-" tagging operations in notmuch-search more flexible Dmitry Kurochkin
@ 2012-02-05  7:13   ` Dmitry Kurochkin
  2012-02-05  7:13   ` [PATCH v5 05/12] test: fix emacs tests after tagging operations changes Dmitry Kurochkin
                     ` (8 subsequent siblings)
  12 siblings, 0 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-02-05  7:13 UTC (permalink / raw)
  To: notmuch

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 |   73 +++++++++++++++++-------------------------------
 1 files changed, 26 insertions(+), 47 deletions(-)

diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
index 7469e2e..48a2a60 100644
--- a/emacs/notmuch-show.el
+++ b/emacs/notmuch-show.el
@@ -38,9 +38,10 @@
 
 (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-next-thread "notmuch" nil)
 (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.
@@ -1282,7 +1283,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.
@@ -1495,51 +1496,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."
@@ -1587,10 +1569,8 @@ argument, hide all of the messages."
 If the remove switch is given, tags will be removed instead of
 added."
   (goto-char (point-min))
-  (let ((tag-function (if remove
-			  'notmuch-show-remove-tag
-			'notmuch-show-add-tag)))
-    (loop do (funcall tag-function tag)
+  (let ((op (if remove "-" "+")))
+    (loop do (notmuch-show-tag-message (concat op tag))
 	  until (not (notmuch-show-goto-message-next)))))
 
 (defun notmuch-show-add-tag-thread (tag)
@@ -1653,9 +1633,8 @@ If a prefix argument is given, the message will be
 \"unarchived\" (ie. the \"inbox\" tag will be added instead of
 removed)."
   (interactive "P")
-  (if unarchive
-      (notmuch-show-add-tag "inbox")
-    (notmuch-show-remove-tag "inbox")))
+  (let ((op (if unarchive "+" "-")))
+    (notmuch-show-tag-message (concat op "inbox"))))
 
 (defun notmuch-show-archive-message-then-next ()
   "Archive the current message, then show the next open message in the current thread."
-- 
1.7.9

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v5 05/12] test: fix emacs tests after tagging operations changes
  2012-02-05  7:13 ` [PATCH v5 00/12] emacs: more flexible and consistent tagging operations Dmitry Kurochkin
                     ` (3 preceding siblings ...)
  2012-02-05  7:13   ` [PATCH v5 04/12] emacs: make "+" and "-" tagging operations in notmuch-show " Dmitry Kurochkin
@ 2012-02-05  7:13   ` Dmitry Kurochkin
  2012-02-05  7:13   ` [PATCH v5 06/12] emacs: rename `notmuch-search-operate-all' to `notmuch-search-tag-all' Dmitry Kurochkin
                     ` (7 subsequent siblings)
  12 siblings, 0 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-02-05  7:13 UTC (permalink / raw)
  To: notmuch

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 256a738..b74cfa9 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:ddd65cda0911171950o4eea4389v86de9525e46052d3@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.9

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v5 06/12] emacs: rename `notmuch-search-operate-all' to `notmuch-search-tag-all'
  2012-02-05  7:13 ` [PATCH v5 00/12] emacs: more flexible and consistent tagging operations Dmitry Kurochkin
                     ` (4 preceding siblings ...)
  2012-02-05  7:13   ` [PATCH v5 05/12] test: fix emacs tests after tagging operations changes Dmitry Kurochkin
@ 2012-02-05  7:13   ` Dmitry Kurochkin
  2012-02-05  7:13   ` [PATCH v5 07/12] emacs: add "*" binding for notmuch-show view Dmitry Kurochkin
                     ` (6 subsequent siblings)
  12 siblings, 0 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-02-05  7:13 UTC (permalink / raw)
  To: notmuch

`Notmuch-search-tag-all' is more clear and consistent with other
tagging function names.
---
 emacs/notmuch.el |    6 +++---
 1 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/emacs/notmuch.el b/emacs/notmuch.el
index 1b472dd..1f351a5 100644
--- a/emacs/notmuch.el
+++ b/emacs/notmuch.el
@@ -270,7 +270,7 @@ For a mouse binding, return nil."
     (define-key map "t" 'notmuch-search-filter-by-tag)
     (define-key map "f" 'notmuch-search-filter)
     (define-key map [mouse-1] 'notmuch-search-show-thread)
-    (define-key map "*" 'notmuch-search-operate-all)
+    (define-key map "*" 'notmuch-search-tag-all)
     (define-key map "a" 'notmuch-search-archive-thread)
     (define-key map "-" 'notmuch-search-remove-tag)
     (define-key map "+" 'notmuch-search-add-tag)
@@ -419,7 +419,7 @@ any tags).
 Pressing \\[notmuch-search-show-thread] on any line displays that thread. The '\\[notmuch-search-add-tag]' and '\\[notmuch-search-remove-tag]'
 keys can be used to add or remove tags from a thread. The '\\[notmuch-search-archive-thread]' key
 is a convenience for archiving a thread (removing the \"inbox\"
-tag). The '\\[notmuch-search-operate-all]' key can be used to add or remove a tag from all
+tag). The '\\[notmuch-search-tag-all]' key can be used to add or remove a tag from all
 threads in the current buffer.
 
 Other useful commands are '\\[notmuch-search-filter]' for filtering the current search
@@ -876,7 +876,7 @@ non-authors is found, assume that all of the authors match."
 	      (goto-char found-target)))
       (delete-process proc))))
 
-(defun notmuch-search-operate-all (&rest actions)
+(defun notmuch-search-tag-all (&rest actions)
   "Add/remove tags from all matching messages.
 
 This command adds or removes tags from all messages matching the
-- 
1.7.9

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v5 07/12] emacs: add "*" binding for notmuch-show view
  2012-02-05  7:13 ` [PATCH v5 00/12] emacs: more flexible and consistent tagging operations Dmitry Kurochkin
                     ` (5 preceding siblings ...)
  2012-02-05  7:13   ` [PATCH v5 06/12] emacs: rename `notmuch-search-operate-all' to `notmuch-search-tag-all' Dmitry Kurochkin
@ 2012-02-05  7:13   ` Dmitry Kurochkin
  2012-02-05  7:13   ` [PATCH v5 08/12] emacs: separate history for operations which accept single and multiple tags Dmitry Kurochkin
                     ` (5 subsequent siblings)
  12 siblings, 0 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-02-05  7:13 UTC (permalink / raw)
  To: notmuch

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 |   35 +++++++++++++++++++++++++++++++++++
 1 files changed, 35 insertions(+), 0 deletions(-)

diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
index 48a2a60..faa9f9b 100644
--- a/emacs/notmuch-show.el
+++ b/emacs/notmuch-show.el
@@ -1084,6 +1084,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)
@@ -1181,6 +1182,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.
 
@@ -1233,6 +1243,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 ()
@@ -1513,6 +1535,19 @@ 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-get-messages-ids-search) tag-changes)
+  (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 '+'."
   (interactive)
-- 
1.7.9

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v5 08/12] emacs: separate history for operations which accept single and multiple tags
  2012-02-05  7:13 ` [PATCH v5 00/12] emacs: more flexible and consistent tagging operations Dmitry Kurochkin
                     ` (6 preceding siblings ...)
  2012-02-05  7:13   ` [PATCH v5 07/12] emacs: add "*" binding for notmuch-show view Dmitry Kurochkin
@ 2012-02-05  7:13   ` Dmitry Kurochkin
  2012-02-05  7:13   ` [PATCH v5 09/12] emacs: relax tag syntax check in `notmuch-tag' function Dmitry Kurochkin
                     ` (4 subsequent siblings)
  12 siblings, 0 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-02-05  7:13 UTC (permalink / raw)
  To: notmuch

Some tag-related operations accept a single tag without prefix
(`notmuch-select-tag-with-completion'), others accept multiple tags
prefixed with '+' or '-' (`notmuch-read-tag-changes').  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 |   13 +++++++++++--
 1 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/emacs/notmuch.el b/emacs/notmuch.el
index 1f351a5..862d9e8 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 minibuffer history for
+`notmuch-select-tag-with-completion' function.")
+
+(defvar notmuch-read-tag-changes-history nil
+  "Variable to store minibuffer history for
+`notmuch-read-tag-changes' function.")
+
 (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-read-tag-changes (&optional initial-input &rest search-terms)
   (let* ((all-tag-list (notmuch-tag-completions))
@@ -106,7 +114,8 @@ For example:
 	    (define-key map " " 'self-insert-command)
 	    map)))
     (delete "" (completing-read-multiple "Tags (+add -drop): "
-		tag-list nil nil initial-input))))
+		tag-list nil nil initial-input
+		'notmuch-read-tag-changes-history))))
 
 (defun notmuch-update-tags (tags tag-changes)
   "Return a copy of TAGS with additions and removals from TAG-CHANGES.
-- 
1.7.9

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v5 09/12] emacs: relax tag syntax check in `notmuch-tag' function
  2012-02-05  7:13 ` [PATCH v5 00/12] emacs: more flexible and consistent tagging operations Dmitry Kurochkin
                     ` (7 preceding siblings ...)
  2012-02-05  7:13   ` [PATCH v5 08/12] emacs: separate history for operations which accept single and multiple tags Dmitry Kurochkin
@ 2012-02-05  7:13   ` Dmitry Kurochkin
  2012-02-05  7:13   ` [PATCH v5 10/12] emacs: accept empty tag list in `notmuch-tag' Dmitry Kurochkin
                     ` (3 subsequent siblings)
  12 siblings, 0 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-02-05  7:13 UTC (permalink / raw)
  To: notmuch

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 862d9e8..b06d8a1 100644
--- a/emacs/notmuch.el
+++ b/emacs/notmuch.el
@@ -550,7 +550,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.9

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v5 10/12] emacs: accept empty tag list in `notmuch-tag'
  2012-02-05  7:13 ` [PATCH v5 00/12] emacs: more flexible and consistent tagging operations Dmitry Kurochkin
                     ` (8 preceding siblings ...)
  2012-02-05  7:13   ` [PATCH v5 09/12] emacs: relax tag syntax check in `notmuch-tag' function Dmitry Kurochkin
@ 2012-02-05  7:13   ` Dmitry Kurochkin
  2012-02-05  7:13   ` [PATCH v5 11/12] emacs: s/tags/tag-changes/ for arguments of tagging functions Dmitry Kurochkin
                     ` (2 subsequent siblings)
  12 siblings, 0 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-02-05  7:13 UTC (permalink / raw)
  To: notmuch

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 b06d8a1..0ffdf9c 100644
--- a/emacs/notmuch.el
+++ b/emacs/notmuch.el
@@ -548,15 +548,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.9

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v5 11/12] emacs: s/tags/tag-changes/ for arguments of tagging functions
  2012-02-05  7:13 ` [PATCH v5 00/12] emacs: more flexible and consistent tagging operations Dmitry Kurochkin
                     ` (9 preceding siblings ...)
  2012-02-05  7:13   ` [PATCH v5 10/12] emacs: accept empty tag list in `notmuch-tag' Dmitry Kurochkin
@ 2012-02-05  7:13   ` Dmitry Kurochkin
  2012-02-05  7:13   ` [PATCH v5 12/12] NEWS: document Emacs UI tagging operations changes Dmitry Kurochkin
  2012-02-08 15:58   ` [PATCH v5 00/12] emacs: more flexible and consistent tagging operations David Bremner
  12 siblings, 0 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-02-05  7:13 UTC (permalink / raw)
  To: notmuch

This makes the argument names more consistent and clear.  The
following functions changed: `notmuch-tag',
`notmuch-search-tag-thread', `notmuch-search-tag-region' and
`notmuch-search-tag-all'.
---
 emacs/notmuch.el |   33 +++++++++++++++++----------------
 1 files changed, 17 insertions(+), 16 deletions(-)

diff --git a/emacs/notmuch.el b/emacs/notmuch.el
index 0ffdf9c..8250961 100644
--- a/emacs/notmuch.el
+++ b/emacs/notmuch.el
@@ -537,25 +537,26 @@ and will also appear in a buffer named \"*Notmuch errors*\"."
 	    (error (buffer-substring beg end))
 	    ))))))
 
-(defun notmuch-tag (query &rest tags)
-  "Add/remove tags in TAGS to messages matching QUERY.
+(defun notmuch-tag (query &rest tag-changes)
+  "Add/remove tags in TAG-CHANGES to messages matching QUERY.
 
-TAGS should be a list of strings of the form \"+TAG\" or \"-TAG\" and
-QUERY should be a string containing the search-query.
+TAG-CHANGES should be a list of strings of the form \"+tag\" or
+\"-tag\" and QUERY should be a string containing the
+search-query.
 
 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
-  (mapc (lambda (tag)
-	  (unless (string-match-p "^[-+]\\S-+$" tag)
+  (mapc (lambda (tag-change)
+	  (unless (string-match-p "^[-+]\\S-+$" tag-change)
 	    (error "Tag must be of the form `+this_tag' or `-that_tag'")))
-	tags)
-  (unless (null tags)
+	tag-changes)
+  (unless (null tag-changes)
     (run-hooks 'notmuch-before-tag-hook)
     (apply 'notmuch-call-notmuch-process "tag"
-	   (append tags (list "--" query)))
+	   (append tag-changes (list "--" query)))
     (run-hooks 'notmuch-after-tag-hook)))
 
 (defcustom notmuch-before-tag-hook nil
@@ -615,26 +616,26 @@ the messages that were tagged"
 	(forward-line 1))
       output)))
 
-(defun notmuch-search-tag-thread (&rest tags)
+(defun notmuch-search-tag-thread (&rest tag-changes)
   "Change tags for the currently selected thread.
 
 See `notmuch-search-tag-region' for details."
-  (apply 'notmuch-search-tag-region (point) (point) tags))
+  (apply 'notmuch-search-tag-region (point) (point) tag-changes))
 
-(defun notmuch-search-tag-region (beg end &rest tags)
+(defun notmuch-search-tag-region (beg end &rest tag-changes)
   "Change tags for threads in the given region.
 
 TAGS is a list of tag operations for `notmuch-tag'.  The tags are
 added or removed for all threads in the region from BEG to END."
   (let ((search-string (notmuch-search-find-thread-id-region-search beg end)))
-    (apply 'notmuch-tag search-string tags)
+    (apply 'notmuch-tag search-string tag-changes)
     (save-excursion
       (let ((last-line (line-number-at-pos end))
 	    (max-line (- (line-number-at-pos (point-max)) 2)))
 	(goto-char beg)
 	(while (<= (line-number-at-pos) (min last-line max-line))
 	  (notmuch-search-set-tags
-	   (notmuch-update-tags (notmuch-search-get-tags) tags))
+	   (notmuch-update-tags (notmuch-search-get-tags) tag-changes))
 	  (forward-line))))))
 
 (defun notmuch-search-tag (&optional initial-input)
@@ -885,7 +886,7 @@ non-authors is found, assume that all of the authors match."
 	      (goto-char found-target)))
       (delete-process proc))))
 
-(defun notmuch-search-tag-all (&rest actions)
+(defun notmuch-search-tag-all (&rest tag-changes)
   "Add/remove tags from all matching messages.
 
 This command adds or removes tags from all messages matching the
@@ -897,7 +898,7 @@ Each character of the tag name may consist of alphanumeric
 characters as well as `_.+-'.
 "
   (interactive (notmuch-read-tag-changes))
-  (apply 'notmuch-tag notmuch-search-query-string actions))
+  (apply 'notmuch-tag notmuch-search-query-string tag-changes))
 
 (defun notmuch-search-buffer-title (query)
   "Returns the title for a buffer with notmuch search results."
-- 
1.7.9

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v5 12/12] NEWS: document Emacs UI tagging operations changes
  2012-02-05  7:13 ` [PATCH v5 00/12] emacs: more flexible and consistent tagging operations Dmitry Kurochkin
                     ` (10 preceding siblings ...)
  2012-02-05  7:13   ` [PATCH v5 11/12] emacs: s/tags/tag-changes/ for arguments of tagging functions Dmitry Kurochkin
@ 2012-02-05  7:13   ` Dmitry Kurochkin
  2012-02-08 15:58   ` [PATCH v5 00/12] emacs: more flexible and consistent tagging operations David Bremner
  12 siblings, 0 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-02-05  7:13 UTC (permalink / raw)
  To: notmuch

---
 NEWS |   18 ++++++++++++++++++
 1 files changed, 18 insertions(+), 0 deletions(-)

diff --git a/NEWS b/NEWS
index 5c5b645..f449fba 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 flexible and consistent tagging operations
+
+  All tagging operations ("+", "-", "*") now accept multiple tags with
+  "+" or "-" prefix, like "*" operation in notmuch-search view before.
+
+  "*" operation (`notmuch-show-tag-all') is now available in
+  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
 ---------------
 
-- 
1.7.9

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* Re: [PATCH v5 00/12] emacs: more flexible and consistent tagging operations
  2012-02-05  7:13 ` [PATCH v5 00/12] emacs: more flexible and consistent tagging operations Dmitry Kurochkin
                     ` (11 preceding siblings ...)
  2012-02-05  7:13   ` [PATCH v5 12/12] NEWS: document Emacs UI tagging operations changes Dmitry Kurochkin
@ 2012-02-08 15:58   ` David Bremner
  2012-02-23 23:07     ` Pieter Praet
  2012-02-24 22:30     ` [PATCH v2 0/6] `notmuch-show-tag-all' with prefix arg only tags open messages Pieter Praet
  12 siblings, 2 replies; 136+ messages in thread
From: David Bremner @ 2012-02-08 15:58 UTC (permalink / raw)
  To: Dmitry Kurochkin, notmuch

On Sun,  5 Feb 2012 11:13:41 +0400, Dmitry Kurochkin <dmitry.kurochkin@gmail.com> wrote:
> Changes:
> 
> v4:
> 
> * rebased on master, no conflicts so no need for another review
> 

I pushed this series.  

Maybe this was discussed already, but I think ideally * would apply only
to open messages. So consider that a feature request if someone is
looking for a project.

d

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH 7/6] emacs: relax tag syntax check in `notmuch-tag' function
  2012-01-28  8:56   ` Jani Nikula
  2012-01-28  9:49     ` Dmitry Kurochkin
@ 2012-02-19 20:53     ` Pieter Praet
  1 sibling, 0 replies; 136+ messages in thread
From: Pieter Praet @ 2012-02-19 20:53 UTC (permalink / raw)
  To: Jani Nikula, Dmitry Kurochkin; +Cc: notmuch

On Sat, 28 Jan 2012 10:56:21 +0200, Jani Nikula <jani@nikula.org> wrote:
> On Jan 28, 2012 7:06 AM, "Dmitry Kurochkin" <dmitry.kurochkin@gmail.com>
> wrote:
> >
> > 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.
> 
> Imho the syntax check should be in cli, or lib even. I posted a patch to
> cli some time ago when I realized it's possible to add tag "-" but you
> can't remove it with the current cli. (On the road, can't find the message
> id now.)
>

Here you go:
  id:"3da260c7687fafe2cbc17bad129a8b1edb05c6d0.1320958534.git.jani@nikula.org"

> > ---
> >  emacs/notmuch.el |    2 +-
> >  1 files changed, 1 insertions(+), 1 deletions(-)
> >
> > diff --git a/emacs/notmuch.el b/emacs/notmuch.el
> > index 9813e0a..0de6123 100644
> > --- a/emacs/notmuch.el
> > +++ b/emacs/notmuch.el
> > @@ -555,7 +555,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
Non-text part: text/html
> _______________________________________________
> notmuch mailing list
> notmuch@notmuchmail.org
> http://notmuchmail.org/mailman/listinfo/notmuch


Peace

-- 
Pieter

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v5 00/12] emacs: more flexible and consistent tagging operations
  2012-02-08 15:58   ` [PATCH v5 00/12] emacs: more flexible and consistent tagging operations David Bremner
@ 2012-02-23 23:07     ` Pieter Praet
  2012-02-23 23:09       ` [PATCH 1/6] test: emacs: new tests "notmuch-show: {add, remove} multiple tags {to, from} single message" Pieter Praet
                         ` (7 more replies)
  2012-02-24 22:30     ` [PATCH v2 0/6] `notmuch-show-tag-all' with prefix arg only tags open messages Pieter Praet
  1 sibling, 8 replies; 136+ messages in thread
From: Pieter Praet @ 2012-02-23 23:07 UTC (permalink / raw)
  To: David Bremner, Dmitry Kurochkin, notmuch

On Wed, 08 Feb 2012 11:58:32 -0400, David Bremner <david@tethera.net> wrote:
> On Sun,  5 Feb 2012 11:13:41 +0400, Dmitry Kurochkin <dmitry.kurochkin@gmail.com> wrote:
> > Changes:
> > 
> > v4:
> > 
> > * rebased on master, no conflicts so no need for another review
> > 
> 
> I pushed this series.  
> 
> Maybe this was discussed already, but I think ideally * would apply only
> to open messages. So consider that a feature request if someone is
> looking for a project.
>

How about if '*' applies to all messages (as it currently does),
but 'C-u *' only to open messages?  That would make more sense IMHO.

But, conforming to your original request, I've implemented the inverse.

Patches follow.


> d
> _______________________________________________
> notmuch mailing list
> notmuch@notmuchmail.org
> http://notmuchmail.org/mailman/listinfo/notmuch


Peace

-- 
Pieter

^ permalink raw reply	[flat|nested] 136+ messages in thread

* [PATCH 1/6] test: emacs: new tests "notmuch-show: {add, remove} multiple tags {to, from} single message"
  2012-02-23 23:07     ` Pieter Praet
@ 2012-02-23 23:09       ` Pieter Praet
  2012-02-24 10:35         ` Dmitry Kurochkin
  2012-02-23 23:09       ` [PATCH 2/6] test: emacs: new test "notmuch-show: change tags of all messages in current buffer" Pieter Praet
                         ` (6 subsequent siblings)
  7 siblings, 1 reply; 136+ messages in thread
From: Pieter Praet @ 2012-02-23 23:09 UTC (permalink / raw)
  To: David Bremner, Dmitry Kurochkin; +Cc: Notmuch Mail

* test/emacs:

  - Rename subtests "{Add,Remove} tag from notmuch-show view" to
    "notmuch-show: {add,remove} single tag {to,from} single message"
    to be consistent with the following tests.

  - New subtest "notmuch-show: add multiple tags to single message":
    `notmuch-show-add-tag' ("+") can add multiple tags to a message.

  - New subtest "notmuch-show: remove multiple tags from single message":
    `notmuch-show-remove-tag' ("-") can remove multiple tags from a message.
---
 test/emacs |   16 ++++++++++++++--
 1 files changed, 14 insertions(+), 2 deletions(-)

diff --git a/test/emacs b/test/emacs
index b74cfa9..ec1dbb0 100755
--- a/test/emacs
+++ b/test/emacs
@@ -112,18 +112,30 @@ test_emacs "(notmuch-search \"$os_x_darwin_thread\")
 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_begin_subtest "notmuch-show: add single tag to single message"
 test_emacs "(notmuch-show \"$os_x_darwin_thread\")
 	    (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_begin_subtest "notmuch-show: remove single tag from single message"
 test_emacs "(notmuch-show \"$os_x_darwin_thread\")
 	    (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)"
 
+test_begin_subtest "notmuch-show: add multiple tags to single message"
+test_emacs "(notmuch-show \"$os_x_darwin_thread\")
+	    (execute-kbd-macro \"+tag1-from-show-view +tag2-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 tag1-from-show-view tag2-from-show-view unread)"
+
+test_begin_subtest "notmuch-show: remove multiple tags from single message"
+test_emacs "(notmuch-show \"$os_x_darwin_thread\")
+	    (execute-kbd-macro \"-tag1-from-show-view -tag2-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)"
+
 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\"")
-- 
1.7.8.1

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH 2/6] test: emacs: new test "notmuch-show: change tags of all messages in current buffer"
  2012-02-23 23:07     ` Pieter Praet
  2012-02-23 23:09       ` [PATCH 1/6] test: emacs: new tests "notmuch-show: {add, remove} multiple tags {to, from} single message" Pieter Praet
@ 2012-02-23 23:09       ` Pieter Praet
  2012-02-23 23:09       ` [PATCH 3/6] test: emacs: `notmuch-show-tag-all' sans prefix arg should only tag open messages Pieter Praet
                         ` (5 subsequent siblings)
  7 siblings, 0 replies; 136+ messages in thread
From: Pieter Praet @ 2012-02-23 23:09 UTC (permalink / raw)
  To: David Bremner, Dmitry Kurochkin; +Cc: Notmuch Mail

* test/emacs:

  New subtest "notmuch-show: change tags of all messages in current buffer":
  `notmuch-show-tag-all' ("*") changes tags of *all* messages in current buffer.
---
 test/emacs |   15 +++++++++++++++
 1 files changed, 15 insertions(+), 0 deletions(-)

diff --git a/test/emacs b/test/emacs
index ec1dbb0..d2dbafc 100755
--- a/test/emacs
+++ b/test/emacs
@@ -136,6 +136,21 @@ test_emacs "(notmuch-show \"$os_x_darwin_thread\")
 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 "notmuch-show: change tags of all messages in current buffer"
+query="$os_x_darwin_thread"
+filter="from:Jiang"
+add_tag="notmuch-show-tag-all"
+del_tag="inbox"
+count_total=$(notmuch count -- "$query")               # = 4
+count_match=$(notmuch count -- "$query" AND "$filter") # = 2
+test_emacs "(notmuch-search \"$query AND $filter\")
+        (notmuch-test-wait)
+        (notmuch-search-show-thread)
+        (execute-kbd-macro \"*+$add_tag -$del_tag\")"
+count_changed=$(notmuch count -- "$query" AND tag:"$add_tag" AND NOT tag:"$del_tag")
+notmuch tag +"$del_tag" -"$add_tag" -- "$query" # revert tag changes
+test_expect_equal "$count_changed" "$count_total" # assert that CHANGED == TOTAL
+
 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\"")
-- 
1.7.8.1

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH 3/6] test: emacs: `notmuch-show-tag-all' sans prefix arg should only tag open messages
  2012-02-23 23:07     ` Pieter Praet
  2012-02-23 23:09       ` [PATCH 1/6] test: emacs: new tests "notmuch-show: {add, remove} multiple tags {to, from} single message" Pieter Praet
  2012-02-23 23:09       ` [PATCH 2/6] test: emacs: new test "notmuch-show: change tags of all messages in current buffer" Pieter Praet
@ 2012-02-23 23:09       ` Pieter Praet
  2012-02-23 23:09       ` [PATCH 4/6] emacs: add predicate arg to `notmuch-show-mapc' Pieter Praet
                         ` (4 subsequent siblings)
  7 siblings, 0 replies; 136+ messages in thread
From: Pieter Praet @ 2012-02-23 23:09 UTC (permalink / raw)
  To: David Bremner, Dmitry Kurochkin; +Cc: Notmuch Mail

* test/emacs:

  - Alter subtest "notmuch-show: change tags of all messages in current buffer":
    Pass a prefix arg to `notmuch-show-tag-all' ("*").

  - New subtest "notmuch-show: change tags of open messages in current buffer":
    When called *without* a prefix arg, `notmuch-show-tag-all' ("*") should only
    change the tags of *open* messages.  Currently broken, fix follows later.
---
 test/emacs |   18 +++++++++++++++++-
 1 files changed, 17 insertions(+), 1 deletions(-)

diff --git a/test/emacs b/test/emacs
index d2dbafc..644ef59 100755
--- a/test/emacs
+++ b/test/emacs
@@ -146,11 +146,27 @@ count_match=$(notmuch count -- "$query" AND "$filter") # = 2
 test_emacs "(notmuch-search \"$query AND $filter\")
         (notmuch-test-wait)
         (notmuch-search-show-thread)
-        (execute-kbd-macro \"*+$add_tag -$del_tag\")"
+        (execute-kbd-macro \"\x15*+$add_tag -$del_tag\")"
 count_changed=$(notmuch count -- "$query" AND tag:"$add_tag" AND NOT tag:"$del_tag")
 notmuch tag +"$del_tag" -"$add_tag" -- "$query" # revert tag changes
 test_expect_equal "$count_changed" "$count_total" # assert that CHANGED == TOTAL
 
+test_begin_subtest "notmuch-show: change tags of open messages in current buffer"
+test_subtest_known_broken
+query="$os_x_darwin_thread"
+filter="from:Jiang"
+add_tag="notmuch-show-tag-all"
+del_tag="inbox"
+count_total=$(notmuch count -- "$query")               # = 4
+count_match=$(notmuch count -- "$query" AND "$filter") # = 2
+test_emacs "(notmuch-search \"$query AND $filter\")
+        (notmuch-test-wait)
+        (notmuch-search-show-thread)
+        (execute-kbd-macro \"*+$add_tag -$del_tag\")"
+count_changed=$(notmuch count -- "$query" AND tag:"$add_tag" AND NOT tag:"$del_tag")
+notmuch tag +"$del_tag" -"$add_tag" -- "$query" # revert tag changes
+test_expect_equal "$count_changed" "$count_match" # assert that CHANGED == MATCHING
+
 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\"")
-- 
1.7.8.1

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH 4/6] emacs: add predicate arg to `notmuch-show-mapc'
  2012-02-23 23:07     ` Pieter Praet
                         ` (2 preceding siblings ...)
  2012-02-23 23:09       ` [PATCH 3/6] test: emacs: `notmuch-show-tag-all' sans prefix arg should only tag open messages Pieter Praet
@ 2012-02-23 23:09       ` Pieter Praet
  2012-02-24 10:39         ` Dmitry Kurochkin
  2012-02-23 23:09       ` [PATCH 5/6] emacs: simplify `notmuch-show-get-messages-ids{, -search}' Pieter Praet
                         ` (3 subsequent siblings)
  7 siblings, 1 reply; 136+ messages in thread
From: Pieter Praet @ 2012-02-23 23:09 UTC (permalink / raw)
  To: David Bremner, Dmitry Kurochkin; +Cc: Notmuch Mail

* emacs/notmuch-show.el

  (notmuch-show-mapc):
    Only call FUNCTION if new argument PREDICATE is satisfied.
    Also correct original docstring: 's/thread/buffer/'.

  (notmuch-show-get-messages-ids):
    Update wrt changes to `notmuch-show-mapc'.

  (notmuch-show-tag-all):
    Update wrt changes to `notmuch-show-mapc'.
---
 emacs/notmuch-show.el |   15 ++++++++-------
 1 files changed, 8 insertions(+), 7 deletions(-)

diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
index aa9ccee..5fc0e43 100644
--- a/emacs/notmuch-show.el
+++ b/emacs/notmuch-show.el
@@ -1272,13 +1272,14 @@ (defun notmuch-show-goto-message-previous ()
     (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."
+(defun notmuch-show-mapc (predicate function)
+  "Iterate through all messages in the current buffer with
+`notmuch-show-goto-message-next'.  If PREDICATE is satisfied,
+call FUNCTION for side effects."
   (save-excursion
     (goto-char (point-min))
-    (loop do (funcall function)
+    (loop do (if (eval predicate)
+		 (funcall function))
 	  while (notmuch-show-goto-message-next))))
 
 ;; Functions relating to the visibility of messages and their
@@ -1336,7 +1337,7 @@ (defun notmuch-show-get-message-id ()
 (defun notmuch-show-get-messages-ids ()
   "Return all message ids of messages in the current thread."
   (let ((message-ids))
-    (notmuch-show-mapc
+    (notmuch-show-mapc t
      (lambda () (push (notmuch-show-get-message-id) message-ids)))
     message-ids))
 
@@ -1633,7 +1634,7 @@ (defun notmuch-show-tag-all (&rest tag-changes)
 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)
-  (notmuch-show-mapc
+  (notmuch-show-mapc t
    (lambda ()
      (let* ((current-tags (notmuch-show-get-tags))
 	    (new-tags (notmuch-update-tags current-tags tag-changes)))
-- 
1.7.8.1

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH 5/6] emacs: simplify `notmuch-show-get-messages-ids{, -search}'
  2012-02-23 23:07     ` Pieter Praet
                         ` (3 preceding siblings ...)
  2012-02-23 23:09       ` [PATCH 4/6] emacs: add predicate arg to `notmuch-show-mapc' Pieter Praet
@ 2012-02-23 23:09       ` Pieter Praet
  2012-02-24 10:42         ` Dmitry Kurochkin
  2012-02-23 23:09       ` [PATCH 6/6] emacs: `notmuch-show-tag-all' sans prefix arg only tags open messages Pieter Praet
                         ` (2 subsequent siblings)
  7 siblings, 1 reply; 136+ messages in thread
From: Pieter Praet @ 2012-02-23 23:09 UTC (permalink / raw)
  To: David Bremner, Dmitry Kurochkin; +Cc: Notmuch Mail

* emacs/notmuch-show.el

  (notmuch-show-get-messages-ids):
    If provided with optional arg SEPARATOR, return a string consisting
    of all Message-Id's, separated by SEPARATOR.  Also improve original
    docstring wrt default return value.

  (notmuch-show-get-messages-ids-search):
    Removed, as its functionality is now in `notmuch-show-get-messages-ids'.

  (notmuch-show-tag-all):
    Call `notmuch-show-get-messages-ids' with SEPARATOR arg instead of
    `notmuch-show-get-messages-ids-search'.
---
 emacs/notmuch-show.el |   18 +++++++++---------
 1 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
index 5fc0e43..4b37c77 100644
--- a/emacs/notmuch-show.el
+++ b/emacs/notmuch-show.el
@@ -1334,17 +1334,17 @@ (defun notmuch-show-get-message-id ()
   "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."
+(defun notmuch-show-get-messages-ids (&optional separator)
+  "Return a list of Message-Id's of all messages in the current buffer.
+
+If provided with optional argument SEPARATOR, return a string
+instead, consisting of all Message-Id's separated by SEPARATOR."
   (let ((message-ids))
     (notmuch-show-mapc t
      (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 "))
+    (if separator
+	(mapconcat 'identity message-ids separator)
+      message-ids)))
 
 ;; dme: Would it make sense to use a macro for many of these?
 
@@ -1633,7 +1633,7 @@ (defun notmuch-show-tag-all (&rest tag-changes)
 
 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)
+  (apply 'notmuch-tag (notmuch-show-get-messages-ids " or ") tag-changes)
   (notmuch-show-mapc t
    (lambda ()
      (let* ((current-tags (notmuch-show-get-tags))
-- 
1.7.8.1

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH 6/6] emacs: `notmuch-show-tag-all' sans prefix arg only tags open messages
  2012-02-23 23:07     ` Pieter Praet
                         ` (4 preceding siblings ...)
  2012-02-23 23:09       ` [PATCH 5/6] emacs: simplify `notmuch-show-get-messages-ids{, -search}' Pieter Praet
@ 2012-02-23 23:09       ` Pieter Praet
  2012-02-24 10:47         ` Dmitry Kurochkin
  2012-02-24 10:30       ` [PATCH v5 00/12] emacs: more flexible and consistent tagging operations Dmitry Kurochkin
  2012-02-25 16:20       ` David Bremner
  7 siblings, 1 reply; 136+ messages in thread
From: Pieter Praet @ 2012-02-23 23:09 UTC (permalink / raw)
  To: David Bremner, Dmitry Kurochkin; +Cc: Notmuch Mail

* emacs/notmuch-show.el

  (notmuch-show-get-messages-ids):
    New optional argument ONLY-OPEN.  If non-nil, only return
    Message-Id's for messages which are currently visible.

  (notmuch-show-tag-all):
    New optional argument IGNORE-VISIBILITY, of which the inverse is
    passed as ONLY-OPEN argument to `notmuch-show-get-messages-ids':
    If called with a prefix arg, affect *all* messages in the current
    buffer.  Otherwise, only change tags of visible messages.

  (notmuch-show-archive-thread):
    Update wrt changes to `notmuch-show-tag-all'.

* test/emacs

  - Subtest "notmuch-show: change tags of open messages in current buffer"
    is no longer broken.
---
 emacs/notmuch-show.el |   28 ++++++++++++++++++++--------
 test/emacs            |    1 -
 2 files changed, 20 insertions(+), 9 deletions(-)

diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
index 4b37c77..4499fcd 100644
--- a/emacs/notmuch-show.el
+++ b/emacs/notmuch-show.el
@@ -1334,13 +1334,17 @@ (defun notmuch-show-get-message-id ()
   "Return the message id of the current message."
   (concat "id:\"" (notmuch-show-get-prop :id) "\""))
 
-(defun notmuch-show-get-messages-ids (&optional separator)
+(defun notmuch-show-get-messages-ids (&optional only-open separator)
   "Return a list of Message-Id's of all messages in the current buffer.
 
+If optional argument ONLY-OPEN is non-nil, only return
+Message-Id's for messages which are currently visible.
+
 If provided with optional argument SEPARATOR, return a string
 instead, consisting of all Message-Id's separated by SEPARATOR."
   (let ((message-ids))
-    (notmuch-show-mapc t
+    (notmuch-show-mapc
+     `(if only-open (notmuch-show-message-visible-p) t)
      (lambda () (push (notmuch-show-get-message-id) message-ids)))
     (if separator
 	(mapconcat 'identity message-ids separator)
@@ -1628,13 +1632,21 @@ (defun notmuch-show-tag (&optional initial-input)
 		      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.
+(defun notmuch-show-tag-all (&optional ignore-visibility &rest tag-changes)
+  "Change tags of all open messages in the current buffer.
+
+If optional arg IGNORE-VISIBILITY is non-nil, change tags of
+*all* messages in the current buffer, independent of their
+visibility.
 
 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 " or ") tag-changes)
-  (notmuch-show-mapc t
+  (interactive (cons current-prefix-arg
+		     (notmuch-read-tag-changes nil notmuch-show-thread-id)))
+  (apply 'notmuch-tag
+	 (notmuch-show-get-messages-ids (not ignore-visibility) " or ")
+	 tag-changes)
+  (notmuch-show-mapc
+   `(if ignore-visibility t (notmuch-show-message-visible-p))
    (lambda ()
      (let* ((current-tags (notmuch-show-get-tags))
 	    (new-tags (notmuch-update-tags current-tags tag-changes)))
@@ -1719,7 +1731,7 @@ (defun notmuch-show-archive-thread (&optional unarchive)
 buffer."
   (interactive "P")
   (let ((op (if unarchive "+" "-")))
-    (notmuch-show-tag-all (concat op "inbox"))))
+    (notmuch-show-tag-all t (concat op "inbox"))))
 
 (defun notmuch-show-archive-thread-then-next ()
   "Archive each message in thread, then show next thread from search."
diff --git a/test/emacs b/test/emacs
index 644ef59..c286ff5 100755
--- a/test/emacs
+++ b/test/emacs
@@ -152,7 +152,6 @@ notmuch tag +"$del_tag" -"$add_tag" -- "$query" # revert tag changes
 test_expect_equal "$count_changed" "$count_total" # assert that CHANGED == TOTAL
 
 test_begin_subtest "notmuch-show: change tags of open messages in current buffer"
-test_subtest_known_broken
 query="$os_x_darwin_thread"
 filter="from:Jiang"
 add_tag="notmuch-show-tag-all"
-- 
1.7.8.1

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* Re: [PATCH v5 00/12] emacs: more flexible and consistent tagging operations
  2012-02-23 23:07     ` Pieter Praet
                         ` (5 preceding siblings ...)
  2012-02-23 23:09       ` [PATCH 6/6] emacs: `notmuch-show-tag-all' sans prefix arg only tags open messages Pieter Praet
@ 2012-02-24 10:30       ` Dmitry Kurochkin
  2012-02-24 10:33         ` Dmitry Kurochkin
  2012-02-24 22:38         ` Pieter Praet
  2012-02-25 16:20       ` David Bremner
  7 siblings, 2 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-02-24 10:30 UTC (permalink / raw)
  To: Pieter Praet, David Bremner, notmuch

On Fri, 24 Feb 2012 00:07:27 +0100, Pieter Praet <pieter@praet.org> wrote:
> On Wed, 08 Feb 2012 11:58:32 -0400, David Bremner <david@tethera.net> wrote:
> > On Sun,  5 Feb 2012 11:13:41 +0400, Dmitry Kurochkin <dmitry.kurochkin@gmail.com> wrote:
> > > Changes:
> > > 
> > > v4:
> > > 
> > > * rebased on master, no conflicts so no need for another review
> > > 
> > 
> > I pushed this series.  
> > 
> > Maybe this was discussed already, but I think ideally * would apply only
> > to open messages. So consider that a feature request if someone is
> > looking for a project.
> >
> 
> How about if '*' applies to all messages (as it currently does),
> but 'C-u *' only to open messages?  That would make more sense IMHO.
> 
> But, conforming to your original request, I've implemented the inverse.
> 

I personally do like '*' as is and do not want to change it's behavior.
Though I am not against adding a prefix argument for it.

Regards,
  Dmitry

> Patches follow.
> 
> 
> > d
> > _______________________________________________
> > notmuch mailing list
> > notmuch@notmuchmail.org
> > http://notmuchmail.org/mailman/listinfo/notmuch
> 
> 
> Peace
> 
> -- 
> Pieter

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v5 00/12] emacs: more flexible and consistent tagging operations
  2012-02-24 10:30       ` [PATCH v5 00/12] emacs: more flexible and consistent tagging operations Dmitry Kurochkin
@ 2012-02-24 10:33         ` Dmitry Kurochkin
  2012-02-24 17:39           ` Jani Nikula
  2012-02-24 22:40           ` Pieter Praet
  2012-02-24 22:38         ` Pieter Praet
  1 sibling, 2 replies; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-02-24 10:33 UTC (permalink / raw)
  To: Pieter Praet, David Bremner, notmuch

On Fri, 24 Feb 2012 14:30:29 +0400, Dmitry Kurochkin <dmitry.kurochkin@gmail.com> wrote:
> On Fri, 24 Feb 2012 00:07:27 +0100, Pieter Praet <pieter@praet.org> wrote:
> > On Wed, 08 Feb 2012 11:58:32 -0400, David Bremner <david@tethera.net> wrote:
> > > On Sun,  5 Feb 2012 11:13:41 +0400, Dmitry Kurochkin <dmitry.kurochkin@gmail.com> wrote:
> > > > Changes:
> > > > 
> > > > v4:
> > > > 
> > > > * rebased on master, no conflicts so no need for another review
> > > > 
> > > 
> > > I pushed this series.  
> > > 
> > > Maybe this was discussed already, but I think ideally * would apply only
> > > to open messages. So consider that a feature request if someone is
> > > looking for a project.
> > >
> > 
> > How about if '*' applies to all messages (as it currently does),
> > but 'C-u *' only to open messages?  That would make more sense IMHO.
> > 
> > But, conforming to your original request, I've implemented the inverse.
> > 
> 
> I personally do like '*' as is and do not want to change it's behavior.
> Though I am not against adding a prefix argument for it.
> 

Also can you please send new patches (and patch series) in a new
separate thread?  If they are related to another thread, you can add a
reference.  But having multiple patch series with multiple versions in a
single thread is very confusing IMO.

Regards,
  Dmitry

> Regards,
>   Dmitry
> 
> > Patches follow.
> > 
> > 
> > > d
> > > _______________________________________________
> > > notmuch mailing list
> > > notmuch@notmuchmail.org
> > > http://notmuchmail.org/mailman/listinfo/notmuch
> > 
> > 
> > Peace
> > 
> > -- 
> > Pieter

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH 1/6] test: emacs: new tests "notmuch-show: {add, remove} multiple tags {to, from} single message"
  2012-02-23 23:09       ` [PATCH 1/6] test: emacs: new tests "notmuch-show: {add, remove} multiple tags {to, from} single message" Pieter Praet
@ 2012-02-24 10:35         ` Dmitry Kurochkin
  2012-02-24 22:33           ` Pieter Praet
  0 siblings, 1 reply; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-02-24 10:35 UTC (permalink / raw)
  To: Pieter Praet, David Bremner; +Cc: Notmuch Mail

On Fri, 24 Feb 2012 00:09:09 +0100, Pieter Praet <pieter@praet.org> wrote:
> * test/emacs:
> 
>   - Rename subtests "{Add,Remove} tag from notmuch-show view" to
>     "notmuch-show: {add,remove} single tag {to,from} single message"
>     to be consistent with the following tests.
> 
>   - New subtest "notmuch-show: add multiple tags to single message":
>     `notmuch-show-add-tag' ("+") can add multiple tags to a message.
> 
>   - New subtest "notmuch-show: remove multiple tags from single message":
>     `notmuch-show-remove-tag' ("-") can remove multiple tags from a message.
> ---

Would be nice to have another patch that moves notmuch-show tests to
emacs-show file.

Regards,
  Dmitry

>  test/emacs |   16 ++++++++++++++--
>  1 files changed, 14 insertions(+), 2 deletions(-)
> 
> diff --git a/test/emacs b/test/emacs
> index b74cfa9..ec1dbb0 100755
> --- a/test/emacs
> +++ b/test/emacs
> @@ -112,18 +112,30 @@ test_emacs "(notmuch-search \"$os_x_darwin_thread\")
>  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_begin_subtest "notmuch-show: add single tag to single message"
>  test_emacs "(notmuch-show \"$os_x_darwin_thread\")
>  	    (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_begin_subtest "notmuch-show: remove single tag from single message"
>  test_emacs "(notmuch-show \"$os_x_darwin_thread\")
>  	    (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)"
>  
> +test_begin_subtest "notmuch-show: add multiple tags to single message"
> +test_emacs "(notmuch-show \"$os_x_darwin_thread\")
> +	    (execute-kbd-macro \"+tag1-from-show-view +tag2-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 tag1-from-show-view tag2-from-show-view unread)"
> +
> +test_begin_subtest "notmuch-show: remove multiple tags from single message"
> +test_emacs "(notmuch-show \"$os_x_darwin_thread\")
> +	    (execute-kbd-macro \"-tag1-from-show-view -tag2-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)"
> +
>  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\"")
> -- 
> 1.7.8.1
> 

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH 4/6] emacs: add predicate arg to `notmuch-show-mapc'
  2012-02-23 23:09       ` [PATCH 4/6] emacs: add predicate arg to `notmuch-show-mapc' Pieter Praet
@ 2012-02-24 10:39         ` Dmitry Kurochkin
  2012-02-24 22:35           ` Pieter Praet
  0 siblings, 1 reply; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-02-24 10:39 UTC (permalink / raw)
  To: Pieter Praet, David Bremner; +Cc: Notmuch Mail

On Fri, 24 Feb 2012 00:09:12 +0100, Pieter Praet <pieter@praet.org> wrote:
> * emacs/notmuch-show.el
> 
>   (notmuch-show-mapc):
>     Only call FUNCTION if new argument PREDICATE is satisfied.
>     Also correct original docstring: 's/thread/buffer/'.
> 
>   (notmuch-show-get-messages-ids):
>     Update wrt changes to `notmuch-show-mapc'.
> 
>   (notmuch-show-tag-all):
>     Update wrt changes to `notmuch-show-mapc'.
> ---
>  emacs/notmuch-show.el |   15 ++++++++-------
>  1 files changed, 8 insertions(+), 7 deletions(-)
> 
> diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
> index aa9ccee..5fc0e43 100644
> --- a/emacs/notmuch-show.el
> +++ b/emacs/notmuch-show.el
> @@ -1272,13 +1272,14 @@ (defun notmuch-show-goto-message-previous ()
>      (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."
> +(defun notmuch-show-mapc (predicate function)

Please make PREDICATE optional to avoid giving t when it is not needed.

I would expect PREDICATE to be a function, but perhaps the way you
implemented it is common in Emacs.

Regards,
  Dmitry

> +  "Iterate through all messages in the current buffer with
> +`notmuch-show-goto-message-next'.  If PREDICATE is satisfied,
> +call FUNCTION for side effects."
>    (save-excursion
>      (goto-char (point-min))
> -    (loop do (funcall function)
> +    (loop do (if (eval predicate)
> +		 (funcall function))
>  	  while (notmuch-show-goto-message-next))))
>  
>  ;; Functions relating to the visibility of messages and their
> @@ -1336,7 +1337,7 @@ (defun notmuch-show-get-message-id ()
>  (defun notmuch-show-get-messages-ids ()
>    "Return all message ids of messages in the current thread."
>    (let ((message-ids))
> -    (notmuch-show-mapc
> +    (notmuch-show-mapc t
>       (lambda () (push (notmuch-show-get-message-id) message-ids)))
>      message-ids))
>  
> @@ -1633,7 +1634,7 @@ (defun notmuch-show-tag-all (&rest tag-changes)
>  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)
> -  (notmuch-show-mapc
> +  (notmuch-show-mapc t
>     (lambda ()
>       (let* ((current-tags (notmuch-show-get-tags))
>  	    (new-tags (notmuch-update-tags current-tags tag-changes)))
> -- 
> 1.7.8.1
> 

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH 5/6] emacs: simplify `notmuch-show-get-messages-ids{, -search}'
  2012-02-23 23:09       ` [PATCH 5/6] emacs: simplify `notmuch-show-get-messages-ids{, -search}' Pieter Praet
@ 2012-02-24 10:42         ` Dmitry Kurochkin
  2012-02-24 22:36           ` Pieter Praet
  0 siblings, 1 reply; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-02-24 10:42 UTC (permalink / raw)
  To: Pieter Praet, David Bremner; +Cc: Notmuch Mail

On Fri, 24 Feb 2012 00:09:13 +0100, Pieter Praet <pieter@praet.org> wrote:
> * emacs/notmuch-show.el
> 
>   (notmuch-show-get-messages-ids):
>     If provided with optional arg SEPARATOR, return a string consisting
>     of all Message-Id's, separated by SEPARATOR.  Also improve original
>     docstring wrt default return value.
> 
>   (notmuch-show-get-messages-ids-search):
>     Removed, as its functionality is now in `notmuch-show-get-messages-ids'.
> 
>   (notmuch-show-tag-all):
>     Call `notmuch-show-get-messages-ids' with SEPARATOR arg instead of
>     `notmuch-show-get-messages-ids-search'.
> ---

There is another similar case in notmuch.el:
`notmuch-show-get-messages-ids' and
`notmuch-show-get-messages-ids-search'.  There may be more.

Please change them as well.

Regards,
  Dmitry

>  emacs/notmuch-show.el |   18 +++++++++---------
>  1 files changed, 9 insertions(+), 9 deletions(-)
> 
> diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
> index 5fc0e43..4b37c77 100644
> --- a/emacs/notmuch-show.el
> +++ b/emacs/notmuch-show.el
> @@ -1334,17 +1334,17 @@ (defun notmuch-show-get-message-id ()
>    "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."
> +(defun notmuch-show-get-messages-ids (&optional separator)
> +  "Return a list of Message-Id's of all messages in the current buffer.
> +
> +If provided with optional argument SEPARATOR, return a string
> +instead, consisting of all Message-Id's separated by SEPARATOR."
>    (let ((message-ids))
>      (notmuch-show-mapc t
>       (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 "))
> +    (if separator
> +	(mapconcat 'identity message-ids separator)
> +      message-ids)))
>  
>  ;; dme: Would it make sense to use a macro for many of these?
>  
> @@ -1633,7 +1633,7 @@ (defun notmuch-show-tag-all (&rest tag-changes)
>  
>  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)
> +  (apply 'notmuch-tag (notmuch-show-get-messages-ids " or ") tag-changes)
>    (notmuch-show-mapc t
>     (lambda ()
>       (let* ((current-tags (notmuch-show-get-tags))
> -- 
> 1.7.8.1
> 

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH 6/6] emacs: `notmuch-show-tag-all' sans prefix arg only tags open messages
  2012-02-23 23:09       ` [PATCH 6/6] emacs: `notmuch-show-tag-all' sans prefix arg only tags open messages Pieter Praet
@ 2012-02-24 10:47         ` Dmitry Kurochkin
  2012-02-24 22:37           ` Pieter Praet
  0 siblings, 1 reply; 136+ messages in thread
From: Dmitry Kurochkin @ 2012-02-24 10:47 UTC (permalink / raw)
  To: Pieter Praet, David Bremner; +Cc: Notmuch Mail

On Fri, 24 Feb 2012 00:09:14 +0100, Pieter Praet <pieter@praet.org> wrote:
> * emacs/notmuch-show.el
> 
>   (notmuch-show-get-messages-ids):
>     New optional argument ONLY-OPEN.  If non-nil, only return
>     Message-Id's for messages which are currently visible.
> 
>   (notmuch-show-tag-all):
>     New optional argument IGNORE-VISIBILITY, of which the inverse is
>     passed as ONLY-OPEN argument to `notmuch-show-get-messages-ids':
>     If called with a prefix arg, affect *all* messages in the current
>     buffer.  Otherwise, only change tags of visible messages.
> 
>   (notmuch-show-archive-thread):
>     Update wrt changes to `notmuch-show-tag-all'.
> 
> * test/emacs
> 
>   - Subtest "notmuch-show: change tags of open messages in current buffer"
>     is no longer broken.
> ---
>  emacs/notmuch-show.el |   28 ++++++++++++++++++++--------
>  test/emacs            |    1 -
>  2 files changed, 20 insertions(+), 9 deletions(-)
> 
> diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
> index 4b37c77..4499fcd 100644
> --- a/emacs/notmuch-show.el
> +++ b/emacs/notmuch-show.el
> @@ -1334,13 +1334,17 @@ (defun notmuch-show-get-message-id ()
>    "Return the message id of the current message."
>    (concat "id:\"" (notmuch-show-get-prop :id) "\""))
>  
> -(defun notmuch-show-get-messages-ids (&optional separator)
> +(defun notmuch-show-get-messages-ids (&optional only-open separator)
>    "Return a list of Message-Id's of all messages in the current buffer.
>  
> +If optional argument ONLY-OPEN is non-nil, only return
> +Message-Id's for messages which are currently visible.
> +
>  If provided with optional argument SEPARATOR, return a string
>  instead, consisting of all Message-Id's separated by SEPARATOR."
>    (let ((message-ids))
> -    (notmuch-show-mapc t
> +    (notmuch-show-mapc
> +     `(if only-open (notmuch-show-message-visible-p) t)

How about changing ONLY-OPEN to a general optional PREDICATE argument
and pass it as is to `notmuch-show-mapc'?  Please make it the last
argument.

Regards,
  Dmitry

>       (lambda () (push (notmuch-show-get-message-id) message-ids)))
>      (if separator
>  	(mapconcat 'identity message-ids separator)
> @@ -1628,13 +1632,21 @@ (defun notmuch-show-tag (&optional initial-input)
>  		      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.
> +(defun notmuch-show-tag-all (&optional ignore-visibility &rest tag-changes)
> +  "Change tags of all open messages in the current buffer.
> +
> +If optional arg IGNORE-VISIBILITY is non-nil, change tags of
> +*all* messages in the current buffer, independent of their
> +visibility.
>  
>  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 " or ") tag-changes)
> -  (notmuch-show-mapc t
> +  (interactive (cons current-prefix-arg
> +		     (notmuch-read-tag-changes nil notmuch-show-thread-id)))
> +  (apply 'notmuch-tag
> +	 (notmuch-show-get-messages-ids (not ignore-visibility) " or ")
> +	 tag-changes)
> +  (notmuch-show-mapc
> +   `(if ignore-visibility t (notmuch-show-message-visible-p))
>     (lambda ()
>       (let* ((current-tags (notmuch-show-get-tags))
>  	    (new-tags (notmuch-update-tags current-tags tag-changes)))
> @@ -1719,7 +1731,7 @@ (defun notmuch-show-archive-thread (&optional unarchive)
>  buffer."
>    (interactive "P")
>    (let ((op (if unarchive "+" "-")))
> -    (notmuch-show-tag-all (concat op "inbox"))))
> +    (notmuch-show-tag-all t (concat op "inbox"))))
>  
>  (defun notmuch-show-archive-thread-then-next ()
>    "Archive each message in thread, then show next thread from search."
> diff --git a/test/emacs b/test/emacs
> index 644ef59..c286ff5 100755
> --- a/test/emacs
> +++ b/test/emacs
> @@ -152,7 +152,6 @@ notmuch tag +"$del_tag" -"$add_tag" -- "$query" # revert tag changes
>  test_expect_equal "$count_changed" "$count_total" # assert that CHANGED == TOTAL
>  
>  test_begin_subtest "notmuch-show: change tags of open messages in current buffer"
> -test_subtest_known_broken
>  query="$os_x_darwin_thread"
>  filter="from:Jiang"
>  add_tag="notmuch-show-tag-all"
> -- 
> 1.7.8.1
> 

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v5 00/12] emacs: more flexible and consistent tagging operations
  2012-02-24 10:33         ` Dmitry Kurochkin
@ 2012-02-24 17:39           ` Jani Nikula
  2012-02-24 22:40           ` Pieter Praet
  1 sibling, 0 replies; 136+ messages in thread
From: Jani Nikula @ 2012-02-24 17:39 UTC (permalink / raw)
  To: Dmitry Kurochkin, Pieter Praet, David Bremner, notmuch

On Fri, 24 Feb 2012 14:33:35 +0400, Dmitry Kurochkin <dmitry.kurochkin@gmail.com> wrote:
> Also can you please send new patches (and patch series) in a new
> separate thread?  If they are related to another thread, you can add a
> reference.  But having multiple patch series with multiple versions in a
> single thread is very confusing IMO.

IMHO the same thread is okay if the new versions are in-reply-to the
cover letter of the first version.

Jani.

^ permalink raw reply	[flat|nested] 136+ messages in thread

* [PATCH v2 0/6] `notmuch-show-tag-all' with prefix arg only tags open messages
  2012-02-08 15:58   ` [PATCH v5 00/12] emacs: more flexible and consistent tagging operations David Bremner
  2012-02-23 23:07     ` Pieter Praet
@ 2012-02-24 22:30     ` Pieter Praet
  2012-02-24 22:30       ` [PATCH v2 1/6] test: emacs: new tests "notmuch-show: {add, remove} multiple tags {to, from} single message" Pieter Praet
                         ` (5 more replies)
  1 sibling, 6 replies; 136+ messages in thread
From: Pieter Praet @ 2012-02-24 22:30 UTC (permalink / raw)
  To: David Bremner, Dmitry Kurochkin; +Cc: Notmuch Mail

Addresses Dmitry's comments [1,2,3], save for the ones that aren't
directly related to this series [4,5] and will be dealt with later.

Also made `notmuch-show-tag-all's ONLY-OPEN arg non-optional.
Otherwise it would cause issues when running non-interactively.


Peace

-- 
Pieter

[1] id:"87fwe0jz0y.fsf@gmail.com"
[2] id:"87aa48jynx.fsf@gmail.com"
[3] id:"87obsojzga.fsf@gmail.com"
[4] id:"87ipiwjz85.fsf@gmail.com"
[5] id:"87d394jyvm.fsf@gmail.com"

^ permalink raw reply	[flat|nested] 136+ messages in thread

* [PATCH v2 1/6] test: emacs: new tests "notmuch-show: {add, remove} multiple tags {to, from} single message"
  2012-02-24 22:30     ` [PATCH v2 0/6] `notmuch-show-tag-all' with prefix arg only tags open messages Pieter Praet
@ 2012-02-24 22:30       ` Pieter Praet
  2012-03-21  1:06         ` Mark Walters
                           ` (2 more replies)
  2012-02-24 22:30       ` [PATCH v2 2/6] test: emacs: new test "notmuch-show: change tags of all messages in current buffer" Pieter Praet
                         ` (4 subsequent siblings)
  5 siblings, 3 replies; 136+ messages in thread
From: Pieter Praet @ 2012-02-24 22:30 UTC (permalink / raw)
  To: David Bremner, Dmitry Kurochkin; +Cc: Notmuch Mail

* test/emacs:

  - Rename subtests "{Add,Remove} tag from notmuch-show view" to
    "notmuch-show: {add,remove} single tag {to,from} single message"
    to be consistent with the following tests.

  - New subtest "notmuch-show: add multiple tags to single message":
    `notmuch-show-add-tag' ("+") can add multiple tags to a message.

  - New subtest "notmuch-show: remove multiple tags from single message":
    `notmuch-show-remove-tag' ("-") can remove multiple tags from a message.
---
 test/emacs |   16 ++++++++++++++--
 1 files changed, 14 insertions(+), 2 deletions(-)

diff --git a/test/emacs b/test/emacs
index b74cfa9..ec1dbb0 100755
--- a/test/emacs
+++ b/test/emacs
@@ -112,18 +112,30 @@ test_emacs "(notmuch-search \"$os_x_darwin_thread\")
 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_begin_subtest "notmuch-show: add single tag to single message"
 test_emacs "(notmuch-show \"$os_x_darwin_thread\")
 	    (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_begin_subtest "notmuch-show: remove single tag from single message"
 test_emacs "(notmuch-show \"$os_x_darwin_thread\")
 	    (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)"
 
+test_begin_subtest "notmuch-show: add multiple tags to single message"
+test_emacs "(notmuch-show \"$os_x_darwin_thread\")
+	    (execute-kbd-macro \"+tag1-from-show-view +tag2-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 tag1-from-show-view tag2-from-show-view unread)"
+
+test_begin_subtest "notmuch-show: remove multiple tags from single message"
+test_emacs "(notmuch-show \"$os_x_darwin_thread\")
+	    (execute-kbd-macro \"-tag1-from-show-view -tag2-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)"
+
 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\"")
-- 
1.7.8.1

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v2 2/6] test: emacs: new test "notmuch-show: change tags of all messages in current buffer"
  2012-02-24 22:30     ` [PATCH v2 0/6] `notmuch-show-tag-all' with prefix arg only tags open messages Pieter Praet
  2012-02-24 22:30       ` [PATCH v2 1/6] test: emacs: new tests "notmuch-show: {add, remove} multiple tags {to, from} single message" Pieter Praet
@ 2012-02-24 22:30       ` Pieter Praet
  2012-10-16  2:15         ` Ethan Glasser-Camp
  2012-02-24 22:30       ` [PATCH v2 3/6] test: emacs: `notmuch-show-tag-all' with prefix arg should only tag open messages Pieter Praet
                         ` (3 subsequent siblings)
  5 siblings, 1 reply; 136+ messages in thread
From: Pieter Praet @ 2012-02-24 22:30 UTC (permalink / raw)
  To: David Bremner, Dmitry Kurochkin; +Cc: Notmuch Mail

* test/emacs:

  New subtest "notmuch-show: change tags of all messages in current buffer":
  `notmuch-show-tag-all' ("*") changes tags of *all* messages in current buffer.
---
 test/emacs |   15 +++++++++++++++
 1 files changed, 15 insertions(+), 0 deletions(-)

diff --git a/test/emacs b/test/emacs
index ec1dbb0..d2dbafc 100755
--- a/test/emacs
+++ b/test/emacs
@@ -136,6 +136,21 @@ test_emacs "(notmuch-show \"$os_x_darwin_thread\")
 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 "notmuch-show: change tags of all messages in current buffer"
+query="$os_x_darwin_thread"
+filter="from:Jiang"
+add_tag="notmuch-show-tag-all"
+del_tag="inbox"
+count_total=$(notmuch count -- "$query")               # = 4
+count_match=$(notmuch count -- "$query" AND "$filter") # = 2
+test_emacs "(notmuch-search \"$query AND $filter\")
+        (notmuch-test-wait)
+        (notmuch-search-show-thread)
+        (execute-kbd-macro \"*+$add_tag -$del_tag\")"
+count_changed=$(notmuch count -- "$query" AND tag:"$add_tag" AND NOT tag:"$del_tag")
+notmuch tag +"$del_tag" -"$add_tag" -- "$query" # revert tag changes
+test_expect_equal "$count_changed" "$count_total" # assert that CHANGED == TOTAL
+
 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\"")
-- 
1.7.8.1

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v2 3/6] test: emacs: `notmuch-show-tag-all' with prefix arg should only tag open messages
  2012-02-24 22:30     ` [PATCH v2 0/6] `notmuch-show-tag-all' with prefix arg only tags open messages Pieter Praet
  2012-02-24 22:30       ` [PATCH v2 1/6] test: emacs: new tests "notmuch-show: {add, remove} multiple tags {to, from} single message" Pieter Praet
  2012-02-24 22:30       ` [PATCH v2 2/6] test: emacs: new test "notmuch-show: change tags of all messages in current buffer" Pieter Praet
@ 2012-02-24 22:30       ` Pieter Praet
  2013-02-19  0:27         ` David Bremner
  2012-02-24 22:30       ` [PATCH v2 4/6] emacs: add optional predicate arg to `notmuch-show-mapc' Pieter Praet
                         ` (2 subsequent siblings)
  5 siblings, 1 reply; 136+ messages in thread
From: Pieter Praet @ 2012-02-24 22:30 UTC (permalink / raw)
  To: David Bremner, Dmitry Kurochkin; +Cc: Notmuch Mail

* test/emacs:

  - New subtest "notmuch-show: change tags of open messages in current buffer":
    When called with a prefix arg, `notmuch-show-tag-all' ("*") should only
    change the tags of *open* messages.  Currently broken, fix follows later.
---
 test/emacs |   16 ++++++++++++++++
 1 files changed, 16 insertions(+), 0 deletions(-)

diff --git a/test/emacs b/test/emacs
index d2dbafc..9088ced 100755
--- a/test/emacs
+++ b/test/emacs
@@ -151,6 +151,22 @@ count_changed=$(notmuch count -- "$query" AND tag:"$add_tag" AND NOT tag:"$del_t
 notmuch tag +"$del_tag" -"$add_tag" -- "$query" # revert tag changes
 test_expect_equal "$count_changed" "$count_total" # assert that CHANGED == TOTAL
 
+test_begin_subtest "notmuch-show: change tags of open messages in current buffer"
+test_subtest_known_broken
+query="$os_x_darwin_thread"
+filter="from:Jiang"
+add_tag="notmuch-show-tag-all"
+del_tag="inbox"
+count_total=$(notmuch count -- "$query")               # = 4
+count_match=$(notmuch count -- "$query" AND "$filter") # = 2
+test_emacs "(notmuch-search \"$query AND $filter\")
+        (notmuch-test-wait)
+        (notmuch-search-show-thread)
+        (execute-kbd-macro \"\x15*+$add_tag -$del_tag\")"
+count_changed=$(notmuch count -- "$query" AND tag:"$add_tag" AND NOT tag:"$del_tag")
+notmuch tag +"$del_tag" -"$add_tag" -- "$query" # revert tag changes
+test_expect_equal "$count_changed" "$count_match" # assert that CHANGED == MATCHING
+
 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\"")
-- 
1.7.8.1

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v2 4/6] emacs: add optional predicate arg to `notmuch-show-mapc'
  2012-02-24 22:30     ` [PATCH v2 0/6] `notmuch-show-tag-all' with prefix arg only tags open messages Pieter Praet
                         ` (2 preceding siblings ...)
  2012-02-24 22:30       ` [PATCH v2 3/6] test: emacs: `notmuch-show-tag-all' with prefix arg should only tag open messages Pieter Praet
@ 2012-02-24 22:30       ` Pieter Praet
  2012-03-21  1:33         ` Mark Walters
  2012-10-16  2:18         ` Ethan Glasser-Camp
  2012-02-24 22:30       ` [PATCH v2 5/6] emacs: simplify `notmuch-show-get-messages-ids{, -search}' Pieter Praet
  2012-02-24 22:30       ` [PATCH v2 6/6] emacs: `notmuch-show-tag-all' with prefix arg only tags open messages Pieter Praet
  5 siblings, 2 replies; 136+ messages in thread
From: Pieter Praet @ 2012-02-24 22:30 UTC (permalink / raw)
  To: David Bremner, Dmitry Kurochkin; +Cc: Notmuch Mail

* emacs/notmuch-show.el (notmuch-show-mapc):

  If provided with optional argument PREDICATE, only call
  FUNCTION if calling PREDICATE returns non-nil.

  Also correct original docstring: 's/thread/buffer/'.
---
 emacs/notmuch-show.el |   14 ++++++++++----
 1 files changed, 10 insertions(+), 4 deletions(-)

diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
index aa9ccee..6adbdc0 100644
--- a/emacs/notmuch-show.el
+++ b/emacs/notmuch-show.el
@@ -1272,13 +1272,19 @@ (defun notmuch-show-goto-message-previous ()
     (notmuch-show-move-to-message-top)
     t))
 
-(defun notmuch-show-mapc (function)
-  "Iterate through all messages in the current thread with
+(defun notmuch-show-mapc (function &optional predicate)
+  "Iterate through all messages in the current buffer with
 `notmuch-show-goto-message-next' and call FUNCTION for side
-effects."
+effects.
+
+If provided with optional argument PREDICATE, only call
+FUNCTION if calling PREDICATE returns non-nil."
   (save-excursion
     (goto-char (point-min))
-    (loop do (funcall function)
+    (loop do (if predicate
+		 (if (funcall predicate)
+		     (funcall function))
+	       (funcall function))
 	  while (notmuch-show-goto-message-next))))
 
 ;; Functions relating to the visibility of messages and their
-- 
1.7.8.1

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v2 5/6] emacs: simplify `notmuch-show-get-messages-ids{, -search}'
  2012-02-24 22:30     ` [PATCH v2 0/6] `notmuch-show-tag-all' with prefix arg only tags open messages Pieter Praet
                         ` (3 preceding siblings ...)
  2012-02-24 22:30       ` [PATCH v2 4/6] emacs: add optional predicate arg to `notmuch-show-mapc' Pieter Praet
@ 2012-02-24 22:30       ` Pieter Praet
  2012-03-21  1:36         ` Mark Walters
  2012-03-21  1:40         ` Mark Walters
  2012-02-24 22:30       ` [PATCH v2 6/6] emacs: `notmuch-show-tag-all' with prefix arg only tags open messages Pieter Praet
  5 siblings, 2 replies; 136+ messages in thread
From: Pieter Praet @ 2012-02-24 22:30 UTC (permalink / raw)
  To: David Bremner, Dmitry Kurochkin; +Cc: Notmuch Mail

* emacs/notmuch-show.el

  (notmuch-show-get-messages-ids):
    If provided with optional arg SEPARATOR, return a string consisting
    of all Message-Id's, separated by SEPARATOR.  Also improve original
    docstring wrt default return value.

  (notmuch-show-get-messages-ids-search):
    Removed, as its functionality is now in `notmuch-show-get-messages-ids'.

  (notmuch-show-tag-all):
    Call `notmuch-show-get-messages-ids' with SEPARATOR arg instead of
    `notmuch-show-get-messages-ids-search'.
---
 emacs/notmuch-show.el |   18 +++++++++---------
 1 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
index 6adbdc0..05606fc 100644
--- a/emacs/notmuch-show.el
+++ b/emacs/notmuch-show.el
@@ -1339,17 +1339,17 @@ (defun notmuch-show-get-message-id ()
   "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."
+(defun notmuch-show-get-messages-ids (&optional separator)
+  "Return a list of Message-Id's of all messages in the current buffer.
+
+If provided with optional argument SEPARATOR, return a string
+instead, consisting of all Message-Id's separated by SEPARATOR."
   (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 "))
+    (if separator
+	(mapconcat 'identity message-ids separator)
+      message-ids)))
 
 ;; dme: Would it make sense to use a macro for many of these?
 
@@ -1638,7 +1638,7 @@ (defun notmuch-show-tag-all (&rest tag-changes)
 
 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)
+  (apply 'notmuch-tag (notmuch-show-get-messages-ids " or ") tag-changes)
   (notmuch-show-mapc
    (lambda ()
      (let* ((current-tags (notmuch-show-get-tags))
-- 
1.7.8.1

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v2 6/6] emacs: `notmuch-show-tag-all' with prefix arg only tags open messages
  2012-02-24 22:30     ` [PATCH v2 0/6] `notmuch-show-tag-all' with prefix arg only tags open messages Pieter Praet
                         ` (4 preceding siblings ...)
  2012-02-24 22:30       ` [PATCH v2 5/6] emacs: simplify `notmuch-show-get-messages-ids{, -search}' Pieter Praet
@ 2012-02-24 22:30       ` Pieter Praet
  2012-10-16  3:39         ` Ethan Glasser-Camp
  5 siblings, 1 reply; 136+ messages in thread
From: Pieter Praet @ 2012-02-24 22:30 UTC (permalink / raw)
  To: David Bremner, Dmitry Kurochkin; +Cc: Notmuch Mail

* emacs/notmuch-show.el

  (notmuch-show-get-messages-ids):
    If provided with optional argument PREDICATE, only return
    Message-Id's of messages for which PREDICATE returns non-nil.

  (notmuch-show-tag-all):
    New argument ONLY-OPEN (set to `current-prefix-arg' if running
    interactively): if non-nil, only change tags of *open* messages.
    Also correct original docstring: 's/thread/buffer/'.

  (notmuch-show-archive-thread):
    Update wrt changes to `notmuch-show-tag-all'.

* test/emacs

  - Subtest "notmuch-show: change tags of open messages in current buffer"
    is no longer broken...
---
 emacs/notmuch-show.el |   33 ++++++++++++++++++++++++---------
 test/emacs            |    1 -
 2 files changed, 24 insertions(+), 10 deletions(-)

diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
index 05606fc..4bd1a7c 100644
--- a/emacs/notmuch-show.el
+++ b/emacs/notmuch-show.el
@@ -1339,14 +1339,18 @@ (defun notmuch-show-get-message-id ()
   "Return the message id of the current message."
   (concat "id:\"" (notmuch-show-get-prop :id) "\""))
 
-(defun notmuch-show-get-messages-ids (&optional separator)
+(defun notmuch-show-get-messages-ids (&optional separator predicate)
   "Return a list of Message-Id's of all messages in the current buffer.
 
 If provided with optional argument SEPARATOR, return a string
-instead, consisting of all Message-Id's separated by SEPARATOR."
+instead, consisting of all Message-Id's separated by SEPARATOR.
+
+If provided with optional argument PREDICATE, only return
+Message-Id's of messages for which PREDICATE returns non-nil."
   (let ((message-ids))
     (notmuch-show-mapc
-     (lambda () (push (notmuch-show-get-message-id) message-ids)))
+     (lambda () (push (notmuch-show-get-message-id) message-ids))
+     predicate)
     (if separator
 	(mapconcat 'identity message-ids separator)
       message-ids)))
@@ -1633,18 +1637,29 @@ (defun notmuch-show-tag (&optional initial-input)
 		      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.
+(defun notmuch-show-tag-all (only-open &rest tag-changes)
+  "Change tags of all messages in the current buffer.
+
+If ONLY-OPEN is non-nil, only change tags of *open* messages in
+the current buffer.
 
 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 " or ") tag-changes)
+  (interactive (cons current-prefix-arg
+		     (notmuch-read-tag-changes nil notmuch-show-thread-id)))
+  (apply 'notmuch-tag
+	 (notmuch-show-get-messages-ids
+	  " or "
+	  `(lambda ()
+	     ,(if only-open '(notmuch-show-message-visible-p) t)))
+	 tag-changes)
   (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))))))
+	 (notmuch-show-set-tags new-tags))))
+   `(lambda ()
+      ,(if only-open '(notmuch-show-message-visible-p) t))))
 
 (defun notmuch-show-add-tag ()
   "Same as `notmuch-show-tag' but sets initial input to '+'."
@@ -1724,7 +1739,7 @@ (defun notmuch-show-archive-thread (&optional unarchive)
 buffer."
   (interactive "P")
   (let ((op (if unarchive "+" "-")))
-    (notmuch-show-tag-all (concat op "inbox"))))
+    (notmuch-show-tag-all nil (concat op "inbox"))))
 
 (defun notmuch-show-archive-thread-then-next ()
   "Archive each message in thread, then show next thread from search."
diff --git a/test/emacs b/test/emacs
index 9088ced..e6b0503 100755
--- a/test/emacs
+++ b/test/emacs
@@ -152,7 +152,6 @@ notmuch tag +"$del_tag" -"$add_tag" -- "$query" # revert tag changes
 test_expect_equal "$count_changed" "$count_total" # assert that CHANGED == TOTAL
 
 test_begin_subtest "notmuch-show: change tags of open messages in current buffer"
-test_subtest_known_broken
 query="$os_x_darwin_thread"
 filter="from:Jiang"
 add_tag="notmuch-show-tag-all"
-- 
1.7.8.1

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* Re: [PATCH 1/6] test: emacs: new tests "notmuch-show: {add, remove} multiple tags {to, from} single message"
  2012-02-24 10:35         ` Dmitry Kurochkin
@ 2012-02-24 22:33           ` Pieter Praet
  0 siblings, 0 replies; 136+ messages in thread
From: Pieter Praet @ 2012-02-24 22:33 UTC (permalink / raw)
  To: Dmitry Kurochkin, David Bremner; +Cc: Notmuch Mail

On Fri, 24 Feb 2012 14:35:22 +0400, Dmitry Kurochkin <dmitry.kurochkin@gmail.com> wrote:
> On Fri, 24 Feb 2012 00:09:09 +0100, Pieter Praet <pieter@praet.org> wrote:
> > * test/emacs:
> > 
> >   - Rename subtests "{Add,Remove} tag from notmuch-show view" to
> >     "notmuch-show: {add,remove} single tag {to,from} single message"
> >     to be consistent with the following tests.
> > 
> >   - New subtest "notmuch-show: add multiple tags to single message":
> >     `notmuch-show-add-tag' ("+") can add multiple tags to a message.
> > 
> >   - New subtest "notmuch-show: remove multiple tags from single message":
> >     `notmuch-show-remove-tag' ("-") can remove multiple tags from a message.
> > ---
> 
> Would be nice to have another patch that moves notmuch-show tests to
> emacs-show file.
>

TL;DR: It's on my todo list.

Yeah, the Emacs test series *as a whole* desperately needs some
reorganizing, not in the least because it's still severely
lacking in coverage.

Some more structure/consistency would considerably increase the
feasibility (or at least reduce the PITAness...)  of filling in
the numerous blanks and reducing duplication of effort (regarding
both hard- and wetware based cycles), as well as increasing the
likelihood that developers (not looking in any specific direction)
serve their code with a side dish of tests.

Ideally (IMHO), it would be split up into separate files by mode,
i.e. `notmuch-hello', `notmuch-search', `notmuch-show',
`notmuch-{message,mua}', and those can be further divided into
sections like navigation, tagging, visibility stuff, hooks, ...

There's probably quite a number of implicit interdependencies that
need to be taken care of though, and I (as well as others) still
have a bunch of tests waiting to be applied, so we might want to do
this gradually.


> Regards,
>   Dmitry
> 
> >  test/emacs |   16 ++++++++++++++--
> >  1 files changed, 14 insertions(+), 2 deletions(-)
> > 
> > diff --git a/test/emacs b/test/emacs
> > index b74cfa9..ec1dbb0 100755
> > --- a/test/emacs
> > +++ b/test/emacs
> > @@ -112,18 +112,30 @@ test_emacs "(notmuch-search \"$os_x_darwin_thread\")
> >  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_begin_subtest "notmuch-show: add single tag to single message"
> >  test_emacs "(notmuch-show \"$os_x_darwin_thread\")
> >  	    (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_begin_subtest "notmuch-show: remove single tag from single message"
> >  test_emacs "(notmuch-show \"$os_x_darwin_thread\")
> >  	    (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)"
> >  
> > +test_begin_subtest "notmuch-show: add multiple tags to single message"
> > +test_emacs "(notmuch-show \"$os_x_darwin_thread\")
> > +	    (execute-kbd-macro \"+tag1-from-show-view +tag2-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 tag1-from-show-view tag2-from-show-view unread)"
> > +
> > +test_begin_subtest "notmuch-show: remove multiple tags from single message"
> > +test_emacs "(notmuch-show \"$os_x_darwin_thread\")
> > +	    (execute-kbd-macro \"-tag1-from-show-view -tag2-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)"
> > +
> >  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\"")
> > -- 
> > 1.7.8.1
> > 


Peace

-- 
Pieter

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH 4/6] emacs: add predicate arg to `notmuch-show-mapc'
  2012-02-24 10:39         ` Dmitry Kurochkin
@ 2012-02-24 22:35           ` Pieter Praet
  0 siblings, 0 replies; 136+ messages in thread
From: Pieter Praet @ 2012-02-24 22:35 UTC (permalink / raw)
  To: Dmitry Kurochkin, David Bremner; +Cc: Notmuch Mail

On Fri, 24 Feb 2012 14:39:41 +0400, Dmitry Kurochkin <dmitry.kurochkin@gmail.com> wrote:
> On Fri, 24 Feb 2012 00:09:12 +0100, Pieter Praet <pieter@praet.org> wrote:
> > * emacs/notmuch-show.el
> > 
> >   (notmuch-show-mapc):
> >     Only call FUNCTION if new argument PREDICATE is satisfied.
> >     Also correct original docstring: 's/thread/buffer/'.
> > 
> >   (notmuch-show-get-messages-ids):
> >     Update wrt changes to `notmuch-show-mapc'.
> > 
> >   (notmuch-show-tag-all):
> >     Update wrt changes to `notmuch-show-mapc'.
> > ---
> >  emacs/notmuch-show.el |   15 ++++++++-------
> >  1 files changed, 8 insertions(+), 7 deletions(-)
> > 
> > diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
> > index aa9ccee..5fc0e43 100644
> > --- a/emacs/notmuch-show.el
> > +++ b/emacs/notmuch-show.el
> > @@ -1272,13 +1272,14 @@ (defun notmuch-show-goto-message-previous ()
> >      (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."
> > +(defun notmuch-show-mapc (predicate function)
> 
> Please make PREDICATE optional to avoid giving t when it is not needed.
>

Done.

> I would expect PREDICATE to be a function, [...]

Well, it *can* be a function actually (see later usage in e.g.
`notmuch-show-get-messages-ids' [1]), but should be provided
as a form instead of as a quoted symbol.

> [...] but perhaps the way you
> implemented it is common in Emacs.
>

Far from it, apparently.  I did it that way to prevent `funcall' from
choking on t/nil, which -in retrospect- was rather shortsighted...

I've used a more sensible approach in v2 [2].

> Regards,
>   Dmitry
> 
> > +  "Iterate through all messages in the current buffer with
> > +`notmuch-show-goto-message-next'.  If PREDICATE is satisfied,
> > +call FUNCTION for side effects."
> >    (save-excursion
> >      (goto-char (point-min))
> > -    (loop do (funcall function)
> > +    (loop do (if (eval predicate)
> > +		 (funcall function))
> >  	  while (notmuch-show-goto-message-next))))
> >  
> >  ;; Functions relating to the visibility of messages and their
> > @@ -1336,7 +1337,7 @@ (defun notmuch-show-get-message-id ()
> >  (defun notmuch-show-get-messages-ids ()
> >    "Return all message ids of messages in the current thread."
> >    (let ((message-ids))
> > -    (notmuch-show-mapc
> > +    (notmuch-show-mapc t
> >       (lambda () (push (notmuch-show-get-message-id) message-ids)))
> >      message-ids))
> >  
> > @@ -1633,7 +1634,7 @@ (defun notmuch-show-tag-all (&rest tag-changes)
> >  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)
> > -  (notmuch-show-mapc
> > +  (notmuch-show-mapc t
> >     (lambda ()
> >       (let* ((current-tags (notmuch-show-get-tags))
> >  	    (new-tags (notmuch-update-tags current-tags tag-changes)))
> > -- 
> > 1.7.8.1
> > 


Peace

-- 
Pieter

[1] id:"1330038554-10347-6-git-send-email-pieter@praet.org"
[2] id:"1330122640-18895-5-git-send-email-pieter@praet.org"

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH 5/6] emacs: simplify `notmuch-show-get-messages-ids{, -search}'
  2012-02-24 10:42         ` Dmitry Kurochkin
@ 2012-02-24 22:36           ` Pieter Praet
  0 siblings, 0 replies; 136+ messages in thread
From: Pieter Praet @ 2012-02-24 22:36 UTC (permalink / raw)
  To: Dmitry Kurochkin, David Bremner; +Cc: Notmuch Mail

On Fri, 24 Feb 2012 14:42:53 +0400, Dmitry Kurochkin <dmitry.kurochkin@gmail.com> wrote:
> On Fri, 24 Feb 2012 00:09:13 +0100, Pieter Praet <pieter@praet.org> wrote:
> > * emacs/notmuch-show.el
> > 
> >   (notmuch-show-get-messages-ids):
> >     If provided with optional arg SEPARATOR, return a string consisting
> >     of all Message-Id's, separated by SEPARATOR.  Also improve original
> >     docstring wrt default return value.
> > 
> >   (notmuch-show-get-messages-ids-search):
> >     Removed, as its functionality is now in `notmuch-show-get-messages-ids'.
> > 
> >   (notmuch-show-tag-all):
> >     Call `notmuch-show-get-messages-ids' with SEPARATOR arg instead of
> >     `notmuch-show-get-messages-ids-search'.
> > ---
> 
> There is another similar case in notmuch.el:
> `notmuch-show-get-messages-ids' and
> `notmuch-show-get-messages-ids-search'.  There may be more.
> 
> Please change them as well.
>

You mean `notmuch-search-find-thread-id-region{,-search}' ?

They aren't relevant to this series, so I'll submit a separate patch
for that (later).  A quick `rgrep' doesn't reveal any others, but if
you happen to stumble across any, feel free to point them out.

> Regards,
>   Dmitry
> 
> >  emacs/notmuch-show.el |   18 +++++++++---------
> >  1 files changed, 9 insertions(+), 9 deletions(-)
> > 
> > diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
> > index 5fc0e43..4b37c77 100644
> > --- a/emacs/notmuch-show.el
> > +++ b/emacs/notmuch-show.el
> > @@ -1334,17 +1334,17 @@ (defun notmuch-show-get-message-id ()
> >    "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."
> > +(defun notmuch-show-get-messages-ids (&optional separator)
> > +  "Return a list of Message-Id's of all messages in the current buffer.
> > +
> > +If provided with optional argument SEPARATOR, return a string
> > +instead, consisting of all Message-Id's separated by SEPARATOR."
> >    (let ((message-ids))
> >      (notmuch-show-mapc t
> >       (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 "))
> > +    (if separator
> > +	(mapconcat 'identity message-ids separator)
> > +      message-ids)))
> >  
> >  ;; dme: Would it make sense to use a macro for many of these?
> >  
> > @@ -1633,7 +1633,7 @@ (defun notmuch-show-tag-all (&rest tag-changes)
> >  
> >  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)
> > +  (apply 'notmuch-tag (notmuch-show-get-messages-ids " or ") tag-changes)
> >    (notmuch-show-mapc t
> >     (lambda ()
> >       (let* ((current-tags (notmuch-show-get-tags))
> > -- 
> > 1.7.8.1
> > 


Peace

-- 
Pieter

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH 6/6] emacs: `notmuch-show-tag-all' sans prefix arg only tags open messages
  2012-02-24 10:47         ` Dmitry Kurochkin
@ 2012-02-24 22:37           ` Pieter Praet
  0 siblings, 0 replies; 136+ messages in thread
From: Pieter Praet @ 2012-02-24 22:37 UTC (permalink / raw)
  To: Dmitry Kurochkin, David Bremner; +Cc: Notmuch Mail

On Fri, 24 Feb 2012 14:47:30 +0400, Dmitry Kurochkin <dmitry.kurochkin@gmail.com> wrote:
> On Fri, 24 Feb 2012 00:09:14 +0100, Pieter Praet <pieter@praet.org> wrote:
> > * emacs/notmuch-show.el
> > 
> >   (notmuch-show-get-messages-ids):
> >     New optional argument ONLY-OPEN.  If non-nil, only return
> >     Message-Id's for messages which are currently visible.
> > 
> >   (notmuch-show-tag-all):
> >     New optional argument IGNORE-VISIBILITY, of which the inverse is
> >     passed as ONLY-OPEN argument to `notmuch-show-get-messages-ids':
> >     If called with a prefix arg, affect *all* messages in the current
> >     buffer.  Otherwise, only change tags of visible messages.
> > 
> >   (notmuch-show-archive-thread):
> >     Update wrt changes to `notmuch-show-tag-all'.
> > 
> > * test/emacs
> > 
> >   - Subtest "notmuch-show: change tags of open messages in current buffer"
> >     is no longer broken.
> > ---
> >  emacs/notmuch-show.el |   28 ++++++++++++++++++++--------
> >  test/emacs            |    1 -
> >  2 files changed, 20 insertions(+), 9 deletions(-)
> > 
> > diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
> > index 4b37c77..4499fcd 100644
> > --- a/emacs/notmuch-show.el
> > +++ b/emacs/notmuch-show.el
> > @@ -1334,13 +1334,17 @@ (defun notmuch-show-get-message-id ()
> >    "Return the message id of the current message."
> >    (concat "id:\"" (notmuch-show-get-prop :id) "\""))
> >  
> > -(defun notmuch-show-get-messages-ids (&optional separator)
> > +(defun notmuch-show-get-messages-ids (&optional only-open separator)
> >    "Return a list of Message-Id's of all messages in the current buffer.
> >  
> > +If optional argument ONLY-OPEN is non-nil, only return
> > +Message-Id's for messages which are currently visible.
> > +
> >  If provided with optional argument SEPARATOR, return a string
> >  instead, consisting of all Message-Id's separated by SEPARATOR."
> >    (let ((message-ids))
> > -    (notmuch-show-mapc t
> > +    (notmuch-show-mapc
> > +     `(if only-open (notmuch-show-message-visible-p) t)
> 
> How about changing ONLY-OPEN to a general optional PREDICATE argument
> and pass it as is to `notmuch-show-mapc'?  Please make it the last
> argument.
>

Done.


> Regards,
>   Dmitry
> 
> >       (lambda () (push (notmuch-show-get-message-id) message-ids)))
> >      (if separator
> >  	(mapconcat 'identity message-ids separator)
> > @@ -1628,13 +1632,21 @@ (defun notmuch-show-tag (&optional initial-input)
> >  		      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.
> > +(defun notmuch-show-tag-all (&optional ignore-visibility &rest tag-changes)
> > +  "Change tags of all open messages in the current buffer.
> > +
> > +If optional arg IGNORE-VISIBILITY is non-nil, change tags of
> > +*all* messages in the current buffer, independent of their
> > +visibility.
> >  
> >  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 " or ") tag-changes)
> > -  (notmuch-show-mapc t
> > +  (interactive (cons current-prefix-arg
> > +		     (notmuch-read-tag-changes nil notmuch-show-thread-id)))
> > +  (apply 'notmuch-tag
> > +	 (notmuch-show-get-messages-ids (not ignore-visibility) " or ")
> > +	 tag-changes)
> > +  (notmuch-show-mapc
> > +   `(if ignore-visibility t (notmuch-show-message-visible-p))
> >     (lambda ()
> >       (let* ((current-tags (notmuch-show-get-tags))
> >  	    (new-tags (notmuch-update-tags current-tags tag-changes)))
> > @@ -1719,7 +1731,7 @@ (defun notmuch-show-archive-thread (&optional unarchive)
> >  buffer."
> >    (interactive "P")
> >    (let ((op (if unarchive "+" "-")))
> > -    (notmuch-show-tag-all (concat op "inbox"))))
> > +    (notmuch-show-tag-all t (concat op "inbox"))))
> >  
> >  (defun notmuch-show-archive-thread-then-next ()
> >    "Archive each message in thread, then show next thread from search."
> > diff --git a/test/emacs b/test/emacs
> > index 644ef59..c286ff5 100755
> > --- a/test/emacs
> > +++ b/test/emacs
> > @@ -152,7 +152,6 @@ notmuch tag +"$del_tag" -"$add_tag" -- "$query" # revert tag changes
> >  test_expect_equal "$count_changed" "$count_total" # assert that CHANGED == TOTAL
> >  
> >  test_begin_subtest "notmuch-show: change tags of open messages in current buffer"
> > -test_subtest_known_broken
> >  query="$os_x_darwin_thread"
> >  filter="from:Jiang"
> >  add_tag="notmuch-show-tag-all"
> > -- 
> > 1.7.8.1
> > 


Peace

-- 
Pieter

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v5 00/12] emacs: more flexible and consistent tagging operations
  2012-02-24 10:30       ` [PATCH v5 00/12] emacs: more flexible and consistent tagging operations Dmitry Kurochkin
  2012-02-24 10:33         ` Dmitry Kurochkin
@ 2012-02-24 22:38         ` Pieter Praet
  2012-02-25  0:05           ` Pieter Praet
  1 sibling, 1 reply; 136+ messages in thread
From: Pieter Praet @ 2012-02-24 22:38 UTC (permalink / raw)
  To: Dmitry Kurochkin, David Bremner, notmuch

On Fri, 24 Feb 2012 14:30:29 +0400, Dmitry Kurochkin <dmitry.kurochkin@gmail.com> wrote:
> On Fri, 24 Feb 2012 00:07:27 +0100, Pieter Praet <pieter@praet.org> wrote:
> > On Wed, 08 Feb 2012 11:58:32 -0400, David Bremner <david@tethera.net> wrote:
> > > On Sun,  5 Feb 2012 11:13:41 +0400, Dmitry Kurochkin <dmitry.kurochkin@gmail.com> wrote:
> > > > Changes:
> > > > 
> > > > v4:
> > > > 
> > > > * rebased on master, no conflicts so no need for another review
> > > > 
> > > 
> > > I pushed this series.  
> > > 
> > > Maybe this was discussed already, but I think ideally * would apply only
> > > to open messages. So consider that a feature request if someone is
> > > looking for a project.
> > >
> > 
> > How about if '*' applies to all messages (as it currently does),
> > but 'C-u *' only to open messages?  That would make more sense IMHO.
> > 
> > But, conforming to your original request, I've implemented the inverse.
> > 
> 
> I personally do like '*' as is and do not want to change it's behavior.
> Though I am not against adding a prefix argument for it.
>

Same here.  In v2 [1], '*' tags all and 'C-u *' tags only open.

One can always swap the keybindings if so inclined.


> Regards,
>   Dmitry
> 
> > Patches follow.
> > 
> > 
> > > d
> > > _______________________________________________
> > > 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


Peace

-- 
Pieter

[1] id:"1330122640-18895-1-git-send-email-pieter@praet.org"

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v5 00/12] emacs: more flexible and consistent tagging operations
  2012-02-24 10:33         ` Dmitry Kurochkin
  2012-02-24 17:39           ` Jani Nikula
@ 2012-02-24 22:40           ` Pieter Praet
  1 sibling, 0 replies; 136+ messages in thread
From: Pieter Praet @ 2012-02-24 22:40 UTC (permalink / raw)
  To: Dmitry Kurochkin, David Bremner, notmuch

On Fri, 24 Feb 2012 14:33:35 +0400, Dmitry Kurochkin <dmitry.kurochkin@gmail.com> wrote:
> On Fri, 24 Feb 2012 14:30:29 +0400, Dmitry Kurochkin <dmitry.kurochkin@gmail.com> wrote:
> > On Fri, 24 Feb 2012 00:07:27 +0100, Pieter Praet <pieter@praet.org> wrote:
> > > On Wed, 08 Feb 2012 11:58:32 -0400, David Bremner <david@tethera.net> wrote:
> > > > On Sun,  5 Feb 2012 11:13:41 +0400, Dmitry Kurochkin <dmitry.kurochkin@gmail.com> wrote:
> > > > > Changes:
> > > > > 
> > > > > v4:
> > > > > 
> > > > > * rebased on master, no conflicts so no need for another review
> > > > > 
> > > > 
> > > > I pushed this series.  
> > > > 
> > > > Maybe this was discussed already, but I think ideally * would apply only
> > > > to open messages. So consider that a feature request if someone is
> > > > looking for a project.
> > > >
> > > 
> > > How about if '*' applies to all messages (as it currently does),
> > > but 'C-u *' only to open messages?  That would make more sense IMHO.
> > > 
> > > But, conforming to your original request, I've implemented the inverse.
> > > 
> > 
> > I personally do like '*' as is and do not want to change it's behavior.
> > Though I am not against adding a prefix argument for it.
> > 
> 
> Also can you please send new patches (and patch series) in a new
> separate thread?  If they are related to another thread, you can add a
> reference.  But having multiple patch series with multiple versions in a
> single thread is very confusing IMO.
>

Since I've already soiled this thread with my initial series,
I've sent v2 [1] in reply to David's request as well, but will
make sure to start a fresh thread from now on.


> Regards,
>   Dmitry
> 
> > Regards,
> >   Dmitry
> > 
> > > Patches follow.
> > > 
> > > 
> > > > d
> > > > _______________________________________________
> > > > notmuch mailing list
> > > > notmuch@notmuchmail.org
> > > > http://notmuchmail.org/mailman/listinfo/notmuch
> > > 
> > > 
> > > Peace
> > > 
> > > -- 
> > > Pieter

Thanks for all your comments!


Peace

-- 
Pieter

[1] id:"1330122640-18895-1-git-send-email-pieter@praet.org"

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v5 00/12] emacs: more flexible and consistent tagging operations
  2012-02-24 22:38         ` Pieter Praet
@ 2012-02-25  0:05           ` Pieter Praet
  0 siblings, 0 replies; 136+ messages in thread
From: Pieter Praet @ 2012-02-25  0:05 UTC (permalink / raw)
  To: Dmitry Kurochkin, David Bremner, notmuch

On Fri, 24 Feb 2012 23:38:20 +0100, Pieter Praet <pieter@praet.org> wrote:
> [...]
> Same here.  In v2 [1], '*' tags all and 'C-u *' tags only open.
> 
> One can always swap the keybindings if so inclined.
>

Did I really say that?

There's only a single keybinding, so swap it with *what* ?!?  Itself ?

This should work though:

  #+begin_src emacs-lisp
    (define-key notmuch-show-mode-map "*"
      (lambda (prefix &rest tag-changes)
        (interactive
         (cons
          (not current-prefix-arg)
          (notmuch-read-tag-changes nil notmuch-show-thread-id)))
        (apply 'notmuch-show-tag-all prefix tag-changes)))
  #+end_src

> [...]


Peace

-- 
Pieter

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v5 00/12] emacs: more flexible and consistent tagging operations
  2012-02-23 23:07     ` Pieter Praet
                         ` (6 preceding siblings ...)
  2012-02-24 10:30       ` [PATCH v5 00/12] emacs: more flexible and consistent tagging operations Dmitry Kurochkin
@ 2012-02-25 16:20       ` David Bremner
  2012-02-27 14:50         ` Tomi Ollila
  7 siblings, 1 reply; 136+ messages in thread
From: David Bremner @ 2012-02-25 16:20 UTC (permalink / raw)
  To: Pieter Praet, Dmitry Kurochkin, notmuch

On Fri, 24 Feb 2012 00:07:27 +0100, Pieter Praet <pieter@praet.org> wrote:
> On Wed, 08 Feb 2012 11:58:32 -0400, David Bremner <david@tethera.net> wrote:
> > On Sun,  5 Feb 2012 11:13:41 +0400, Dmitry Kurochkin <dmitry.kurochkin@gmail.com> wrote:
> 
> How about if '*' applies to all messages (as it currently does),
> but 'C-u *' only to open messages?  That would make more sense IMHO.
> 
> But, conforming to your original request, I've implemented the inverse.
> 

Thanks for implementing that. I could live with either way. Do other
people have opinions on this? My reasoning is if you descend into a
thread from some search page, it seems likely that you want to operate
on the messages matching the search.

d

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v5 00/12] emacs: more flexible and consistent tagging operations
  2012-02-25 16:20       ` David Bremner
@ 2012-02-27 14:50         ` Tomi Ollila
  2012-02-28 19:34           ` Pieter Praet
  0 siblings, 1 reply; 136+ messages in thread
From: Tomi Ollila @ 2012-02-27 14:50 UTC (permalink / raw)
  To: David Bremner, Pieter Praet, Dmitry Kurochkin, notmuch

On Sat, 25 Feb 2012 12:20:31 -0400, David Bremner <david@tethera.net> wrote:
> On Fri, 24 Feb 2012 00:07:27 +0100, Pieter Praet <pieter@praet.org> wrote:
> > On Wed, 08 Feb 2012 11:58:32 -0400, David Bremner <david@tethera.net> wrote:
> > > On Sun,  5 Feb 2012 11:13:41 +0400, Dmitry Kurochkin <dmitry.kurochkin@gmail.com> wrote:
> > 
> > How about if '*' applies to all messages (as it currently does),
> > but 'C-u *' only to open messages?  That would make more sense IMHO.
> > 
> > But, conforming to your original request, I've implemented the inverse.
> > 
> 
> Thanks for implementing that. I could live with either way. Do other
> people have opinions on this? My reasoning is if you descend into a
> thread from some search page, it seems likely that you want to operate
> on the messages matching the search.

I've pretty soon lost the original open/close status as I often navigate
through messages by opening/closing messages, so for me not operating
on all messages in thread is magic behaviour. In case I'd use C-u *
I first have to check through the full thread what are the actual
messages currently open (lots of screen scrolling :( )

So, I prefer '*' operating on all messages in a thread and C-u '*'
for all open messages in a thread.

> 
> d

Tomi

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v5 00/12] emacs: more flexible and consistent tagging operations
  2012-02-27 14:50         ` Tomi Ollila
@ 2012-02-28 19:34           ` Pieter Praet
  0 siblings, 0 replies; 136+ messages in thread
From: Pieter Praet @ 2012-02-28 19:34 UTC (permalink / raw)
  To: Tomi Ollila, David Bremner, Dmitry Kurochkin, notmuch

On Mon, 27 Feb 2012 16:50:53 +0200, Tomi Ollila <tomi.ollila@iki.fi> wrote:
> On Sat, 25 Feb 2012 12:20:31 -0400, David Bremner <david@tethera.net> wrote:
> > On Fri, 24 Feb 2012 00:07:27 +0100, Pieter Praet <pieter@praet.org> wrote:
> > > On Wed, 08 Feb 2012 11:58:32 -0400, David Bremner <david@tethera.net> wrote:
> > > > On Sun,  5 Feb 2012 11:13:41 +0400, Dmitry Kurochkin <dmitry.kurochkin@gmail.com> wrote:
> > > 
> > > How about if '*' applies to all messages (as it currently does),
> > > but 'C-u *' only to open messages?  That would make more sense IMHO.
> > > 
> > > But, conforming to your original request, I've implemented the inverse.
> > > 
> > 
> > Thanks for implementing that. I could live with either way. Do other
> > people have opinions on this? My reasoning is if you descend into a
> > thread from some search page, it seems likely that you want to operate
> > on the messages matching the search.
> 
> I've pretty soon lost the original open/close status as I often navigate
> through messages by opening/closing messages, so for me not operating
> on all messages in thread is magic behaviour. In case I'd use C-u *
> I first have to check through the full thread what are the actual
> messages currently open (lots of screen scrolling :( )
>

I share your sentiment.  Also, the function is called `notmuch-show-tag-all',
so having it operate only on open messages would be counterintuitive IMO.

In other words, I think of the prefix arg as being a modifier for the
meaning of 'all'.

But either way, it's fairly trivial to invert its behavior [1].

> So, I prefer '*' operating on all messages in a thread and C-u '*'
> for all open messages in a thread.
> 
> > 
> > d
> 
> Tomi


Peace

-- 
Pieter

[1] id:"87sjhz22vw.fsf@praet.org"

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v2 1/6] test: emacs: new tests "notmuch-show: {add, remove} multiple tags {to, from} single message"
  2012-02-24 22:30       ` [PATCH v2 1/6] test: emacs: new tests "notmuch-show: {add, remove} multiple tags {to, from} single message" Pieter Praet
@ 2012-03-21  1:06         ` Mark Walters
  2012-12-10  2:48         ` David Bremner
  2012-12-11 14:04         ` David Bremner
  2 siblings, 0 replies; 136+ messages in thread
From: Mark Walters @ 2012-03-21  1:06 UTC (permalink / raw)
  To: Pieter Praet, David Bremner, Dmitry Kurochkin; +Cc: Notmuch Mail


Hi

> * test/emacs:
> 
>   - Rename subtests "{Add,Remove} tag from notmuch-show view" to
>     "notmuch-show: {add,remove} single tag {to,from} single message"
>     to be consistent with the following tests.
> 
>   - New subtest "notmuch-show: add multiple tags to single message":
>     `notmuch-show-add-tag' ("+") can add multiple tags to a message.
> 
>   - New subtest "notmuch-show: remove multiple tags from single message":
>     `notmuch-show-remove-tag' ("-") can remove multiple tags from a message.
> ---
>  test/emacs |   16 ++++++++++++++--
>  1 files changed, 14 insertions(+), 2 deletions(-)
> 
> diff --git a/test/emacs b/test/emacs
> index b74cfa9..ec1dbb0 100755
> --- a/test/emacs
> +++ b/test/emacs
> @@ -112,18 +112,30 @@ test_emacs "(notmuch-search \"$os_x_darwin_thread\")
>  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_begin_subtest "notmuch-show: add single tag to single message"
>  test_emacs "(notmuch-show \"$os_x_darwin_thread\")
>  	    (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_begin_subtest "notmuch-show: remove single tag from single message"
>  test_emacs "(notmuch-show \"$os_x_darwin_thread\")
>  	    (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)"
>  
> +test_begin_subtest "notmuch-show: add multiple tags to single message"
> +test_emacs "(notmuch-show \"$os_x_darwin_thread\")
> +	    (execute-kbd-macro \"+tag1-from-show-view +tag2-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 tag1-from-show-view tag2-from-show-view unread)"
> +
> +test_begin_subtest "notmuch-show: remove multiple tags from single message"
> +test_emacs "(notmuch-show \"$os_x_darwin_thread\")
> +	    (execute-kbd-macro \"-tag1-from-show-view -tag2-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)"
> +
>  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\"")


This looks good to me but I think it would be nice to have an extra test
for adding a tag and removing a tag simultaneously.

Best wishes 

Mark

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v2 4/6] emacs: add optional predicate arg to `notmuch-show-mapc'
  2012-02-24 22:30       ` [PATCH v2 4/6] emacs: add optional predicate arg to `notmuch-show-mapc' Pieter Praet
@ 2012-03-21  1:33         ` Mark Walters
  2012-10-16  2:59           ` Ethan Glasser-Camp
  2012-10-16  2:18         ` Ethan Glasser-Camp
  1 sibling, 1 reply; 136+ messages in thread
From: Mark Walters @ 2012-03-21  1:33 UTC (permalink / raw)
  To: Pieter Praet, David Bremner, Dmitry Kurochkin; +Cc: Notmuch Mail

On Fri, 24 Feb 2012 23:30:38 +0100, Pieter Praet <pieter@praet.org> wrote:
> * emacs/notmuch-show.el (notmuch-show-mapc):
> 
>   If provided with optional argument PREDICATE, only call
>   FUNCTION if calling PREDICATE returns non-nil.
> 
>   Also correct original docstring: 's/thread/buffer/'.
> ---
>  emacs/notmuch-show.el |   14 ++++++++++----
>  1 files changed, 10 insertions(+), 4 deletions(-)
> 
> diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
> index aa9ccee..6adbdc0 100644
> --- a/emacs/notmuch-show.el
> +++ b/emacs/notmuch-show.el
> @@ -1272,13 +1272,19 @@ (defun notmuch-show-goto-message-previous ()
>      (notmuch-show-move-to-message-top)
>      t))
>  
> -(defun notmuch-show-mapc (function)
> -  "Iterate through all messages in the current thread with
> +(defun notmuch-show-mapc (function &optional predicate)
> +  "Iterate through all messages in the current buffer with
>  `notmuch-show-goto-message-next' and call FUNCTION for side
> -effects."
> +effects.
> +
> +If provided with optional argument PREDICATE, only call
> +FUNCTION if calling PREDICATE returns non-nil."
>    (save-excursion
>      (goto-char (point-min))
> -    (loop do (funcall function)
> +    (loop do (if predicate
> +		 (if (funcall predicate)
> +		     (funcall function))
> +	       (funcall function))
>  	  while (notmuch-show-goto-message-next))))
>  
>  ;; Functions relating to the visibility of messages and their

The change looks fine.

The original function feels a little fragile to me as to what happens if
predicate or function move point. Eg what happens if function collapses
the message: where does point go, and so where does
notmuch-show-goto-message-next go. Is this just my naivete as a lisp
beginner? Is there someway of writing it so the user doesn't need to
worry about such things?

Best wishes

Mark

(sorry for the duplicate mail: I sent the first message from the wrong address)

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v2 5/6] emacs: simplify `notmuch-show-get-messages-ids{, -search}'
  2012-02-24 22:30       ` [PATCH v2 5/6] emacs: simplify `notmuch-show-get-messages-ids{, -search}' Pieter Praet
@ 2012-03-21  1:36         ` Mark Walters
  2012-10-16  3:12           ` Ethan Glasser-Camp
  2012-03-21  1:40         ` Mark Walters
  1 sibling, 1 reply; 136+ messages in thread
From: Mark Walters @ 2012-03-21  1:36 UTC (permalink / raw)
  To: Pieter Praet, David Bremner, Dmitry Kurochkin; +Cc: Notmuch Mail

On Fri, 24 Feb 2012 23:30:39 +0100, Pieter Praet <pieter@praet.org> wrote:
> * emacs/notmuch-show.el
> 
>   (notmuch-show-get-messages-ids):
>     If provided with optional arg SEPARATOR, return a string consisting
>     of all Message-Id's, separated by SEPARATOR.  Also improve original
>     docstring wrt default return value.
> 
>   (notmuch-show-get-messages-ids-search):
>     Removed, as its functionality is now in `notmuch-show-get-messages-ids'.
> 
>   (notmuch-show-tag-all):
>     Call `notmuch-show-get-messages-ids' with SEPARATOR arg instead of
>     `notmuch-show-get-messages-ids-search'.
> ---
>  emacs/notmuch-show.el |   18 +++++++++---------
>  1 files changed, 9 insertions(+), 9 deletions(-)
> 
> diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
> index 6adbdc0..05606fc 100644
> --- a/emacs/notmuch-show.el
> +++ b/emacs/notmuch-show.el
> @@ -1339,17 +1339,17 @@ (defun notmuch-show-get-message-id ()
>    "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."
> +(defun notmuch-show-get-messages-ids (&optional separator)
> +  "Return a list of Message-Id's of all messages in the current buffer.
> +
> +If provided with optional argument SEPARATOR, return a string
> +instead, consisting of all Message-Id's separated by SEPARATOR."
>    (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 "))
> +    (if separator
> +	(mapconcat 'identity message-ids separator)
> +      message-ids)))
>  
>  ;; dme: Would it make sense to use a macro for many of these?
>  
> @@ -1638,7 +1638,7 @@ (defun notmuch-show-tag-all (&rest tag-changes)
>  
>  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)
> +  (apply 'notmuch-tag (notmuch-show-get-messages-ids " or ") tag-changes)
>    (notmuch-show-mapc
>     (lambda ()
>       (let* ((current-tags (notmuch-show-get-tags))

I like the use of separator rather than hard-wiring " or ". My personal
preference would be to make that change but keep the two functions
separate (my "C"ness makes me like functions that have clear return
types!) But I am happy with the change too.

Best wishes

Mark

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v2 5/6] emacs: simplify `notmuch-show-get-messages-ids{, -search}'
  2012-02-24 22:30       ` [PATCH v2 5/6] emacs: simplify `notmuch-show-get-messages-ids{, -search}' Pieter Praet
  2012-03-21  1:36         ` Mark Walters
@ 2012-03-21  1:40         ` Mark Walters
  1 sibling, 0 replies; 136+ messages in thread
From: Mark Walters @ 2012-03-21  1:40 UTC (permalink / raw)
  To: Pieter Praet, David Bremner, Dmitry Kurochkin; +Cc: Notmuch Mail

On Fri, 24 Feb 2012 23:30:39 +0100, Pieter Praet <pieter@praet.org> wrote:
> * emacs/notmuch-show.el
> 
>   (notmuch-show-get-messages-ids):
>     If provided with optional arg SEPARATOR, return a string consisting
>     of all Message-Id's, separated by SEPARATOR.  Also improve original
>     docstring wrt default return value.
> 
>   (notmuch-show-get-messages-ids-search):
>     Removed, as its functionality is now in `notmuch-show-get-messages-ids'.
> 
>   (notmuch-show-tag-all):
>     Call `notmuch-show-get-messages-ids' with SEPARATOR arg instead of
>     `notmuch-show-get-messages-ids-search'.
> ---
>  emacs/notmuch-show.el |   18 +++++++++---------
>  1 files changed, 9 insertions(+), 9 deletions(-)
> 
> diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
> index 6adbdc0..05606fc 100644
> --- a/emacs/notmuch-show.el
> +++ b/emacs/notmuch-show.el
> @@ -1339,17 +1339,17 @@ (defun notmuch-show-get-message-id ()
>    "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."
> +(defun notmuch-show-get-messages-ids (&optional separator)
> +  "Return a list of Message-Id's of all messages in the current buffer.
> +
> +If provided with optional argument SEPARATOR, return a string
> +instead, consisting of all Message-Id's separated by SEPARATOR."
>    (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 "))
> +    (if separator
> +	(mapconcat 'identity message-ids separator)
> +      message-ids)))
>  
>  ;; dme: Would it make sense to use a macro for many of these?
>  
> @@ -1638,7 +1638,7 @@ (defun notmuch-show-tag-all (&rest tag-changes)
>  
>  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)
> +  (apply 'notmuch-tag (notmuch-show-get-messages-ids " or ") tag-changes)
>    (notmuch-show-mapc
>     (lambda ()
>       (let* ((current-tags (notmuch-show-get-tags))

Oh and I forgot to add that this patch doesn't seem to apply anymore.

MW

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v2 2/6] test: emacs: new test "notmuch-show: change tags of all messages in current buffer"
  2012-02-24 22:30       ` [PATCH v2 2/6] test: emacs: new test "notmuch-show: change tags of all messages in current buffer" Pieter Praet
@ 2012-10-16  2:15         ` Ethan Glasser-Camp
  0 siblings, 0 replies; 136+ messages in thread
From: Ethan Glasser-Camp @ 2012-10-16  2:15 UTC (permalink / raw)
  To: Pieter Praet, David Bremner, Dmitry Kurochkin; +Cc: Notmuch Mail

Pieter Praet <pieter@praet.org> writes:

> * test/emacs:
>
>   New subtest "notmuch-show: change tags of all messages in current buffer":
>   `notmuch-show-tag-all' ("*") changes tags of *all* messages in current buffer.
> ---
>  test/emacs |   15 +++++++++++++++
>  1 files changed, 15 insertions(+), 0 deletions(-)
>
> diff --git a/test/emacs b/test/emacs
> index ec1dbb0..d2dbafc 100755
> --- a/test/emacs
> +++ b/test/emacs
> @@ -136,6 +136,21 @@ test_emacs "(notmuch-show \"$os_x_darwin_thread\")
>  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 "notmuch-show: change tags of all messages in current buffer"
> +query="$os_x_darwin_thread"
> +filter="from:Jiang"
> +add_tag="notmuch-show-tag-all"
> +del_tag="inbox"
> +count_total=$(notmuch count -- "$query")               # = 4
> +count_match=$(notmuch count -- "$query" AND "$filter") # = 2

In this test, what use is count_match? Just so that the tests' forms
are the same? Maybe you want to put an assertion that count_total !=
count_match, just for sanity's sake?

Otherwise, patches 1-3 look fine to me.

Ethan

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v2 4/6] emacs: add optional predicate arg to `notmuch-show-mapc'
  2012-02-24 22:30       ` [PATCH v2 4/6] emacs: add optional predicate arg to `notmuch-show-mapc' Pieter Praet
  2012-03-21  1:33         ` Mark Walters
@ 2012-10-16  2:18         ` Ethan Glasser-Camp
  1 sibling, 0 replies; 136+ messages in thread
From: Ethan Glasser-Camp @ 2012-10-16  2:18 UTC (permalink / raw)
  To: Pieter Praet, David Bremner, Dmitry Kurochkin; +Cc: Notmuch Mail

Pieter Praet <pieter@praet.org> writes:

> * emacs/notmuch-show.el (notmuch-show-mapc):
>
>   If provided with optional argument PREDICATE, only call
>   FUNCTION if calling PREDICATE returns non-nil.
>
>   Also correct original docstring: 's/thread/buffer/'.
> ---

This patch was marked stale, but isn't.

> -(defun notmuch-show-mapc (function)
> -  "Iterate through all messages in the current thread with
> +(defun notmuch-show-mapc (function &optional predicate)
> +  "Iterate through all messages in the current buffer with
>  `notmuch-show-goto-message-next' and call FUNCTION for side
> -effects."
> +effects.
> +
> +If provided with optional argument PREDICATE, only call
> +FUNCTION if calling PREDICATE returns non-nil."
>    (save-excursion
>      (goto-char (point-min))
> -    (loop do (funcall function)
> +    (loop do (if predicate
> +		 (if (funcall predicate)
> +		     (funcall function))
> +	       (funcall function))

I don't like the way this if-structure looks, since I have to squint to
see whether the "else" clause matches the inner or the outer "if". Maybe
change the inner "if" to a "when" or an "and"?

Ethan

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v2 4/6] emacs: add optional predicate arg to `notmuch-show-mapc'
  2012-03-21  1:33         ` Mark Walters
@ 2012-10-16  2:59           ` Ethan Glasser-Camp
  0 siblings, 0 replies; 136+ messages in thread
From: Ethan Glasser-Camp @ 2012-10-16  2:59 UTC (permalink / raw)
  To: Mark Walters, Pieter Praet, David Bremner, Dmitry Kurochkin; +Cc: Notmuch Mail

Mark Walters <markwalters1009@gmail.com> writes:

> The original function feels a little fragile to me as to what happens if
> predicate or function move point. Eg what happens if function collapses
> the message: where does point go, and so where does
> notmuch-show-goto-message-next go. Is this just my naivete as a lisp
> beginner? Is there someway of writing it so the user doesn't need to
> worry about such things?

Although collapsing the message doesn't seem to move point, it would
probably be a good idea to wrap the calls to predicate and function in
save-excursion, as a guard against subtle and hard-to-spot bugs with
operations not being applied to all the right messages..

Ethan

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v2 5/6] emacs: simplify `notmuch-show-get-messages-ids{, -search}'
  2012-03-21  1:36         ` Mark Walters
@ 2012-10-16  3:12           ` Ethan Glasser-Camp
  0 siblings, 0 replies; 136+ messages in thread
From: Ethan Glasser-Camp @ 2012-10-16  3:12 UTC (permalink / raw)
  To: Mark Walters, Pieter Praet, David Bremner, Dmitry Kurochkin; +Cc: Notmuch Mail

Mark Walters <markwalters1009@gmail.com> writes:

> I like the use of separator rather than hard-wiring " or ". My personal
> preference would be to make that change but keep the two functions
> separate (my "C"ness makes me like functions that have clear return
> types!) But I am happy with the change too.

I agree with this comment. Especially in dynamic languages, it's a good
idea for each function to have only one return type.

Also, it seems that the commit message has a TAB character in it (",<TAB>-search").

Ethan

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v2 6/6] emacs: `notmuch-show-tag-all' with prefix arg only tags open messages
  2012-02-24 22:30       ` [PATCH v2 6/6] emacs: `notmuch-show-tag-all' with prefix arg only tags open messages Pieter Praet
@ 2012-10-16  3:39         ` Ethan Glasser-Camp
  0 siblings, 0 replies; 136+ messages in thread
From: Ethan Glasser-Camp @ 2012-10-16  3:39 UTC (permalink / raw)
  To: Pieter Praet, David Bremner, Dmitry Kurochkin; +Cc: Notmuch Mail

Pieter Praet <pieter@praet.org> writes:

> * emacs/notmuch-show.el
>
>   (notmuch-show-get-messages-ids):
>     If provided with optional argument PREDICATE, only return
>     Message-Id's of messages for which PREDICATE returns non-nil.
>
>   (notmuch-show-tag-all):
>     New argument ONLY-OPEN (set to `current-prefix-arg' if running
>     interactively): if non-nil, only change tags of *open* messages.
>     Also correct original docstring: 's/thread/buffer/'.
>
>   (notmuch-show-archive-thread):
>     Update wrt changes to `notmuch-show-tag-all'.
>
> * test/emacs
>
>   - Subtest "notmuch-show: change tags of open messages in current buffer"
>     is no longer broken...

This patch is stale, but in case it helps..

> ---
>  emacs/notmuch-show.el |   33 ++++++++++++++++++++++++---------
>  test/emacs            |    1 -
>  2 files changed, 24 insertions(+), 10 deletions(-)
>
> diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
> index 05606fc..4bd1a7c 100644
> --- a/emacs/notmuch-show.el
> +++ b/emacs/notmuch-show.el
> @@ -1339,14 +1339,18 @@ (defun notmuch-show-get-message-id ()
>    "Return the message id of the current message."
>    (concat "id:\"" (notmuch-show-get-prop :id) "\""))
>  
> -(defun notmuch-show-get-messages-ids (&optional separator)
> +(defun notmuch-show-get-messages-ids (&optional separator predicate)
>    "Return a list of Message-Id's of all messages in the current buffer.
>  
>  If provided with optional argument SEPARATOR, return a string
> -instead, consisting of all Message-Id's separated by SEPARATOR."
> +instead, consisting of all Message-Id's separated by SEPARATOR.
> +
> +If provided with optional argument PREDICATE, only return
> +Message-Id's of messages for which PREDICATE returns non-nil."
>    (let ((message-ids))
>      (notmuch-show-mapc
> -     (lambda () (push (notmuch-show-get-message-id) message-ids)))
> +     (lambda () (push (notmuch-show-get-message-id) message-ids))
> +     predicate)
>      (if separator
>  	(mapconcat 'identity message-ids separator)
>        message-ids)))
> @@ -1633,18 +1637,29 @@ (defun notmuch-show-tag (&optional initial-input)
>  		      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.
> +(defun notmuch-show-tag-all (only-open &rest tag-changes)
> +  "Change tags of all messages in the current buffer.

I'm not crazy about notmuch-show-tag-all having an argument to control
whether or not it tags all. Introduce another function, or perhaps
change this one's name?

I also don't really like that the only-open argument comes before the
tag changes. This means changing every caller (although I guess there's
just one right now). I think tag-changes are more important and should
come first. (tag-changes are &optional instead of &rest in master, so
you can just put only-open after instead of before.)

> +
> +If ONLY-OPEN is non-nil, only change tags of *open* messages in
> +the current buffer.
>  
>  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 " or ") tag-changes)
> +  (interactive (cons current-prefix-arg
> +		     (notmuch-read-tag-changes nil notmuch-show-thread-id)))
> +  (apply 'notmuch-tag
> +	 (notmuch-show-get-messages-ids
> +	  " or "
> +	  `(lambda ()
> +	     ,(if only-open '(notmuch-show-message-visible-p) t)))
> +	 tag-changes)

This is a very awkward use of backquote, to my eyes. Besides, can't
you just replace this with (if only-open 'notmuch-show-message-visible-p
nil) ?

>    (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))))))
> +	 (notmuch-show-set-tags new-tags))))
> +   `(lambda ()
> +      ,(if only-open '(notmuch-show-message-visible-p) t))))

Same.

Ethan

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v2 1/6] test: emacs: new tests "notmuch-show: {add, remove} multiple tags {to, from} single message"
  2012-02-24 22:30       ` [PATCH v2 1/6] test: emacs: new tests "notmuch-show: {add, remove} multiple tags {to, from} single message" Pieter Praet
  2012-03-21  1:06         ` Mark Walters
@ 2012-12-10  2:48         ` David Bremner
  2012-12-11 14:04         ` David Bremner
  2 siblings, 0 replies; 136+ messages in thread
From: David Bremner @ 2012-12-10  2:48 UTC (permalink / raw)
  To: Pieter Praet, Dmitry Kurochkin; +Cc: Notmuch Mail

Pieter Praet <pieter@praet.org> writes:

> * test/emacs:
>
>   - Rename subtests "{Add,Remove} tag from notmuch-show view" to
>     "notmuch-show: {add,remove} single tag {to,from} single message"
>     to be consistent with the following tests.
>
>   - New subtest "notmuch-show: add multiple tags to single message":
>     `notmuch-show-add-tag' ("+") can add multiple tags to a message.
>
>   - New subtest "notmuch-show: remove multiple tags from single message":
>     `notmuch-show-remove-tag' ("-") can remove multiple tags from a message.

This applies clean, seems sensible.

I can probably be (finally) merged.

d

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v2 1/6] test: emacs: new tests "notmuch-show: {add, remove} multiple tags {to, from} single message"
  2012-02-24 22:30       ` [PATCH v2 1/6] test: emacs: new tests "notmuch-show: {add, remove} multiple tags {to, from} single message" Pieter Praet
  2012-03-21  1:06         ` Mark Walters
  2012-12-10  2:48         ` David Bremner
@ 2012-12-11 14:04         ` David Bremner
  2 siblings, 0 replies; 136+ messages in thread
From: David Bremner @ 2012-12-11 14:04 UTC (permalink / raw)
  To: Pieter Praet, Dmitry Kurochkin; +Cc: Notmuch Mail

Pieter Praet <pieter@praet.org> writes:

> * test/emacs:
>
>   - Rename subtests "{Add,Remove} tag from notmuch-show view" to
>     "notmuch-show: {add,remove} single tag {to,from} single message"
>     to be consistent with the following tests.
>
>   - New subtest "notmuch-show: add multiple tags to single message":
>     `notmuch-show-add-tag' ("+") can add multiple tags to a message.
>
>   - New subtest "notmuch-show: remove multiple tags from single message":
>     `notmuch-show-remove-tag' ("-") can remove multiple tags from a message.

pushed this one test.

d

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v2 3/6] test: emacs: `notmuch-show-tag-all' with prefix arg should only tag open messages
  2012-02-24 22:30       ` [PATCH v2 3/6] test: emacs: `notmuch-show-tag-all' with prefix arg should only tag open messages Pieter Praet
@ 2013-02-19  0:27         ` David Bremner
  0 siblings, 0 replies; 136+ messages in thread
From: David Bremner @ 2013-02-19  0:27 UTC (permalink / raw)
  To: Pieter Praet; +Cc: Notmuch Mail

Pieter Praet <pieter@praet.org> writes:

> * test/emacs:
>
>   - New subtest "notmuch-show: change tags of open messages in current buffer":
>     When called with a prefix arg, `notmuch-show-tag-all' ("*") should only
>     change the tags of *open* messages.  Currently broken, fix follows later.

I'm afraid this patch doesn't apply anymore, sorry about that. A rebased
version would be welcome (and doesn't need further review).

d

^ permalink raw reply	[flat|nested] 136+ messages in thread

end of thread, other threads:[~2013-02-19  0:27 UTC | newest]

Thread overview: 136+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-01-28  4:41 [PATCH 1/6] emacs: move tag format validation to `notmuch-tag' function Dmitry Kurochkin
2012-01-28  4:41 ` [PATCH 2/6] emacs: remove text properties from `notmuch-search-get-tags' result Dmitry Kurochkin
2012-01-28  4:41 ` [PATCH 3/6] emacs: make "+" and "-" tagging operations more robust Dmitry Kurochkin
2012-01-28 16:49   ` Jeremy Nickurak
2012-01-28 17:17     ` Dmitry Kurochkin
2012-01-29 22:57   ` Austin Clements
2012-01-30  1:32     ` Dmitry Kurochkin
2012-01-28  4:41 ` [PATCH 4/6] test: fix emacs tests after tagging operations changes Dmitry Kurochkin
2012-01-29 22:58   ` Austin Clements
2012-01-29 23:09     ` Dmitry Kurochkin
2012-01-28  4:41 ` [PATCH 5/6] emacs: add "*" binding for notmuch-show view Dmitry Kurochkin
2012-01-28  4:41 ` [PATCH 6/6] emacs: separate history for operations which accept single and multiple tags Dmitry Kurochkin
2012-01-29 23:02   ` Austin Clements
2012-01-30  1:42     ` Dmitry Kurochkin
2012-01-28  5:05 ` [PATCH 7/6] emacs: relax tag syntax check in `notmuch-tag' function Dmitry Kurochkin
2012-01-28  8:56   ` Jani Nikula
2012-01-28  9:49     ` Dmitry Kurochkin
2012-02-19 20:53     ` Pieter Praet
2012-01-28  5:59 ` [PATCH 8/6] emacs: use message ids instead of thread id in `notmuch-show-operate-all' Dmitry Kurochkin
2012-01-28  5:59   ` [PATCH 9/6] emacs: code cleanup in `notmuch-show-operate-all', no functional changes Dmitry Kurochkin
2012-01-28  9:09   ` [PATCH 8/6] emacs: use message ids instead of thread id in `notmuch-show-operate-all' Jani Nikula
2012-01-28  9:42     ` Dmitry Kurochkin
2012-01-29 23:11   ` Austin Clements
2012-01-30  1:50     ` Dmitry Kurochkin
2012-01-29 21:34 ` [PATCH 1/6] emacs: move tag format validation to `notmuch-tag' function Austin Clements
2012-01-29 22:54   ` Dmitry Kurochkin
2012-01-29 23:16     ` Austin Clements
2012-01-29 23:32       ` Dmitry Kurochkin
2012-01-30  2:26 ` [PATCH v2 00/13] emacs: more robust and consistent tagging operations Dmitry Kurochkin
2012-01-30  2:26   ` [PATCH v2 01/13] emacs: move tag format validation to `notmuch-tag' function Dmitry Kurochkin
2012-01-30  2:26   ` [PATCH v2 02/13] emacs: remove text properties from `notmuch-search-get-tags' result Dmitry Kurochkin
2012-01-30  2:26   ` [PATCH v2 03/13] emacs: make "+" and "-" tagging operations in notmuch-search more robust Dmitry Kurochkin
2012-01-30  4:48     ` Austin Clements
2012-01-30  5:10       ` Dmitry Kurochkin
2012-01-30  2:26   ` [PATCH v2 04/13] emacs: make "+" and "-" tagging operations in notmuch-show " Dmitry Kurochkin
2012-01-30  2:26   ` [PATCH v2 05/13] test: fix emacs tests after tagging operations changes Dmitry Kurochkin
2012-01-30  2:26   ` [PATCH v2 06/13] emacs: rename `notmuch-search-operate-all' to `notmuch-search-tag-all' Dmitry Kurochkin
2012-01-30  2:26   ` [PATCH v2 07/13] emacs: add "*" binding for notmuch-show view Dmitry Kurochkin
2012-01-30  2:26   ` [PATCH v2 08/13] emacs: separate history for operations which accept single and multiple tags Dmitry Kurochkin
2012-01-30  2:26   ` [PATCH v2 09/13] emacs: relax tag syntax check in `notmuch-tag' function Dmitry Kurochkin
2012-01-30  2:26   ` [PATCH v2 10/13] emacs: use message ids instead of thread id in `notmuch-show-operate-all' Dmitry Kurochkin
2012-01-30  4:57     ` Austin Clements
2012-01-30  5:21       ` Dmitry Kurochkin
2012-01-30  2:26   ` [PATCH v2 11/13] emacs: code cleanup in `notmuch-show-operate-all', no functional changes Dmitry Kurochkin
2012-01-30  4:59     ` Austin Clements
2012-01-30  5:25       ` Dmitry Kurochkin
2012-01-30  2:26   ` [PATCH v2 12/13] emacs: accept empty tag list in `notmuch-tag' Dmitry Kurochkin
2012-01-30  2:26   ` [PATCH v2 13/13] NEWS: document Emacs UI tagging operations changes Dmitry Kurochkin
2012-01-30  5:04     ` Austin Clements
2012-01-30  5:16       ` Dmitry Kurochkin
2012-01-30  5:33 ` emacs: more flexible and consistent tagging operations Dmitry Kurochkin
2012-01-30  5:33   ` [PATCH v3 01/12] emacs: move tag format validation to `notmuch-tag' function Dmitry Kurochkin
2012-01-30  5:33   ` [PATCH v3 02/12] emacs: remove text properties from `notmuch-search-get-tags' result Dmitry Kurochkin
2012-01-30  5:33   ` [PATCH v3 03/12] emacs: make "+" and "-" tagging operations in notmuch-search more flexible Dmitry Kurochkin
2012-01-30  5:33   ` [PATCH v3 04/12] emacs: make "+" and "-" tagging operations in notmuch-show " Dmitry Kurochkin
2012-01-30  5:33   ` [PATCH v3 05/12] test: fix emacs tests after tagging operations changes Dmitry Kurochkin
2012-01-30  5:33   ` [PATCH v3 06/12] emacs: rename `notmuch-search-operate-all' to `notmuch-search-tag-all' Dmitry Kurochkin
2012-01-30  5:33   ` [PATCH v3 07/12] emacs: add "*" binding for notmuch-show view Dmitry Kurochkin
2012-01-30  5:34   ` [PATCH v3 08/12] emacs: separate history for operations which accept single and multiple tags Dmitry Kurochkin
2012-01-30  5:34   ` [PATCH v3 09/12] emacs: relax tag syntax check in `notmuch-tag' function Dmitry Kurochkin
2012-01-30  5:34   ` [PATCH v3 10/12] emacs: accept empty tag list in `notmuch-tag' Dmitry Kurochkin
2012-01-30  5:34   ` [PATCH v3 11/12] emacs: s/tags/tag-changes/ for arguments of tagging functions Dmitry Kurochkin
2012-01-30  5:34   ` [PATCH v3 12/12] NEWS: document Emacs UI tagging operations changes Dmitry Kurochkin
2012-01-30 15:20   ` emacs: more flexible and consistent tagging operations Austin Clements
2012-01-30 15:55   ` Tomi Ollila
2012-01-31  4:54   ` [PATCH v4 00/12] " Dmitry Kurochkin
2012-01-31  4:54     ` [PATCH v4 01/12] emacs: move tag format validation to `notmuch-tag' function Dmitry Kurochkin
2012-01-31  4:54     ` [PATCH v4 02/12] emacs: remove text properties from `notmuch-search-get-tags' result Dmitry Kurochkin
2012-02-04  1:49       ` David Bremner
2012-01-31  4:54     ` [PATCH v4 03/12] emacs: make "+" and "-" tagging operations in notmuch-search more flexible Dmitry Kurochkin
2012-01-31  4:54     ` [PATCH v4 04/12] emacs: make "+" and "-" tagging operations in notmuch-show " Dmitry Kurochkin
2012-01-31  4:54     ` [PATCH v4 05/12] test: fix emacs tests after tagging operations changes Dmitry Kurochkin
2012-01-31  4:54     ` [PATCH v4 06/12] emacs: rename `notmuch-search-operate-all' to `notmuch-search-tag-all' Dmitry Kurochkin
2012-01-31  4:54     ` [PATCH v4 07/12] emacs: add "*" binding for notmuch-show view Dmitry Kurochkin
2012-01-31  4:54     ` [PATCH v4 08/12] emacs: separate history for operations which accept single and multiple tags Dmitry Kurochkin
2012-01-31  4:54     ` [PATCH v4 09/12] emacs: relax tag syntax check in `notmuch-tag' function Dmitry Kurochkin
2012-01-31  4:54     ` [PATCH v4 10/12] emacs: accept empty tag list in `notmuch-tag' Dmitry Kurochkin
2012-01-31  4:54     ` [PATCH v4 11/12] emacs: s/tags/tag-changes/ for arguments of tagging functions Dmitry Kurochkin
2012-01-31  4:54     ` [PATCH v4 12/12] NEWS: document Emacs UI tagging operations changes Dmitry Kurochkin
2012-02-05  7:13 ` [PATCH v5 00/12] emacs: more flexible and consistent tagging operations Dmitry Kurochkin
2012-02-05  7:13   ` [PATCH v5 01/12] emacs: move tag format validation to `notmuch-tag' function Dmitry Kurochkin
2012-02-05  7:13   ` [PATCH v5 02/12] emacs: remove text properties from `notmuch-search-get-tags' result Dmitry Kurochkin
2012-02-05  7:13   ` [PATCH v5 03/12] emacs: make "+" and "-" tagging operations in notmuch-search more flexible Dmitry Kurochkin
2012-02-05  7:13   ` [PATCH v5 04/12] emacs: make "+" and "-" tagging operations in notmuch-show " Dmitry Kurochkin
2012-02-05  7:13   ` [PATCH v5 05/12] test: fix emacs tests after tagging operations changes Dmitry Kurochkin
2012-02-05  7:13   ` [PATCH v5 06/12] emacs: rename `notmuch-search-operate-all' to `notmuch-search-tag-all' Dmitry Kurochkin
2012-02-05  7:13   ` [PATCH v5 07/12] emacs: add "*" binding for notmuch-show view Dmitry Kurochkin
2012-02-05  7:13   ` [PATCH v5 08/12] emacs: separate history for operations which accept single and multiple tags Dmitry Kurochkin
2012-02-05  7:13   ` [PATCH v5 09/12] emacs: relax tag syntax check in `notmuch-tag' function Dmitry Kurochkin
2012-02-05  7:13   ` [PATCH v5 10/12] emacs: accept empty tag list in `notmuch-tag' Dmitry Kurochkin
2012-02-05  7:13   ` [PATCH v5 11/12] emacs: s/tags/tag-changes/ for arguments of tagging functions Dmitry Kurochkin
2012-02-05  7:13   ` [PATCH v5 12/12] NEWS: document Emacs UI tagging operations changes Dmitry Kurochkin
2012-02-08 15:58   ` [PATCH v5 00/12] emacs: more flexible and consistent tagging operations David Bremner
2012-02-23 23:07     ` Pieter Praet
2012-02-23 23:09       ` [PATCH 1/6] test: emacs: new tests "notmuch-show: {add, remove} multiple tags {to, from} single message" Pieter Praet
2012-02-24 10:35         ` Dmitry Kurochkin
2012-02-24 22:33           ` Pieter Praet
2012-02-23 23:09       ` [PATCH 2/6] test: emacs: new test "notmuch-show: change tags of all messages in current buffer" Pieter Praet
2012-02-23 23:09       ` [PATCH 3/6] test: emacs: `notmuch-show-tag-all' sans prefix arg should only tag open messages Pieter Praet
2012-02-23 23:09       ` [PATCH 4/6] emacs: add predicate arg to `notmuch-show-mapc' Pieter Praet
2012-02-24 10:39         ` Dmitry Kurochkin
2012-02-24 22:35           ` Pieter Praet
2012-02-23 23:09       ` [PATCH 5/6] emacs: simplify `notmuch-show-get-messages-ids{, -search}' Pieter Praet
2012-02-24 10:42         ` Dmitry Kurochkin
2012-02-24 22:36           ` Pieter Praet
2012-02-23 23:09       ` [PATCH 6/6] emacs: `notmuch-show-tag-all' sans prefix arg only tags open messages Pieter Praet
2012-02-24 10:47         ` Dmitry Kurochkin
2012-02-24 22:37           ` Pieter Praet
2012-02-24 10:30       ` [PATCH v5 00/12] emacs: more flexible and consistent tagging operations Dmitry Kurochkin
2012-02-24 10:33         ` Dmitry Kurochkin
2012-02-24 17:39           ` Jani Nikula
2012-02-24 22:40           ` Pieter Praet
2012-02-24 22:38         ` Pieter Praet
2012-02-25  0:05           ` Pieter Praet
2012-02-25 16:20       ` David Bremner
2012-02-27 14:50         ` Tomi Ollila
2012-02-28 19:34           ` Pieter Praet
2012-02-24 22:30     ` [PATCH v2 0/6] `notmuch-show-tag-all' with prefix arg only tags open messages Pieter Praet
2012-02-24 22:30       ` [PATCH v2 1/6] test: emacs: new tests "notmuch-show: {add, remove} multiple tags {to, from} single message" Pieter Praet
2012-03-21  1:06         ` Mark Walters
2012-12-10  2:48         ` David Bremner
2012-12-11 14:04         ` David Bremner
2012-02-24 22:30       ` [PATCH v2 2/6] test: emacs: new test "notmuch-show: change tags of all messages in current buffer" Pieter Praet
2012-10-16  2:15         ` Ethan Glasser-Camp
2012-02-24 22:30       ` [PATCH v2 3/6] test: emacs: `notmuch-show-tag-all' with prefix arg should only tag open messages Pieter Praet
2013-02-19  0:27         ` David Bremner
2012-02-24 22:30       ` [PATCH v2 4/6] emacs: add optional predicate arg to `notmuch-show-mapc' Pieter Praet
2012-03-21  1:33         ` Mark Walters
2012-10-16  2:59           ` Ethan Glasser-Camp
2012-10-16  2:18         ` Ethan Glasser-Camp
2012-02-24 22:30       ` [PATCH v2 5/6] emacs: simplify `notmuch-show-get-messages-ids{, -search}' Pieter Praet
2012-03-21  1:36         ` Mark Walters
2012-10-16  3:12           ` Ethan Glasser-Camp
2012-03-21  1:40         ` Mark Walters
2012-02-24 22:30       ` [PATCH v2 6/6] emacs: `notmuch-show-tag-all' with prefix arg only tags open messages Pieter Praet
2012-10-16  3:39         ` Ethan Glasser-Camp

Code repositories for project(s) associated with this public inbox

	https://yhetil.org/notmuch.git/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).