X-Git-Url: https://git.notmuchmail.org/git?p=notmuch;a=blobdiff_plain;f=emacs%2Fnotmuch-show.el;h=9f6fe077df0caa5843454c91cd93a27d87db50f6;hp=8ba81676f10245ee0f5d6a2b1539a14340df902b;hb=71fb37d48236e49b64e300c3764c0e17e02c8f9e;hpb=99d474c484d89d3436c910f1ac447640c533e811 diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el index 8ba81676..9f6fe077 100644 --- a/emacs/notmuch-show.el +++ b/emacs/notmuch-show.el @@ -44,6 +44,9 @@ (declare-function notmuch-foreach-mime-part "notmuch" (function mm-handle)) (declare-function notmuch-count-attachments "notmuch" (mm-handle)) (declare-function notmuch-save-attachments "notmuch" (mm-handle &optional queryp)) +(declare-function notmuch-tree "notmuch-tree" + (&optional query query-context target buffer-name open-target)) +(declare-function notmuch-tree-get-message-properties "notmuch-tree" nil) (defcustom notmuch-message-headers '("Subject" "To" "Cc" "Date") "Headers that should be shown in a message, in this order. @@ -157,10 +160,19 @@ indentation." (make-variable-buffer-local 'notmuch-show-indent-content) (put 'notmuch-show-indent-content 'permanent-local t) +(defvar notmuch-show-attachment-debug nil + "If t log stdout and stderr from attachment handlers + +When set to nil (the default) stdout and stderr from attachment +handlers is discarded. When set to t the stdout and stderr from +each attachment handler is logged in buffers with names beginning +\" *notmuch-part*\". This option requires emacs version at least +24.3 to work.") + (defcustom notmuch-show-stash-mlarchive-link-alist '(("Gmane" . "http://mid.gmane.org/") ("MARC" . "http://marc.info/?i=") - ("Mail Archive, The" . "http://mail-archive.com/search?l=mid&q=") + ("Mail Archive, The" . "http://mid.mail-archive.com/") ("LKML" . "http://lkml.kernel.org/r/") ;; FIXME: can these services be searched by `Message-Id' ? ;; ("MarkMail" . "http://markmail.org/") @@ -169,10 +181,21 @@ indentation." ) "List of Mailing List Archives to use when stashing links. -These URIs are concatenated with the current message's -Message-Id in `notmuch-show-stash-mlarchive-link'." +This list is used for generating a Mailing List Archive reference +URI with the current message's Message-Id in +`notmuch-show-stash-mlarchive-link'. + +If the cdr of the alist element is not a function, the cdr is +expected to contain a URI that is concatenated with the current +message's Message-Id to create a ML archive reference URI. + +If the cdr is a function, the function is called with the +Message-Id as the argument, and the function is expected to +return the ML archive reference URI." :type '(alist :key-type (string :tag "Name") - :value-type (string :tag "URL")) + :value-type (choice + (string :tag "URL") + (function :tag "Function returning the URL"))) :group 'notmuch-show) (defcustom notmuch-show-stash-mlarchive-link-default "Gmane" @@ -200,6 +223,16 @@ For example, if you wanted to remove an \"unread\" tag and add a :type '(repeat string) :group 'notmuch-show) +(defcustom notmuch-show-mark-read-function #'notmuch-show-seen-current-message + "Function to control which messages are marked read. + +The function should take two arguments START and END which will +be the start and end of the visible portion of the buffer and +should mark the appropriate messages read by applying +`notmuch-show-mark-read'. This function will be called after +every user interaction with notmuch." + :type 'function + :group 'notmuch-show) (defmacro with-current-notmuch-show-message (&rest body) "Evaluate body with current buffer set to the text of current message" @@ -208,9 +241,9 @@ For example, if you wanted to remove an \"unread\" tag and add a (let ((buf (generate-new-buffer (concat "*notmuch-msg-" id "*")))) (with-current-buffer buf (let ((coding-system-for-read 'no-conversion)) - (call-process notmuch-command nil t nil "show" "--format=raw" id) - ,@body) - (kill-buffer buf)))))) + (call-process notmuch-command nil t nil "show" "--format=raw" id)) + ,@body) + (kill-buffer buf))))) (defun notmuch-show-turn-on-visual-line-mode () "Enable Visual Line mode." @@ -333,7 +366,7 @@ operation on the contents of the current buffer." (if (re-search-forward "(\\([^()]*\\))$" (line-end-position) t) (let ((inhibit-read-only t)) (replace-match (concat "(" - (notmuch-tag-format-tags tags) + (notmuch-tag-format-tags tags (notmuch-show-get-prop :orig-tags)) ")")))))) (defun notmuch-clean-address (address) @@ -407,17 +440,18 @@ unchanged ADDRESS if parsing fails." message at DEPTH in the current thread." (let ((start (point))) (insert (notmuch-show-spaces-n (* notmuch-show-indent-messages-width depth)) - (notmuch-show-clean-address (plist-get headers :From)) + (notmuch-sanitize + (notmuch-show-clean-address (plist-get headers :From))) " (" date ") (" - (notmuch-tag-format-tags tags) + (notmuch-tag-format-tags tags tags) ")\n") (overlay-put (make-overlay start (point)) 'face 'notmuch-message-summary-face))) (defun notmuch-show-insert-header (header header-value) "Insert a single header." - (insert header ": " header-value "\n")) + (insert header ": " (notmuch-sanitize header-value) "\n")) (defun notmuch-show-insert-headers (headers) "Insert the headers of the current message." @@ -683,7 +717,7 @@ message at DEPTH in the current thread." (let ((start (if button (button-start button) (point)))) - (insert (notmuch-get-bodypart-content msg part nth notmuch-show-process-crypto)) + (insert (notmuch-get-bodypart-content msg part notmuch-show-process-crypto)) (save-excursion (save-restriction (narrow-to-region start (point-max)) @@ -692,7 +726,7 @@ message at DEPTH in the current thread." (defun notmuch-show-insert-part-text/calendar (msg part content-type nth depth button) (insert (with-temp-buffer - (insert (notmuch-get-bodypart-content msg part nth notmuch-show-process-crypto)) + (insert (notmuch-get-bodypart-content msg part notmuch-show-process-crypto)) ;; notmuch-get-bodypart-content provides "raw", non-converted ;; data. Replace CRLF with LF before icalendar can use it. (goto-char (point-min)) @@ -744,7 +778,7 @@ message at DEPTH in the current thread." (defun notmuch-show-insert-part-*/* (msg part content-type nth depth button) ;; This handler _must_ succeed - it is the handler of last resort. - (notmuch-mm-display-part-inline msg part nth content-type notmuch-show-process-crypto) + (notmuch-mm-display-part-inline msg part content-type notmuch-show-process-crypto) t) ;; Functions for determining how to handle MIME parts. @@ -773,7 +807,10 @@ message at DEPTH in the current thread." (while (and handlers (not (condition-case err (funcall (car handlers) msg part content-type nth depth button) - (error (progn + ;; Specifying `debug' here lets the debugger + ;; run if `debug-on-error' is non-nil. + ((debug error) + (progn (insert "!!! Bodypart insert error: ") (insert (error-message-string err)) (insert " !!!\n") nil))))) @@ -1130,9 +1167,12 @@ function is used." (let ((inhibit-read-only t)) (notmuch-show-mode) + (add-hook 'post-command-hook #'notmuch-show-command-hook nil t) + ;; Don't track undo information for this buffer (set 'buffer-undo-list t) + (notmuch-tag-clear-cache) (erase-buffer) (goto-char (point-min)) (save-excursion @@ -1155,8 +1195,10 @@ function is used." (jit-lock-register #'notmuch-show-buttonise-links) + (notmuch-show-mapc (lambda () (notmuch-show-set-prop :orig-tags (notmuch-show-get-tags)))) + ;; Set the header line to the subject of the first message. - (setq header-line-format (notmuch-show-strip-re (notmuch-show-get-subject))) + (setq header-line-format (notmuch-sanitize (notmuch-show-strip-re (notmuch-show-get-subject)))) (run-hooks 'notmuch-show-hook)))) @@ -1168,6 +1210,15 @@ This includes: - the current message." (list (notmuch-show-get-message-id) (notmuch-show-get-message-ids-for-open-messages))) +(defun notmuch-show-get-query () + "Return the current query in this show buffer" + (if notmuch-show-query-context + (concat notmuch-show-thread-id + " and (" + notmuch-show-query-context + ")") + notmuch-show-thread-id)) + (defun notmuch-show-apply-state (state) "Apply STATE to the current buffer. @@ -1229,6 +1280,8 @@ reset based on the original query." (define-key map "t" 'notmuch-show-stash-to) (define-key map "l" 'notmuch-show-stash-mlarchive-link) (define-key map "L" 'notmuch-show-stash-mlarchive-link-and-go) + (define-key map "G" 'notmuch-show-stash-git-send-email) + (define-key map "?" 'notmuch-subkeymap-help) map) "Submap for stash commands") (fset 'notmuch-show-stash-map notmuch-show-stash-map) @@ -1239,50 +1292,52 @@ reset based on the original query." (define-key map "v" 'notmuch-show-view-part) (define-key map "o" 'notmuch-show-interactively-view-part) (define-key map "|" 'notmuch-show-pipe-part) + (define-key map "?" 'notmuch-subkeymap-help) map) "Submap for part commands") (fset 'notmuch-show-part-map notmuch-show-part-map) (defvar notmuch-show-mode-map - (let ((map (make-sparse-keymap))) - (set-keymap-parent map notmuch-common-keymap) - (define-key map (kbd "") 'widget-backward) - (define-key map (kbd "M-TAB") 'notmuch-show-previous-button) - (define-key map (kbd "") 'notmuch-show-previous-button) - (define-key map (kbd "TAB") 'notmuch-show-next-button) - (define-key map "f" 'notmuch-show-forward-message) - (define-key map "r" 'notmuch-show-reply-sender) - (define-key map "R" 'notmuch-show-reply) - (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 "c" 'notmuch-show-stash-map) - (define-key map "h" 'notmuch-show-toggle-visibility-headers) - (define-key map "*" 'notmuch-show-tag-all) - (define-key map "-" 'notmuch-show-remove-tag) - (define-key map "+" 'notmuch-show-add-tag) - (define-key map "X" 'notmuch-show-archive-thread-then-exit) - (define-key map "x" 'notmuch-show-archive-message-then-next-or-exit) - (define-key map "A" 'notmuch-show-archive-thread-then-next) - (define-key map "a" 'notmuch-show-archive-message-then-next-or-next-thread) - (define-key map "N" 'notmuch-show-next-message) - (define-key map "P" 'notmuch-show-previous-message) - (define-key map "n" 'notmuch-show-next-open-message) - (define-key map "p" 'notmuch-show-previous-open-message) - (define-key map (kbd "M-n") 'notmuch-show-next-thread-show) - (define-key map (kbd "M-p") 'notmuch-show-previous-thread-show) - (define-key map (kbd "DEL") 'notmuch-show-rewind) - (define-key map " " 'notmuch-show-advance-and-archive) - (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-thread-indentation) - (define-key map "t" 'toggle-truncate-lines) - (define-key map "." 'notmuch-show-part-map) - map) - "Keymap for \"notmuch show\" buffers.") + (let ((map (make-sparse-keymap))) + (set-keymap-parent map notmuch-common-keymap) + (define-key map "Z" 'notmuch-tree-from-show-current-query) + (define-key map (kbd "") 'widget-backward) + (define-key map (kbd "M-TAB") 'notmuch-show-previous-button) + (define-key map (kbd "") 'notmuch-show-previous-button) + (define-key map (kbd "TAB") 'notmuch-show-next-button) + (define-key map "f" 'notmuch-show-forward-message) + (define-key map "r" 'notmuch-show-reply-sender) + (define-key map "R" 'notmuch-show-reply) + (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 "c" 'notmuch-show-stash-map) + (define-key map "h" 'notmuch-show-toggle-visibility-headers) + (define-key map "*" 'notmuch-show-tag-all) + (define-key map "-" 'notmuch-show-remove-tag) + (define-key map "+" 'notmuch-show-add-tag) + (define-key map "X" 'notmuch-show-archive-thread-then-exit) + (define-key map "x" 'notmuch-show-archive-message-then-next-or-exit) + (define-key map "A" 'notmuch-show-archive-thread-then-next) + (define-key map "a" 'notmuch-show-archive-message-then-next-or-next-thread) + (define-key map "N" 'notmuch-show-next-message) + (define-key map "P" 'notmuch-show-previous-message) + (define-key map "n" 'notmuch-show-next-open-message) + (define-key map "p" 'notmuch-show-previous-open-message) + (define-key map (kbd "M-n") 'notmuch-show-next-thread-show) + (define-key map (kbd "M-p") 'notmuch-show-previous-thread-show) + (define-key map (kbd "DEL") 'notmuch-show-rewind) + (define-key map " " 'notmuch-show-advance-and-archive) + (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-thread-indentation) + (define-key map "t" 'toggle-truncate-lines) + (define-key map "." 'notmuch-show-part-map) + map) + "Keymap for \"notmuch show\" buffers.") (fset 'notmuch-show-mode-map notmuch-show-mode-map) (defun notmuch-show-mode () @@ -1322,6 +1377,13 @@ All currently available key bindings: (setq buffer-read-only t truncate-lines t)) +(defun notmuch-tree-from-show-current-query () + "Call notmuch tree with the current query" + (interactive) + (notmuch-tree notmuch-show-thread-id + notmuch-show-query-context + (notmuch-show-get-message-id))) + (defun notmuch-show-move-to-message-top () (goto-char (notmuch-show-message-top))) @@ -1420,8 +1482,18 @@ an error if there is no part containing point." (notmuch-show-set-message-properties props))) (defun notmuch-show-get-prop (prop &optional props) + "Get property PROP from current message in show or tree mode. + +It gets property PROP from PROPS or, if PROPS is nil, the current +message in either tree or show. This means that several utility +functions in notmuch-show can be used directly by notmuch-tree as +they just need the correct message properties." (let ((props (or props - (notmuch-show-get-message-properties)))) + (cond ((eq major-mode 'notmuch-show-mode) + (notmuch-show-get-message-properties)) + ((eq major-mode 'notmuch-tree-mode) + (notmuch-tree-get-message-properties)) + (t nil))))) (plist-get props prop))) (defun notmuch-show-get-message-id (&optional bare) @@ -1505,6 +1577,23 @@ marked as unread, i.e. the tag changes in (apply 'notmuch-show-tag-message (notmuch-tag-change-list notmuch-show-mark-read-tags unread)))) +(defun notmuch-show-seen-current-message (start end) + "Mark the current message read if it is open. + +We only mark it read once: if it is changed back then that is a +user decision and we should not override it." + (when (and (notmuch-show-message-visible-p) + (not (notmuch-show-get-prop :seen))) + (notmuch-show-mark-read) + (notmuch-show-set-prop :seen t))) + +(defun notmuch-show-command-hook () + (when (eq major-mode 'notmuch-show-mode) + ;; We need to redisplay to get window-start and window-end correct. + (redisplay) + (save-excursion + (funcall notmuch-show-mark-read-function (window-start) (window-end))))) + ;; Functions for getting attributes of several messages in the current ;; thread. @@ -1640,9 +1729,7 @@ If a prefix argument is given and this is the last message in the thread, navigate to the next thread in the parent search buffer." (interactive "P") (if (notmuch-show-goto-message-next) - (progn - (notmuch-show-mark-read) - (notmuch-show-message-adjust)) + (notmuch-show-message-adjust) (if pop-at-end (notmuch-show-next-thread) (goto-char (point-max))))) @@ -1653,7 +1740,6 @@ thread, navigate to the next thread in the parent search buffer." (if (= (point) (notmuch-show-message-top)) (notmuch-show-goto-message-previous) (notmuch-show-move-to-message-top)) - (notmuch-show-mark-read) (notmuch-show-message-adjust)) (defun notmuch-show-next-open-message (&optional pop-at-end) @@ -1668,9 +1754,7 @@ to show, nil otherwise." (while (and (setq r (notmuch-show-goto-message-next)) (not (notmuch-show-message-visible-p)))) (if r - (progn - (notmuch-show-mark-read) - (notmuch-show-message-adjust)) + (notmuch-show-message-adjust) (if pop-at-end (notmuch-show-next-thread) (goto-char (point-max)))) @@ -1683,9 +1767,7 @@ to show, nil otherwise." (while (and (setq r (notmuch-show-goto-message-next)) (not (notmuch-show-get-prop :match)))) (if r - (progn - (notmuch-show-mark-read) - (notmuch-show-message-adjust)) + (notmuch-show-message-adjust) (goto-char (point-max))))) (defun notmuch-show-open-if-matched () @@ -1696,8 +1778,7 @@ to show, nil otherwise." (defun notmuch-show-goto-first-wanted-message () "Move to the first open message and mark it read" (goto-char (point-min)) - (if (notmuch-show-message-visible-p) - (notmuch-show-mark-read) + (unless (notmuch-show-message-visible-p) (notmuch-show-next-open-message)) (when (eobp) ;; There are no matched non-excluded messages so open all matched @@ -1705,8 +1786,7 @@ to show, nil otherwise." (notmuch-show-mapc 'notmuch-show-open-if-matched) (force-window-update) (goto-char (point-min)) - (if (notmuch-show-message-visible-p) - (notmuch-show-mark-read) + (unless (notmuch-show-message-visible-p) (notmuch-show-next-open-message)))) (defun notmuch-show-previous-open-message () @@ -1716,15 +1796,15 @@ to show, nil otherwise." (notmuch-show-goto-message-previous) (notmuch-show-move-to-message-top)) (not (notmuch-show-message-visible-p)))) - (notmuch-show-mark-read) (notmuch-show-message-adjust)) (defun notmuch-show-view-raw-message () - "View the file holding the current message." + "View the original source of the current message." (interactive) (let* ((id (notmuch-show-get-message-id)) (buf (get-buffer-create (concat "*notmuch-raw-" id "*")))) - (call-process notmuch-command nil buf nil "show" "--format=raw" id) + (let ((coding-system-for-read 'no-conversion)) + (call-process notmuch-command nil buf nil "show" "--format=raw" id)) (switch-to-buffer buf) (goto-char (point-min)) (set-buffer-modified-p nil) @@ -1759,10 +1839,14 @@ message." (setq shell-command (concat notmuch-command " show --format=raw " (shell-quote-argument (notmuch-show-get-message-id)) " | " command))) - (let ((buf (get-buffer-create (concat "*notmuch-pipe*")))) + (let ((cwd default-directory) + (buf (get-buffer-create (concat "*notmuch-pipe*")))) (with-current-buffer buf (setq buffer-read-only nil) (erase-buffer) + ;; Use the originating buffer's working directory instead of + ;; that of the pipe buffer. + (cd cwd) (let ((exit-code (call-process-shell-command shell-command nil buf))) (goto-char (point-max)) (set-buffer-modified-p nil) @@ -1782,23 +1866,28 @@ TAG-CHANGES is a list of tag operations for `notmuch-tag'." (notmuch-tag (notmuch-show-get-message-id) tag-changes) (notmuch-show-set-tags new-tags)))) -(defun notmuch-show-tag (&optional tag-changes) +(defun notmuch-show-tag (tag-changes) "Change tags for the current message. See `notmuch-tag' for information on the format of TAG-CHANGES." - (interactive) - (let* ((tag-changes (notmuch-tag (notmuch-show-get-message-id) tag-changes)) - (current-tags (notmuch-show-get-tags)) + (interactive (list (notmuch-read-tag-changes (notmuch-show-get-tags) + "Tag message"))) + (notmuch-tag (notmuch-show-get-message-id) tag-changes) + (let* ((current-tags (notmuch-show-get-tags)) (new-tags (notmuch-update-tags current-tags tag-changes))) (unless (equal current-tags new-tags) (notmuch-show-set-tags new-tags)))) -(defun notmuch-show-tag-all (&optional tag-changes) +(defun notmuch-show-tag-all (tag-changes) "Change tags for all messages in the current show buffer. See `notmuch-tag' for information on the format of TAG-CHANGES." - (interactive) - (setq tag-changes (notmuch-tag (notmuch-show-get-messages-ids-search) tag-changes)) + (interactive + (list (let (tags) + (notmuch-show-mapc + (lambda () (setq tags (append (notmuch-show-get-tags) tags)))) + (notmuch-read-tag-changes tags "Tag thread")))) + (notmuch-tag (notmuch-show-get-messages-ids-search) tag-changes) (notmuch-show-mapc (lambda () (let* ((current-tags (notmuch-show-get-tags)) @@ -1806,19 +1895,21 @@ See `notmuch-tag' for information on the format of TAG-CHANGES." (unless (equal current-tags new-tags) (notmuch-show-set-tags new-tags)))))) -(defun notmuch-show-add-tag () +(defun notmuch-show-add-tag (tag-changes) "Change tags for the current message (defaulting to add). Same as `notmuch-show-tag' but sets initial input to '+'." - (interactive) - (notmuch-show-tag "+")) + (interactive + (list (notmuch-read-tag-changes (notmuch-show-get-tags) "Tag message" "+"))) + (notmuch-show-tag tag-changes)) -(defun notmuch-show-remove-tag () +(defun notmuch-show-remove-tag (tag-changes) "Change tags for the current message (defaulting to remove). Same as `notmuch-show-tag' but sets initial input to '-'." - (interactive) - (notmuch-show-tag "-")) + (interactive + (list (notmuch-read-tag-changes (notmuch-show-get-tags) "Tag message" "-"))) + (notmuch-show-tag tag-changes)) (defun notmuch-show-toggle-visibility-headers () "Toggle the visibility of the current message headers." @@ -1872,7 +1963,7 @@ buffer. If PREVIOUS is non-nil, move to the previous item in the search results instead." (interactive "P") (let ((parent-buffer notmuch-show-parent-buffer)) - (notmuch-kill-this-buffer) + (notmuch-bury-or-kill-this-buffer) (when (buffer-live-p parent-buffer) (switch-to-buffer parent-buffer) (and (if previous @@ -2016,16 +2107,19 @@ This presumes that the message is available at the selected Mailing List Archive If optional argument MLA is non-nil, use the provided key instead of prompting the user (see `notmuch-show-stash-mlarchive-link-alist')." (interactive) - (notmuch-common-do-stash - (concat (cdr (assoc - (or mla - (let ((completion-ignore-case t)) - (completing-read - "Mailing List Archive: " - notmuch-show-stash-mlarchive-link-alist - nil t nil nil notmuch-show-stash-mlarchive-link-default))) - notmuch-show-stash-mlarchive-link-alist)) - (notmuch-show-get-message-id t)))) + (let ((url (cdr (assoc + (or mla + (let ((completion-ignore-case t)) + (completing-read + "Mailing List Archive: " + notmuch-show-stash-mlarchive-link-alist + nil t nil nil + notmuch-show-stash-mlarchive-link-default))) + notmuch-show-stash-mlarchive-link-alist)))) + (notmuch-common-do-stash + (if (functionp url) + (funcall url (notmuch-show-get-message-id t)) + (concat url (notmuch-show-get-message-id t)))))) (defun notmuch-show-stash-mlarchive-link-and-go (&optional mla) "Copy an ML Archive URI for the current message to the kill-ring and visit it. @@ -2038,6 +2132,43 @@ the user (see `notmuch-show-stash-mlarchive-link-alist')." (notmuch-show-stash-mlarchive-link mla) (browse-url (current-kill 0 t))) +(defun notmuch-show-stash-git-helper (addresses prefix) + "Escape, trim, quote, and add PREFIX to each address in list of ADDRESSES, and return the result as a single string." + (mapconcat (lambda (x) + (concat prefix "\"" + ;; escape double-quotes + (replace-regexp-in-string + "\"" "\\\\\"" + ;; trim leading and trailing spaces + (replace-regexp-in-string + "\\(^ *\\| *$\\)" "" + x)) "\"")) + addresses " ")) + +(put 'notmuch-show-stash-git-send-email 'notmuch-prefix-doc + "Copy From/To/Cc of current message to kill-ring in a form suitable for pasting to git send-email command line.") + +(defun notmuch-show-stash-git-send-email (&optional no-in-reply-to) + "Copy From/To/Cc/Message-Id of current message to kill-ring in a form suitable for pasting to git send-email command line. + +If invoked with a prefix argument (or NO-IN-REPLY-TO is non-nil), +omit --in-reply-to=." + (interactive "P") + (notmuch-common-do-stash + (mapconcat 'identity + (remove "" + (list + (notmuch-show-stash-git-helper + (message-tokenize-header (notmuch-show-get-from)) "--to=") + (notmuch-show-stash-git-helper + (message-tokenize-header (notmuch-show-get-to)) "--to=") + (notmuch-show-stash-git-helper + (message-tokenize-header (notmuch-show-get-cc)) "--cc=") + (unless no-in-reply-to + (notmuch-show-stash-git-helper + (list (notmuch-show-get-message-id t)) "--in-reply-to=")))) + " "))) + ;; Interactive part functions and their helpers (defun notmuch-show-generate-part-buffer (message-id nth) @@ -2071,8 +2202,16 @@ caller is responsible for killing this buffer as appropriate." This ensures that the temporary buffer created for the mm-handle is destroyed when FN returns." (let ((handle (notmuch-show-current-part-handle))) + ;; emacs 24.3+ puts stdout/stderr into the calling buffer so we + ;; call it from a temp-buffer, unless + ;; notmuch-show-attachment-debug is non-nil in which case we put + ;; it in " *notmuch-part*". (unwind-protect - (funcall fn handle) + (if notmuch-show-attachment-debug + (with-current-buffer (generate-new-buffer " *notmuch-part*") + (funcall fn handle)) + (with-temp-buffer + (funcall fn handle))) (kill-buffer (mm-handle-buffer handle))))) (defun notmuch-show-part-button-default (&optional button)