mirror of https://github.com/djcb/mu.git
mu4e-view: whitespace cleanup
This commit is contained in:
parent
98fcf0192c
commit
9ae567f5f5
|
@ -60,7 +60,7 @@ Otherwise, don't move to the next message."
|
||||||
|
|
||||||
(defcustom mu4e-view-fields
|
(defcustom mu4e-view-fields
|
||||||
'(:from :to :cc :subject :flags :date :maildir :mailing-list :tags
|
'(:from :to :cc :subject :flags :date :maildir :mailing-list :tags
|
||||||
:attachments :signature :decryption)
|
:attachments :signature :decryption)
|
||||||
"Header fields to display in the message view buffer.
|
"Header fields to display in the message view buffer.
|
||||||
For the complete list of available headers, see
|
For the complete list of available headers, see
|
||||||
`mu4e-header-info'.
|
`mu4e-header-info'.
|
||||||
|
@ -75,11 +75,11 @@ details."
|
||||||
|
|
||||||
(defcustom mu4e-view-actions
|
(defcustom mu4e-view-actions
|
||||||
(seq-filter 'identity
|
(seq-filter 'identity
|
||||||
`( ("capture message" . mu4e-action-capture-message)
|
`( ("capture message" . mu4e-action-capture-message)
|
||||||
("view in browser" . mu4e-action-view-in-browser)
|
("view in browser" . mu4e-action-view-in-browser)
|
||||||
,(when (fboundp 'xwidget-webkit-browse-url)
|
,(when (fboundp 'xwidget-webkit-browse-url)
|
||||||
'("xview in xwidget" . mu4e-action-view-in-xwidget))
|
'("xview in xwidget" . mu4e-action-view-in-xwidget))
|
||||||
("show this thread" . mu4e-action-show-thread)))
|
("show this thread" . mu4e-action-show-thread)))
|
||||||
"List of actions to perform on messages in view mode.
|
"List of actions to perform on messages in view mode.
|
||||||
The actions are cons-cells of the form:
|
The actions are cons-cells of the form:
|
||||||
(NAME . FUNC)
|
(NAME . FUNC)
|
||||||
|
@ -136,13 +136,13 @@ other windows."
|
||||||
"Display the raw contents of message at point in a new buffer."
|
"Display the raw contents of message at point in a new buffer."
|
||||||
(interactive)
|
(interactive)
|
||||||
(let ((path (mu4e-message-readable-path))
|
(let ((path (mu4e-message-readable-path))
|
||||||
(buf (get-buffer-create mu4e~view-raw-buffer-name)))
|
(buf (get-buffer-create mu4e~view-raw-buffer-name)))
|
||||||
(with-current-buffer buf
|
(with-current-buffer buf
|
||||||
(let ((inhibit-read-only t))
|
(let ((inhibit-read-only t))
|
||||||
(erase-buffer)
|
(erase-buffer)
|
||||||
(mu4e-raw-view-mode)
|
(mu4e-raw-view-mode)
|
||||||
(insert-file-contents path)
|
(insert-file-contents path)
|
||||||
(goto-char (point-min))))
|
(goto-char (point-min))))
|
||||||
(mu4e-display-buffer buf t)))
|
(mu4e-display-buffer buf t)))
|
||||||
|
|
||||||
(defun mu4e-view-pipe (cmd)
|
(defun mu4e-view-pipe (cmd)
|
||||||
|
@ -156,38 +156,38 @@ Then, display the results."
|
||||||
"Evaluate BODY in the context of the headers buffer."
|
"Evaluate BODY in the context of the headers buffer."
|
||||||
`(progn
|
`(progn
|
||||||
(let* ((msg (mu4e-message-at-point))
|
(let* ((msg (mu4e-message-at-point))
|
||||||
(buffer (cond
|
(buffer (cond
|
||||||
;; are we already inside a headers buffer?
|
;; are we already inside a headers buffer?
|
||||||
((mu4e-current-buffer-type-p 'headers) (current-buffer))
|
((mu4e-current-buffer-type-p 'headers) (current-buffer))
|
||||||
;; if not, are we inside a view buffer, and does
|
;; if not, are we inside a view buffer, and does
|
||||||
;; it have linked headers buffer?
|
;; it have linked headers buffer?
|
||||||
((mu4e-current-buffer-type-p 'view)
|
((mu4e-current-buffer-type-p 'view)
|
||||||
(when (mu4e--view-detached-p (current-buffer))
|
(when (mu4e--view-detached-p (current-buffer))
|
||||||
(mu4e-error
|
(mu4e-error
|
||||||
"Cannot navigate in a detached view buffer."))
|
"Cannot navigate in a detached view buffer."))
|
||||||
(mu4e-get-headers-buffer))
|
(mu4e-get-headers-buffer))
|
||||||
;; fallback; but what would trigger this?
|
;; fallback; but what would trigger this?
|
||||||
(t (mu4e-get-headers-buffer))))
|
(t (mu4e-get-headers-buffer))))
|
||||||
(docid (mu4e-message-field msg :docid)))
|
(docid (mu4e-message-field msg :docid)))
|
||||||
(unless docid
|
(unless docid
|
||||||
(mu4e-error "Message without docid: action is not possible"))
|
(mu4e-error "Message without docid: action is not possible"))
|
||||||
(with-current-buffer buffer
|
(with-current-buffer buffer
|
||||||
(mu4e-display-buffer buffer)
|
(mu4e-display-buffer buffer)
|
||||||
(if (or (mu4e~headers-goto-docid docid)
|
(if (or (mu4e~headers-goto-docid docid)
|
||||||
;; TODO: Is this the best way to find another
|
;; TODO: Is this the best way to find another
|
||||||
;; relevant docid for a view buffer?
|
;; relevant docid for a view buffer?
|
||||||
;;
|
;;
|
||||||
;; If you attach a view buffer to another headers
|
;; If you attach a view buffer to another headers
|
||||||
;; buffer that does not contain the current docid
|
;; buffer that does not contain the current docid
|
||||||
;; then `mu4e~headers-goto-docid' returns nil and we
|
;; then `mu4e~headers-goto-docid' returns nil and we
|
||||||
;; get an error. This "hack" instead gets its
|
;; get an error. This "hack" instead gets its
|
||||||
;; now-changed headers buffer's current message as a
|
;; now-changed headers buffer's current message as a
|
||||||
;; docid
|
;; docid
|
||||||
(mu4e~headers-goto-docid
|
(mu4e~headers-goto-docid
|
||||||
(with-current-buffer buffer
|
(with-current-buffer buffer
|
||||||
(mu4e-message-field (mu4e-message-at-point) :docid))))
|
(mu4e-message-field (mu4e-message-at-point) :docid))))
|
||||||
,@body
|
,@body
|
||||||
(mu4e-error "Cannot find message in headers buffer"))))))
|
(mu4e-error "Cannot find message in headers buffer"))))))
|
||||||
|
|
||||||
(defun mu4e-view-headers-next (&optional n)
|
(defun mu4e-view-headers-next (&optional n)
|
||||||
"Move point to the next message header.
|
"Move point to the next message header.
|
||||||
|
@ -239,7 +239,7 @@ bymessage-at-point. The actions are specified in
|
||||||
`mu4e-view-actions'."
|
`mu4e-view-actions'."
|
||||||
(interactive)
|
(interactive)
|
||||||
(let* ((msg (or msg (mu4e-message-at-point)))
|
(let* ((msg (or msg (mu4e-message-at-point)))
|
||||||
(actionfunc (mu4e-read-option "Action: " mu4e-view-actions)))
|
(actionfunc (mu4e-read-option "Action: " mu4e-view-actions)))
|
||||||
(funcall actionfunc msg)))
|
(funcall actionfunc msg)))
|
||||||
|
|
||||||
(defun mu4e-view-mark-pattern ()
|
(defun mu4e-view-mark-pattern ()
|
||||||
|
@ -290,25 +290,25 @@ Add this function to `mu4e-view-mode-hook' to enable this feature."
|
||||||
(save-excursion
|
(save-excursion
|
||||||
(goto-char (point-min))
|
(goto-char (point-min))
|
||||||
(while (re-search-forward
|
(while (re-search-forward
|
||||||
(concat "^" message-mark-insert-begin) nil t)
|
(concat "^" message-mark-insert-begin) nil t)
|
||||||
(setq ov-beg (match-beginning 0)
|
(setq ov-beg (match-beginning 0)
|
||||||
ov-end (match-end 0)
|
ov-end (match-end 0)
|
||||||
ov-inv (make-overlay ov-beg ov-end)
|
ov-inv (make-overlay ov-beg ov-end)
|
||||||
beg ov-end)
|
beg ov-end)
|
||||||
(overlay-put ov-inv 'invisible t)
|
(overlay-put ov-inv 'invisible t)
|
||||||
(overlay-put ov-inv 'mu4e-overlay t)
|
(overlay-put ov-inv 'mu4e-overlay t)
|
||||||
(when (re-search-forward
|
(when (re-search-forward
|
||||||
(concat "^" message-mark-insert-end) nil t)
|
(concat "^" message-mark-insert-end) nil t)
|
||||||
(setq ov-beg (match-beginning 0)
|
(setq ov-beg (match-beginning 0)
|
||||||
ov-end (match-end 0)
|
ov-end (match-end 0)
|
||||||
ov-inv (make-overlay ov-beg ov-end)
|
ov-inv (make-overlay ov-beg ov-end)
|
||||||
end ov-beg)
|
end ov-beg)
|
||||||
(overlay-put ov-inv 'invisible t))
|
(overlay-put ov-inv 'invisible t))
|
||||||
(when (and beg end)
|
(when (and beg end)
|
||||||
(let ((ov (make-overlay beg end)))
|
(let ((ov (make-overlay beg end)))
|
||||||
(overlay-put ov 'mu4e-overlay t)
|
(overlay-put ov 'mu4e-overlay t)
|
||||||
(overlay-put ov 'face 'mu4e-region-code))
|
(overlay-put ov 'face 'mu4e-region-code))
|
||||||
(setq beg nil end nil))))))
|
(setq beg nil end nil))))))
|
||||||
|
|
||||||
;;; View Utilities
|
;;; View Utilities
|
||||||
|
|
||||||
|
@ -328,19 +328,19 @@ Add this function to `mu4e-view-mode-hook' to enable this feature."
|
||||||
(unless mu4e-linked-headers-buffer
|
(unless mu4e-linked-headers-buffer
|
||||||
(mu4e-error "This view buffer is already detached."))
|
(mu4e-error "This view buffer is already detached."))
|
||||||
(mu4e-message "Detached view buffer from %s"
|
(mu4e-message "Detached view buffer from %s"
|
||||||
(prog1 mu4e-linked-headers-buffer
|
(prog1 mu4e-linked-headers-buffer
|
||||||
(with-current-buffer mu4e-linked-headers-buffer
|
(with-current-buffer mu4e-linked-headers-buffer
|
||||||
(when (eq (selected-window) mu4e~headers-view-win)
|
(when (eq (selected-window) mu4e~headers-view-win)
|
||||||
(setq mu4e~headers-view-win nil)))
|
(setq mu4e~headers-view-win nil)))
|
||||||
(setq mu4e-linked-headers-buffer nil))))
|
(setq mu4e-linked-headers-buffer nil))))
|
||||||
|
|
||||||
(defun mu4e-view-attach (headers-buffer)
|
(defun mu4e-view-attach (headers-buffer)
|
||||||
"Attaches a view buffer to a headers buffer."
|
"Attaches a view buffer to a headers buffer."
|
||||||
(interactive
|
(interactive
|
||||||
(list (get-buffer (read-buffer
|
(list (get-buffer (read-buffer
|
||||||
"Select a headers buffer to attach to: " nil t
|
"Select a headers buffer to attach to: " nil t
|
||||||
(lambda (buf) (with-current-buffer (car buf)
|
(lambda (buf) (with-current-buffer (car buf)
|
||||||
(mu4e-current-buffer-type-p 'headers)))))))
|
(mu4e-current-buffer-type-p 'headers)))))))
|
||||||
(mu4e-message "Attached view buffer to %s" headers-buffer)
|
(mu4e-message "Attached view buffer to %s" headers-buffer)
|
||||||
(setq mu4e-linked-headers-buffer headers-buffer)
|
(setq mu4e-linked-headers-buffer headers-buffer)
|
||||||
(with-current-buffer headers-buffer
|
(with-current-buffer headers-buffer
|
||||||
|
@ -392,12 +392,12 @@ list."
|
||||||
(defmacro mu4e~view-defun-mark-for (mark)
|
(defmacro mu4e~view-defun-mark-for (mark)
|
||||||
"Define a function mu4e-view-mark-for- MARK."
|
"Define a function mu4e-view-mark-for- MARK."
|
||||||
(let ((funcname (intern (format "mu4e-view-mark-for-%s" mark)))
|
(let ((funcname (intern (format "mu4e-view-mark-for-%s" mark)))
|
||||||
(docstring (format "Mark the current message for %s." mark)))
|
(docstring (format "Mark the current message for %s." mark)))
|
||||||
`(progn
|
`(progn
|
||||||
(defun ,funcname () ,docstring
|
(defun ,funcname () ,docstring
|
||||||
(interactive)
|
(interactive)
|
||||||
(mu4e~view-in-headers-context
|
(mu4e~view-in-headers-context
|
||||||
(mu4e-headers-mark-and-next ',mark)))
|
(mu4e-headers-mark-and-next ',mark)))
|
||||||
(put ',funcname 'definition-name ',mark))))
|
(put ',funcname 'definition-name ',mark))))
|
||||||
|
|
||||||
(mu4e~view-defun-mark-for move)
|
(mu4e~view-defun-mark-for move)
|
||||||
|
@ -447,8 +447,8 @@ If the url is mailto link, start writing an email to that address."
|
||||||
(let* (( url (or url (mu4e~view-get-property-from-event 'mu4e-url))))
|
(let* (( url (or url (mu4e~view-get-property-from-event 'mu4e-url))))
|
||||||
(when url
|
(when url
|
||||||
(if (string-match-p "^mailto:" url)
|
(if (string-match-p "^mailto:" url)
|
||||||
(browse-url-mail url)
|
(browse-url-mail url)
|
||||||
(browse-url url)))))
|
(browse-url url)))))
|
||||||
|
|
||||||
|
|
||||||
(defun mu4e~view-get-property-from-event (prop)
|
(defun mu4e~view-get-property-from-event (prop)
|
||||||
|
@ -456,13 +456,13 @@ If the url is mailto link, start writing an email to that address."
|
||||||
The action is chosen based on the `last-command-event'.
|
The action is chosen based on the `last-command-event'.
|
||||||
Meant to be evoked from interactive commands."
|
Meant to be evoked from interactive commands."
|
||||||
(if (and (eventp last-command-event)
|
(if (and (eventp last-command-event)
|
||||||
(mouse-event-p last-command-event))
|
(mouse-event-p last-command-event))
|
||||||
(let ((posn (event-end last-command-event)))
|
(let ((posn (event-end last-command-event)))
|
||||||
(when (numberp (posn-point posn))
|
(when (numberp (posn-point posn))
|
||||||
(get-text-property
|
(get-text-property
|
||||||
(posn-point posn)
|
(posn-point posn)
|
||||||
prop
|
prop
|
||||||
(window-buffer (posn-window posn)))))
|
(window-buffer (posn-window posn)))))
|
||||||
(get-text-property (point) prop)))
|
(get-text-property (point) prop)))
|
||||||
|
|
||||||
;; this is fairly simplistic...
|
;; this is fairly simplistic...
|
||||||
|
@ -472,27 +472,27 @@ Also number them so they can be opened using `mu4e-view-go-to-url'."
|
||||||
(let ((num 0))
|
(let ((num 0))
|
||||||
(save-excursion
|
(save-excursion
|
||||||
(setq mu4e~view-link-map ;; buffer local
|
(setq mu4e~view-link-map ;; buffer local
|
||||||
(make-hash-table :size 32 :weakness nil))
|
(make-hash-table :size 32 :weakness nil))
|
||||||
(goto-char (point-min))
|
(goto-char (point-min))
|
||||||
(while (re-search-forward mu4e~view-beginning-of-url-regexp nil t)
|
(while (re-search-forward mu4e~view-beginning-of-url-regexp nil t)
|
||||||
(let ((bounds (thing-at-point-bounds-of-url-at-point)))
|
(let ((bounds (thing-at-point-bounds-of-url-at-point)))
|
||||||
(when bounds
|
(when bounds
|
||||||
(let* ((url (thing-at-point-url-at-point))
|
(let* ((url (thing-at-point-url-at-point))
|
||||||
(ov (make-overlay (car bounds) (cdr bounds))))
|
(ov (make-overlay (car bounds) (cdr bounds))))
|
||||||
(puthash (cl-incf num) url mu4e~view-link-map)
|
(puthash (cl-incf num) url mu4e~view-link-map)
|
||||||
(add-text-properties
|
(add-text-properties
|
||||||
(car bounds)
|
(car bounds)
|
||||||
(cdr bounds)
|
(cdr bounds)
|
||||||
`(face mu4e-link-face
|
`(face mu4e-link-face
|
||||||
mouse-face highlight
|
mouse-face highlight
|
||||||
mu4e-url ,url
|
mu4e-url ,url
|
||||||
keymap ,mu4e-view-active-urls-keymap
|
keymap ,mu4e-view-active-urls-keymap
|
||||||
help-echo
|
help-echo
|
||||||
"[mouse-1] or [M-RET] to open the link"))
|
"[mouse-1] or [M-RET] to open the link"))
|
||||||
(overlay-put ov 'mu4e-overlay t)
|
(overlay-put ov 'mu4e-overlay t)
|
||||||
(overlay-put ov 'after-string
|
(overlay-put ov 'after-string
|
||||||
(propertize (format "\u200B[%d]" num)
|
(propertize (format "\u200B[%d]" num)
|
||||||
'face 'mu4e-url-number-face)))))))))
|
'face 'mu4e-url-number-face)))))))))
|
||||||
|
|
||||||
|
|
||||||
(defun mu4e~view-get-urls-num (prompt &optional multi)
|
(defun mu4e~view-get-urls-num (prompt &optional multi)
|
||||||
|
@ -505,21 +505,21 @@ string."
|
||||||
(let* ((count (hash-table-count mu4e~view-link-map)) (def))
|
(let* ((count (hash-table-count mu4e~view-link-map)) (def))
|
||||||
(when (zerop count) (mu4e-error "No links for this message"))
|
(when (zerop count) (mu4e-error "No links for this message"))
|
||||||
(if (not multi)
|
(if (not multi)
|
||||||
(if (= count 1)
|
(if (= count 1)
|
||||||
(read-number (mu4e-format "%s: " prompt) 1)
|
(read-number (mu4e-format "%s: " prompt) 1)
|
||||||
(read-number (mu4e-format "%s (1-%d): " prompt count)))
|
(read-number (mu4e-format "%s (1-%d): " prompt count)))
|
||||||
(progn
|
(progn
|
||||||
(setq def (if (= count 1) "1" (format "1-%d" count)))
|
(setq def (if (= count 1) "1" (format "1-%d" count)))
|
||||||
(read-string (mu4e-format "%s (default %s): " prompt def)
|
(read-string (mu4e-format "%s (default %s): " prompt def)
|
||||||
nil nil def)))))
|
nil nil def)))))
|
||||||
|
|
||||||
(defun mu4e-view-go-to-url (&optional multi)
|
(defun mu4e-view-go-to-url (&optional multi)
|
||||||
"Offer to go visit one or more URLs.
|
"Offer to go visit one or more URLs.
|
||||||
If MULTI (prefix-argument) is non-nil, offer to go to a range of URLs."
|
If MULTI (prefix-argument) is non-nil, offer to go to a range of URLs."
|
||||||
(interactive "P")
|
(interactive "P")
|
||||||
(mu4e~view-handle-urls "URL to visit"
|
(mu4e~view-handle-urls "URL to visit"
|
||||||
multi
|
multi
|
||||||
(lambda (url) (mu4e~view-browse-url-from-binding url))))
|
(lambda (url) (mu4e~view-browse-url-from-binding url))))
|
||||||
|
|
||||||
(defun mu4e-view-save-url (&optional multi)
|
(defun mu4e-view-save-url (&optional multi)
|
||||||
"Offer to save URLs to the kill ring.
|
"Offer to save URLs to the kill ring.
|
||||||
|
@ -527,9 +527,9 @@ If MULTI (prefix-argument) is nil, save a single one, otherwise, offer
|
||||||
to save a range of URLs."
|
to save a range of URLs."
|
||||||
(interactive "P")
|
(interactive "P")
|
||||||
(mu4e~view-handle-urls "URL to save" multi
|
(mu4e~view-handle-urls "URL to save" multi
|
||||||
(lambda (url)
|
(lambda (url)
|
||||||
(kill-new url)
|
(kill-new url)
|
||||||
(mu4e-message "Saved %s to the kill-ring" url))))
|
(mu4e-message "Saved %s to the kill-ring" url))))
|
||||||
|
|
||||||
(defun mu4e-view-fetch-url (&optional multi)
|
(defun mu4e-view-fetch-url (&optional multi)
|
||||||
"Offer to fetch (download) URLs.
|
"Offer to fetch (download) URLs.
|
||||||
|
@ -541,7 +541,7 @@ URLs. The urls are fetched to `mu4e-attachment-dir'."
|
||||||
"URL to fetch" multi
|
"URL to fetch" multi
|
||||||
(lambda (url)
|
(lambda (url)
|
||||||
(let ((target (concat (mu4e~get-attachment-dir url) "/"
|
(let ((target (concat (mu4e~get-attachment-dir url) "/"
|
||||||
(file-name-nondirectory url))))
|
(file-name-nondirectory url))))
|
||||||
(url-copy-file url target)
|
(url-copy-file url target)
|
||||||
(mu4e-message "Fetched %s -> %s" url target)))))
|
(mu4e-message "Fetched %s -> %s" url target)))))
|
||||||
|
|
||||||
|
@ -557,7 +557,7 @@ it to a range of uris. PROMPT is the query to present to the user."
|
||||||
"Apply URLFUNC to some URL with NUM in the current message.
|
"Apply URLFUNC to some URL with NUM in the current message.
|
||||||
Prompting the user with PROMPT for the number."
|
Prompting the user with PROMPT for the number."
|
||||||
(let* ((num (or num (mu4e~view-get-urls-num prompt)))
|
(let* ((num (or num (mu4e~view-get-urls-num prompt)))
|
||||||
(url (gethash num mu4e~view-link-map)))
|
(url (gethash num mu4e~view-link-map)))
|
||||||
(unless url (mu4e-warn "Invalid number for URL"))
|
(unless url (mu4e-warn "Invalid number for URL"))
|
||||||
(funcall urlfunc url)))
|
(funcall urlfunc url)))
|
||||||
|
|
||||||
|
@ -573,9 +573,9 @@ of urls. You can type multiple values separated by space, e.g. 1
|
||||||
Furthermore, there is a shortcut \"a\" which means all urls, but as
|
Furthermore, there is a shortcut \"a\" which means all urls, but as
|
||||||
this is the default, you may not need it."
|
this is the default, you may not need it."
|
||||||
(let* ((linkstr (mu4e~view-get-urls-num
|
(let* ((linkstr (mu4e~view-get-urls-num
|
||||||
"URL number range (or 'a' for 'all')" t))
|
"URL number range (or 'a' for 'all')" t))
|
||||||
(count (hash-table-count mu4e~view-link-map))
|
(count (hash-table-count mu4e~view-link-map))
|
||||||
(linknums (mu4e-split-ranges-to-numbers linkstr count)))
|
(linknums (mu4e-split-ranges-to-numbers linkstr count)))
|
||||||
(dolist (num linknums)
|
(dolist (num linknums)
|
||||||
(mu4e~view-handle-single-url prompt urlfunc num))))
|
(mu4e~view-handle-single-url prompt urlfunc num))))
|
||||||
|
|
||||||
|
@ -629,14 +629,14 @@ As a side-effect, a message that is being viewed loses its
|
||||||
(setq gnus-article-buffer (mu4e-get-view-buffer nil t))
|
(setq gnus-article-buffer (mu4e-get-view-buffer nil t))
|
||||||
(with-current-buffer gnus-article-buffer
|
(with-current-buffer gnus-article-buffer
|
||||||
(when linked-headers-buffer
|
(when linked-headers-buffer
|
||||||
(setq mu4e-linked-headers-buffer linked-headers-buffer))
|
(setq mu4e-linked-headers-buffer linked-headers-buffer))
|
||||||
(let ((inhibit-read-only t))
|
(let ((inhibit-read-only t))
|
||||||
(remove-overlays (point-min)(point-max) 'mu4e-overlay t)
|
(remove-overlays (point-min)(point-max) 'mu4e-overlay t)
|
||||||
(erase-buffer)
|
(erase-buffer)
|
||||||
(insert-file-contents-literally
|
(insert-file-contents-literally
|
||||||
(mu4e-message-readable-path msg) nil nil nil t)
|
(mu4e-message-readable-path msg) nil nil nil t)
|
||||||
(setq-local mu4e~view-message msg)
|
(setq-local mu4e~view-message msg)
|
||||||
(mu4e~view-render-buffer msg))
|
(mu4e~view-render-buffer msg))
|
||||||
(mu4e-loading-mode 0)))
|
(mu4e-loading-mode 0)))
|
||||||
(unless (mu4e--view-detached-p gnus-article-buffer)
|
(unless (mu4e--view-detached-p gnus-article-buffer)
|
||||||
(with-current-buffer mu4e-linked-headers-buffer
|
(with-current-buffer mu4e-linked-headers-buffer
|
||||||
|
@ -647,9 +647,9 @@ As a side-effect, a message that is being viewed loses its
|
||||||
;; Otherwise, `mu4e-display-buffer' may adjust the view buffer's
|
;; Otherwise, `mu4e-display-buffer' may adjust the view buffer's
|
||||||
;; window height based on a buffer that has no text in it yet!
|
;; window height based on a buffer that has no text in it yet!
|
||||||
(setq-local mu4e~headers-view-win
|
(setq-local mu4e~headers-view-win
|
||||||
(mu4e-display-buffer gnus-article-buffer nil))
|
(mu4e-display-buffer gnus-article-buffer nil))
|
||||||
(unless (window-live-p mu4e~headers-view-win)
|
(unless (window-live-p mu4e~headers-view-win)
|
||||||
(mu4e-error "Cannot get a message view"))
|
(mu4e-error "Cannot get a message view"))
|
||||||
(select-window mu4e~headers-view-win)))
|
(select-window mu4e~headers-view-win)))
|
||||||
(with-current-buffer gnus-article-buffer
|
(with-current-buffer gnus-article-buffer
|
||||||
(run-hooks 'mu4e-after-view-message-hook)))
|
(run-hooks 'mu4e-after-view-message-hook)))
|
||||||
|
@ -675,17 +675,17 @@ determine which browser function to use."
|
||||||
(mu4e-message-readable-path msg) nil nil nil t)
|
(mu4e-message-readable-path msg) nil nil nil t)
|
||||||
(run-hooks 'gnus-article-decode-hook)
|
(run-hooks 'gnus-article-decode-hook)
|
||||||
(let ((header (unless skip-headers
|
(let ((header (unless skip-headers
|
||||||
(cl-loop for field in '("from" "to" "cc" "date" "subject")
|
(cl-loop for field in '("from" "to" "cc" "date" "subject")
|
||||||
when (message-fetch-field field)
|
when (message-fetch-field field)
|
||||||
concat (format "%s: %s\n" (capitalize field) it))))
|
concat (format "%s: %s\n" (capitalize field) it))))
|
||||||
(parts (mm-dissect-buffer t t)))
|
(parts (mm-dissect-buffer t t)))
|
||||||
;; If singlepart, enforce a list.
|
;; If singlepart, enforce a list.
|
||||||
(when (and (bufferp (car parts))
|
(when (and (bufferp (car parts))
|
||||||
(stringp (car (mm-handle-type parts))))
|
(stringp (car (mm-handle-type parts))))
|
||||||
(setq parts (list parts)))
|
(setq parts (list parts)))
|
||||||
;; Process the list
|
;; Process the list
|
||||||
(unless (gnus-article-browse-html-parts parts header)
|
(unless (gnus-article-browse-html-parts parts header)
|
||||||
(mu4e-warn "Message does not contain a \"text/html\" part"))
|
(mu4e-warn "Message does not contain a \"text/html\" part"))
|
||||||
(mm-destroy-parts parts))))
|
(mm-destroy-parts parts))))
|
||||||
|
|
||||||
(defun mu4e-action-view-in-xwidget (msg)
|
(defun mu4e-action-view-in-xwidget (msg)
|
||||||
|
@ -693,47 +693,47 @@ determine which browser function to use."
|
||||||
(unless (fboundp 'xwidget-webkit-browse-url)
|
(unless (fboundp 'xwidget-webkit-browse-url)
|
||||||
(mu4e-error "No xwidget support available"))
|
(mu4e-error "No xwidget support available"))
|
||||||
(let ((browse-url-handlers nil)
|
(let ((browse-url-handlers nil)
|
||||||
(browse-url-browser-function
|
(browse-url-browser-function
|
||||||
(lambda (url &optional _rest)
|
(lambda (url &optional _rest)
|
||||||
(xwidget-webkit-browse-url url))))
|
(xwidget-webkit-browse-url url))))
|
||||||
(mu4e-action-view-in-browser msg)))
|
(mu4e-action-view-in-browser msg)))
|
||||||
|
|
||||||
(defun mu4e~view-render-buffer (msg)
|
(defun mu4e~view-render-buffer (msg)
|
||||||
"Render current buffer with MSG using Gnus' article mode."
|
"Render current buffer with MSG using Gnus' article mode."
|
||||||
(setq gnus-summary-buffer (get-buffer-create " *appease-gnus*"))
|
(setq gnus-summary-buffer (get-buffer-create " *appease-gnus*"))
|
||||||
(let* ((inhibit-read-only t)
|
(let* ((inhibit-read-only t)
|
||||||
(max-specpdl-size mu4e-view-max-specpdl-size)
|
(max-specpdl-size mu4e-view-max-specpdl-size)
|
||||||
(mm-decrypt-option 'known)
|
(mm-decrypt-option 'known)
|
||||||
(ct (mail-fetch-field "Content-Type"))
|
(ct (mail-fetch-field "Content-Type"))
|
||||||
(ct (and ct (mail-header-parse-content-type ct)))
|
(ct (and ct (mail-header-parse-content-type ct)))
|
||||||
(charset (mail-content-type-get ct 'charset))
|
(charset (mail-content-type-get ct 'charset))
|
||||||
(charset (and charset (intern charset)))
|
(charset (and charset (intern charset)))
|
||||||
(mu4e~view-rendering t); Needed if e.g. an ics file is buttonized
|
(mu4e~view-rendering t); Needed if e.g. an ics file is buttonized
|
||||||
(gnus-article-emulate-mime t)
|
(gnus-article-emulate-mime t)
|
||||||
(gnus-unbuttonized-mime-types '(".*/.*"))
|
(gnus-unbuttonized-mime-types '(".*/.*"))
|
||||||
(gnus-buttonized-mime-types
|
(gnus-buttonized-mime-types
|
||||||
(append (list "multipart/signed" "multipart/encrypted")
|
(append (list "multipart/signed" "multipart/encrypted")
|
||||||
gnus-buttonized-mime-types))
|
gnus-buttonized-mime-types))
|
||||||
(gnus-newsgroup-charset
|
(gnus-newsgroup-charset
|
||||||
(if (and charset (coding-system-p charset)) charset
|
(if (and charset (coding-system-p charset)) charset
|
||||||
(detect-coding-region (point-min) (point-max) t)))
|
(detect-coding-region (point-min) (point-max) t)))
|
||||||
;; Possibly add headers (before "Attachments")
|
;; Possibly add headers (before "Attachments")
|
||||||
(gnus-display-mime-function (mu4e~view-gnus-display-mime msg))
|
(gnus-display-mime-function (mu4e~view-gnus-display-mime msg))
|
||||||
(gnus-icalendar-additional-identities
|
(gnus-icalendar-additional-identities
|
||||||
(mu4e-personal-addresses 'no-regexp)))
|
(mu4e-personal-addresses 'no-regexp)))
|
||||||
(condition-case err
|
(condition-case err
|
||||||
(progn
|
(progn
|
||||||
(mm-enable-multibyte)
|
(mm-enable-multibyte)
|
||||||
(run-hooks 'gnus-article-decode-hook)
|
(run-hooks 'gnus-article-decode-hook)
|
||||||
(gnus-article-prepare-display)
|
(gnus-article-prepare-display)
|
||||||
(mu4e~view-activate-urls)
|
(mu4e~view-activate-urls)
|
||||||
(setq mu4e~gnus-article-mime-handles gnus-article-mime-handles
|
(setq mu4e~gnus-article-mime-handles gnus-article-mime-handles
|
||||||
gnus-article-decoded-p gnus-article-decode-hook)
|
gnus-article-decoded-p gnus-article-decode-hook)
|
||||||
(set-buffer-modified-p nil)
|
(set-buffer-modified-p nil)
|
||||||
(add-hook 'kill-buffer-hook #'mu4e~view-kill-mime-handles))
|
(add-hook 'kill-buffer-hook #'mu4e~view-kill-mime-handles))
|
||||||
(epg-error
|
(epg-error
|
||||||
(mu4e-warn "EPG error: %s; fall back to raw view"
|
(mu4e-warn "EPG error: %s; fall back to raw view"
|
||||||
(error-message-string err))))))
|
(error-message-string err))))))
|
||||||
|
|
||||||
(defun mu4e~view-kill-mime-handles ()
|
(defun mu4e~view-kill-mime-handles ()
|
||||||
"Kill cached MIME-handles, if any."
|
"Kill cached MIME-handles, if any."
|
||||||
|
@ -752,7 +752,7 @@ determine which browser function to use."
|
||||||
"Toggle whether to show all MIME-parts."
|
"Toggle whether to show all MIME-parts."
|
||||||
(interactive)
|
(interactive)
|
||||||
(setq gnus-inhibit-mime-unbuttonizing
|
(setq gnus-inhibit-mime-unbuttonizing
|
||||||
(not gnus-inhibit-mime-unbuttonizing))
|
(not gnus-inhibit-mime-unbuttonizing))
|
||||||
(mu4e-view-refresh))
|
(mu4e-view-refresh))
|
||||||
|
|
||||||
(defun mu4e-view-toggle-fill-flowed()
|
(defun mu4e-view-toggle-fill-flowed()
|
||||||
|
@ -767,54 +767,54 @@ determine which browser function to use."
|
||||||
(gnus-display-mime ihandles)
|
(gnus-display-mime ihandles)
|
||||||
(unless ihandles
|
(unless ihandles
|
||||||
(save-restriction
|
(save-restriction
|
||||||
(article-goto-body)
|
(article-goto-body)
|
||||||
(forward-line -1)
|
(forward-line -1)
|
||||||
(narrow-to-region (point) (point))
|
(narrow-to-region (point) (point))
|
||||||
(dolist (field mu4e-view-fields)
|
(dolist (field mu4e-view-fields)
|
||||||
(let ((fieldval (mu4e-message-field msg field)))
|
(let ((fieldval (mu4e-message-field msg field)))
|
||||||
(pcase field
|
(pcase field
|
||||||
((or ':path ':maildir :list ':user-agent ':message-id)
|
((or ':path ':maildir :list ':user-agent ':message-id)
|
||||||
(mu4e~view-gnus-insert-header field fieldval))
|
(mu4e~view-gnus-insert-header field fieldval))
|
||||||
(':mailing-list
|
(':mailing-list
|
||||||
(let ((list (plist-get msg :list)))
|
(let ((list (plist-get msg :list)))
|
||||||
(if list (mu4e-get-mailing-list-shortname list) "")))
|
(if list (mu4e-get-mailing-list-shortname list) "")))
|
||||||
((or ':flags ':tags)
|
((or ':flags ':tags)
|
||||||
(let ((flags (mapconcat (lambda (flag)
|
(let ((flags (mapconcat (lambda (flag)
|
||||||
(if (symbolp flag)
|
(if (symbolp flag)
|
||||||
(symbol-name flag)
|
(symbol-name flag)
|
||||||
flag)) fieldval ", ")))
|
flag)) fieldval ", ")))
|
||||||
(mu4e~view-gnus-insert-header field flags)))
|
(mu4e~view-gnus-insert-header field flags)))
|
||||||
(':size (mu4e~view-gnus-insert-header
|
(':size (mu4e~view-gnus-insert-header
|
||||||
field (mu4e-display-size fieldval)))
|
field (mu4e-display-size fieldval)))
|
||||||
((or ':subject ':to ':from ':cc ':bcc ':from-or-to
|
((or ':subject ':to ':from ':cc ':bcc ':from-or-to
|
||||||
':date :attachments ':signature
|
':date :attachments ':signature
|
||||||
':decryption)) ; handled by Gnus
|
':decryption)) ; handled by Gnus
|
||||||
(_
|
(_
|
||||||
(mu4e~view-gnus-insert-header-custom msg field)))))
|
(mu4e~view-gnus-insert-header-custom msg field)))))
|
||||||
(let ((gnus-treatment-function-alist
|
(let ((gnus-treatment-function-alist
|
||||||
'((gnus-treat-highlight-headers
|
'((gnus-treat-highlight-headers
|
||||||
gnus-article-highlight-headers))))
|
gnus-article-highlight-headers))))
|
||||||
(gnus-treat-article 'head))))))
|
(gnus-treat-article 'head))))))
|
||||||
|
|
||||||
(defun mu4e~view-gnus-insert-header (field val)
|
(defun mu4e~view-gnus-insert-header (field val)
|
||||||
"Insert a header FIELD with value VAL."
|
"Insert a header FIELD with value VAL."
|
||||||
(let* ((info (cdr (assoc field mu4e-header-info)))
|
(let* ((info (cdr (assoc field mu4e-header-info)))
|
||||||
(key (plist-get info :name))
|
(key (plist-get info :name))
|
||||||
(help (plist-get info :help)))
|
(help (plist-get info :help)))
|
||||||
(if (and val (> (length val) 0))
|
(if (and val (> (length val) 0))
|
||||||
(insert (propertize (concat key ":") 'help-echo help)
|
(insert (propertize (concat key ":") 'help-echo help)
|
||||||
" " val "\n"))))
|
" " val "\n"))))
|
||||||
|
|
||||||
(defun mu4e~view-gnus-insert-header-custom (msg field)
|
(defun mu4e~view-gnus-insert-header-custom (msg field)
|
||||||
"Insert MSG's custom FIELD."
|
"Insert MSG's custom FIELD."
|
||||||
(let* ((info (cdr-safe (or (assoc field mu4e-header-info-custom)
|
(let* ((info (cdr-safe (or (assoc field mu4e-header-info-custom)
|
||||||
(mu4e-error "Custom field %S not found" field))))
|
(mu4e-error "Custom field %S not found" field))))
|
||||||
(key (plist-get info :name))
|
(key (plist-get info :name))
|
||||||
(func (or (plist-get info :function)
|
(func (or (plist-get info :function)
|
||||||
(mu4e-error "No :function defined for custom field %S %S"
|
(mu4e-error "No :function defined for custom field %S %S"
|
||||||
field info)))
|
field info)))
|
||||||
(val (funcall func msg))
|
(val (funcall func msg))
|
||||||
(help (plist-get info :help)))
|
(help (plist-get info :help)))
|
||||||
(when (and val (> (length val) 0))
|
(when (and val (> (length val) 0))
|
||||||
(insert (propertize (concat key ":") 'help-echo help) " " val "\n"))))
|
(insert (propertize (concat key ":") 'help-echo help) " " val "\n"))))
|
||||||
|
|
||||||
|
@ -823,14 +823,14 @@ determine which browser function to use."
|
||||||
"Avoid error when displaying an ical attachment without a charset."
|
"Avoid error when displaying an ical attachment without a charset."
|
||||||
(if (and (boundp 'mu4e~view-rendering) mu4e~view-rendering)
|
(if (and (boundp 'mu4e~view-rendering) mu4e~view-rendering)
|
||||||
(let* ((handle (car handle-attendee))
|
(let* ((handle (car handle-attendee))
|
||||||
(attendee (cadr handle-attendee))
|
(attendee (cadr handle-attendee))
|
||||||
(buf (mm-handle-buffer handle))
|
(buf (mm-handle-buffer handle))
|
||||||
(ty (mm-handle-type handle))
|
(ty (mm-handle-type handle))
|
||||||
(rest (cddr handle)))
|
(rest (cddr handle)))
|
||||||
;; Put the fallback at the end:
|
;; Put the fallback at the end:
|
||||||
(setq ty (append ty '((charset . "utf-8"))))
|
(setq ty (append ty '((charset . "utf-8"))))
|
||||||
(setq handle (cons buf (cons ty rest)))
|
(setq handle (cons buf (cons ty rest)))
|
||||||
(list handle attendee))
|
(list handle attendee))
|
||||||
handle-attendee))
|
handle-attendee))
|
||||||
|
|
||||||
(defun mu4e~view-mode-p ()
|
(defun mu4e~view-mode-p ()
|
||||||
|
@ -961,26 +961,26 @@ This is useful for advising some Gnus-functionality that does not work in mu4e."
|
||||||
(define-key map [menu-bar headers] (cons "Mu4e" menumap))
|
(define-key map [menu-bar headers] (cons "Mu4e" menumap))
|
||||||
|
|
||||||
(define-key menumap [quit-buffer]
|
(define-key menumap [quit-buffer]
|
||||||
'("Quit view" . mu4e~view-quit-buffer))
|
'("Quit view" . mu4e~view-quit-buffer))
|
||||||
(define-key menumap [display-help] '("Help" . mu4e-display-manual))
|
(define-key menumap [display-help] '("Help" . kill-buffer-and-window))
|
||||||
|
|
||||||
(define-key menumap [sepa0] '("--"))
|
(define-key menumap [sepa0] '("--"))
|
||||||
(define-key menumap [wrap-lines]
|
(define-key menumap [wrap-lines]
|
||||||
'("Toggle wrap lines" . visual-line-mode))
|
'("Toggle wrap lines" . visual-line-mode))
|
||||||
(define-key menumap [raw-view]
|
(define-key menumap [raw-view]
|
||||||
'("View raw message" . mu4e-view-raw-message))
|
'("View raw message" . mu4e-view-raw-message))
|
||||||
(define-key menumap [pipe]
|
(define-key menumap [pipe]
|
||||||
'("Pipe through shell" . mu4e-view-pipe))
|
'("Pipe through shell" . mu4e-view-pipe))
|
||||||
|
|
||||||
(define-key menumap [sepa1] '("--"))
|
(define-key menumap [sepa1] '("--"))
|
||||||
(define-key menumap [mark-delete]
|
(define-key menumap [mark-delete]
|
||||||
'("Mark for deletion" . mu4e-view-mark-for-delete))
|
'("Mark for deletion" . mu4e-view-mark-for-delete))
|
||||||
(define-key menumap [mark-untrash]
|
(define-key menumap [mark-untrash]
|
||||||
'("Mark for untrash" . mu4e-view-mark-for-untrash))
|
'("Mark for untrash" . mu4e-view-mark-for-untrash))
|
||||||
(define-key menumap [mark-trash]
|
(define-key menumap [mark-trash]
|
||||||
'("Mark for trash" . mu4e-view-mark-for-trash))
|
'("Mark for trash" . mu4e-view-mark-for-trash))
|
||||||
(define-key menumap [mark-move]
|
(define-key menumap [mark-move]
|
||||||
'("Mark for move" . mu4e-view-mark-for-move))
|
'("Mark for move" . mu4e-view-mark-for-move))
|
||||||
|
|
||||||
(define-key menumap [sepa2] '("--"))
|
(define-key menumap [sepa2] '("--"))
|
||||||
(define-key menumap [resend] '("Resend" . mu4e-compose-resend))
|
(define-key menumap [resend] '("Resend" . mu4e-compose-resend))
|
||||||
|
@ -990,17 +990,17 @@ This is useful for advising some Gnus-functionality that does not work in mu4e."
|
||||||
(define-key menumap [sepa3] '("--"))
|
(define-key menumap [sepa3] '("--"))
|
||||||
|
|
||||||
(define-key menumap [query-next]
|
(define-key menumap [query-next]
|
||||||
'("Next query" . mu4e-headers-query-next))
|
'("Next query" . mu4e-headers-query-next))
|
||||||
(define-key menumap [query-prev]
|
(define-key menumap [query-prev]
|
||||||
'("Previous query" . mu4e-headers-query-prev))
|
'("Previous query" . mu4e-headers-query-prev))
|
||||||
(define-key menumap [narrow-search]
|
(define-key menumap [narrow-search]
|
||||||
'("Narrow search" . mu4e-headers-search-narrow))
|
'("Narrow search" . mu4e-headers-search-narrow))
|
||||||
(define-key menumap [bookmark]
|
(define-key menumap [bookmark]
|
||||||
'("Search bookmark" . mu4e-headers-search-bookmark))
|
'("Search bookmark" . mu4e-headers-search-bookmark))
|
||||||
(define-key menumap [jump]
|
(define-key menumap [jump]
|
||||||
'("Jump to maildir" . mu4e~headers-jump-to-maildir))
|
'("Jump to maildir" . mu4e~headers-jump-to-maildir))
|
||||||
(define-key menumap [search]
|
(define-key menumap [search]
|
||||||
'("Search" . mu4e-headers-search))
|
'("Search" . mu4e-headers-search))
|
||||||
|
|
||||||
(define-key menumap [sepa4] '("--"))
|
(define-key menumap [sepa4] '("--"))
|
||||||
(define-key menumap [next] '("Next" . mu4e-view-headers-next))
|
(define-key menumap [next] '("Next" . mu4e-view-headers-next))
|
||||||
|
@ -1048,9 +1048,9 @@ Based on Gnus' article-mode."
|
||||||
;; advice gnus-block-private-groups to always return "."
|
;; advice gnus-block-private-groups to always return "."
|
||||||
;; so that by default we block images.
|
;; so that by default we block images.
|
||||||
(advice-add 'gnus-block-private-groups :around
|
(advice-add 'gnus-block-private-groups :around
|
||||||
(lambda(func &rest args)
|
(lambda(func &rest args)
|
||||||
(if (mu4e~view-mode-p)
|
(if (mu4e~view-mode-p)
|
||||||
"." (apply func args))))
|
"." (apply func args))))
|
||||||
(use-local-map mu4e-view-mode-map)
|
(use-local-map mu4e-view-mode-map)
|
||||||
(mu4e-context-minor-mode)
|
(mu4e-context-minor-mode)
|
||||||
(mu4e-search-minor-mode)
|
(mu4e-search-minor-mode)
|
||||||
|
@ -1094,12 +1094,12 @@ The alist uniquely maps the number to the gnus-part."
|
||||||
(save-excursion
|
(save-excursion
|
||||||
(goto-char (point-min))
|
(goto-char (point-min))
|
||||||
(while (not (eobp))
|
(while (not (eobp))
|
||||||
(let ((part (get-text-property (point) 'gnus-data))
|
(let ((part (get-text-property (point) 'gnus-data))
|
||||||
(index (get-text-property (point) 'gnus-part)))
|
(index (get-text-property (point) 'gnus-part)))
|
||||||
(when (and part (numberp index) (not (assoc index parts))
|
(when (and part (numberp index) (not (assoc index parts))
|
||||||
(push `(,index . ,part) parts)))
|
(push `(,index . ,part) parts)))
|
||||||
(goto-char (or (next-single-property-change (point) 'gnus-part)
|
(goto-char (or (next-single-property-change (point) 'gnus-part)
|
||||||
(point-max))))))
|
(point-max))))))
|
||||||
parts))
|
parts))
|
||||||
|
|
||||||
|
|
||||||
|
@ -1118,47 +1118,47 @@ Note, currently this does not work well with file names
|
||||||
containing commas."
|
containing commas."
|
||||||
(interactive "P")
|
(interactive "P")
|
||||||
(cl-assert (and (eq major-mode 'mu4e-view-mode)
|
(cl-assert (and (eq major-mode 'mu4e-view-mode)
|
||||||
(derived-mode-p 'gnus-article-mode)))
|
(derived-mode-p 'gnus-article-mode)))
|
||||||
(let* ((parts (mu4e~view-gather-mime-parts))
|
(let* ((parts (mu4e~view-gather-mime-parts))
|
||||||
(handles '())
|
(handles '())
|
||||||
(files '())
|
(files '())
|
||||||
(compfn (if (and (boundp 'helm-mode) helm-mode)
|
(compfn (if (and (boundp 'helm-mode) helm-mode)
|
||||||
#'completing-read
|
#'completing-read
|
||||||
;; Fallback to `completing-read-multiple' with poor
|
;; Fallback to `completing-read-multiple' with poor
|
||||||
;; completion
|
;; completion
|
||||||
#'completing-read-multiple))
|
#'completing-read-multiple))
|
||||||
dir)
|
dir)
|
||||||
(dolist (part parts)
|
(dolist (part parts)
|
||||||
(let ((fname (or (cdr (assoc 'filename (assoc "attachment" (cdr part))))
|
(let ((fname (or (cdr (assoc 'filename (assoc "attachment" (cdr part))))
|
||||||
(cl-loop for item in part
|
(cl-loop for item in part
|
||||||
for name = (and (listp item)
|
for name = (and (listp item)
|
||||||
(assoc-default 'name item))
|
(assoc-default 'name item))
|
||||||
thereis (and (stringp name) name)))))
|
thereis (and (stringp name) name)))))
|
||||||
(when fname
|
(when fname
|
||||||
(push `(,fname . ,(cdr part)) handles)
|
(push `(,fname . ,(cdr part)) handles)
|
||||||
(push fname files))))
|
(push fname files))))
|
||||||
(if files
|
(if files
|
||||||
(progn
|
(progn
|
||||||
(setq files (let ((helm-comp-read-use-marked t))
|
(setq files (let ((helm-comp-read-use-marked t))
|
||||||
(funcall compfn "Save part(s): " files))
|
(funcall compfn "Save part(s): " files))
|
||||||
dir (if arg (read-directory-name "Save to directory: ")
|
dir (if arg (read-directory-name "Save to directory: ")
|
||||||
mu4e-attachment-dir))
|
mu4e-attachment-dir))
|
||||||
(cl-loop for (f . h) in handles
|
(cl-loop for (f . h) in handles
|
||||||
when (member f files)
|
when (member f files)
|
||||||
do (mm-save-part-to-file
|
do (mm-save-part-to-file
|
||||||
h (let ((file (expand-file-name f dir)))
|
h (let ((file (expand-file-name f dir)))
|
||||||
(if (file-exists-p file)
|
(if (file-exists-p file)
|
||||||
(let (newname (count 1))
|
(let (newname (count 1))
|
||||||
(while (and
|
(while (and
|
||||||
(setq newname
|
(setq newname
|
||||||
(concat
|
(concat
|
||||||
(file-name-sans-extension file)
|
(file-name-sans-extension file)
|
||||||
(format "(%s)" count)
|
(format "(%s)" count)
|
||||||
(file-name-extension file t)))
|
(file-name-extension file t)))
|
||||||
(file-exists-p newname))
|
(file-exists-p newname))
|
||||||
(cl-incf count))
|
(cl-incf count))
|
||||||
newname)
|
newname)
|
||||||
file)))))
|
file)))))
|
||||||
(mu4e-message "No attached files found"))))
|
(mu4e-message "No attached files found"))))
|
||||||
|
|
||||||
|
|
||||||
|
@ -1176,7 +1176,7 @@ containing commas."
|
||||||
(:name "open" :handler mu4e~view-open-file :receives temp)
|
(:name "open" :handler mu4e~view-open-file :receives temp)
|
||||||
;; open with some custom file.
|
;; open with some custom file.
|
||||||
(:name "wopen-with" :handler (lambda (file)(mu4e~view-open-file file t))
|
(:name "wopen-with" :handler (lambda (file)(mu4e~view-open-file file t))
|
||||||
:receives temp)
|
:receives temp)
|
||||||
|
|
||||||
;;
|
;;
|
||||||
;; some more examples
|
;; some more examples
|
||||||
|
@ -1191,13 +1191,13 @@ containing commas."
|
||||||
(:name "emacs" :handler find-file-read-only :receives temp)
|
(:name "emacs" :handler find-file-read-only :receives temp)
|
||||||
;; open in this emacs instance, "raw"
|
;; open in this emacs instance, "raw"
|
||||||
(:name "raw" :handler (lambda (str)
|
(:name "raw" :handler (lambda (str)
|
||||||
(let ((tmpbuf
|
(let ((tmpbuf
|
||||||
(get-buffer-create " *mu4e-raw-mime*")))
|
(get-buffer-create " *mu4e-raw-mime*")))
|
||||||
(with-current-buffer tmpbuf
|
(with-current-buffer tmpbuf
|
||||||
(insert str)
|
(insert str)
|
||||||
(view-mode)
|
(view-mode)
|
||||||
(goto-char (point-min)))
|
(goto-char (point-min)))
|
||||||
(display-buffer tmpbuf))) :receives pipe))
|
(display-buffer tmpbuf))) :receives pipe))
|
||||||
|
|
||||||
"Specifies actions for MIME-parts.
|
"Specifies actions for MIME-parts.
|
||||||
|
|
||||||
|
@ -1205,16 +1205,16 @@ Each of the actions is a plist with keys
|
||||||
`(:name <name> ;; name of the action; shortcut is first letter of name
|
`(:name <name> ;; name of the action; shortcut is first letter of name
|
||||||
|
|
||||||
:handler ;; one of:
|
:handler ;; one of:
|
||||||
;; - a function receiving the index/temp/pipe
|
;; - a function receiving the index/temp/pipe
|
||||||
;; - a string, which is taken as a shell command
|
;; - a string, which is taken as a shell command
|
||||||
|
|
||||||
:receives ;; a symbol specifying what the handler receives
|
:receives ;; a symbol specifying what the handler receives
|
||||||
;; - index: the index number of the mime part (default)
|
;; - index: the index number of the mime part (default)
|
||||||
;; - temp: the full path to the mime part in a
|
;; - temp: the full path to the mime part in a
|
||||||
;; temporary file, which is deleted immediately
|
;; temporary file, which is deleted immediately
|
||||||
;; after invoking handler
|
;; after invoking handler
|
||||||
;; - pipe: the attachment is piped to some shell command
|
;; - pipe: the attachment is piped to some shell command
|
||||||
;; or as a string parameter to a function
|
;; or as a string parameter to a function
|
||||||
).")
|
).")
|
||||||
|
|
||||||
|
|
||||||
|
@ -1225,17 +1225,17 @@ otherwise random; the result is placed in a temporary directory
|
||||||
with a unique name. Returns the full path for the file created.
|
with a unique name. Returns the full path for the file created.
|
||||||
The directory and file are self-destructed."
|
The directory and file are self-destructed."
|
||||||
(let* ((tmpdir (make-temp-file "mu4e-temp-" t))
|
(let* ((tmpdir (make-temp-file "mu4e-temp-" t))
|
||||||
(fname (mm-handle-filename handle))
|
(fname (mm-handle-filename handle))
|
||||||
(fname (and fname
|
(fname (and fname
|
||||||
(gnus-map-function mm-file-name-rewrite-functions
|
(gnus-map-function mm-file-name-rewrite-functions
|
||||||
(file-name-nondirectory fname))))
|
(file-name-nondirectory fname))))
|
||||||
(fname (if fname
|
(fname (if fname
|
||||||
(concat tmpdir "/" (replace-regexp-in-string "/" "-" fname))
|
(concat tmpdir "/" (replace-regexp-in-string "/" "-" fname))
|
||||||
(let ((temporary-file-directory tmpdir))
|
(let ((temporary-file-directory tmpdir))
|
||||||
(make-temp-file "mimepart")))))
|
(make-temp-file "mimepart")))))
|
||||||
(mm-save-part-to-file handle fname)
|
(mm-save-part-to-file handle fname)
|
||||||
(run-at-time "30 sec" nil
|
(run-at-time "30 sec" nil
|
||||||
(lambda () (ignore-errors (delete-directory tmpdir t))))
|
(lambda () (ignore-errors (delete-directory tmpdir t))))
|
||||||
fname))
|
fname))
|
||||||
|
|
||||||
|
|
||||||
|
@ -1244,12 +1244,12 @@ The directory and file are self-destructed."
|
||||||
Otherwise, or if FORCE-ASK is set, ask user for the program to
|
Otherwise, or if FORCE-ASK is set, ask user for the program to
|
||||||
open with."
|
open with."
|
||||||
(if (and (not force-ask)
|
(if (and (not force-ask)
|
||||||
(functionp mu4e-view-open-program))
|
(functionp mu4e-view-open-program))
|
||||||
(funcall mu4e-view-open-program file)
|
(funcall mu4e-view-open-program file)
|
||||||
(let ((opener
|
(let ((opener
|
||||||
(or (and (not force-ask) mu4e-view-open-program
|
(or (and (not force-ask) mu4e-view-open-program
|
||||||
(executable-find mu4e-view-open-program))
|
(executable-find mu4e-view-open-program))
|
||||||
(read-shell-command "Open MIME-part with: "))))
|
(read-shell-command "Open MIME-part with: "))))
|
||||||
(call-process opener nil 0 nil file))))
|
(call-process opener nil 0 nil file))))
|
||||||
|
|
||||||
(defun mu4e-view-mime-part-action (&optional n)
|
(defun mu4e-view-mime-part-action (&optional n)
|
||||||
|
@ -1258,43 +1258,43 @@ If N is not specified, ask for it. For instance, '3 A o' opens
|
||||||
the third MIME-part."
|
the third MIME-part."
|
||||||
(interactive "NNumber of MIME-part: ")
|
(interactive "NNumber of MIME-part: ")
|
||||||
(let* ((parts (mu4e~view-gather-mime-parts))
|
(let* ((parts (mu4e~view-gather-mime-parts))
|
||||||
(options
|
(options
|
||||||
(mapcar (lambda (action) `(,(plist-get action :name) . ,action))
|
(mapcar (lambda (action) `(,(plist-get action :name) . ,action))
|
||||||
mu4e-view-mime-part-actions))
|
mu4e-view-mime-part-actions))
|
||||||
(handle
|
(handle
|
||||||
(or (cdr-safe (seq-find (lambda (part) (eq (car part) n)) parts))
|
(or (cdr-safe (seq-find (lambda (part) (eq (car part) n)) parts))
|
||||||
(mu4e-error "MIME-part %s not found" n)))
|
(mu4e-error "MIME-part %s not found" n)))
|
||||||
(action
|
(action
|
||||||
(or (and options (mu4e-read-option "Action on MIME-part: " options))
|
(or (and options (mu4e-read-option "Action on MIME-part: " options))
|
||||||
(mu4e-error "No such action")))
|
(mu4e-error "No such action")))
|
||||||
(handler
|
(handler
|
||||||
(or (plist-get action :handler)
|
(or (plist-get action :handler)
|
||||||
(mu4e-error "No :handler item found for action %S" action)))
|
(mu4e-error "No :handler item found for action %S" action)))
|
||||||
(receives
|
(receives
|
||||||
(or (plist-get action :receives)
|
(or (plist-get action :receives)
|
||||||
(mu4e-error "No :receives item found for action %S" action))))
|
(mu4e-error "No :receives item found for action %S" action))))
|
||||||
(save-excursion
|
(save-excursion
|
||||||
(cond
|
(cond
|
||||||
((functionp handler)
|
((functionp handler)
|
||||||
(cond
|
(cond
|
||||||
((eq receives 'index) (funcall handler n))
|
((eq receives 'index) (funcall handler n))
|
||||||
((eq receives 'pipe) (funcall handler (mm-with-unibyte-buffer
|
((eq receives 'pipe) (funcall handler (mm-with-unibyte-buffer
|
||||||
(mm-insert-part handle)
|
(mm-insert-part handle)
|
||||||
(buffer-string))))
|
(buffer-string))))
|
||||||
((eq receives 'temp)
|
((eq receives 'temp)
|
||||||
(funcall handler (mu4e~view-mime-part-to-temp-file handle)))
|
(funcall handler (mu4e~view-mime-part-to-temp-file handle)))
|
||||||
(t (mu4e-error "Invalid :receive for %S" action))))
|
(t (mu4e-error "Invalid :receive for %S" action))))
|
||||||
((stringp handler)
|
((stringp handler)
|
||||||
(cond
|
(cond
|
||||||
((eq receives 'index)
|
((eq receives 'index)
|
||||||
(shell-command (concat handler " " (shell-quote-argument n))))
|
(shell-command (concat handler " " (shell-quote-argument n))))
|
||||||
((eq receives 'pipe) (mm-pipe-part handle handler))
|
((eq receives 'pipe) (mm-pipe-part handle handler))
|
||||||
((eq receives 'temp)
|
((eq receives 'temp)
|
||||||
(shell-command
|
(shell-command
|
||||||
(shell-command (concat handler " "
|
(shell-command (concat handler " "
|
||||||
(shell-quote-argument
|
(shell-quote-argument
|
||||||
(mu4e~view-mime-part-to-temp-file handle))))))
|
(mu4e~view-mime-part-to-temp-file handle))))))
|
||||||
(t (mu4e-error "Invalid action %S" action))))))))
|
(t (mu4e-error "Invalid action %S" action))))))))
|
||||||
|
|
||||||
(defun mu4e-view-toggle-html ()
|
(defun mu4e-view-toggle-html ()
|
||||||
"Toggle html-display of the first html-part found."
|
"Toggle html-display of the first html-part found."
|
||||||
|
@ -1303,10 +1303,10 @@ the third MIME-part."
|
||||||
;; pertinence, i.e. the first HTML part found in it is the most important one.
|
;; pertinence, i.e. the first HTML part found in it is the most important one.
|
||||||
(save-excursion
|
(save-excursion
|
||||||
(if-let ((html-part
|
(if-let ((html-part
|
||||||
(seq-find (lambda (handle)
|
(seq-find (lambda (handle)
|
||||||
(equal (mm-handle-media-type (cdr handle)) "text/html"))
|
(equal (mm-handle-media-type (cdr handle)) "text/html"))
|
||||||
gnus-article-mime-handle-alist)))
|
gnus-article-mime-handle-alist)))
|
||||||
(gnus-article-inline-part (car html-part))
|
(gnus-article-inline-part (car html-part))
|
||||||
(mu4e-warn "No html part in this message"))))
|
(mu4e-warn "No html part in this message"))))
|
||||||
|
|
||||||
(defun mu4e-process-file-through-pipe (path pipecmd)
|
(defun mu4e-process-file-through-pipe (path pipecmd)
|
||||||
|
@ -1314,9 +1314,9 @@ the third MIME-part."
|
||||||
(let ((buf (get-buffer-create "*mu4e-output")))
|
(let ((buf (get-buffer-create "*mu4e-output")))
|
||||||
(with-current-buffer buf
|
(with-current-buffer buf
|
||||||
(let ((inhibit-read-only t))
|
(let ((inhibit-read-only t))
|
||||||
(erase-buffer)
|
(erase-buffer)
|
||||||
(call-process-shell-command pipecmd path t t)
|
(call-process-shell-command pipecmd path t t)
|
||||||
(view-mode)))
|
(view-mode)))
|
||||||
(display-buffer buf)))
|
(display-buffer buf)))
|
||||||
|
|
||||||
;;; Bug Reference mode support
|
;;; Bug Reference mode support
|
||||||
|
@ -1337,17 +1337,17 @@ value against HEADER-REGEXP in
|
||||||
(when (derived-mode-p 'mu4e-view-mode)
|
(when (derived-mode-p 'mu4e-view-mode)
|
||||||
(let (header-values)
|
(let (header-values)
|
||||||
(save-excursion
|
(save-excursion
|
||||||
(goto-char (point-min))
|
(goto-char (point-min))
|
||||||
(dolist (field '("list" "list-id" "to" "from" "cc" "subject"))
|
(dolist (field '("list" "list-id" "to" "from" "cc" "subject"))
|
||||||
(let ((val (mail-fetch-field field)))
|
(let ((val (mail-fetch-field field)))
|
||||||
(when val
|
(when val
|
||||||
(push val header-values)))))
|
(push val header-values)))))
|
||||||
(bug-reference-maybe-setup-from-mail
|
(bug-reference-maybe-setup-from-mail
|
||||||
(mail-fetch-field "maildir")
|
(mail-fetch-field "maildir")
|
||||||
header-values))))
|
header-values))))
|
||||||
|
|
||||||
(add-hook 'bug-reference-auto-setup-functions
|
(add-hook 'bug-reference-auto-setup-functions
|
||||||
#'mu4e--view-try-setup-bug-reference-mode)
|
#'mu4e--view-try-setup-bug-reference-mode)
|
||||||
|
|
||||||
|
|
||||||
(provide 'mu4e-view)
|
(provide 'mu4e-view)
|
||||||
|
|
Loading…
Reference in New Issue