(declare-function notmuch-call-notmuch-process "notmuch" (&rest args))
(declare-function notmuch-fontify-headers "notmuch" nil)
(declare-function notmuch-select-tag-with-completion "notmuch" (prompt &rest search-terms))
+(declare-function notmuch-search-next-thread "notmuch" nil)
(declare-function notmuch-search-show-thread "notmuch" nil)
(defcustom notmuch-message-headers '("Subject" "To" "Cc" "Date")
"A list of functions called to decorate the headers listed in
`notmuch-message-headers'.")
-(defcustom notmuch-show-hook nil
+(defcustom notmuch-show-hook '(notmuch-show-turn-on-visual-line-mode)
"Functions called after populating a `notmuch-show' buffer."
:type 'hook
+ :options '(notmuch-show-turn-on-visual-line-mode)
:group 'notmuch-show
:group 'notmuch-hooks)
,@body)
(kill-buffer buf)))))
+(defun notmuch-show-turn-on-visual-line-mode ()
+ "Enable Visual Line mode."
+ (visual-line-mode t))
+
(defun notmuch-show-view-all-mime-parts ()
"Use external viewers to view all attachments from the current message."
(interactive)
(with-current-notmuch-show-message
- ; We override the mm-inline-media-tests to indicate which message
- ; parts are already sufficiently handled by the original
- ; presentation of the message in notmuch-show mode. These parts
- ; will be inserted directly into the temporary buffer of
- ; with-current-notmuch-show-message and silently discarded.
- ;
- ; Any MIME part not explicitly mentioned here will be handled by an
- ; external viewer as configured in the various mailcap files.
+ ;; We override the mm-inline-media-tests to indicate which message
+ ;; parts are already sufficiently handled by the original
+ ;; presentation of the message in notmuch-show mode. These parts
+ ;; will be inserted directly into the temporary buffer of
+ ;; with-current-notmuch-show-message and silently discarded.
+ ;;
+ ;; Any MIME part not explicitly mentioned here will be handled by an
+ ;; external viewer as configured in the various mailcap files.
(let ((mm-inline-media-tests '(
("text/.*" ignore identity)
("application/pgp-signature" ignore identity)
"Try to clean a single email ADDRESS for display. Return
unchanged ADDRESS if parsing fails."
(condition-case nil
- (let* ((parsed (mail-header-parse-address address))
- (address (car parsed))
- (name (cdr parsed)))
- ;; Remove double quotes. They might be required during transport,
- ;; but we don't need to see them.
- (when name
- (setq name (replace-regexp-in-string "\"" "" name)))
+ (let (p-name p-address)
+ ;; It would be convenient to use `mail-header-parse-address',
+ ;; but that expects un-decoded mailbox parts, whereas our
+ ;; mailbox parts are already decoded (and hence may contain
+ ;; UTF-8). Given that notmuch should handle most of the awkward
+ ;; cases, some simple string deconstruction should be sufficient
+ ;; here.
+ (cond
+ ;; "User <user@dom.ain>" style.
+ ((string-match "\\(.*\\) <\\(.*\\)>" address)
+ (setq p-name (match-string 1 address)
+ p-address (match-string 2 address)))
+
+ ;; "<user@dom.ain>" style.
+ ((string-match "<\\(.*\\)>" address)
+ (setq p-address (match-string 1 address)))
+
+ ;; Everything else.
+ (t
+ (setq p-address address)))
+
+ ;; Remove elements of the mailbox part that are not relevant for
+ ;; display, even if they are required during transport.
+ (when p-name
+ ;; Outer double quotes.
+ (when (string-match "^\"\\(.*\\)\"$" p-name)
+ (setq p-name (match-string 1 p-name)))
+
+ ;; Backslashes.
+ (setq p-name (replace-regexp-in-string "\\\\" "" p-name)))
+
;; If the address is 'foo@bar.com <foo@bar.com>' then show just
;; 'foo@bar.com'.
- (when (string= name address)
- (setq name nil))
-
- (if (not name)
- address
- (concat name " <" address ">")))
+ (when (string= p-name p-address)
+ (setq p-name nil))
+
+ ;; If no name results, return just the address.
+ (if (not p-name)
+ p-address
+ ;; Otherwise format the name and address together.
+ (concat p-name " <" p-address ">")))
(error address)))
(defun notmuch-show-insert-headerline (headers date tags depth)
(with-temp-buffer
(let* ((charset (plist-get part :content-charset))
(handle (mm-make-handle (current-buffer) `(,content-type (charset . ,charset)))))
- (if (and (mm-inlinable-p handle)
- (mm-inlined-p handle))
- (let ((content (notmuch-show-get-bodypart-content msg part nth)))
- (insert content)
- (set-buffer display-buffer)
- (mm-display-part handle)
- t)
- nil)))))
+ ;; If the user wants the part inlined, insert the content and
+ ;; test whether we are able to inline it (which includes both
+ ;; capability and suitability tests).
+ (when (mm-inlined-p handle)
+ (insert (notmuch-show-get-bodypart-content msg part nth))
+ (when (mm-inlinable-p handle)
+ (set-buffer display-buffer)
+ (mm-display-part handle)
+ t))))))
(defvar notmuch-show-multipart/alternative-discouraged
'(
(interactive "P\nsPipe message to command: ")
(let (shell-command)
(if entire-thread
- (setq shell-command
+ (setq shell-command
(concat notmuch-command " show --format=mbox "
(shell-quote-argument
(mapconcat 'identity (notmuch-show-get-message-ids-for-open-messages) " OR "))
(interactive)
(backward-button 1))
-(defun notmuch-show-archive-thread-internal (show-next)
- ;; Remove the tag from the current set of messages.
+(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))
- (loop do (notmuch-show-remove-tag "inbox")
- until (not (notmuch-show-goto-message-next)))
- ;; Move to the next item in the search results, if any.
+ (let ((tag-function (if remove
+ 'notmuch-show-remove-tag
+ 'notmuch-show-add-tag)))
+ (loop do (funcall tag-function 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)
- (if parent-buffer
- (progn
- (switch-to-buffer parent-buffer)
- (forward-line)
- (if show-next
- (notmuch-search-show-thread))))))
+ (when parent-buffer
+ (switch-to-buffer parent-buffer)
+ (notmuch-search-next-thread)
+ (if show-next
+ (notmuch-search-show-thread)))))
(defun notmuch-show-archive-thread ()
"Archive each message in thread, then show next thread from search.
entire thread, but only the messages shown in the current
buffer."
(interactive)
- (notmuch-show-archive-thread-internal t))
+ (notmuch-show-remove-tag-thread "inbox")
+ (notmuch-show-next-thread t))
(defun notmuch-show-archive-thread-then-exit ()
"Archive each message in thread, then exit back to search results."
(interactive)
- (notmuch-show-archive-thread-internal nil))
+ (notmuch-show-remove-tag-thread "inbox")
+ (notmuch-show-next-thread))
(defun notmuch-show-stash-cc ()
"Copy CC field of current message to kill-ring."