]> git.notmuchmail.org Git - notmuch/blobdiff - emacs/notmuch-tag.el
util: Fix two corner-cases in boolean term quoting function
[notmuch] / emacs / notmuch-tag.el
index 22a603fcf04ab279a38acba548f0bf26a4de5bc4..908e7ade6270bccce7fb6afbbb3e63eccc261465 100644 (file)
@@ -148,15 +148,16 @@ This can be used with `notmuch-tag-format-image-data'."
        (dolist (format (cdr formats) tag)
          (setq tag (eval format))))))))
 
-(defun notmuch-tag-format-tags (tags)
+(defun notmuch-tag-format-tags (tags &optional face)
   "Return a string representing formatted TAGS."
-  (notmuch-combine-face-text-property-string
-   (mapconcat #'identity
-             ;; nil indicated that the tag was deliberately hidden
-             (delq nil (mapcar #'notmuch-tag-format-tag tags))
-             " ")
-   'notmuch-tag-face
-   t))
+  (let ((face (or face 'notmuch-tag-face)))
+    (notmuch-combine-face-text-property-string
+     (mapconcat #'identity
+               ;; nil indicated that the tag was deliberately hidden
+               (delq nil (mapcar #'notmuch-tag-format-tag tags))
+               " ")
+     face
+     t)))
 
 (defcustom notmuch-before-tag-hook nil
   "Hooks that are run before tags of a message are modified.
@@ -230,8 +231,16 @@ initial input in the minibuffer."
            (set-keymap-parent map crm-local-completion-map)
            (define-key map " " 'self-insert-command)
            map)))
-    (delete "" (completing-read-multiple prompt
-               tag-list nil nil initial-input
+    (delete "" (completing-read-multiple
+               prompt
+               ;; Append the separator to each completion so when the
+               ;; user completes a tag they can immediately begin
+               ;; entering another.  `completing-read-multiple'
+               ;; ultimately splits the input on crm-separator, so we
+               ;; don't need to strip this back off (we just need to
+               ;; delete "empty" entries caused by trailing spaces).
+               (mapcar (lambda (tag-op) (concat tag-op crm-separator)) tag-list)
+               nil nil initial-input
                'notmuch-read-tag-changes-history))))
 
 (defun notmuch-update-tags (tags tag-changes)
@@ -253,6 +262,12 @@ from TAGS if present."
           (error "Changed tag must be of the form `+this_tag' or `-that_tag'")))))
     (sort result-tags 'string<)))
 
+(defconst notmuch-tag-argument-limit 1000
+  "Use batch tagging if the tagging query is longer than this.
+
+This limits the length of arguments passed to the notmuch CLI to
+avoid system argument length limits and performance problems.")
+
 (defun notmuch-tag (query tag-changes)
   "Add/remove tags in TAG-CHANGES to messages matching QUERY.
 
@@ -271,8 +286,13 @@ notmuch-after-tag-hook will be run."
        tag-changes)
   (unless (null tag-changes)
     (run-hooks 'notmuch-before-tag-hook)
-    (apply 'notmuch-call-notmuch-process "tag"
-          (append tag-changes (list "--" query)))
+    (if (<= (length query) notmuch-tag-argument-limit)
+       (apply 'notmuch-call-notmuch-process "tag"
+              (append tag-changes (list "--" query)))
+      ;; Use batch tag mode to avoid argument length limitations
+      (let ((batch-op (concat (mapconcat #'notmuch-hex-encode tag-changes " ")
+                             " -- " query)))
+       (notmuch-call-notmuch-process :stdin-string batch-op "tag" "--batch")))
     (run-hooks 'notmuch-after-tag-hook)))
 
 (defun notmuch-tag-change-list (tags &optional reverse)