]> git.notmuchmail.org Git - notmuch/blobdiff - emacs/notmuch-lib.el
emacs: Use 'and' instead of 'when' when the return value matters
[notmuch] / emacs / notmuch-lib.el
index 010be454e77420c2f945fdfc3a7895283a8d7209..98056eb6558737bdec0bd64ba6fc031915ddf2f9 100644 (file)
 
 ;;; Code:
 
 
 ;;; Code:
 
+(require 'cl-lib)
+
 (require 'mm-util)
 (require 'mm-view)
 (require 'mm-decode)
 (require 'mm-util)
 (require 'mm-view)
 (require 'mm-decode)
-(require 'cl)
+
 (require 'notmuch-compat)
 
 (unless (require 'notmuch-version nil t)
 (require 'notmuch-compat)
 
 (unless (require 'notmuch-version nil t)
@@ -153,8 +155,11 @@ For example, if you wanted to remove an \"inbox\" tag and add an
     (define-key map "?" 'notmuch-help)
     (define-key map "q" 'notmuch-bury-or-kill-this-buffer)
     (define-key map "s" 'notmuch-search)
     (define-key map "?" 'notmuch-help)
     (define-key map "q" 'notmuch-bury-or-kill-this-buffer)
     (define-key map "s" 'notmuch-search)
+    (define-key map "t" 'notmuch-search-by-tag)
     (define-key map "z" 'notmuch-tree)
     (define-key map "z" 'notmuch-tree)
+    (define-key map "u" 'notmuch-unthreaded)
     (define-key map "m" 'notmuch-mua-new-mail)
     (define-key map "m" 'notmuch-mua-new-mail)
+    (define-key map "g" 'notmuch-refresh-this-buffer)
     (define-key map "=" 'notmuch-refresh-this-buffer)
     (define-key map (kbd "M-=") 'notmuch-refresh-all-buffers)
     (define-key map "G" 'notmuch-poll-and-refresh-this-buffer)
     (define-key map "=" 'notmuch-refresh-this-buffer)
     (define-key map (kbd "M-=") 'notmuch-refresh-all-buffers)
     (define-key map "G" 'notmuch-poll-and-refresh-this-buffer)
@@ -184,7 +189,7 @@ If notmuch exits with a non-zero status, output from the process
 will appear in a buffer named \"*Notmuch errors*\" and an error
 will be signaled.
 
 will appear in a buffer named \"*Notmuch errors*\" and an error
 will be signaled.
 
-Otherwise the output will be returned"
+Otherwise the output will be returned."
   (with-temp-buffer
     (let* ((status (apply #'call-process notmuch-command nil t nil args))
           (output (buffer-string)))
   (with-temp-buffer
     (let* ((status (apply #'call-process notmuch-command nil t nil args))
           (output (buffer-string)))
@@ -206,7 +211,7 @@ Otherwise the output will be returned"
   (unless (notmuch-cli-sane-p)
     (notmuch-logged-error
      "notmuch cli seems misconfigured or unconfigured."
   (unless (notmuch-cli-sane-p)
     (notmuch-logged-error
      "notmuch cli seems misconfigured or unconfigured."
-"Perhaps you haven't run \"notmuch setup\" yet? Try running this
+     "Perhaps you haven't run \"notmuch setup\" yet? Try running this
 on the command line, and then retry your notmuch command")))
 
 (defun notmuch-cli-version ()
 on the command line, and then retry your notmuch command")))
 
 (defun notmuch-cli-version ()
@@ -294,10 +299,10 @@ This is basically just `format-kbd-macro' but we also convert ESC to M-."
 
 
 (defun notmuch-describe-key (actual-key binding prefix ua-keys tail)
 
 
 (defun notmuch-describe-key (actual-key binding prefix ua-keys tail)
-  "Prepend cons cells describing prefix-arg ACTUAL-KEY and ACTUAL-KEY to TAIL
+  "Prepend cons cells describing prefix-arg ACTUAL-KEY and ACTUAL-KEY to TAIL.
 
 It does not prepend if ACTUAL-KEY is already listed in TAIL."
 
 It does not prepend if ACTUAL-KEY is already listed in TAIL."
-  (let ((key-string (concat prefix (format-kbd-macro actual-key))))
+  (let ((key-string (concat prefix (key-description actual-key))))
     ;; We don't include documentation if the key-binding is
     ;; over-ridden. Note, over-riding a binding automatically hides the
     ;; prefixed version too.
     ;; We don't include documentation if the key-binding is
     ;; over-ridden. Note, over-riding a binding automatically hides the
     ;; prefixed version too.
@@ -311,10 +316,12 @@ It does not prepend if ACTUAL-KEY is already listed in TAIL."
                tail)))
       ;; Documentation for command
       (push (cons key-string
                tail)))
       ;; Documentation for command
       (push (cons key-string
-                 (or (and (symbolp binding) (get binding 'notmuch-doc))
-                     (notmuch-documentation-first-line binding)))
+                 (or (and (symbolp binding)
+                          (get binding 'notmuch-doc))
+                     (and (functionp binding)
+                          (notmuch-documentation-first-line binding))))
            tail)))
            tail)))
-    tail)
+  tail)
 
 (defun notmuch-describe-remaps (remap-keymap ua-keys base-keymap prefix tail)
   ;; Remappings are represented as a binding whose first "event" is
 
 (defun notmuch-describe-remaps (remap-keymap ua-keys base-keymap prefix tail)
   ;; Remappings are represented as a binding whose first "event" is
@@ -322,13 +329,13 @@ It does not prepend if ACTUAL-KEY is already listed in TAIL."
   ;; binding whose "key" is 'remap, and whose "binding" is itself a
   ;; keymap that maps not from keys to commands, but from old (remapped)
   ;; functions to the commands to use in their stead.
   ;; binding whose "key" is 'remap, and whose "binding" is itself a
   ;; keymap that maps not from keys to commands, but from old (remapped)
   ;; functions to the commands to use in their stead.
-  (map-keymap
-   (lambda (command binding)
-     (mapc
-      (lambda (actual-key)
-       (setq tail (notmuch-describe-key actual-key binding prefix ua-keys tail)))
-      (where-is-internal command base-keymap)))
-   remap-keymap)
+  (map-keymap (lambda (command binding)
+               (mapc (lambda (actual-key)
+                       (setq tail
+                             (notmuch-describe-key actual-key binding
+                                                   prefix ua-keys tail)))
+                     (where-is-internal command base-keymap)))
+             remap-keymap)
   tail)
 
 (defun notmuch-describe-keymap (keymap ua-keys base-keymap &optional prefix tail)
   tail)
 
 (defun notmuch-describe-keymap (keymap ua-keys base-keymap &optional prefix tail)
@@ -351,9 +358,13 @@ prefix argument.  PREFIX and TAIL are used internally."
                      (notmuch-describe-remaps
                       binding ua-keys base-keymap prefix tail)
                    (notmuch-describe-keymap
                      (notmuch-describe-remaps
                       binding ua-keys base-keymap prefix tail)
                    (notmuch-describe-keymap
-                    binding ua-keys base-keymap (notmuch-prefix-key-description key) tail))))
+                    binding ua-keys base-keymap
+                    (notmuch-prefix-key-description key)
+                    tail))))
           (binding
           (binding
-           (setq tail (notmuch-describe-key (vector key) binding prefix ua-keys tail)))))
+           (setq tail
+                 (notmuch-describe-key (vector key)
+                                       binding prefix ua-keys tail)))))
    keymap)
   tail)
 
    keymap)
   tail)
 
@@ -363,11 +374,15 @@ prefix argument.  PREFIX and TAIL are used internally."
     (while (string-match "\\\\{\\([^}[:space:]]*\\)}" doc beg)
       (let ((desc
             (save-match-data
     (while (string-match "\\\\{\\([^}[:space:]]*\\)}" doc beg)
       (let ((desc
             (save-match-data
-              (let* ((keymap-name (substring doc (match-beginning 1) (match-end 1)))
+              (let* ((keymap-name (substring doc
+                                             (match-beginning 1)
+                                             (match-end 1)))
                      (keymap (symbol-value (intern keymap-name)))
                      (ua-keys (where-is-internal 'universal-argument keymap t))
                      (desc-alist (notmuch-describe-keymap keymap ua-keys keymap))
                      (keymap (symbol-value (intern keymap-name)))
                      (ua-keys (where-is-internal 'universal-argument keymap t))
                      (desc-alist (notmuch-describe-keymap keymap ua-keys keymap))
-                     (desc-list (mapcar (lambda (arg) (concat (car arg) "\t" (cdr arg))) desc-alist)))
+                     (desc-list (mapcar (lambda (arg)
+                                          (concat (car arg) "\t" (cdr arg)))
+                                        desc-alist)))
                 (mapconcat #'identity desc-list "\n")))))
        (setq doc (replace-match desc 1 1 doc)))
       (setq beg (match-end 0)))
                 (mapconcat #'identity desc-list "\n")))))
        (setq doc (replace-match desc 1 1 doc)))
       (setq beg (match-end 0)))
@@ -386,7 +401,8 @@ its prefixed behavior by setting the 'notmuch-prefix-doc property
 of its command symbol."
   (interactive)
   (let* ((mode major-mode)
 of its command symbol."
   (interactive)
   (let* ((mode major-mode)
-        (doc (substitute-command-keys (notmuch-substitute-command-keys (documentation mode t)))))
+        (doc (substitute-command-keys
+              (notmuch-substitute-command-keys (documentation mode t)))))
     (with-current-buffer (generate-new-buffer "*notmuch-help*")
       (insert doc)
       (goto-char (point-min))
     (with-current-buffer (generate-new-buffer "*notmuch-help*")
       (insert doc)
       (goto-char (point-min))
@@ -397,17 +413,18 @@ of its command symbol."
   "Show help for a subkeymap."
   (interactive)
   (let* ((key (this-command-keys-vector))
   "Show help for a subkeymap."
   (interactive)
   (let* ((key (this-command-keys-vector))
-       (prefix (make-vector (1- (length key)) nil))
-       (i 0))
+        (prefix (make-vector (1- (length key)) nil))
+        (i 0))
     (while (< i (length prefix))
       (aset prefix i (aref key i))
       (setq i (1+ i)))
     (while (< i (length prefix))
       (aset prefix i (aref key i))
       (setq i (1+ i)))
-
     (let* ((subkeymap (key-binding prefix))
           (ua-keys (where-is-internal 'universal-argument nil t))
           (prefix-string (notmuch-prefix-key-description prefix))
     (let* ((subkeymap (key-binding prefix))
           (ua-keys (where-is-internal 'universal-argument nil t))
           (prefix-string (notmuch-prefix-key-description prefix))
-          (desc-alist (notmuch-describe-keymap subkeymap ua-keys subkeymap prefix-string))
-          (desc-list (mapcar (lambda (arg) (concat (car arg) "\t" (cdr arg))) desc-alist))
+          (desc-alist (notmuch-describe-keymap
+                       subkeymap ua-keys subkeymap prefix-string))
+          (desc-list (mapcar (lambda (arg) (concat (car arg) "\t" (cdr arg)))
+                             desc-alist))
           (desc (mapconcat #'identity desc-list "\n")))
       (with-help-window (help-buffer)
        (with-current-buffer standard-output
           (desc (mapconcat #'identity desc-list "\n")))
       (with-help-window (help-buffer)
        (with-current-buffer standard-output
@@ -468,7 +485,6 @@ This includes newlines, tabs, and other funny characters."
 The caller is responsible for prepending the term prefix and a
 colon.  This performs minimal escaping in order to produce
 user-friendly queries."
 The caller is responsible for prepending the term prefix and a
 colon.  This performs minimal escaping in order to produce
 user-friendly queries."
-
   (save-match-data
     (if (or (equal term "")
            ;; To be pessimistic, only pass through terms composed
   (save-match-data
     (if (or (equal term "")
            ;; To be pessimistic, only pass through terms composed
@@ -511,7 +527,7 @@ This replaces spaces, percents, and double quotes in STR with
   (let (out)
     (while list
       (when (funcall predicate (car list))
   (let (out)
     (while list
       (when (funcall predicate (car list))
-        (push (car list) out))
+       (push (car list) out))
       (setq list (cdr list)))
     (nreverse out)))
 
       (setq list (cdr list)))
     (nreverse out)))
 
@@ -525,11 +541,11 @@ This replaces spaces, percents, and double quotes in STR with
     (cdr xplist)))
 
 (defun notmuch-split-content-type (content-type)
     (cdr xplist)))
 
 (defun notmuch-split-content-type (content-type)
-  "Split content/type into 'content' and 'type'"
+  "Split content/type into 'content' and 'type'."
   (split-string content-type "/"))
 
 (defun notmuch-match-content-type (t1 t2)
   (split-string content-type "/"))
 
 (defun notmuch-match-content-type (t1 t2)
-  "Return t if t1 and t2 are matching content types, taking wildcards into account"
+  "Return t if t1 and t2 are matching content types, taking wildcards into account."
   (let ((st1 (notmuch-split-content-type t1))
        (st2 (notmuch-split-content-type t2)))
     (if (or (string= (cadr st1) "*")
   (let ((st1 (notmuch-split-content-type t1))
        (st2 (notmuch-split-content-type t2)))
     (if (or (string= (cadr st1) "*")
@@ -539,12 +555,11 @@ This replaces spaces, percents, and double quotes in STR with
       (string= (downcase t1) (downcase t2)))))
 
 (defvar notmuch-multipart/alternative-discouraged
       (string= (downcase t1) (downcase t2)))))
 
 (defvar notmuch-multipart/alternative-discouraged
-  '(
-    ;; Avoid HTML parts.
+  '(;; Avoid HTML parts.
     "text/html"
     "text/html"
-    ;; multipart/related usually contain a text/html part and some associated graphics.
-    "multipart/related"
-    ))
+    ;; multipart/related usually contain a text/html part and some
+    ;; associated graphics.
+    "multipart/related"))
 
 (defun notmuch-multipart/alternative-determine-discouraged (msg)
   "Return the discouraged alternatives for the specified message."
 
 (defun notmuch-multipart/alternative-determine-discouraged (msg)
   "Return the discouraged alternatives for the specified message."
@@ -571,7 +586,7 @@ for this message, if present."
 (defun notmuch-parts-filter-by-type (parts type)
   "Given a list of message parts, return a list containing the ones matching
 the given type."
 (defun notmuch-parts-filter-by-type (parts type)
   "Given a list of message parts, return a list containing the ones matching
 the given type."
-  (remove-if-not
+  (cl-remove-if-not
    (lambda (part) (notmuch-match-content-type (plist-get part :content-type) type))
    parts))
 
    (lambda (part) (notmuch-match-content-type (plist-get part :content-type) type))
    parts))
 
@@ -593,12 +608,13 @@ the given type."
                       (set-buffer-multibyte nil))
                     (let ((args `("show" "--format=raw"
                                   ,(format "--part=%s" (plist-get part :id))
                       (set-buffer-multibyte nil))
                     (let ((args `("show" "--format=raw"
                                   ,(format "--part=%s" (plist-get part :id))
-                                  ,@(when process-crypto '("--decrypt"))
+                                  ,@(and process-crypto '("--decrypt=true"))
                                   ,(notmuch-id-to-query (plist-get msg :id))))
                           (coding-system-for-read
                            (if binaryp 'no-conversion
                                   ,(notmuch-id-to-query (plist-get msg :id))))
                           (coding-system-for-read
                            (if binaryp 'no-conversion
-                             (let ((coding-system (mm-charset-to-coding-system
-                                                   (plist-get part :content-charset))))
+                             (let ((coding-system
+                                    (mm-charset-to-coding-system
+                                     (plist-get part :content-charset))))
                                ;; Sadly,
                                ;; `mm-charset-to-coding-system' seems
                                ;; to return things that are not
                                ;; Sadly,
                                ;; `mm-charset-to-coding-system' seems
                                ;; to return things that are not
@@ -610,7 +626,8 @@ the given type."
                                  ;; charset is US-ASCII. RFC6657
                                  ;; complicates this somewhat.
                                  'us-ascii)))))
                                  ;; charset is US-ASCII. RFC6657
                                  ;; complicates this somewhat.
                                  'us-ascii)))))
-                      (apply #'call-process notmuch-command nil '(t nil) nil args)
+                      (apply #'call-process
+                             notmuch-command nil '(t nil) nil args)
                       (buffer-string))))))
     (when (and cache data)
       (plist-put part plist-elem data))
                       (buffer-string))))))
     (when (and cache data)
       (plist-put part plist-elem data))
@@ -665,7 +682,8 @@ current buffer, if possible."
       (let* ((have-content (plist-member part :content))
             (charset (if have-content 'gnus-decoded
                        (plist-get part :content-charset)))
       (let* ((have-content (plist-member part :content))
             (charset (if have-content 'gnus-decoded
                        (plist-get part :content-charset)))
-            (handle (mm-make-handle (current-buffer) `(,content-type (charset . ,charset)))))
+            (handle (mm-make-handle (current-buffer)
+                                    `(,content-type (charset . ,charset)))))
        ;; If the user wants the part inlined, insert the content and
        ;; test whether we are able to inline it (which includes both
        ;; capability and suitability tests).
        ;; If the user wants the part inlined, insert the content and
        ;; test whether we are able to inline it (which includes both
        ;; capability and suitability tests).
@@ -682,8 +700,8 @@ current buffer, if possible."
 ;; have symbols of the form :Header as keys, and the resulting alist will have
 ;; symbols of the form 'Header as keys.
 (defun notmuch-headers-plist-to-alist (plist)
 ;; have symbols of the form :Header as keys, and the resulting alist will have
 ;; symbols of the form 'Header as keys.
 (defun notmuch-headers-plist-to-alist (plist)
-  (loop for (key value . rest) on plist by #'cddr
-       collect (cons (intern (substring (symbol-name key) 1)) value)))
+  (cl-loop for (key value . rest) on plist by #'cddr
+          collect (cons (intern (substring (symbol-name key) 1)) value)))
 
 (defun notmuch-face-ensure-list-form (face)
   "Return FACE in face list form.
 
 (defun notmuch-face-ensure-list-form (face)
   "Return FACE in face list form.
@@ -709,7 +727,6 @@ must be a face name (a symbol or string), a property list of face
 attributes, or a list of these.  If START and/or END are omitted,
 they default to the beginning/end of OBJECT.  For convenience
 when applied to strings, this returns OBJECT."
 attributes, or a list of these.  If START and/or END are omitted,
 they default to the beginning/end of OBJECT.  For convenience
 when applied to strings, this returns OBJECT."
-
   ;; A face property can have three forms: a face name (a string or
   ;; symbol), a property list, or a list of these two forms.  In the
   ;; list case, the faces will be combined, with the earlier faces
   ;; A face property can have three forms: a face name (a string or
   ;; symbol), a property list, or a list of these two forms.  In the
   ;; list case, the faces will be combined, with the earlier faces
@@ -752,7 +769,6 @@ This logs MSG and EXTRA to the *Notmuch errors* buffer and
 signals MSG as an error.  If EXTRA is non-nil, text referring the
 user to the *Notmuch errors* buffer will be appended to the
 signaled error.  This function does not return."
 signals MSG as an error.  If EXTRA is non-nil, text referring the
 user to the *Notmuch errors* buffer will be appended to the
 signaled error.  This function does not return."
-
   (with-current-buffer (get-buffer-create "*Notmuch errors*")
     (goto-char (point-max))
     (unless (bobp)
   (with-current-buffer (get-buffer-create "*Notmuch errors*")
     (goto-char (point-max))
     (unless (bobp)
@@ -765,8 +781,8 @@ signaled error.  This function does not return."
        (insert extra)
        (unless (bolp)
          (newline)))))
        (insert extra)
        (unless (bolp)
          (newline)))))
-  (error "%s" (concat msg (when extra
-                           " (see *Notmuch errors* for more details)"))))
+  (error "%s"
+        (concat msg (and extra " (see *Notmuch errors* for more details)"))))
 
 (defun notmuch-check-async-exit-status (proc msg &optional command err)
   "If PROC exited abnormally, pop up an error buffer and signal an error.
 
 (defun notmuch-check-async-exit-status (proc msg &optional command err)
   "If PROC exited abnormally, pop up an error buffer and signal an error.
@@ -777,11 +793,12 @@ arguments passed to the sentinel.  COMMAND and ERR, if provided,
 are passed to `notmuch-check-exit-status'.  If COMMAND is not
 provided, it is taken from `process-command'."
   (let ((exit-status
 are passed to `notmuch-check-exit-status'.  If COMMAND is not
 provided, it is taken from `process-command'."
   (let ((exit-status
-        (case (process-status proc)
+        (cl-case (process-status proc)
           ((exit) (process-exit-status proc))
           ((signal) msg))))
     (when exit-status
           ((exit) (process-exit-status proc))
           ((signal) msg))))
     (when exit-status
-      (notmuch-check-exit-status exit-status (or command (process-command proc))
+      (notmuch-check-exit-status exit-status
+                                (or command (process-command proc))
                                 nil err))))
 
 (defun notmuch-check-exit-status (exit-status command &optional output err)
                                 nil err))))
 
 (defun notmuch-check-exit-status (exit-status command &optional output err)
@@ -796,7 +813,6 @@ command and its arguments.  OUTPUT, if provided, is a string
 giving the output of command.  ERR, if provided, is the error
 output of command.  OUTPUT and ERR will be included in the error
 message."
 giving the output of command.  ERR, if provided, is the error
 output of command.  OUTPUT and ERR will be included in the error
 message."
-
   (cond
    ((eq exit-status 0) t)
    ((eq exit-status 20)
   (cond
    ((eq exit-status 0) t)
    ((eq exit-status 20)
@@ -817,24 +833,22 @@ You may need to restart Emacs or upgrade your notmuch package."))
                       command " "))
           (extra
            (concat "command: " command-string "\n"
                       command " "))
           (extra
            (concat "command: " command-string "\n"
-            (if (integerp exit-status)
-                (format "exit status: %s\n" exit-status)
-              (format "exit signal: %s\n" exit-status))
-            (when err
-              (concat "stderr:\n" err))
-            (when output
-              (concat "stdout:\n" output)))))
-       (if err
-           ;; We have an error message straight from the CLI.
-           (notmuch-logged-error
-            (replace-regexp-in-string "[ \n\r\t\f]*\\'" "" err) extra)
-         ;; We only have combined output from the CLI; don't inundate
-         ;; the user with it.  Mimic `process-lines'.
-         (notmuch-logged-error (format "%s exited with status %s"
-                                       (car command) exit-status)
-                               extra))
-       ;; `notmuch-logged-error' does not return.
-       ))))
+                   (if (integerp exit-status)
+                       (format "exit status: %s\n" exit-status)
+                     (format "exit signal: %s\n" exit-status))
+                   (and err    (concat "stderr:\n" err))
+                   (and output (concat "stdout:\n" output)))))
+      (if err
+         ;; We have an error message straight from the CLI.
+         (notmuch-logged-error
+          (replace-regexp-in-string "[ \n\r\t\f]*\\'" "" err) extra)
+       ;; We only have combined output from the CLI; don't inundate
+       ;; the user with it.  Mimic `process-lines'.
+       (notmuch-logged-error (format "%s exited with status %s"
+                                     (car command) exit-status)
+                             extra))
+      ;; `notmuch-logged-error' does not return.
+      ))))
 
 (defun notmuch-call-notmuch--helper (destination args)
   "Helper for synchronous notmuch invocation commands.
 
 (defun notmuch-call-notmuch--helper (destination args)
   "Helper for synchronous notmuch invocation commands.
@@ -842,12 +856,11 @@ You may need to restart Emacs or upgrade your notmuch package."))
 This wraps `call-process'.  DESTINATION has the same meaning as
 for `call-process'.  ARGS is as described for
 `notmuch-call-notmuch-process'."
 This wraps `call-process'.  DESTINATION has the same meaning as
 for `call-process'.  ARGS is as described for
 `notmuch-call-notmuch-process'."
-
   (let (stdin-string)
     (while (keywordp (car args))
   (let (stdin-string)
     (while (keywordp (car args))
-      (case (car args)
-       (:stdin-string (setq stdin-string (cadr args)
-                            args (cddr args)))
+      (cl-case (car args)
+       (:stdin-string (setq stdin-string (cadr args))
+                      (setq args (cddr args)))
        (otherwise
         (error "Unknown keyword argument: %s" (car args)))))
     (if (null stdin-string)
        (otherwise
         (error "Unknown keyword argument: %s" (car args)))))
     (if (null stdin-string)
@@ -880,7 +893,6 @@ notmuch's output as an S-expression and returns the parsed value.
 Like `notmuch-call-notmuch-process', if notmuch exits with a
 non-zero status, this will report its output and signal an
 error."
 Like `notmuch-call-notmuch-process', if notmuch exits with a
 non-zero status, this will report its output and signal an
 error."
-
   (with-temp-buffer
     (let ((err-file (make-temp-file "nmerr")))
       (unwind-protect
   (with-temp-buffer
     (let ((err-file (make-temp-file "nmerr")))
       (unwind-protect
@@ -908,11 +920,10 @@ when the process exits, or nil for none.  The caller must *not*
 invoke `set-process-sentinel' directly on the returned process,
 as that will interfere with the handling of stderr and the exit
 status."
 invoke `set-process-sentinel' directly on the returned process,
 as that will interfere with the handling of stderr and the exit
 status."
-
-  (let (err-file err-buffer proc
-       ;; Find notmuch using Emacs' `exec-path'
-       (command (or (executable-find notmuch-command)
-                    (error "Command not found: %s" notmuch-command))))
+  (let (err-file err-buffer proc err-proc
+                ;; Find notmuch using Emacs' `exec-path'
+                (command (or (executable-find notmuch-command)
+                             (error "Command not found: %s" notmuch-command))))
     (if (fboundp 'make-process)
        (progn
          (setq err-buffer (generate-new-buffer " *notmuch-stderr*"))
     (if (fboundp 'make-process)
        (progn
          (setq err-buffer (generate-new-buffer " *notmuch-stderr*"))
@@ -927,11 +938,12 @@ status."
                      :command (cons command args)
                      :connection-type 'pipe
                      :stderr err-buffer))
                      :command (cons command args)
                      :connection-type 'pipe
                      :stderr err-buffer))
+         (setq err-proc (get-buffer-process err-buffer))
          (process-put proc 'err-buffer err-buffer)
          (process-put proc 'err-buffer err-buffer)
-         ;; Silence "Process NAME stderr finished" in stderr by adding a
-         ;; no-op sentinel to the fake stderr process object
-         (set-process-sentinel (get-buffer-process err-buffer) #'ignore))
 
 
+         (process-put err-proc 'err-file err-file)
+         (process-put err-proc 'err-buffer err-buffer)
+         (set-process-sentinel err-proc #'notmuch-start-notmuch-error-sentinel))
       ;; On Emacs versions before 25, there is no way to capture
       ;; stdout and stderr separately for asynchronous processes, or
       ;; even to redirect stderr to a file, so we use a trivial shell
       ;; On Emacs versions before 25, there is no way to capture
       ;; stdout and stderr separately for asynchronous processes, or
       ;; even to redirect stderr to a file, so we use a trivial shell
@@ -944,7 +956,6 @@ status."
                          "exec 2>\"$1\"; shift; exec \"$0\" \"$@\""
                          command err-file args)))
       (process-put proc 'err-file err-file))
                          "exec 2>\"$1\"; shift; exec \"$0\" \"$@\""
                          command err-file args)))
       (process-put proc 'err-file err-file))
-
     (process-put proc 'sub-sentinel sentinel)
     (process-put proc 'real-command (cons notmuch-command args))
     (set-process-sentinel proc #'notmuch-start-notmuch-sentinel)
     (process-put proc 'sub-sentinel sentinel)
     (process-put proc 'real-command (cons notmuch-command args))
     (set-process-sentinel proc #'notmuch-start-notmuch-sentinel)
@@ -955,8 +966,8 @@ status."
   (let* ((err-file (process-get proc 'err-file))
         (err-buffer (or (process-get proc 'err-buffer)
                         (find-file-noselect err-file)))
   (let* ((err-file (process-get proc 'err-file))
         (err-buffer (or (process-get proc 'err-buffer)
                         (find-file-noselect err-file)))
-        (err (when (not (zerop (buffer-size err-buffer)))
-               (with-current-buffer err-buffer (buffer-string))))
+        (err (and (not (zerop (buffer-size err-buffer)))
+                  (with-current-buffer err-buffer (buffer-string))))
         (sub-sentinel (process-get proc 'sub-sentinel))
         (real-command (process-get proc 'real-command)))
     (condition-case err
         (sub-sentinel (process-get proc 'sub-sentinel))
         (real-command (process-get proc 'real-command)))
     (condition-case err
@@ -974,34 +985,52 @@ status."
          ;; If that didn't signal an error, then any error output was
          ;; really warning output.  Show warnings, if any.
          (let ((warnings
          ;; If that didn't signal an error, then any error output was
          ;; really warning output.  Show warnings, if any.
          (let ((warnings
-                (when err
-                  (with-current-buffer err-buffer
-                    (goto-char (point-min))
-                    (end-of-line)
-                    ;; Show first line; stuff remaining lines in the
-                    ;; errors buffer.
-                    (let ((l1 (buffer-substring (point-min) (point))))
-                      (skip-chars-forward "\n")
-                      (cons l1 (unless (eobp)
-                                 (buffer-substring (point) (point-max)))))))))
+                (and err
+                     (with-current-buffer err-buffer
+                       (goto-char (point-min))
+                       (end-of-line)
+                       ;; Show first line; stuff remaining lines in the
+                       ;; errors buffer.
+                       (let ((l1 (buffer-substring (point-min) (point))))
+                         (skip-chars-forward "\n")
+                         (cons l1 (and (not (eobp))
+                                       (buffer-substring (point)
+                                                         (point-max)))))))))
            (when warnings
              (notmuch-logged-error (car warnings) (cdr warnings)))))
       (error
        ;; Emacs behaves strangely if an error escapes from a sentinel,
        ;; so turn errors into messages.
        (message "%s" (error-message-string err))))
            (when warnings
              (notmuch-logged-error (car warnings) (cdr warnings)))))
       (error
        ;; Emacs behaves strangely if an error escapes from a sentinel,
        ;; so turn errors into messages.
        (message "%s" (error-message-string err))))
-    (when err-buffer (kill-buffer err-buffer))
     (when err-file (ignore-errors (delete-file err-file)))))
 
     (when err-file (ignore-errors (delete-file err-file)))))
 
+(defun notmuch-start-notmuch-error-sentinel (proc event)
+  (let* ((err-file (process-get proc 'err-file))
+        ;; When `make-process' is available, use the error buffer
+        ;; associated with the process, otherwise the error file.
+        (err-buffer (or (process-get proc 'err-buffer)
+                        (find-file-noselect err-file))))
+    (when err-buffer (kill-buffer err-buffer))))
+
 ;; This variable is used only buffer local, but it needs to be
 ;; declared globally first to avoid compiler warnings.
 (defvar notmuch-show-process-crypto nil)
 (make-variable-buffer-local 'notmuch-show-process-crypto)
 
 ;; This variable is used only buffer local, but it needs to be
 ;; declared globally first to avoid compiler warnings.
 (defvar notmuch-show-process-crypto nil)
 (make-variable-buffer-local 'notmuch-show-process-crypto)
 
-(provide 'notmuch-lib)
+(defun notmuch-interactive-region ()
+  "Return the bounds of the current interactive region.
+
+This returns (BEG END), where BEG and END are the bounds of the
+region if the region is active, or both `point' otherwise."
+  (if (region-active-p)
+      (list (region-beginning) (region-end))
+    (list (point) (point))))
 
 
-;; Local Variables:
-;; byte-compile-warnings: (not cl-functions)
-;; End:
+(define-obsolete-function-alias
+  'notmuch-search-interactive-region
+  'notmuch-interactive-region
+  "notmuch 0.29")
+
+(provide 'notmuch-lib)
 
 ;;; notmuch-lib.el ends here
 
 ;;; notmuch-lib.el ends here