]> git.notmuchmail.org Git - notmuch/blobdiff - emacs/notmuch-tree.el
python-cffi: enable out-of-tree builds
[notmuch] / emacs / notmuch-tree.el
index 895c05f48c9c9dccf36db58c0378daa15f9494f4..254664c4718bfa0affbeb48b4e76054f3db022fa 100644 (file)
@@ -24,6 +24,8 @@
 
 ;;; Code:
 
+(eval-when-compile (require 'cl-lib))
+
 (require 'mail-parse)
 
 (require 'notmuch-lib)
@@ -32,7 +34,6 @@
 (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))
@@ -294,6 +295,8 @@ FUNC."
     (define-key map [remap notmuch-jump-search] (notmuch-tree-close-message-pane-and #'notmuch-jump-search))
 
     (define-key map "S" 'notmuch-search-from-tree-current-query)
+    (define-key map "U" 'notmuch-unthreaded-from-tree-current-query)
+    (define-key map "Z" 'notmuch-tree-from-unthreaded-current-query)
 
     ;; these use notmuch-show functions directly
     (define-key map "|" 'notmuch-show-pipe-message)
@@ -317,7 +320,8 @@ FUNC."
     ;; 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)
@@ -474,6 +478,18 @@ NOT change the database."
     (notmuch-tree-close-message-window)
     (notmuch-tree query)))
 
+(defun notmuch-unthreaded-from-tree-current-query ()
+  "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"
+  (interactive)
+  (when notmuch-tree-unthreaded
+    (notmuch-tree-refresh-view 'tree)))
+
 (defun notmuch-search-from-tree-current-query ()
   "Call notmuch search with the current query"
   (interactive)
@@ -570,10 +586,10 @@ Shows in split pane or whole window according to value of
   (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 ()
@@ -603,6 +619,21 @@ message will be \"unarchived\", i.e. the tag changes in
   (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)
@@ -617,37 +648,55 @@ message will be \"unarchived\", i.e. the tag changes in
   (when (window-live-p notmuch-tree-message-window)
     (notmuch-tree-show-message-in)))
 
-(defun notmuch-tree-prev-matching-message ()
+(defun notmuch-tree-goto-matching-message (&optional prev)
+  "Move to the next or previous matching message.
+
+Returns t if there was a next matching message in the thread to show,
+nil otherwise."
+  (let ((dir (if prev -1 nil))
+       (eobfn (if prev #'bobp #'eobp)))
+    (while (and (not (funcall eobfn))
+               (not (notmuch-tree-get-match)))
+      (forward-line dir))
+    (not (funcall eobfn))))
+
+(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))
+  (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 (&optional pop-at-end)
   "Move to previous matching message."
-  (interactive)
-  (forward-line -1)
-  (while (and (not (bobp)) (not (notmuch-tree-get-match)))
-    (forward-line -1))
-  (when (window-live-p notmuch-tree-message-window)
-    (notmuch-tree-show-message-in)))
+  (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)
-  (forward-line)
-  (while (and (not (eobp)) (not (notmuch-tree-get-match)))
-    (forward-line))
-  (when (window-live-p notmuch-tree-message-window)
-    (notmuch-tree-show-message-in)))
+  (interactive "P")
+  (notmuch-tree-matching-message nil pop-at-end))
 
-(defun notmuch-tree-refresh-view ()
+(defun notmuch-tree-refresh-view (&optional view)
   "Refresh view."
   (interactive)
   (when (get-buffer-process (current-buffer))
     (error "notmuch tree process already running for current buffer"))
   (let ((inhibit-read-only t)
        (basic-query notmuch-tree-basic-query)
+       (unthreaded (cond ((eq view 'unthreaded) t)
+                         ((eq view 'tree) nil)
+                         (t notmuch-tree-unthreaded)))
        (query-context notmuch-tree-query-context)
        (target (notmuch-tree-get-message-id)))
     (erase-buffer)
     (notmuch-tree-worker basic-query
                         query-context
-                        target)))
+                        target
+                        nil
+                        unthreaded)))
 
 (defun notmuch-tree-thread-top ()
   (when (notmuch-tree-get-message-properties)
@@ -660,20 +709,23 @@ message will be \"unarchived\", i.e. the tag changes in
   (notmuch-tree-thread-top))
 
 (defun notmuch-tree-next-thread ()
+  "Get the next thread in the current tree. Returns t if a thread was
+found or nil if not."
   (interactive)
   (forward-line 1)
   (while (not (or (notmuch-tree-get-prop :first) (eobp)))
-    (forward-line 1)))
+    (forward-line 1))
+  (not (eobp)))
 
 (defun notmuch-tree-thread-mapcar (function)
   "Iterate through all messages in the current thread
  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."
@@ -854,10 +906,11 @@ message together with all its descendents."
 (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."