24.3 to work.")
(defcustom notmuch-show-stash-mlarchive-link-alist
- '(("Gmane" . "http://mid.gmane.org/")
+ '(("Gmane" . "https://mid.gmane.org/")
("MARC" . "https://marc.info/?i=")
("Mail Archive, The" . "https://mid.mail-archive.com/")
("LKML" . "https://lkml.kernel.org/r/")
: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
(with-temp-buffer
(insert all)
(if indenting
- (indent-rigidly (point-min) (point-max) (- depth)))
+ (indent-rigidly (point-min) (point-max) (- (* notmuch-show-indent-messages-width depth))))
;; Remove the original header.
(goto-char (point-min))
(re-search-forward "^$" (point-max) nil)
(unless (assq 'notmuch-show-mode w3m-cid-retrieve-function-alist)
(push (cons 'notmuch-show-mode #'notmuch-show--cid-w3m-retrieve)
w3m-cid-retrieve-function-alist)))
- (setq mm-inline-text-html-with-images t))
+ (setq mm-html-inhibit-images nil))
(defvar w3m-current-buffer) ;; From `w3m.el'.
(defun notmuch-show--cid-w3m-retrieve (url &rest args)
(defun notmuch-show-insert-part-text/x-vcalendar (msg part content-type nth depth button)
(notmuch-show-insert-part-text/calendar msg part content-type nth depth button))
+(if (version< emacs-version "25.3")
+ ;; https://bugs.gnu.org/28350
+ ;;
+ ;; For newer emacs, we fall back to notmuch-show-insert-part-*/*
+ ;; (see notmuch-show-handlers-for)
+ (defun notmuch-show-insert-part-text/enriched (msg part content-type nth depth button)
+ ;; By requiring enriched below, we ensure that the function enriched-decode-display-prop
+ ;; is defined before it will be shadowed by the letf below. Otherwise the version
+ ;; in enriched.el may be loaded a bit later and used instead (for the first time).
+ (require 'enriched)
+ (letf (((symbol-function 'enriched-decode-display-prop)
+ (lambda (start end &optional param) (list start end))))
+ (notmuch-show-insert-part-*/* msg part content-type nth depth button))))
+
(defun notmuch-show-get-mime-type-of-application/octet-stream (part)
;; If we can deduce a MIME type from the filename of the attachment,
;; we return that.
(narrow-to-region part-beg part-end)
(delete-region part-beg part-end)
(apply #'notmuch-show-insert-bodypart-internal part-args)
- (indent-rigidly part-beg part-end depth))
+ (indent-rigidly part-beg part-end (* notmuch-show-indent-messages-width depth)))
(goto-char part-end)
(delete-char 1)
(notmuch-show-record-part-information (second part-args)
(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)
;; aren't wiped out.
(setq notmuch-show-thread-id thread-id
notmuch-show-parent-buffer parent-buffer
- notmuch-show-query-context query-context
+ notmuch-show-query-context (if (or (string= query-context "")
+ (string= query-context "*"))
+ nil query-context)
notmuch-show-process-crypto notmuch-crypto-process-mime
;; If `elide-toggle', invert the default value.
(define-key map "<" 'notmuch-show-toggle-thread-indentation)
(define-key map "t" 'toggle-truncate-lines)
(define-key map "." 'notmuch-show-part-map)
+ (define-key map "B" 'notmuch-show-browse-urls)
map)
"Keymap for \"notmuch show\" buffers.")
(fset 'notmuch-show-mode-map notmuch-show-mode-map)
\\{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"
;; region a->b is not found when point is at b. We walk backwards
;; until finding the property.
(defun notmuch-show-message-extent ()
+ "Return a cons cell containing the start and end buffer offset
+of the current message."
(let (r)
(save-excursion
(while (not (setq r (get-text-property (point) :notmuch-message-extent)))
;; dme: Would it make sense to use a macro for many of these?
+;; XXX TODO figure out what to do about multiple filenames
(defun notmuch-show-get-filename ()
"Return the filename of the current message."
- (notmuch-show-get-prop :filename))
+ (car (notmuch-show-get-prop :filename)))
(defun notmuch-show-get-header (header &optional props)
"Return the named header of the current message, if any."
(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))
(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."
(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)))
+
+(defmacro notmuch-show--with-currently-shown-message (&rest body)
+ "Evaluate BODY with display restricted to the currently shown
+message."
+ `(save-excursion
+ (save-restriction
+ (let ((extent (notmuch-show-message-extent)))
+ (narrow-to-region (car extent) (cdr extent))
+ ,@body))))
+
+(defun notmuch-show--gather-urls ()
+ "Gather any URLs in the current message."
+ (notmuch-show--with-currently-shown-message
+ (let (urls)
+ (goto-char (point-min))
+ (while (re-search-forward goto-address-url-regexp (point-max) t)
+ (push (match-string-no-properties 0) urls))
+ (reverse urls))))
+
+(defun notmuch-show-browse-urls ()
+ "Offer to browse any URLs in the current message."
+ (interactive)
+ (let ((urls (notmuch-show--gather-urls)))
+ (if urls
+ (browse-url (completing-read "Browse URL: " (cdr urls) nil nil (car urls)))
+ (message "No URLs found."))))
+
(provide 'notmuch-show)
;;; notmuch-show.el ends here