]> git.notmuchmail.org Git - notmuch/blobdiff - contrib/notmuch-pick/notmuch-pick.el
contrib: pick: update notmuch-show calls
[notmuch] / contrib / notmuch-pick / notmuch-pick.el
index 04e37ee59a1e5a15abbdba152909aabadcff0962..a492214d5b0a122864cdedd80c79d216fd123773 100644 (file)
   "Showing message and thread structure."
   :group 'notmuch)
 
-;; This is ugly. We can't run setup-show-out until it has been defined
-;; which needs the keymap to be defined. So we defer setting up to
-;; notmuch-pick-init.
 (defcustom notmuch-pick-show-out nil
   "View selected messages in new window rather than split-pane."
   :type 'boolean
-  :group 'notmuch-pick
-  :set (lambda (symbol value)
-        (set-default symbol value)
-        (when (fboundp 'notmuch-pick-setup-show-out)
-          (notmuch-pick-setup-show-out))))
+  :group 'notmuch-pick)
 
 (defcustom notmuch-pick-result-format
   `(("date" . "%12s  ")
     ("authors" . "%-20s")
-    ("subject" . " %-54s ")
+    ((("tree" . "%s")("subject" . "%s")) ." %-54s ")
     ("tags" . "(%s)"))
   "Result formatting for Pick. Supported fields are: date,
-        authors, subject, tags Note: subject includes the tree
-        structure graphics, and the author string should not
-        contain whitespace (put it in the neighbouring fields
-        instead).  For example:
+        authors, subject, tree, tags.  Tree means the thread tree
+        box graphics. The field may also be a list in which case
+        the formatting rules are applied recursively and then the
+        output of all the fields in the list is inserted
+        according to format-string.
+
+Note the author string should not contain
+        whitespace (put it in the neighbouring fields instead).
+        For example:
         (setq notmuch-pick-result-format \(\(\"authors\" . \"%-40s\"\)
                                              \(\"subject\" . \"%s\"\)\)\)"
   :type '(alist :key-type (string) :value-type (string))
   :group 'notmuch-pick)
 
-(defcustom notmuch-pick-asynchronous-parser t
-  "Use the asynchronous parser."
-  :type 'boolean
-  :group 'notmuch-pick)
-
 ;; Faces for messages that match the query.
 (defface notmuch-pick-match-date-face
   '((t :inherit default))
   :group 'notmuch-pick
   :group 'notmuch-faces)
 
+(defface notmuch-pick-match-tree-face
+  '((t :inherit default))
+  "Face used in pick mode for the thread tree block graphics in messages matching the query."
+  :group 'notmuch-pick
+  :group 'notmuch-faces)
+
 (defface notmuch-pick-match-tag-face
   '((((class color)
       (background dark))
   :group 'notmuch-pick
   :group 'notmuch-faces)
 
+(defface notmuch-pick-no-match-tree-face
+  '((t (:foreground "gray")))
+  "Face used in pick mode for the thread tree block graphics in messages matching the query."
+  :group 'notmuch-pick
+  :group 'notmuch-faces)
+
 (defface notmuch-pick-no-match-author-face
   '((t (:foreground "gray")))
   "Face used in pick mode for the date in messages matching the query."
   "A buffer local copy of argument open-target to the function notmuch-pick")
 (make-variable-buffer-local 'notmuch-pick-open-target)
 
-(defvar notmuch-pick-buffer-name nil
-  "A buffer local copy of argument buffer-name to the function notmuch-pick")
-(make-variable-buffer-local 'notmuch-pick-buffer-name)
-
 (defvar notmuch-pick-message-window nil
   "The window of the message pane.
 
@@ -187,47 +188,92 @@ if the user has loaded a different buffer in that window.")
 (make-variable-buffer-local 'notmuch-pick-message-buffer)
 (put 'notmuch-pick-message-buffer 'permanent-local t)
 
+(defun notmuch-pick-to-message-pane (func)
+  "Execute FUNC in message pane.
+
+This function returns a function (so can be used as a keybinding)
+which executes function FUNC in the message pane if it is
+open (if the message pane is closed it does nothing)."
+  `(lambda ()
+      ,(concat "(In message pane) " (documentation func t))
+     (interactive)
+     (when (window-live-p notmuch-pick-message-window)
+       (with-selected-window notmuch-pick-message-window
+        (call-interactively #',func)))))
+
+(defun notmuch-pick-button-activate (&optional button)
+  "Activate BUTTON or button at point
+
+This function does not give an error if there is no button."
+  (interactive)
+  (let ((button (or button (button-at (point)))))
+    (when button (button-activate button))))
+
+(defun notmuch-pick-close-message-pane-and (func)
+  "Close message pane and execute FUNC.
+
+This function returns a function (so can be used as a keybinding)
+which closes the message pane if open and then executes function
+FUNC."
+  `(lambda ()
+      ,(concat "(Close message pane and) " (documentation func t))
+     (interactive)
+     (notmuch-pick-close-message-window)
+     (call-interactively #',func)))
+
 (defvar notmuch-pick-mode-map
   (let ((map (make-sparse-keymap)))
-    (define-key map [mouse-1] 'notmuch-pick-show-message)
+    (set-keymap-parent map notmuch-common-keymap)
+    ;; The following override the global keymap.
+    ;; Override because we want to close message pane first.
+    (define-key map "?" (notmuch-pick-close-message-pane-and #'notmuch-help))
+    ;; Override because we first close message pane and then close pick buffer.
     (define-key map "q" 'notmuch-pick-quit)
+    ;; Override because we close message pane after the search query is entered.
+    (define-key map "s" 'notmuch-pick-to-search)
+    ;; Override because we want to close message pane first.
+    (define-key map "m" (notmuch-pick-close-message-pane-and #'notmuch-mua-new-mail))
+
+    ;; these use notmuch-show functions directly
+    (define-key map "|" 'notmuch-show-pipe-message)
+    (define-key map "w" 'notmuch-show-save-attachments)
+    (define-key map "v" 'notmuch-show-view-all-mime-parts)
+    (define-key map "c" 'notmuch-show-stash-map)
+
+    ;; these apply to the message pane
+    (define-key map (kbd "M-TAB") (notmuch-pick-to-message-pane #'notmuch-show-previous-button))
+    (define-key map (kbd "<backtab>")  (notmuch-pick-to-message-pane #'notmuch-show-previous-button))
+    (define-key map (kbd "TAB") (notmuch-pick-to-message-pane #'notmuch-show-next-button))
+    (define-key map "e" (notmuch-pick-to-message-pane #'notmuch-pick-button-activate))
+
+    ;; bindings from show (or elsewhere) but we close the message pane first.
+    (define-key map "f" (notmuch-pick-close-message-pane-and #'notmuch-show-forward-message))
+    (define-key map "r" (notmuch-pick-close-message-pane-and #'notmuch-show-reply-sender))
+    (define-key map "R" (notmuch-pick-close-message-pane-and #'notmuch-show-reply))
+    (define-key map "V" (notmuch-pick-close-message-pane-and #'notmuch-show-view-raw-message))
+
+    ;; The main pick bindings
+    (define-key map (kbd "RET") 'notmuch-pick-show-message)
+    (define-key map [mouse-1] 'notmuch-pick-show-message)
     (define-key map "x" 'notmuch-pick-quit)
-    (define-key map "?" 'notmuch-help)
+    (define-key map "A" 'notmuch-pick-archive-thread)
     (define-key map "a" 'notmuch-pick-archive-message-then-next)
     (define-key map "=" 'notmuch-pick-refresh-view)
-    (define-key map "s" 'notmuch-pick-to-search)
     (define-key map "z" 'notmuch-pick-to-pick)
-    (define-key map "m" 'notmuch-pick-new-mail)
-    (define-key map "f" 'notmuch-pick-forward-message)
-    (define-key map "r" 'notmuch-pick-reply-sender)
-    (define-key map "R" 'notmuch-pick-reply)
     (define-key map "n" 'notmuch-pick-next-matching-message)
     (define-key map "p" 'notmuch-pick-prev-matching-message)
     (define-key map "N" 'notmuch-pick-next-message)
     (define-key map "P" 'notmuch-pick-prev-message)
-    (define-key map "|" 'notmuch-pick-pipe-message)
+    (define-key map (kbd "M-p") 'notmuch-pick-prev-thread)
+    (define-key map (kbd "M-n") 'notmuch-pick-next-thread)
     (define-key map "-" 'notmuch-pick-remove-tag)
     (define-key map "+" 'notmuch-pick-add-tag)
+    (define-key map "*" 'notmuch-pick-tag-thread)
     (define-key map " " 'notmuch-pick-scroll-or-next)
     (define-key map "b" 'notmuch-pick-scroll-message-window-back)
     map))
 (fset 'notmuch-pick-mode-map notmuch-pick-mode-map)
 
-(defun notmuch-pick-setup-show-out ()
-  "Set up the keymap for showing a thread
-
-This uses the value of the defcustom notmuch-pick-show-out to
-decide whether to show a message in the message pane or in the
-whole window."
-  (let ((map notmuch-pick-mode-map))
-    (if notmuch-pick-show-out
-       (progn
-         (define-key map (kbd "M-RET") 'notmuch-pick-show-message)
-         (define-key map (kbd "RET") 'notmuch-pick-show-message-out))
-      (progn
-       (define-key map (kbd "RET") 'notmuch-pick-show-message)
-       (define-key map (kbd "M-RET") 'notmuch-pick-show-message-out)))))
-
 (defun notmuch-pick-get-message-properties ()
   "Return the properties of the current message as a plist.
 
@@ -361,17 +407,6 @@ Does NOT change the database."
     (notmuch-pick-close-message-window)
     (notmuch-pick query)))
 
-;; This function should be in notmuch-hello.el but we are trying to
-;; minimise impact on the rest of the codebase.
-(defun notmuch-pick-from-hello (&optional search)
-  "Run a query and display results in experimental notmuch-pick mode"
-  (interactive)
-  (unless (null search)
-    (setq search (notmuch-hello-trim search))
-    (let ((history-delete-duplicates t))
-      (add-to-history 'notmuch-search-history search)))
-  (notmuch-pick search))
-
 ;; This function should be in notmuch-show.el but be we trying to
 ;; minimise impact on the rest of the codebase.
 (defun notmuch-pick-from-show-current-query ()
@@ -410,7 +445,7 @@ Does NOT change the database."
       (ignore-errors
        (delete-window notmuch-pick-message-window)))))
 
-(defun notmuch-pick-show-message ()
+(defun notmuch-pick-show-message-in ()
   "Show the current message (in split-pane)."
   (interactive)
   (let ((id (notmuch-pick-get-message-id))
@@ -426,7 +461,7 @@ Does NOT change the database."
        ;; Since we are only displaying one message do not indent.
        (let ((notmuch-show-indent-messages-width 0)
              (notmuch-show-only-matching-messages t))
-         (setq buffer (notmuch-show id nil nil nil))))
+         (setq buffer (notmuch-show id))))
       ;; We need the `let' as notmuch-pick-message-window is buffer local.
       (let ((window notmuch-pick-message-window))
        (with-current-buffer buffer
@@ -445,7 +480,18 @@ Does NOT change the database."
     (when id
       ;; We close the window to kill off un-needed buffers.
       (notmuch-pick-close-message-window)
-      (notmuch-show id nil nil nil))))
+      (notmuch-show id))))
+
+(defun notmuch-pick-show-message (arg)
+  "Show the current message.
+
+Shows in split pane or whole window according to value of
+`notmuch-pick-show-out'. A prefix argument reverses the choice."
+  (interactive "P")
+  (if (or (and notmuch-pick-show-out  (not arg))
+         (and (not notmuch-pick-show-out) arg))
+      (notmuch-pick-show-message-out)
+    (notmuch-pick-show-message-in)))
 
 (defun notmuch-pick-scroll-message-window ()
   "Scroll the message window (if it exists)"
@@ -510,14 +556,14 @@ message will be \"unarchived\", i.e. the tag changes in
   (interactive)
   (forward-line)
   (when (window-live-p notmuch-pick-message-window)
-    (notmuch-pick-show-message)))
+    (notmuch-pick-show-message-in)))
 
 (defun notmuch-pick-prev-message ()
   "Move to previous message."
   (interactive)
   (forward-line -1)
   (when (window-live-p notmuch-pick-message-window)
-    (notmuch-pick-show-message)))
+    (notmuch-pick-show-message-in)))
 
 (defun notmuch-pick-prev-matching-message ()
   "Move to previous matching message."
@@ -526,7 +572,7 @@ message will be \"unarchived\", i.e. the tag changes in
   (while (and (not (bobp)) (not (notmuch-pick-get-match)))
     (forward-line -1))
   (when (window-live-p notmuch-pick-message-window)
-    (notmuch-pick-show-message)))
+    (notmuch-pick-show-message-in)))
 
 (defun notmuch-pick-next-matching-message ()
   "Move to next matching message."
@@ -535,7 +581,7 @@ message will be \"unarchived\", i.e. the tag changes in
   (while (and (not (eobp)) (not (notmuch-pick-get-match)))
     (forward-line))
   (when (window-live-p notmuch-pick-message-window)
-    (notmuch-pick-show-message)))
+    (notmuch-pick-show-message-in)))
 
 (defun notmuch-pick-refresh-view ()
   "Refresh view."
@@ -543,76 +589,70 @@ message will be \"unarchived\", i.e. the tag changes in
   (let ((inhibit-read-only t)
        (basic-query notmuch-pick-basic-query)
        (query-context notmuch-pick-query-context)
-       (target (notmuch-pick-get-message-id))
-       (buffer-name notmuch-pick-buffer-name))
+       (target (notmuch-pick-get-message-id)))
     (erase-buffer)
     (notmuch-pick-worker basic-query
                         query-context
-                        target
-                        (get-buffer buffer-name))))
-
-(defmacro with-current-notmuch-pick-message (&rest body)
-  "Evaluate body with current buffer set to the text of current message"
-  `(save-excursion
-     (let ((id (notmuch-pick-get-message-id)))
-       (let ((buf (generate-new-buffer (concat "*notmuch-msg-" id "*"))))
-         (with-current-buffer buf
-           (call-process notmuch-command nil t nil "show" "--format=raw" id)
-           ,@body)
-        (kill-buffer buf)))))
-
-(defun notmuch-pick-new-mail (&optional prompt-for-sender)
-  "Compose new mail."
-  (interactive "P")
-  (notmuch-pick-close-message-window)
-  (notmuch-mua-new-mail prompt-for-sender ))
+                        target)))
 
-(defun notmuch-pick-forward-message (&optional prompt-for-sender)
-  "Forward the current message."
-  (interactive "P")
-  (notmuch-pick-close-message-window)
-  (with-current-notmuch-pick-message
-   (notmuch-mua-new-forward-message prompt-for-sender)))
+(defun notmuch-pick-thread-top ()
+  (when (notmuch-pick-get-message-properties)
+    (while (not (or (notmuch-pick-get-prop :first) (eobp)))
+      (forward-line -1))))
 
-(defun notmuch-pick-reply (&optional prompt-for-sender)
-  "Reply to the sender and all recipients of the current message."
-  (interactive "P")
-  (notmuch-pick-close-message-window)
-  (notmuch-mua-new-reply (notmuch-pick-get-message-id) prompt-for-sender t))
+(defun notmuch-pick-prev-thread ()
+  (interactive)
+  (forward-line -1)
+  (notmuch-pick-thread-top))
 
-(defun notmuch-pick-reply-sender (&optional prompt-for-sender)
-  "Reply to the sender of the current message."
+(defun notmuch-pick-next-thread ()
+  (interactive)
+  (forward-line 1)
+  (while (not (or (notmuch-pick-get-prop :first) (eobp)))
+    (forward-line 1)))
+
+(defun notmuch-pick-thread-mapcar (function)
+  "Iterate through all messages in the current thread
+ and call FUNCTION for side effects."
+  (save-excursion
+    (notmuch-pick-thread-top)
+    (loop collect (funcall function)
+         do (forward-line)
+         while (and (notmuch-pick-get-message-properties)
+                    (not (notmuch-pick-get-prop :first))))))
+
+(defun notmuch-pick-get-messages-ids-thread-search ()
+  "Return a search string for all message ids of messages in the current thread."
+  (mapconcat 'identity
+            (notmuch-pick-thread-mapcar 'notmuch-pick-get-message-id)
+            " or "))
+
+(defun notmuch-pick-tag-thread (&optional tag-changes)
+  "Tag all messages in the current thread"
+  (interactive)
+  (when (notmuch-pick-get-message-properties)
+    (let ((tag-changes (notmuch-tag (notmuch-pick-get-messages-ids-thread-search) tag-changes)))
+      (notmuch-pick-thread-mapcar
+       (lambda () (notmuch-pick-tag-update-display tag-changes))))))
+
+(defun notmuch-pick-archive-thread (&optional unarchive)
+  "Archive each message in thread.
+
+Archive each message currently shown by applying the tag changes
+in `notmuch-archive-tags' to each. If a prefix argument is given,
+the messages will be \"unarchived\", i.e. the tag changes in
+`notmuch-archive-tags' will be reversed.
+
+Note: This command is safe from any race condition of new messages
+being delivered to the same thread. It does not archive the
+entire thread, but only the messages shown in the current
+buffer."
   (interactive "P")
-  (notmuch-pick-close-message-window)
-  (notmuch-mua-new-reply (notmuch-pick-get-message-id) prompt-for-sender nil))
-
-;; Shamelessly stolen from notmuch-show.el: maybe should be unified.
-(defun notmuch-pick-pipe-message (command)
-  "Pipe the contents of the current message to the given command.
-
-The given command will be executed with the raw contents of the
-current email message as stdin. Anything printed by the command
-to stdout or stderr will appear in the *notmuch-pipe* buffer.
-
-When invoked with a prefix argument, the command will receive all
-open messages in the current thread (formatted as an mbox) rather
-than only the current message."
-  (interactive "sPipe message to command: ")
-  (let ((shell-command
-        (concat notmuch-command " show --format=raw "
-                (shell-quote-argument (notmuch-pick-get-message-id)) " | " command))
-        (buf (get-buffer-create (concat "*notmuch-pipe*"))))
-    (with-current-buffer buf
-      (setq buffer-read-only nil)
-      (erase-buffer)
-      (let ((exit-code (call-process-shell-command shell-command nil buf)))
-       (goto-char (point-max))
-       (set-buffer-modified-p nil)
-       (setq buffer-read-only t)
-       (unless (zerop exit-code)
-         (switch-to-buffer-other-window buf)
-         (message (format "Command '%s' exited abnormally with code %d"
-                          shell-command exit-code)))))))
+  (when notmuch-archive-tags
+    (notmuch-pick-tag-thread
+     (notmuch-tag-change-list notmuch-archive-tags unarchive))))
+
+;; Functions below here display the pick buffer itself.
 
 (defun notmuch-pick-clean-address (address)
   "Try to clean a single email ADDRESS for display. Return
@@ -625,31 +665,43 @@ unchanged ADDRESS if parsing fails."
     ;; If we have a name return that otherwise return the address.
     (or p-name p-address)))
 
-(defun notmuch-pick-insert-field (field format-string msg)
+(defun notmuch-pick-format-field (field format-string msg)
+  "Format a FIELD of MSG according to FORMAT-STRING and return string"
   (let* ((headers (plist-get msg :headers))
-       (match (plist-get msg :match)))
+        (match (plist-get msg :match)))
     (cond
+     ((listp field)
+      (format format-string (notmuch-pick-format-field-list field msg)))
+
      ((string-equal field "date")
       (let ((face (if match
                      'notmuch-pick-match-date-face
                    'notmuch-pick-no-match-date-face)))
-       (insert (propertize (format format-string (plist-get msg :date_relative))
-                           'face face))))
+       (propertize (format format-string (plist-get msg :date_relative)) 'face face)))
 
-     ((string-equal field "subject")
+     ((string-equal field "tree")
       (let ((tree-status (plist-get msg :tree-status))
-           (bare-subject (notmuch-show-strip-re (plist-get headers :Subject)))
+           (face (if match
+                     'notmuch-pick-match-tree-face
+                   'notmuch-pick-no-match-tree-face)))
+
+       (propertize (format format-string
+                           (mapconcat #'identity (reverse tree-status) ""))
+                   'face face)))
+
+     ((string-equal field "subject")
+      (let ((bare-subject (notmuch-show-strip-re (plist-get headers :Subject)))
+           (previous-subject notmuch-pick-previous-subject)
            (face (if match
                      'notmuch-pick-match-subject-face
                    'notmuch-pick-no-match-subject-face)))
-       (insert (propertize (format format-string
-                                   (concat
-                                    (mapconcat #'identity (reverse tree-status) "")
-                                    (if (string= notmuch-pick-previous-subject bare-subject)
-                                        " ..."
-                                      bare-subject)))
-                           'face face))
-       (setq notmuch-pick-previous-subject bare-subject)))
+
+       (setq notmuch-pick-previous-subject bare-subject)
+       (propertize (format format-string
+                           (if (string= previous-subject bare-subject)
+                               " ..."
+                             bare-subject))
+                   'face face)))
 
      ((string-equal field "authors")
       (let ((author (notmuch-pick-clean-address (plist-get headers :From)))
@@ -659,26 +711,31 @@ unchanged ADDRESS if parsing fails."
                    'notmuch-pick-no-match-author-face)))
        (when (> (length author) len)
          (setq author (substring author 0 len)))
-       (insert (propertize (format format-string author)
-                           'face face))))
+       (propertize (format format-string author) 'face face)))
 
      ((string-equal field "tags")
       (let ((tags (plist-get msg :tags))
            (face (if match
-                         'notmuch-pick-match-tag-face
-                       'notmuch-pick-no-match-tag-face)))
-       (when tags
-         (insert (propertize (format format-string
-                                     (mapconcat #'identity tags ", "))
-                             'face face))))))))
+                     'notmuch-pick-match-tag-face
+                   'notmuch-pick-no-match-tag-face)))
+       (propertize (format format-string
+                           (mapconcat #'identity tags ", "))
+                   'face face))))))
+
+
+(defun notmuch-pick-format-field-list (field-list msg)
+  "Format fields of MSG according to FIELD-LIST and return string"
+  (let (result-string)
+    (dolist (spec field-list result-string)
+      (let ((field-string (notmuch-pick-format-field (car spec) (cdr spec) msg)))
+       (setq result-string (concat result-string field-string))))))
 
 (defun notmuch-pick-insert-msg (msg)
   "Insert the message MSG according to notmuch-pick-result-format"
   ;; We need to save the previous subject as it will get overwritten
   ;; by the insert-field calls.
   (let ((previous-subject notmuch-pick-previous-subject))
-    (dolist (spec notmuch-pick-result-format)
-      (notmuch-pick-insert-field (car spec) (cdr spec) msg))
+    (insert (notmuch-pick-format-field-list notmuch-pick-result-format msg))
     (notmuch-pick-set-message-properties msg)
     (notmuch-pick-set-prop :previous-subject previous-subject)
     (insert "\n")))
@@ -696,7 +753,7 @@ unchanged ADDRESS if parsing fails."
       (goto-char (point-max))
       (forward-line -1)
       (when notmuch-pick-open-target
-       (notmuch-pick-show-message)))))
+       (notmuch-pick-show-message-in)))))
 
 (defun notmuch-pick-insert-tree (tree depth tree-status first last)
   "Insert the message tree TREE at depth DEPTH in the current thread.
@@ -722,6 +779,7 @@ message together with all its descendents."
        (push "├" tree-status)))
 
       (push (concat (if replies "┬" "─") "►") tree-status)
+      (plist-put msg :first (and first (eq 0 depth)))
       (notmuch-pick-goto-and-insert-msg (plist-put msg :tree-status tree-status))
       (pop tree-status)
       (pop tree-status)
@@ -770,6 +828,7 @@ Complete list of currently available key bindings:
 
   (interactive)
   (kill-all-local-variables)
+  (setq notmuch-buffer-refresh-function #'notmuch-pick-refresh-view)
   (use-local-map notmuch-pick-mode-map)
   (setq major-mode 'notmuch-pick-mode
        mode-name "notmuch-pick")
@@ -815,12 +874,15 @@ Complete list of currently available key bindings:
        (notmuch-sexp-parse-partial-list 'notmuch-pick-insert-forest-thread
                                         results-buf)))))
 
-(defun notmuch-pick-worker (basic-query &optional query-context target buffer open-target)
+(defun notmuch-pick-worker (basic-query &optional query-context target open-target)
+  "Insert the actual pick search in the current buffer.
+
+This is is a helper function for notmuch-pick. The arguments are
+the same as for the function notmuch-pick."
   (interactive)
   (notmuch-pick-mode)
   (setq notmuch-pick-basic-query basic-query)
   (setq notmuch-pick-query-context query-context)
-  (setq notmuch-pick-buffer-name (buffer-name buffer))
   (setq notmuch-pick-target-msg target)
   (setq notmuch-pick-open-target open-target)
 
@@ -832,26 +894,17 @@ Complete list of currently available key bindings:
         (message-arg "--entire-thread"))
     (if (equal (car (process-lines notmuch-command "count" search-args)) "0")
        (setq search-args basic-query))
-    (if notmuch-pick-asynchronous-parser
-       (let ((proc (notmuch-start-notmuch
-                    "notmuch-pick" buffer #'notmuch-pick-process-sentinel
-                    "show" "--body=false" "--format=sexp"
-                    message-arg search-args))
-             ;; Use a scratch buffer to accumulate partial output.
-              ;; This buffer will be killed by the sentinel, which
-              ;; should be called no matter how the process dies.
-              (parse-buf (generate-new-buffer " *notmuch pick parse*")))
-          (process-put proc 'parse-buf parse-buf)
-         (set-process-filter proc 'notmuch-pick-process-filter)
-         (set-process-query-on-exit-flag proc nil))
-      (progn
-       (notmuch-pick-insert-forest
-        (notmuch-query-get-threads
-         (list "--body=false" message-arg search-args)))
-       (save-excursion
-         (goto-char (point-max))
-         (insert "End of search results.\n"))))))
-
+    (let ((proc (notmuch-start-notmuch
+                "notmuch-pick" (current-buffer) #'notmuch-pick-process-sentinel
+                "show" "--body=false" "--format=sexp"
+                message-arg search-args))
+         ;; Use a scratch buffer to accumulate partial output.
+         ;; This buffer will be killed by the sentinel, which
+         ;; should be called no matter how the process dies.
+         (parse-buf (generate-new-buffer " *notmuch pick parse*")))
+      (process-put proc 'parse-buf parse-buf)
+      (set-process-filter proc 'notmuch-pick-process-filter)
+      (set-process-query-on-exit-flag proc nil))))
 
 (defun notmuch-pick (&optional query query-context target buffer-name open-target)
   "Run notmuch pick with the given `query' and display the results.
@@ -867,7 +920,7 @@ The arguments are:
   BUFFER-NAME: the name of the buffer to show the pick tree. If
       it is nil \"*notmuch-pick\" followed by QUERY is used.
   OPEN-TARGET: If TRUE open the target message in the message pane."
-  (interactive "sNotmuch pick: ")
+  (interactive)
   (if (null query)
       (setq query (notmuch-read-query "Notmuch pick: ")))
   (let ((buffer (get-buffer-create (generate-new-buffer-name
@@ -875,23 +928,19 @@ The arguments are:
                                        (concat "*notmuch-pick-" query "*")))))
        (inhibit-read-only t))
 
-    (switch-to-buffer buffer)
-    ;; Don't track undo information for this buffer
-    (set 'buffer-undo-list t)
+    (switch-to-buffer buffer))
+  ;; Don't track undo information for this buffer
+  (set 'buffer-undo-list t)
 
-    (notmuch-pick-worker query query-context target buffer open-target)
+  (notmuch-pick-worker query query-context target open-target)
 
-    (setq truncate-lines t)))
+  (setq truncate-lines t))
 
 
 ;; Set up key bindings from the rest of notmuch.
-(define-key 'notmuch-search-mode-map "z" 'notmuch-pick)
-(define-key 'notmuch-search-mode-map "Z" 'notmuch-pick-from-search-current-query)
-(define-key 'notmuch-search-mode-map (kbd "M-RET") 'notmuch-pick-from-search-thread)
-(define-key 'notmuch-hello-mode-map "z" 'notmuch-pick-from-hello)
-(define-key 'notmuch-show-mode-map "z" 'notmuch-pick)
-(define-key 'notmuch-show-mode-map "Z" 'notmuch-pick-from-show-current-query)
-(notmuch-pick-setup-show-out)
+(define-key notmuch-common-keymap "z" 'notmuch-pick)
+(define-key notmuch-search-mode-map "Z" 'notmuch-pick-from-search-current-query)
+(define-key notmuch-show-mode-map "Z" 'notmuch-pick-from-show-current-query)
 (message "Initialised notmuch-pick")
 
 (provide 'notmuch-pick)