]> git.notmuchmail.org Git - notmuch/blobdiff - emacs/notmuch-show.el
emacs: `notmuch-show-get-message-id': optionally return Message-Id sans prefix
[notmuch] / emacs / notmuch-show.el
index e209122932de183b724e417cc37ba3f2cabf05c0..529b674ebe6ea1dd154f768e92369547528e2af4 100644 (file)
@@ -126,6 +126,11 @@ indentation."
                 (const :tag "View interactively"
                        notmuch-show-interactively-view-part)))
 
                 (const :tag "View interactively"
                        notmuch-show-interactively-view-part)))
 
+(defcustom notmuch-show-only-matching-messages nil
+  "Only matching messages are shown by default."
+  :type 'boolean
+  :group 'notmuch-show)
+
 (defvar notmuch-show-thread-id nil)
 (make-variable-buffer-local 'notmuch-show-thread-id)
 (put 'notmuch-show-thread-id 'permanent-local t)
 (defvar notmuch-show-thread-id nil)
 (make-variable-buffer-local 'notmuch-show-thread-id)
 (put 'notmuch-show-thread-id 'permanent-local t)
@@ -142,6 +147,14 @@ indentation."
 (make-variable-buffer-local 'notmuch-show-process-crypto)
 (put 'notmuch-show-process-crypto 'permanent-local t)
 
 (make-variable-buffer-local 'notmuch-show-process-crypto)
 (put 'notmuch-show-process-crypto 'permanent-local t)
 
+(defvar notmuch-show-elide-non-matching-messages nil)
+(make-variable-buffer-local 'notmuch-show-elide-non-matching-messages)
+(put 'notmuch-show-elide-non-matching-messages 'permanent-local t)
+
+(defvar notmuch-show-indent-content t)
+(make-variable-buffer-local 'notmuch-show-indent-content)
+(put 'notmuch-show-indent-content 'permanent-local t)
+
 (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
@@ -252,10 +265,12 @@ operation on the contents of the current buffer."
         (all (buffer-substring (notmuch-show-message-top)
                                (notmuch-show-message-bottom)))
 
         (all (buffer-substring (notmuch-show-message-top)
                                (notmuch-show-message-bottom)))
 
-        (props (notmuch-show-get-message-properties)))
+        (props (notmuch-show-get-message-properties))
+        (indenting notmuch-show-indent-content))
     (with-temp-buffer
       (insert all)
     (with-temp-buffer
       (insert all)
-      (indent-rigidly (point-min) (point-max) (- depth))
+      (if indenting
+         (indent-rigidly (point-min) (point-max) (- depth)))
       ;; Remove the original header.
       (goto-char (point-min))
       (re-search-forward "^$" (point-max) nil)
       ;; Remove the original header.
       (goto-char (point-min))
       (re-search-forward "^$" (point-max) nil)
@@ -714,7 +729,7 @@ current buffer, if possible."
        (run-hook-with-args 'notmuch-show-insert-text/plain-hook msg depth))))
   t)
 
        (run-hook-with-args 'notmuch-show-insert-text/plain-hook msg depth))))
   t)
 
-(defun notmuch-show-insert-part-text/x-vcalendar (msg part content-type nth depth declared-type)
+(defun notmuch-show-insert-part-text/calendar (msg part content-type nth depth declared-type)
   (notmuch-show-insert-part-header nth declared-type content-type (plist-get part :filename))
   (insert (with-temp-buffer
            (insert (notmuch-show-get-bodypart-content msg part nth))
   (notmuch-show-insert-part-header nth declared-type content-type (plist-get part :filename))
   (insert (with-temp-buffer
            (insert (notmuch-show-get-bodypart-content msg part nth))
@@ -732,6 +747,10 @@ current buffer, if possible."
              result)))
   t)
 
              result)))
   t)
 
+;; For backwards compatibility.
+(defun notmuch-show-insert-part-text/x-vcalendar (msg part content-type nth depth declared-type)
+  (notmuch-show-insert-part-text/calendar msg part content-type nth depth declared-type))
+
 (defun notmuch-show-insert-part-application/octet-stream (msg part content-type nth depth declared-type)
   ;; If we can deduce a MIME type from the filename of the attachment,
   ;; do so and pass it on to the handler for that type.
 (defun notmuch-show-insert-part-application/octet-stream (msg part content-type nth depth declared-type)
   ;; If we can deduce a MIME type from the filename of the attachment,
   ;; do so and pass it on to the handler for that type.
@@ -896,7 +915,8 @@ current buffer, if possible."
     (setq body-start (point-marker))
     ;; A blank line between the headers and the body.
     (insert "\n")
     (setq body-start (point-marker))
     ;; A blank line between the headers and the body.
     (insert "\n")
-    (notmuch-show-insert-body msg (plist-get msg :body) depth)
+    (notmuch-show-insert-body msg (plist-get msg :body)
+                             (if notmuch-show-indent-content depth 0))
     ;; Ensure that the body ends with a newline.
     (unless (bolp)
       (insert "\n"))
     ;; Ensure that the body ends with a newline.
     (unless (bolp)
       (insert "\n"))
@@ -904,7 +924,8 @@ current buffer, if possible."
     (setq content-end (point-marker))
 
     ;; Indent according to the depth in the thread.
     (setq content-end (point-marker))
 
     ;; Indent according to the depth in the thread.
-    (indent-rigidly content-start content-end (* notmuch-show-indent-messages-width depth))
+    (if notmuch-show-indent-content
+       (indent-rigidly content-start content-end (* notmuch-show-indent-messages-width depth)))
 
     (setq message-end (point-max-marker))
 
 
     (setq message-end (point-max-marker))
 
@@ -940,13 +961,33 @@ current buffer, if possible."
   (message (if notmuch-show-process-crypto
               "Processing cryptographic MIME parts."
             "Not processing cryptographic MIME parts."))
   (message (if notmuch-show-process-crypto
               "Processing cryptographic MIME parts."
             "Not processing cryptographic MIME parts."))
-  (notmuch-show-refresh-view))
+  (notmuch-show-refresh-view t))
+
+(defun notmuch-show-toggle-elide-non-matching ()
+  "Toggle the display of non-matching messages."
+  (interactive)
+  (setq notmuch-show-elide-non-matching-messages (not notmuch-show-elide-non-matching-messages))
+  (message (if notmuch-show-elide-non-matching-messages
+              "Showing matching messages only."
+            "Showing all messages."))
+  (notmuch-show-refresh-view t))
+
+(defun notmuch-show-toggle-thread-indentation ()
+  "Toggle the indentation of threads."
+  (interactive)
+  (setq notmuch-show-indent-content (not notmuch-show-indent-content))
+  (message (if notmuch-show-indent-content
+              "Content is indented."
+            "Content is not indented."))
+  (notmuch-show-refresh-view t))
 
 (defun notmuch-show-insert-tree (tree depth)
   "Insert the message tree TREE at depth DEPTH in the current thread."
   (let ((msg (car tree))
        (replies (cadr tree)))
 
 (defun notmuch-show-insert-tree (tree depth)
   "Insert the message tree TREE at depth DEPTH in the current thread."
   (let ((msg (car tree))
        (replies (cadr tree)))
-    (notmuch-show-insert-msg msg depth)
+    (if (or (not notmuch-show-elide-non-matching-messages)
+           (plist-get msg :match))
+       (notmuch-show-insert-msg msg depth))
     (notmuch-show-insert-thread replies (1+ depth))))
 
 (defun notmuch-show-insert-thread (thread depth)
     (notmuch-show-insert-thread replies (1+ depth))))
 
 (defun notmuch-show-insert-thread (thread depth)
@@ -1000,6 +1041,12 @@ function is used."
     ;; Set the default value for `notmuch-show-process-crypto' in this
     ;; buffer.
     (setq notmuch-show-process-crypto notmuch-crypto-process-mime)
     ;; Set the default value for `notmuch-show-process-crypto' in this
     ;; buffer.
     (setq notmuch-show-process-crypto notmuch-crypto-process-mime)
+    ;; Set the default value for
+    ;; `notmuch-show-elide-non-matching-messages' in this buffer. If
+    ;; there is a prefix argument, invert the default.
+    (setq notmuch-show-elide-non-matching-messages notmuch-show-only-matching-messages)
+    (if current-prefix-arg
+       (setq notmuch-show-elide-non-matching-messages (not notmuch-show-elide-non-matching-messages)))
 
     (setq notmuch-show-thread-id thread-id
          notmuch-show-parent-buffer parent-buffer
 
     (setq notmuch-show-thread-id thread-id
          notmuch-show-parent-buffer parent-buffer
@@ -1042,14 +1089,54 @@ function is used."
 
     (notmuch-show-mark-read)))
 
 
     (notmuch-show-mark-read)))
 
-(defun notmuch-show-refresh-view ()
+(defun notmuch-show-capture-state ()
+  "Capture the state of the current buffer.
+
+This includes:
+ - the list of open messages,
+ - the current message."
+  (list (notmuch-show-get-message-id) (notmuch-show-get-message-ids-for-open-messages)))
+
+(defun notmuch-show-apply-state (state)
+  "Apply STATE to the current buffer.
+
+This includes:
+ - opening the messages previously opened,
+ - closing all other messages,
+ - moving to the correct current message."
+  (let ((current (car state))
+       (open (cadr state)))
+
+    ;; Open those that were open.
+    (goto-char (point-min))
+    (loop do (notmuch-show-message-visible (notmuch-show-get-message-properties)
+                                          (member (notmuch-show-get-message-id) open))
+         until (not (notmuch-show-goto-message-next)))
+
+    ;; Go to the previously open message.
+    (goto-char (point-min))
+    (unless (loop if (string= current (notmuch-show-get-message-id))
+                 return t
+                 until (not (notmuch-show-goto-message-next)))
+      (goto-char (point-min))
+      (message "Previously current message not found."))
+    (notmuch-show-message-adjust)))
+
+(defun notmuch-show-refresh-view (&optional retain-state)
   "Refresh the current view.
 
   "Refresh the current view.
 
-Refreshes the current view, observing changes in cryptographic preferences."
-  (interactive)
-  (let ((inhibit-read-only t))
-    (erase-buffer))
-  (notmuch-show-worker))
+Refreshes the current view, observing changes in display
+preferences. If RETAIN-STATE is non-nil then the state of the
+buffer is stored and re-applied after the refresh."
+  (interactive "P")
+  (let ((inhibit-read-only t)
+       state)
+    (if retain-state
+       (setq state (notmuch-show-capture-state)))
+    (erase-buffer)
+    (notmuch-show-worker)
+    (if state
+       (notmuch-show-apply-state state))))
 
 (defvar notmuch-show-stash-map
   (let ((map (make-sparse-keymap)))
 
 (defvar notmuch-show-stash-map
   (let ((map (make-sparse-keymap)))
@@ -1102,7 +1189,10 @@ Refreshes the current view, observing changes in cryptographic preferences."
        (define-key map (kbd "M-RET") 'notmuch-show-open-or-close-all)
        (define-key map (kbd "RET") 'notmuch-show-toggle-message)
        (define-key map "#" 'notmuch-show-print-message)
        (define-key map (kbd "M-RET") 'notmuch-show-open-or-close-all)
        (define-key map (kbd "RET") 'notmuch-show-toggle-message)
        (define-key map "#" 'notmuch-show-print-message)
+       (define-key map "!" 'notmuch-show-toggle-elide-non-matching)
        (define-key map "$" 'notmuch-show-toggle-process-crypto)
        (define-key map "$" 'notmuch-show-toggle-process-crypto)
+       (define-key map "<" 'notmuch-show-toggle-thread-indentation)
+       (define-key map "t" 'toggle-truncate-lines)
        map)
       "Keymap for \"notmuch show\" buffers.")
 (fset 'notmuch-show-mode-map notmuch-show-mode-map)
        map)
       "Keymap for \"notmuch show\" buffers.")
 (fset 'notmuch-show-mode-map notmuch-show-mode-map)
@@ -1243,9 +1333,14 @@ Some useful entries are:
                   (notmuch-show-get-message-properties))))
     (plist-get props prop)))
 
                   (notmuch-show-get-message-properties))))
     (plist-get props prop)))
 
-(defun notmuch-show-get-message-id ()
-  "Return the message id of the current message."
-  (concat "id:\"" (notmuch-show-get-prop :id) "\""))
+(defun notmuch-show-get-message-id (&optional bare)
+  "Return the Message-Id of the current message.
+
+If optional argument BARE is non-nil, return
+the Message-Id without prefix and quotes."
+  (if bare
+      (notmuch-show-get-prop :id)
+    (concat "id:\"" (notmuch-show-get-prop :id) "\"")))
 
 (defun notmuch-show-get-messages-ids ()
   "Return all message ids of messages in the current thread."
 
 (defun notmuch-show-get-messages-ids ()
   "Return all message ids of messages in the current thread."
@@ -1604,32 +1699,12 @@ argument, hide all of the messages."
   (interactive)
   (backward-button 1))
 
   (interactive)
   (backward-button 1))
 
-(defun notmuch-show-tag-thread-internal (tag &optional remove)
-  "Add tag to the current set of messages.
-
-If the remove switch is given, tags will be removed instead of
-added."
-  (goto-char (point-min))
-  (let ((op (if remove "-" "+")))
-    (loop do (notmuch-show-tag-message (concat op tag))
-         until (not (notmuch-show-goto-message-next)))))
-
-(defun notmuch-show-add-tag-thread (tag)
-  "Add tag to all messages in the current thread."
-  (interactive)
-  (notmuch-show-tag-thread-internal tag))
-
-(defun notmuch-show-remove-tag-thread (tag)
-  "Remove tag from all messages in the current thread."
-  (interactive)
-  (notmuch-show-tag-thread-internal tag t))
-
 (defun notmuch-show-next-thread (&optional show-next)
   "Move to the next item in the search results, if any."
   (interactive "P")
   (let ((parent-buffer notmuch-show-parent-buffer))
     (notmuch-kill-this-buffer)
 (defun notmuch-show-next-thread (&optional show-next)
   "Move to the next item in the search results, if any."
   (interactive "P")
   (let ((parent-buffer notmuch-show-parent-buffer))
     (notmuch-kill-this-buffer)
-    (when parent-buffer
+    (when (buffer-live-p parent-buffer)
       (switch-to-buffer parent-buffer)
       (notmuch-search-next-thread)
       (if show-next
       (switch-to-buffer parent-buffer)
       (notmuch-search-next-thread)
       (if show-next
@@ -1651,9 +1726,8 @@ being delivered to the same thread. It does not archive the
 entire thread, but only the messages shown in the current
 buffer."
   (interactive "P")
 entire thread, but only the messages shown in the current
 buffer."
   (interactive "P")
-  (if unarchive
-      (notmuch-show-add-tag-thread "inbox")
-    (notmuch-show-remove-tag-thread "inbox")))
+  (let ((op (if unarchive "+" "-")))
+    (notmuch-show-tag-all (concat op "inbox"))))
 
 (defun notmuch-show-archive-thread-then-next ()
   "Archive each message in thread, then show next thread from search."
 
 (defun notmuch-show-archive-thread-then-next ()
   "Archive each message in thread, then show next thread from search."
@@ -1724,7 +1798,7 @@ thread from search."
 (defun notmuch-show-stash-message-id-stripped ()
   "Copy message ID of current message (sans `id:' prefix) to kill-ring."
   (interactive)
 (defun notmuch-show-stash-message-id-stripped ()
   "Copy message ID of current message (sans `id:' prefix) to kill-ring."
   (interactive)
-  (notmuch-common-do-stash (substring (notmuch-show-get-message-id) 4 -1)))
+  (notmuch-common-do-stash (notmuch-show-get-message-id t)))
 
 (defun notmuch-show-stash-subject ()
   "Copy Subject field of current message to kill-ring."
 
 (defun notmuch-show-stash-subject ()
   "Copy Subject field of current message to kill-ring."