;;; Code:
+(eval-when-compile (require 'cl-lib))
+
(require 'mail-parse)
(require 'notmuch-lib)
(require 'notmuch-tag)
(require 'notmuch-parser)
-(eval-when-compile (require 'cl))
(declare-function notmuch-search "notmuch" (&optional query oldest-first target-thread target-line))
(declare-function notmuch-call-notmuch-process "notmuch" (&rest args))
(declare-function notmuch-read-query "notmuch" (prompt))
;; this variable distinguishes the unthreaded display from the normal tree display
(defvar notmuch-tree-unthreaded nil
- "A buffer local copy of argument unthreaded to the function notmuch-tree")
+ "A buffer local copy of argument unthreaded to the function notmuch-tree.")
(make-variable-buffer-local 'notmuch-tree-unthreaded)
(defgroup notmuch-tree nil
("authors" . "%-20s")
((("tree" . "%s")("subject" . "%s")) ." %-54s ")
("tags" . "(%s)"))
- "Result formatting for Tree view. Supported fields are: date,
- 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.
+ "Result formatting for tree view. Supported fields are: date,
+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:
+whitespace (put it in the neighbouring fields instead).
+For example:
(setq notmuch-tree-result-format \(\(\"authors\" . \"%-40s\"\)
- \(\"subject\" . \"%s\"\)\)\)"
+ \(\"subject\" . \"%s\"\)\)\)"
:type '(alist :key-type (string) :value-type (string))
:group 'notmuch-tree)
("authors" . "%-20s")
((("subject" . "%s")) ." %-54s ")
("tags" . "(%s)"))
- "Result formatting for unthreaded Tree view. Supported fields are: date,
- 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.
+ "Result formatting for unthreaded tree view. Supported fields are: date,
+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:
+whitespace (put it in the neighbouring fields instead).
+For example:
(setq notmuch-tree-result-format \(\(\"authors\" . \"%-40s\"\)
- \(\"subject\" . \"%s\"\)\)\)"
+ \(\"subject\" . \"%s\"\)\)\)"
:type '(alist :key-type (string) :value-type (string))
:group 'notmuch-tree)
;; Faces for messages that do not match the query.
(defface notmuch-tree-no-match-face
'((t (:foreground "gray")))
- "Default face used in tree mode face for non-matching messages"
+ "Default face used in tree mode face for non-matching messages."
:group 'notmuch-tree
:group 'notmuch-faces)
:group 'notmuch-faces)
(defvar notmuch-tree-previous-subject
- "The subject of the most recent result shown during the async display")
+ "The subject of the most recent result shown during the async display.")
(make-variable-buffer-local 'notmuch-tree-previous-subject)
(defvar notmuch-tree-basic-query nil
- "A buffer local copy of argument query to the function notmuch-tree")
+ "A buffer local copy of argument query to the function notmuch-tree.")
(make-variable-buffer-local 'notmuch-tree-basic-query)
(defvar notmuch-tree-query-context nil
- "A buffer local copy of argument query-context to the function notmuch-tree")
+ "A buffer local copy of argument query-context to the function notmuch-tree.")
(make-variable-buffer-local 'notmuch-tree-query-context)
(defvar notmuch-tree-target-msg nil
- "A buffer local copy of argument target to the function notmuch-tree")
+ "A buffer local copy of argument target to the function notmuch-tree.")
(make-variable-buffer-local 'notmuch-tree-target-msg)
(defvar notmuch-tree-open-target nil
- "A buffer local copy of argument open-target to the function notmuch-tree")
+ "A buffer local copy of argument open-target to the function notmuch-tree.")
(make-variable-buffer-local 'notmuch-tree-open-target)
(defvar notmuch-tree-message-window nil
(call-interactively #',func)))))
(defun notmuch-tree-inherit-from-message-pane (sym)
- "Return value of SYM in message-pane if open, or tree-pane if not"
+ "Return value of SYM in message-pane if open, or tree-pane if not."
(if (window-live-p notmuch-tree-message-window)
(with-selected-window notmuch-tree-message-window
(symbol-value sym))
(symbol-value sym)))
(defun notmuch-tree-button-activate (&optional button)
- "Activate BUTTON or button at point
+ "Activate BUTTON or button at point.
This function does not give an error if there is no button."
(interactive)
;; The main tree view bindings
(define-key map (kbd "RET") 'notmuch-tree-show-message)
(define-key map [mouse-1] 'notmuch-tree-show-message)
- (define-key map "x" 'notmuch-tree-quit)
+ (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-message-then-next)
(define-key map "z" 'notmuch-tree-to-tree)
Some useful entries are:
:headers - Property list containing the headers :Date, :Subject, :From, etc.
-:tags - Tags for this message"
+:tags - Tags for this message."
(save-excursion
(beginning-of-line)
(get-text-property (point) :notmuch-message-properties)))
(notmuch-show-update-tags new-tags)))))))
(defun notmuch-tree-tag (tag-changes)
- "Change tags for the current message"
+ "Change tags for the current message."
(interactive
(list (notmuch-read-tag-changes (notmuch-tree-get-tags) "Tag message")))
(notmuch-tag (notmuch-tree-get-message-id) tag-changes)
(notmuch-search query)))
(defun notmuch-tree-to-tree ()
- "Run a query and display results in Tree view"
+ "Run a query and display results in tree view."
(interactive)
(let ((query (notmuch-read-query "Notmuch tree view search: ")))
(notmuch-tree-close-message-window)
(notmuch-tree query)))
(defun notmuch-unthreaded-from-tree-current-query ()
- "Switch from tree view to unthreaded view"
+ "Switch from tree view to unthreaded view."
(interactive)
(unless notmuch-tree-unthreaded
(notmuch-tree-refresh-view 'unthreaded)))
(defun notmuch-tree-from-unthreaded-current-query ()
- "Switch from unthreaded view to tree view"
+ "Switch from unthreaded view to tree view."
(interactive)
(when notmuch-tree-unthreaded
(notmuch-tree-refresh-view 'tree)))
(defun notmuch-search-from-tree-current-query ()
- "Call notmuch search with the current query"
+ "Call notmuch search with the current query."
(interactive)
(notmuch-tree-close-message-window)
(notmuch-search (notmuch-tree-get-query)))
(notmuch-tree-show-message-in)))
(defun notmuch-tree-scroll-message-window ()
- "Scroll the message window (if it exists)"
+ "Scroll the message window (if it exists)."
(interactive)
(when (window-live-p notmuch-tree-message-window)
(with-selected-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
(when (notmuch-tree-scroll-message-window)
(notmuch-tree-next-matching-message)))
-(defun notmuch-tree-quit ()
+(defun notmuch-tree-quit (&optional kill-both)
"Close the split view or exit tree."
- (interactive)
- (unless (notmuch-tree-close-message-window)
+ (interactive "P")
+ (when (or (not (notmuch-tree-close-message-window)) kill-both)
(kill-buffer (current-buffer))))
(defun notmuch-tree-close-message-window ()
(notmuch-tree-archive-message unarchive)
(notmuch-tree-next-matching-message))
+(defun notmuch-tree-archive-thread-then-exit ()
+ "Archive all messages in the current buffer, then exit notmuch-tree."
+ (interactive)
+ (notmuch-tree-archive-thread)
+ (notmuch-tree-quit t))
+
+(defun notmuch-tree-archive-message-then-next-or-exit ()
+ "Archive current message, then show next open message in current thread.
+
+If at the last open message in the current thread, then exit back
+to search results."
+ (interactive)
+ (notmuch-tree-archive-message)
+ (notmuch-tree-next-matching-message t))
+
(defun notmuch-tree-next-message ()
"Move to next message."
(interactive)
(forward-line dir))
(not (funcall eobfn))))
-(defun notmuch-tree-matching-message (&optional prev)
- "Move to the next or previous matching message"
+(defun notmuch-tree-matching-message (&optional prev pop-at-end)
+ "Move to the next or previous matching message."
(interactive "P")
(forward-line (if prev -1 nil))
- (notmuch-tree-goto-matching-message prev)
- (when (window-live-p notmuch-tree-message-window)
- (notmuch-tree-show-message-in)))
+ (if (and (not (notmuch-tree-goto-matching-message prev)) pop-at-end)
+ (notmuch-tree-quit pop-at-end)
+ (when (window-live-p notmuch-tree-message-window)
+ (notmuch-tree-show-message-in))))
-(defun notmuch-tree-prev-matching-message ()
+(defun notmuch-tree-prev-matching-message (&optional pop-at-end)
"Move to previous matching message."
- (interactive)
- (notmuch-tree-matching-message t))
+ (interactive "P")
+ (notmuch-tree-matching-message t pop-at-end))
-(defun notmuch-tree-next-matching-message ()
+(defun notmuch-tree-next-matching-message (&optional pop-at-end)
"Move to next matching message."
- (interactive)
- (notmuch-tree-matching-message))
+ (interactive "P")
+ (notmuch-tree-matching-message nil pop-at-end))
(defun notmuch-tree-refresh-view (&optional view)
"Refresh view."
and call FUNCTION for side effects."
(save-excursion
(notmuch-tree-thread-top)
- (loop collect (funcall function)
- do (forward-line)
- while (and (notmuch-tree-get-message-properties)
- (not (notmuch-tree-get-prop :first))))))
+ (cl-loop collect (funcall function)
+ do (forward-line)
+ while (and (notmuch-tree-get-message-properties)
+ (not (notmuch-tree-get-prop :first))))))
(defun notmuch-tree-get-messages-ids-thread-search ()
"Return a search string for all message ids of messages in the current thread."
" or "))
(defun notmuch-tree-tag-thread (tag-changes)
- "Tag all messages in the current thread"
+ "Tag all messages in the current thread."
(interactive
(let ((tags (apply #'append (notmuch-tree-thread-mapcar
(lambda () (notmuch-tree-get-tags))))))
(or p-name p-address)))
(defun notmuch-tree-format-field (field format-string msg)
- "Format a FIELD of MSG according to FORMAT-STRING and return string"
+ "Format a FIELD of MSG according to FORMAT-STRING and return string."
(let* ((headers (plist-get msg :headers))
(match (plist-get msg :match)))
(cond
(format format-string (notmuch-tag-format-tags tags orig-tags face)))))))
(defun notmuch-tree-format-field-list (field-list msg)
- "Format fields of MSG according to FIELD-LIST and return string"
+ "Format fields of MSG according to FIELD-LIST and return string."
(let ((face (if (plist-get msg :match)
'notmuch-tree-match-face
'notmuch-tree-no-match-face))
(notmuch-apply-face result-string face t)))
(defun notmuch-tree-insert-msg (msg)
- "Insert the message MSG according to notmuch-tree-result-format"
+ "Insert the message MSG according to notmuch-tree-result-format."
;; We need to save the previous subject as it will get overwritten
;; by the insert-field calls.
(let ((previous-subject notmuch-tree-previous-subject))
(insert "\n")))
(defun notmuch-tree-goto-and-insert-msg (msg)
- "Insert msg at the end of the buffer. Move point to msg if it is the target"
+ "Insert msg at the end of the buffer. Move point to msg if it is the target."
(save-excursion
(goto-char (point-max))
(notmuch-tree-insert-msg msg))
(defun notmuch-tree-insert-thread (thread depth tree-status)
"Insert the collection of sibling sub-threads THREAD at depth DEPTH in the current forest."
(let ((n (length thread)))
- (loop for tree in thread
- for count from 1 to n
-
- do (notmuch-tree-insert-tree tree depth tree-status (eq count 1) (eq count n)))))
+ (cl-loop for tree in thread
+ for count from 1 to n
+ do (notmuch-tree-insert-tree tree depth tree-status
+ (eq count 1)
+ (eq count n)))))
(defun notmuch-tree-insert-forest-thread (forest-thread)
"Insert a single complete thread."
truncate-lines t))
(defun notmuch-tree-process-sentinel (proc msg)
- "Add a message to let user know when \"notmuch tree\" exits"
+ "Add a message to let user know when \"notmuch tree\" exits."
(let ((buffer (process-buffer proc))
(status (process-status proc))
(exit-status (process-exit-status proc))
(insert "\n")))))))))
(defun notmuch-tree-process-filter (proc string)
- "Process and filter the output of \"notmuch show\" for tree view"
+ "Process and filter the output of \"notmuch show\" for tree view."
(let ((results-buf (process-buffer proc))
(parse-buf (process-get proc 'parse-buf))
(inhibit-read-only t)
(set-process-query-on-exit-flag proc nil))))
(defun notmuch-tree-get-query ()
- "Return the current query in this tree buffer"
+ "Return the current query in this tree buffer."
(if notmuch-tree-query-context
(concat notmuch-tree-basic-query
" and ("
notmuch-tree-basic-query))
(defun notmuch-tree (&optional query query-context target buffer-name open-target unthreaded)
- "Display threads matching QUERY in Tree View.
+ "Display threads matching QUERY in tree view.
The arguments are:
QUERY: the main query. This can be any query but in many cases will be