-;;; notmuch-tree.el --- displaying notmuch forests.
+;;; notmuch-tree.el --- displaying notmuch forests
;;
;; Copyright © Carl Worth
;; Copyright © David Edmondson
(require 'notmuch-show)
(require 'notmuch-tag)
(require 'notmuch-parser)
+(require 'notmuch-jump)
(declare-function notmuch-search "notmuch"
(&optional query oldest-first target-thread target-line))
"A buffer local copy of argument open-target to the function notmuch-tree.")
(make-variable-buffer-local 'notmuch-tree-open-target)
+(defvar notmuch-tree-parent-buffer nil)
+(make-variable-buffer-local 'notmuch-tree-parent-buffer)
+
(defvar notmuch-tree-message-window nil
"The window of the message pane.
(define-key map [mouse-1] 'notmuch-tree-show-message)
(define-key map "x" 'notmuch-tree-archive-message-then-next-or-exit)
(define-key map "X" 'notmuch-tree-archive-thread-then-exit)
- (define-key map "A" 'notmuch-tree-archive-thread)
+ (define-key map "A" 'notmuch-tree-archive-thread-then-next)
(define-key map "a" 'notmuch-tree-archive-message-then-next)
(define-key map "z" 'notmuch-tree-to-tree)
(define-key map "n" 'notmuch-tree-next-matching-message)
(notmuch-tree-close-message-window)
(notmuch-tree query)))
+(defun notmuch-tree-archive-thread-then-next ()
+ "Archive all messages in the current buffer, then show next thread from search."
+ (interactive)
+ (notmuch-tree-archive-thread)
+ (notmuch-tree-next-thread))
+
(defun notmuch-unthreaded-from-tree-current-query ()
"Switch from tree view to unthreaded view."
(interactive)
(setq notmuch-tree-message-window
(split-window-vertically (/ (window-height) 4)))
(with-selected-window notmuch-tree-message-window
- ;; Since we are only displaying one message do not indent.
- (let ((notmuch-show-indent-messages-width 0)
- (notmuch-show-only-matching-messages t))
+ (let (;; Since we are only displaying one message do not indent.
+ (notmuch-show-indent-messages-width 0)
+ (notmuch-show-only-matching-messages t)
+ ;; Ensure that `pop-to-buffer-same-window' uses the
+ ;; window we want it to use.
+ (display-buffer-overriding-action
+ '((display-buffer-same-window)
+ (inhibit-same-window . nil))))
(setq buffer (notmuch-show id))))
;; We need the `let' as notmuch-tree-message-window is buffer local.
(let ((window notmuch-tree-message-window))
(scroll-up)))))
(defun notmuch-tree-scroll-message-window-back ()
- "Scroll the message window back(if it exists)."
+ "Scroll the message window back (if it exists)."
(interactive)
(when (window-live-p notmuch-tree-message-window)
(with-selected-window notmuch-tree-message-window
(scroll-down)))))
(defun notmuch-tree-scroll-or-next ()
- "Scroll the message window. If it at end go to next message."
+ "Scroll the message window.
+If it at end go to next message."
(interactive)
(when (notmuch-tree-scroll-message-window)
(notmuch-tree-next-matching-message)))
(while (not (or (notmuch-tree-get-prop :first) (eobp)))
(forward-line -1))))
-(defun notmuch-tree-prev-thread ()
+(defun notmuch-tree-prev-thread-in-tree ()
+ "Move to the previous thread in the current tree"
(interactive)
(forward-line -1)
- (notmuch-tree-thread-top))
+ (notmuch-tree-thread-top)
+ (not (bobp)))
-(defun notmuch-tree-next-thread ()
+(defun notmuch-tree-next-thread-in-tree ()
"Get the next thread in the current tree. Returns t if a thread was
found or nil if not."
(interactive)
(forward-line 1))
(not (eobp)))
+(defun notmuch-tree-next-thread-from-search (&optional previous)
+ "Move to the next thread in the parent search results, if any.
+
+If PREVIOUS is non-nil, move to the previous item in the
+search results instead."
+ (interactive "P")
+ (let ((parent-buffer notmuch-tree-parent-buffer))
+ (notmuch-tree-quit t)
+ (when (buffer-live-p parent-buffer)
+ (switch-to-buffer parent-buffer)
+ (if previous
+ (notmuch-search-previous-thread)
+ (notmuch-search-next-thread))
+ (notmuch-tree-from-search-thread))))
+
+(defun notmuch-tree-next-thread (&optional previous)
+ "Move to the next thread in the current tree or parent search
+results
+
+If PREVIOUS is non-nil, move to the previous thread in the tree or
+search results instead."
+ (interactive)
+ (unless (if previous (notmuch-tree-prev-thread-in-tree)
+ (notmuch-tree-next-thread-in-tree))
+ (notmuch-tree-next-thread-from-search previous)))
+
+(defun notmuch-tree-prev-thread ()
+ "Move to the previous thread in the current tree or parent search
+results"
+ (interactive)
+ (notmuch-tree-next-thread t))
+
(defun notmuch-tree-thread-mapcar (function)
"Iterate through all messages in the current thread
and call FUNCTION for side effects."
(never-found-target-thread nil))
(when (memq status '(exit signal))
(kill-buffer (process-get proc 'parse-buf))
- (if (buffer-live-p buffer)
- (with-current-buffer buffer
- (save-excursion
- (let ((inhibit-read-only t)
- (atbob (bobp)))
- (goto-char (point-max))
- (if (eq status 'signal)
- (insert "Incomplete search results (tree view process was killed).\n"))
- (when (eq status 'exit)
- (insert "End of search results.")
- (unless (= exit-status 0)
- (insert (format " (process returned %d)" exit-status)))
- (insert "\n")))))))))
+ (when (buffer-live-p buffer)
+ (with-current-buffer buffer
+ (save-excursion
+ (let ((inhibit-read-only t)
+ (atbob (bobp)))
+ (goto-char (point-max))
+ (when (eq status 'signal)
+ (insert "Incomplete search results (tree view process was killed).\n"))
+ (when (eq status 'exit)
+ (insert "End of search results.")
+ (unless (= exit-status 0)
+ (insert (format " (process returned %d)" exit-status)))
+ (insert "\n")))))))))
(defun notmuch-tree-process-filter (proc string)
"Process and filter the output of \"notmuch show\" for tree view."
(setq notmuch-tree-basic-query basic-query)
(setq notmuch-tree-query-context (if (or (string= query-context "")
(string= query-context "*"))
- nil query-context))
+ nil
+ query-context))
(setq notmuch-tree-target-msg target)
(setq notmuch-tree-open-target open-target)
;; Set the default value for `notmuch-show-process-crypto' in this
(erase-buffer)
(goto-char (point-min))
(let* ((search-args (concat basic-query
- (if query-context
- (concat " and (" query-context ")"))))
+ (and query-context
+ (concat " and (" query-context ")"))))
(message-arg (if unthreaded "--unthreaded" "--entire-thread")))
- (if (equal (car (process-lines notmuch-command "count" search-args)) "0")
- (setq search-args basic-query))
+ (when (equal (car (process-lines notmuch-command "count" search-args)) "0")
+ (setq search-args basic-query))
(notmuch-tag-clear-cache)
(let ((proc (notmuch-start-notmuch
"notmuch-tree" (current-buffer) #'notmuch-tree-process-sentinel
")")
notmuch-tree-basic-query))
-(defun notmuch-tree (&optional query query-context target buffer-name open-target unthreaded)
+(defun notmuch-tree (&optional query query-context target buffer-name open-target unthreaded parent-buffer)
"Display threads matching QUERY in tree view.
The arguments are:
OPEN-TARGET: If TRUE open the target message in the message pane.
UNTHREADED: If TRUE only show matching messages in an unthreaded view."
(interactive)
- (if (null query)
- (setq query (notmuch-read-query (concat "Notmuch "
- (if unthreaded "unthreaded " "tree ")
- "view search: "))))
+ (unless query
+ (setq query (notmuch-read-query (concat "Notmuch "
+ (if unthreaded "unthreaded " "tree ")
+ "view search: "))))
(let ((buffer (get-buffer-create (generate-new-buffer-name
(or buffer-name
(concat "*notmuch-"
(if unthreaded "unthreaded-" "tree-")
query "*")))))
(inhibit-read-only t))
- (switch-to-buffer buffer))
+ (pop-to-buffer-same-window buffer))
;; Don't track undo information for this buffer
(set 'buffer-undo-list t)
(notmuch-tree-worker query query-context target open-target unthreaded)
+ (setq notmuch-tree-parent-buffer parent-buffer)
(setq truncate-lines t))
(defun notmuch-unthreaded (&optional query query-context target buffer-name open-target)