]> git.notmuchmail.org Git - notmuch/blobdiff - emacs/notmuch-show.el
Add indentation to imenu in notmuch-show
[notmuch] / emacs / notmuch-show.el
index 16ff45adf82e06a843cceb78ac1155c27819dcf3..a4399abb97aa07a4ff08ca125819eb716ac054ae 100644 (file)
@@ -38,6 +38,7 @@
 (require 'notmuch-mua)
 (require 'notmuch-crypto)
 (require 'notmuch-print)
 (require 'notmuch-mua)
 (require 'notmuch-crypto)
 (require 'notmuch-print)
+(require 'notmuch-draft)
 
 (declare-function notmuch-call-notmuch-process "notmuch" (&rest args))
 (declare-function notmuch-search-next-thread "notmuch" nil)
 
 (declare-function notmuch-call-notmuch-process "notmuch" (&rest args))
 (declare-function notmuch-search-next-thread "notmuch" nil)
@@ -50,6 +51,7 @@
                  (&optional query query-context target buffer-name open-target))
 (declare-function notmuch-tree-get-message-properties "notmuch-tree" nil)
 (declare-function notmuch-read-query "notmuch" (prompt))
                  (&optional query query-context target buffer-name open-target))
 (declare-function notmuch-tree-get-message-properties "notmuch-tree" nil)
 (declare-function notmuch-read-query "notmuch" (prompt))
+(declare-function notmuch-draft-resume "notmuch-draft" (id))
 
 (defcustom notmuch-message-headers '("Subject" "To" "Cc" "Date")
   "Headers that should be shown in a message, in this order.
 
 (defcustom notmuch-message-headers '("Subject" "To" "Cc" "Date")
   "Headers that should be shown in a message, in this order.
@@ -245,6 +247,19 @@ every user interaction with notmuch."
   :type 'function
   :group 'notmuch-show)
 
   :type 'function
   :group 'notmuch-show)
 
+(defcustom notmuch-show-imenu-indent nil
+  "Should Imenu display messages indented.
+
+By default, Imenu (see Info node `(emacs) Imenu') in a
+notmuch-show buffer displays all messages straight.  This is
+because the default Emacs frontend for Imenu makes it difficult
+to select an Imenu entry with spaces in front.  Other imenu
+frontends such as counsel-imenu does not have this limitation.
+In these cases, Imenu entries can be indented to reflect the
+position of the message in the thread."
+  :type 'boolean
+  :group 'notmuch-show)
+
 (defmacro with-current-notmuch-show-message (&rest body)
   "Evaluate body with current buffer set to the text of current message"
   `(save-excursion
 (defmacro with-current-notmuch-show-message (&rest body)
   "Evaluate body with current buffer set to the text of current message"
   `(save-excursion
@@ -1225,7 +1240,15 @@ matched."
   (interactive "sNotmuch show: \nP")
   (let ((buffer-name (generate-new-buffer-name
                      (or buffer-name
   (interactive "sNotmuch show: \nP")
   (let ((buffer-name (generate-new-buffer-name
                      (or buffer-name
-                         (concat "*notmuch-" thread-id "*")))))
+                         (concat "*notmuch-" thread-id "*"))))
+       ;; We override mm-inline-override-types to stop application/*
+       ;; parts from being displayed unless the user has customized
+       ;; it themselves.
+       (mm-inline-override-types
+        (if (equal mm-inline-override-types
+                   (eval (car (get 'mm-inline-override-types 'standard-value))))
+            (cons "application/*" mm-inline-override-types)
+          mm-inline-override-types)))
     (switch-to-buffer (get-buffer-create buffer-name))
     ;; No need to track undo information for this buffer.
     (setq buffer-undo-list t)
     (switch-to-buffer (get-buffer-create buffer-name))
     ;; No need to track undo information for this buffer.
     (setq buffer-undo-list t)
@@ -1263,6 +1286,18 @@ matched."
        (message "No messages matched the query!")
        nil))))
 
        (message "No messages matched the query!")
        nil))))
 
+(defun notmuch-show--build-queries (thread context)
+  "Return a list of queries to try for this search.
+
+THREAD and CONTEXT are both strings, though CONTEXT may be nil.
+When CONTEXT is not nil, the first query is the conjunction of it
+and THREAD.  The next query is THREAD alone, and serves as a
+fallback if the prior matches no messages."
+  (let (queries)
+    (push (list thread) queries)
+    (if context (push (list thread "and (" context ")") queries))
+    queries))
+
 (defun notmuch-show--build-buffer (&optional state)
   "Display messages matching the current buffer context.
 
 (defun notmuch-show--build-buffer (&optional state)
   "Display messages matching the current buffer context.
 
@@ -1270,25 +1305,20 @@ Apply the previously saved STATE if supplied, otherwise show the
 first relevant message.
 
 If no messages match the query return NIL."
 first relevant message.
 
 If no messages match the query return NIL."
-  (let* ((basic-args (list notmuch-show-thread-id))
-        (args (if notmuch-show-query-context
-                  (append (list "\'") basic-args
-                          (list "and (" notmuch-show-query-context ")\'"))
-                (append (list "\'") basic-args (list "\'"))))
-        (cli-args (cons "--exclude=false"
+  (let* ((cli-args (cons "--exclude=false"
                         (when notmuch-show-elide-non-matching-messages
                           (list "--entire-thread=false"))))
                         (when notmuch-show-elide-non-matching-messages
                           (list "--entire-thread=false"))))
-
-        (forest (or (notmuch-query-get-threads (append cli-args args))
-                    ;; If a query context reduced the number of
-                    ;; results to zero, try again without it.
-                    (and notmuch-show-query-context
-                         (notmuch-query-get-threads (append cli-args basic-args)))))
-
+        (queries (notmuch-show--build-queries
+                  notmuch-show-thread-id notmuch-show-query-context))
+        (forest nil)
         ;; Must be reset every time we are going to start inserting
         ;; messages into the buffer.
         (notmuch-show-previous-subject ""))
         ;; Must be reset every time we are going to start inserting
         ;; messages into the buffer.
         (notmuch-show-previous-subject ""))
-
+    ;; Use results from the first query that returns some.
+    (while (and (not forest) queries)
+      (setq forest (notmuch-query-get-threads
+                   (append cli-args (list "'") (car queries) (list "'"))))
+      (setq queries (cdr queries)))
     (when forest
       (notmuch-show-insert-forest forest)
 
     (when forest
       (notmuch-show-insert-forest forest)
 
@@ -1438,6 +1468,7 @@ reset based on the original query."
     (define-key map "|" 'notmuch-show-pipe-message)
     (define-key map "w" 'notmuch-show-save-attachments)
     (define-key map "V" 'notmuch-show-view-raw-message)
     (define-key map "|" 'notmuch-show-pipe-message)
     (define-key map "w" 'notmuch-show-save-attachments)
     (define-key map "V" 'notmuch-show-view-raw-message)
+    (define-key map "e" 'notmuch-show-resume-message)
     (define-key map "c" 'notmuch-show-stash-map)
     (define-key map "h" 'notmuch-show-toggle-visibility-headers)
     (define-key map "k" 'notmuch-tag-jump)
     (define-key map "c" 'notmuch-show-stash-map)
     (define-key map "h" 'notmuch-show-toggle-visibility-headers)
     (define-key map "k" 'notmuch-tag-jump)
@@ -1498,7 +1529,11 @@ All currently available key bindings:
 \\{notmuch-show-mode-map}"
   (setq notmuch-buffer-refresh-function #'notmuch-show-refresh-view)
   (setq buffer-read-only t
 \\{notmuch-show-mode-map}"
   (setq notmuch-buffer-refresh-function #'notmuch-show-refresh-view)
   (setq buffer-read-only t
-       truncate-lines t))
+       truncate-lines t)
+  (setq imenu-prev-index-position-function
+        #'notmuch-show-imenu-prev-index-position-function)
+  (setq imenu-extract-index-name-function
+        #'notmuch-show-imenu-extract-index-name-function))
 
 (defun notmuch-tree-from-show-current-query ()
   "Call notmuch tree with the current query"
 
 (defun notmuch-tree-from-show-current-query ()
   "Call notmuch tree with the current query"
@@ -1656,6 +1691,9 @@ current thread."
 (defun notmuch-show-get-date ()
   (notmuch-show-get-header :Date))
 
 (defun notmuch-show-get-date ()
   (notmuch-show-get-header :Date))
 
+(defun notmuch-show-get-timestamp ()
+  (notmuch-show-get-prop :timestamp))
+
 (defun notmuch-show-get-from ()
   (notmuch-show-get-header :From))
 
 (defun notmuch-show-get-from ()
   (notmuch-show-get-header :From))
 
@@ -1975,6 +2013,11 @@ to show, nil otherwise."
     (setq buffer-read-only t)
     (view-buffer buf 'kill-buffer-if-not-modified)))
 
     (setq buffer-read-only t)
     (view-buffer buf 'kill-buffer-if-not-modified)))
 
+(defun notmuch-show-resume-message ()
+  "Resume EDITING the current draft message."
+  (interactive)
+  (notmuch-draft-resume (notmuch-show-get-message-id)))
+
 (put 'notmuch-show-pipe-message 'notmuch-doc
      "Pipe the contents of the current message to a command.")
 (put 'notmuch-show-pipe-message 'notmuch-prefix-doc
 (put 'notmuch-show-pipe-message 'notmuch-doc
      "Pipe the contents of the current message to a command.")
 (put 'notmuch-show-pipe-message 'notmuch-prefix-doc
@@ -2216,10 +2259,17 @@ thread from search."
   (interactive)
   (notmuch-common-do-stash (notmuch-show-get-cc)))
 
   (interactive)
   (notmuch-common-do-stash (notmuch-show-get-cc)))
 
-(defun notmuch-show-stash-date ()
-  "Copy date of current message to kill-ring."
-  (interactive)
-  (notmuch-common-do-stash (notmuch-show-get-date)))
+(put 'notmuch-show-stash-date 'notmuch-prefix-doc
+     "Copy timestamp of current message to kill-ring.")
+(defun notmuch-show-stash-date (&optional stash-timestamp)
+  "Copy date of current message to kill-ring.
+
+If invoked with a prefix argument, copy timestamp of current
+message to kill-ring."
+  (interactive "P")
+  (if stash-timestamp
+      (notmuch-common-do-stash (format "%d" (notmuch-show-get-timestamp)))
+    (notmuch-common-do-stash (notmuch-show-get-date))))
 
 (defun notmuch-show-stash-filename ()
   "Copy filename of current message to kill-ring."
 
 (defun notmuch-show-stash-filename ()
   "Copy filename of current message to kill-ring."
@@ -2432,6 +2482,26 @@ the new buffer."
                          (mailcap-mime-types) nil nil nil nil "text/plain")))
   (notmuch-show-apply-to-current-part-handle #'notmuch-show--mm-display-part mime-type))
 
                          (mailcap-mime-types) nil nil nil nil "text/plain")))
   (notmuch-show-apply-to-current-part-handle #'notmuch-show--mm-display-part mime-type))
 
+(defun notmuch-show-imenu-prev-index-position-function ()
+  "Move point to previous message in notmuch-show buffer.
+This function is used as a value for
+`imenu-prev-index-position-function'."
+  (if (bobp)
+      nil
+    (notmuch-show-previous-message)
+    t))
+
+(defun notmuch-show-imenu-extract-index-name-function ()
+  "Return imenu name for line at point.
+This function is used as a value for
+`imenu-extract-index-name-function'.  Point should be at the
+beginning of the line."
+  (back-to-indentation)
+  (buffer-substring-no-properties (if notmuch-show-imenu-indent
+                                     (line-beginning-position)
+                                   (point))
+                                 (line-end-position)))
+
 (provide 'notmuch-show)
 
 ;;; notmuch-show.el ends here
 (provide 'notmuch-show)
 
 ;;; notmuch-show.el ends here