From 5ff051e64dba625b2f26615c38300faa27023160 Mon Sep 17 00:00:00 2001 From: Jonas Bernoulli Date: Mon, 17 Feb 2020 11:29:49 +0100 Subject: [PATCH 01/17] gitignore: update --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 7990d229..2a1a6137 100644 --- a/.gitignore +++ b/.gitignore @@ -49,6 +49,7 @@ GTAGS *.gcda *.gcno *.trs +aminclude_static.am elisp-comp elc-stamp dummy.cc @@ -94,6 +95,9 @@ build-aux/ /lib/parser/test-tokenizer /lib/parser/test-utils /lib/parser/tokenize +/lib/utils/test-command-parser +/lib/utils/test-mu-utils +/lib/utils/test-sexp-parser *_flymake.* *_flymake_* /perf.data From 173deff6a03bae1171e39ca8da916386ca9bbf67 Mon Sep 17 00:00:00 2001 From: Jonas Bernoulli Date: Mon, 17 Feb 2020 14:00:27 +0100 Subject: [PATCH 02/17] editorconfig: Don't misconfigure indentation for Emacs lisp files 1) It is fairly safe to assume that almost all edits to Emacs lisp files will be done using the Emacs editor, so there is no need to configure this in a way understood by other editors. 2) Trying to configure the intention of lisp code using editorconfig causes the indention to be wrong. Here "wrong" does not mean, "it uses tabs when everyone knows that spaces is the true path" (or vice-versa), but in the sense of "in lisp indentation is subject to the outer expression, and it has been like that for decades, but we are just going to ignore that completely and pretend this is actually python code". For example, if we insert a new line character between the 1 and 2 in (progn (progn 1 2) then there are only two ways to intend that correctly. (We use "." to represent a leading space and "<-->" to represent leading tabs. "<------>" for a tab when it is shown eight characters wide or "<>" if only two.) First correct way: (setq-local indent-tabs-mode t) (progn (progn 1 <------>......2)) Second correct way: (setq-local indent-tabs-mode nil) (progn (progn 1 ..............2)) With the old editorconfig configuration, [*.el] indent_style = tab indent_size = 2 max_line_length = 100 we get: (progn (progn 1 <><><><>.2)) This is not how `progn' is indented. No special indentation rules are defined for it so all arguments are supposed to be aligned. For `prog1' however special indentation are defined and if we replaced the second `progn' in this example with a `prog1', then this would actually be correct. This just demonstrate that it is wrong to indent everything the same for lisp; the reason that `progn' and `prog1' are indented differently communicates different meanings to the reader. I had faint hope that without setting `indent_size' things would work correctly, but no, [*.el] indent_style = tab max_line_length = 100 gives us: (progn (progn 1 <------>.......2)) That doesn't even make sense if we pretend to be looking at python code. Turns out that `indent_size' defaults to 2 even for lisp code as can be demonstrated by additionally doing, (setq-local tab-width 2) which gives us: (progn (progn 1 <>.......2)) which at least makes some sense. --- .editorconfig | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.editorconfig b/.editorconfig index a9c057c0..d7b5d392 100644 --- a/.editorconfig +++ b/.editorconfig @@ -34,8 +34,3 @@ max_line_length = 100 indent_style = tab indent_size = 8 max_line_length = 100 - -[*.el] -indent_style = space -indent_size = 2 -max_line_length = 100 From be1ba1ce68058038e8e695f8df9c9927e50d2dae Mon Sep 17 00:00:00 2001 From: Jonas Bernoulli Date: Tue, 11 Feb 2020 11:38:06 +0100 Subject: [PATCH 03/17] mu4e: Enforce use of spaces for indentation There already is a ".editorconfig" file for cross-editor configuration, but most Emacs users don't use that, so this also has to be configured the traditional Emacs way. (Also I have some doubts that cross-editor configuration is relevant for Emacs Lisp files.) --- .dir-locals.el | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .dir-locals.el diff --git a/.dir-locals.el b/.dir-locals.el new file mode 100644 index 00000000..3a491ef9 --- /dev/null +++ b/.dir-locals.el @@ -0,0 +1,2 @@ +((emacs-lisp-mode + (indent-tabs-mode . nil))) From 6790c0d0157f62692b51e59f6cb15ec07ba5bf10 Mon Sep 17 00:00:00 2001 From: Jonas Bernoulli Date: Tue, 11 Feb 2020 12:00:46 +0100 Subject: [PATCH 04/17] mu4e: Fix indentation --- mu4e/mu4e-actions.el | 186 +++--- mu4e/mu4e-compose.el | 482 +++++++------- mu4e/mu4e-context.el | 66 +- mu4e/mu4e-contrib.el | 28 +- mu4e/mu4e-draft.el | 476 ++++++------- mu4e/mu4e-headers.el | 1302 ++++++++++++++++++------------------ mu4e/mu4e-icalendar.el | 92 +-- mu4e/mu4e-main.el | 213 +++--- mu4e/mu4e-mark.el | 432 ++++++------ mu4e/mu4e-message.el | 178 ++--- mu4e/mu4e-org.el | 66 +- mu4e/mu4e-proc.el | 276 ++++---- mu4e/mu4e-speedbar.el | 50 +- mu4e/mu4e-utils.el | 822 +++++++++++------------ mu4e/mu4e-vars.el | 308 ++++----- mu4e/mu4e-view.el | 1440 ++++++++++++++++++++-------------------- mu4e/mu4e.el | 6 +- mu4e/org-mu4e.el | 146 ++-- 18 files changed, 3284 insertions(+), 3285 deletions(-) diff --git a/mu4e/mu4e-actions.el b/mu4e/mu4e-actions.el index 2082c4d3..a80744a0 100644 --- a/mu4e/mu4e-actions.el +++ b/mu4e/mu4e-actions.el @@ -47,8 +47,8 @@ "Count the number of lines in the e-mail MSG. Works for headers view and message-view." (message "Number of lines: %s" - (shell-command-to-string - (concat "wc -l < " (shell-quote-argument (mu4e-message-field msg :path)))))) + (shell-command-to-string + (concat "wc -l < " (shell-quote-argument (mu4e-message-field msg :path)))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -66,12 +66,12 @@ Works for the message view." (unless (file-executable-p mu4e-msg2pdf) (mu4e-error "Program msg2pdf not found; please set `mu4e-msg2pdf'")) (let* ((pdf - (shell-command-to-string - (concat mu4e-msg2pdf " " - (shell-quote-argument (mu4e-message-field msg :path)) - " 2> /dev/null"))) - (pdf (and pdf (> (length pdf) 5) - (substring pdf 0 -1)))) ;; chop \n + (shell-command-to-string + (concat mu4e-msg2pdf " " + (shell-quote-argument (mu4e-message-field msg :path)) + " 2> /dev/null"))) + (pdf (and pdf (> (length pdf) 5) + (substring pdf 0 -1)))) ;; chop \n (unless (and pdf (file-exists-p pdf)) (mu4e-warn "Failed to create PDF file")) (find-file pdf))) @@ -100,22 +100,22 @@ Works for the message view." "Write MSG's body (either html or text) to a temporary file; return the filename." (let* ((html (mu4e-message-field msg :body-html)) - (txt (mu4e-message-field msg :body-txt)) - (tmpfile (mu4e-make-temp-file "html")) - (attachments (cl-remove-if (lambda (part) - (or (null (plist-get part :attachment)) - (null (plist-get part :cid)))) - (mu4e-message-field msg :parts)))) + (txt (mu4e-message-field msg :body-txt)) + (tmpfile (mu4e-make-temp-file "html")) + (attachments (cl-remove-if (lambda (part) + (or (null (plist-get part :attachment)) + (null (plist-get part :cid)))) + (mu4e-message-field msg :parts)))) (unless (or html txt) (mu4e-error "No body part for this message")) (with-temp-buffer (insert "\n") (insert (concat "

From: " - (mu4e~action-header-to-html msg :from) "
")) + (mu4e~action-header-to-html msg :from) "
")) (insert (concat "To: " - (mu4e~action-header-to-html msg :to) "
")) + (mu4e~action-header-to-html msg :to) "
")) (insert (concat "Date: " - (format-time-string mu4e-view-date-format (mu4e-message-field msg :date)) "
")) + (format-time-string mu4e-view-date-format (mu4e-message-field msg :date)) "
")) (insert (concat "Subject: " (mu4e-message-field msg :subject) "

")) (insert (or html (concat "
" txt "
"))) (write-file tmpfile) @@ -123,20 +123,20 @@ return the filename." (mapc (lambda (attachment) (goto-char (point-min)) (while (re-search-forward (format "src=\"cid:%s\"" - (plist-get attachment :cid)) nil t) + (plist-get attachment :cid)) nil t) (if (plist-get attachment :temp) - (replace-match (format "src=\"%s\"" - (plist-get attachment :temp))) + (replace-match (format "src=\"%s\"" + (plist-get attachment :temp))) (replace-match (format "src=\"%s%s\"" temporary-file-directory - (plist-get attachment :name))) + (plist-get attachment :name))) (let ((tmp-attachment-name - (format "%s%s" temporary-file-directory - (plist-get attachment :name)))) + (format "%s%s" temporary-file-directory + (plist-get attachment :name)))) (mu4e~proc-extract 'save (mu4e-message-field msg :docid) - (plist-get attachment :index) - mu4e-decryption-policy tmp-attachment-name) + (plist-get attachment :index) + mu4e-decryption-policy tmp-attachment-name) (mu4e-remove-file-later tmp-attachment-name))))) - attachments) + attachments) (save-buffer) tmpfile))) @@ -146,7 +146,7 @@ You can influence the browser to use with the variable `browse-url-generic-program', and see the discussion of privacy aspects in `(mu4e) Displaying rich-text messages'." (browse-url (concat "file://" - (mu4e~write-body-to-html msg)))) + (mu4e~write-body-to-html msg)))) (defun mu4e-action-view-with-xwidget (msg) "View the body of MSG inside xwidget-webkit. @@ -155,7 +155,7 @@ privacy aspects in `(mu4e) Displaying rich-text messages'." (unless (fboundp 'xwidget-webkit-browse-url) (mu4e-error "No xwidget support available")) (xwidget-webkit-browse-url - (concat "file://" (mu4e~write-body-to-html msg)) t)) + (concat "file://" (mu4e~write-body-to-html msg)) t)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -172,7 +172,7 @@ privacy aspects in `(mu4e) Displaying rich-text messages'." (with-temp-buffer (insert (mu4e-message-field msg :body-txt)) (shell-command-on-region (point-min) (point-max) - mu4e-text2speech-command))) + mu4e-text2speech-command))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -216,23 +216,23 @@ file where you store your org-contacts." (unless mu4e-org-contacts-file (mu4e-error "Variable `mu4e-org-contacts-file' is nil")) (let* ((sender (car-safe (mu4e-message-field msg :from))) - (name (car-safe sender)) (email (cdr-safe sender)) - (blurb - (format - (concat - "* %%?%s\n" - ":PROPERTIES:\n" - ":EMAIL: %s\n" - ":NICK:\n" - ":BIRTHDAY:\n" - ":END:\n\n") - (or name email "") - (or email ""))) - (key "mu4e-add-org-contact-key") - (org-capture-templates - (append org-capture-templates - (list (list key "contacts" 'entry - (list 'file mu4e-org-contacts-file) blurb))))) + (name (car-safe sender)) (email (cdr-safe sender)) + (blurb + (format + (concat + "* %%?%s\n" + ":PROPERTIES:\n" + ":EMAIL: %s\n" + ":NICK:\n" + ":BIRTHDAY:\n" + ":END:\n\n") + (or name email "") + (or email ""))) + (key "mu4e-add-org-contact-key") + (org-capture-templates + (append org-capture-templates + (list (list key "contacts" 'entry + (list 'file mu4e-org-contacts-file) blurb))))) (message "%S" org-capture-templates) (when (fboundp 'org-capture) (org-capture nil key)))) @@ -252,16 +252,16 @@ file where you store your org-contacts." (unless prompt (setq prompt "Target directory:")) (file-truename - (completing-read prompt 'read-file-name-internal #'file-directory-p - nil nil 'mu4e~patch-directory-history))) + (completing-read prompt 'read-file-name-internal #'file-directory-p + nil nil 'mu4e~patch-directory-history))) (defun mu4e-action-git-apply-patch (msg) "Apply `MSG' as a git patch." (let ((path (mu4e~read-patch-directory "Target directory: "))) (let ((default-directory path)) (shell-command - (format "git apply %s" - (shell-quote-argument (mu4e-message-field msg :path))))))) + (format "git apply %s" + (shell-quote-argument (mu4e-message-field msg :path))))))) (defun mu4e-action-git-apply-mbox (msg &optional signoff) "Apply `MSG' a git patch with optional `SIGNOFF'. @@ -270,15 +270,15 @@ If the `default-directory' matches the most recent history entry don't bother asking for the git tree again (useful for bulk actions)." (let ((cwd (substring-no-properties - (or (car mu4e~patch-directory-history) - "not-a-dir")))) + (or (car mu4e~patch-directory-history) + "not-a-dir")))) (unless (and (stringp cwd) (string= default-directory cwd)) (setq cwd (mu4e~read-patch-directory "Target directory: "))) (let ((default-directory cwd)) (shell-command - (format "git am %s %s" - (if signoff "--signoff" "") - (shell-quote-argument (mu4e-message-field msg :path))))))) + (format "git am %s %s" + (if signoff "--signoff" "") + (shell-quote-argument (mu4e-message-field msg :path))))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -302,7 +302,7 @@ messages can lead to messages with multiple tags headers.") (save-excursion (goto-char (point-min)) (if (re-search-forward regexp nil t) - t + t nil)))) (defun mu4e~replace-first-line-matching (regexp to-string path) @@ -312,7 +312,7 @@ messages can lead to messages with multiple tags headers.") (save-excursion (goto-char (point-min)) (if (re-search-forward regexp nil t) - (replace-match to-string nil nil))))) + (replace-match to-string nil nil))))) (defun mu4e-action-retag-message (msg &optional retag-arg) "Change tags of MSG with RETAG-ARG. @@ -322,33 +322,33 @@ RETAG-ARG is a comma-separated list of additions and removals. Example: +tag,+long tag,-oldtag would add 'tag' and 'long tag', and remove 'oldtag'." (let* ( - (path (mu4e-message-field msg :path)) - (oldtags (mu4e-message-field msg :tags)) - (tags-completion - (append - mu4e-action-tags-completion-list - (mapcar (lambda (tag) (format "+%s" tag)) - mu4e-action-tags-completion-list) - (mapcar (lambda (tag) (format "-%s" tag)) - oldtags))) - (retag (if retag-arg - (split-string retag-arg ",") - (completing-read-multiple "Tags: " tags-completion))) - (header mu4e-action-tags-header) - (sep (cond ((string= header "Keywords") ", ") - ((string= header "X-Label") " ") - ((string= header "X-Keywords") ", ") - (t ", "))) - (taglist (if oldtags (copy-sequence oldtags) '())) - tagstr) + (path (mu4e-message-field msg :path)) + (oldtags (mu4e-message-field msg :tags)) + (tags-completion + (append + mu4e-action-tags-completion-list + (mapcar (lambda (tag) (format "+%s" tag)) + mu4e-action-tags-completion-list) + (mapcar (lambda (tag) (format "-%s" tag)) + oldtags))) + (retag (if retag-arg + (split-string retag-arg ",") + (completing-read-multiple "Tags: " tags-completion))) + (header mu4e-action-tags-header) + (sep (cond ((string= header "Keywords") ", ") + ((string= header "X-Label") " ") + ((string= header "X-Keywords") ", ") + (t ", "))) + (taglist (if oldtags (copy-sequence oldtags) '())) + tagstr) (dolist (tag retag taglist) (cond - ((string-match "^\\+\\(.+\\)" tag) - (setq taglist (push (match-string 1 tag) taglist))) - ((string-match "^\\-\\(.+\\)" tag) - (setq taglist (delete (match-string 1 tag) taglist))) - (t - (setq taglist (push tag taglist))))) + ((string-match "^\\+\\(.+\\)" tag) + (setq taglist (push (match-string 1 tag) taglist))) + ((string-match "^\\-\\(.+\\)" tag) + (setq taglist (delete (match-string 1 tag) taglist))) + (t + (setq taglist (push tag taglist))))) (setq taglist (sort (delete-dups taglist) 'string<)) (setq tagstr (mapconcat 'identity taglist sep)) @@ -357,15 +357,15 @@ would add 'tag' and 'long tag', and remove 'oldtag'." (setq tagstr (replace-regexp-in-string "[/]" "\\&" tagstr)) (if (not (mu4e~contains-line-matching (concat header ":.*") path)) - ;; Add tags header just before the content - (mu4e~replace-first-line-matching - "^$" (concat header ": " tagstr "\n") path) + ;; Add tags header just before the content + (mu4e~replace-first-line-matching + "^$" (concat header ": " tagstr "\n") path) ;; replaces keywords, restricted to the header (mu4e~replace-first-line-matching - (concat header ":.*") - (concat header ": " tagstr) - path)) + (concat header ":.*") + (concat header ": " tagstr) + path)) (mu4e-message (concat "tagging: " (mapconcat 'identity taglist ", "))) (mu4e-refresh-message path))) @@ -378,12 +378,12 @@ the message." (let ((msgid (mu4e-message-field msg :message-id))) (when msgid (let ((mu4e-headers-show-threads t) - (mu4e-headers-include-related t)) + (mu4e-headers-include-related t)) (mu4e-headers-search - (format "msgid:%s" msgid) - nil nil nil - msgid (and (eq major-mode 'mu4e-view-mode) - (not (eq mu4e-split-view 'single-window)))))))) + (format "msgid:%s" msgid) + nil nil nil + msgid (and (eq major-mode 'mu4e-view-mode) + (not (eq mu4e-split-view 'single-window)))))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (provide 'mu4e-actions) diff --git a/mu4e/mu4e-compose.el b/mu4e/mu4e-compose.el index 12442033..fe1ef3ec 100644 --- a/mu4e/mu4e-compose.el +++ b/mu4e/mu4e-compose.el @@ -109,8 +109,8 @@ symbols, for example: The various `message-' functions from `message-mode' are available for querying the message information." :type '(choice (const :tag "move message to mu4e-sent-folder" sent) - (const :tag "move message to mu4e-trash-folder" trash) - (const :tag "delete message" delete)) + (const :tag "move message to mu4e-trash-folder" trash) + (const :tag "delete message" delete)) :group 'mu4e-compose) (defcustom mu4e-compose-context-policy 'ask @@ -129,11 +129,11 @@ contexts match, we have the following choices: Also see `mu4e-context-policy'." :type '(choice - (const :tag "Always ask what context to use" always-ask) - (const :tag "Ask if none of the contexts match" ask) - (const :tag "Ask when there's no context yet" ask-if-none) - (const :tag "Pick the first context if none match" pick-first) - (const :tag "Don't change the context when none match" nil)) + (const :tag "Always ask what context to use" always-ask) + (const :tag "Ask if none of the contexts match" ask) + (const :tag "Ask when there's no context yet" ask-if-none) + (const :tag "Pick the first context if none match" pick-first) + (const :tag "Don't change the context when none match" nil)) :safe 'symbolp :group 'mu4e-compose) @@ -146,10 +146,10 @@ We have the following choices: - `encrypt': encrypt the reply, but don't sign it. - anything else: do nothing." :type '(choice - (const :tag "Sign the reply" sign) - (const :tag "Sign and encrypt the reply" sign-and-encrypt) - (const :tag "Encrypt the reply" encrypt) - (const :tag "Don't do anything" nil)) + (const :tag "Sign the reply" sign) + (const :tag "Sign and encrypt the reply" sign-and-encrypt) + (const :tag "Encrypt the reply" encrypt) + (const :tag "Don't do anything" nil)) :safe 'symbolp :group 'mu4e-compose) @@ -162,10 +162,10 @@ We have the following choices: - `encrypt': encrypt the reply, but don't sign it. - anything else: do nothing." :type '(choice - (const :tag "Sign the reply" sign) - (const :tag "Sign and encrypt the reply" sign-and-encrypt) - (const :tag "Encrypt the reply" encrypt) - (const :tag "Don't do anything" nil)) + (const :tag "Sign the reply" sign) + (const :tag "Sign and encrypt the reply" sign-and-encrypt) + (const :tag "Encrypt the reply" encrypt) + (const :tag "Don't do anything" nil)) :safe 'symbolp :group 'mu4e-compose) @@ -173,7 +173,7 @@ We have the following choices: 'mu4e-compose-crypto-reply-policy' variable is deprecated. 'mu4e-compose-crypto-reply-plain-policy' and 'mu4e-compose-crypto-reply-encrypted-policy' should be used instead" - "2017-09-02") + "2017-09-02") (defcustom mu4e-compose-format-flowed nil "Whether to compose messages to be sent as format=flowed. @@ -211,10 +211,10 @@ This is a symbol, `new', `forward', `reply' or `edit'.") (unless (file-exists-p path) (mu4e-warn "Message file not found")) (mml-attach-file - path - "message/rfc822" - (or (plist-get msg :subject) "No subject") - "attachment"))) + path + "message/rfc822" + (or (plist-get msg :subject) "No subject") + "attachment"))) (defun mu4e-compose-attach-captured-message () "Insert the last captured message file as an attachment. @@ -243,25 +243,25 @@ Messages are captured with `mu4e-action-capture-message'." "Maybe setup Fcc, based on `mu4e-sent-messages-behavior'. If needed, set the Fcc header, and register the handler function." (let* ((sent-behavior - ;; Note; we cannot simply use functionp here, since at least - ;; delete is a function, too... - (if (member mu4e-sent-messages-behavior '(delete trash sent)) - mu4e-sent-messages-behavior - (if (functionp mu4e-sent-messages-behavior) - (funcall mu4e-sent-messages-behavior) - mu4e-sent-messages-behavior))) - (mdir - (cl-case sent-behavior - (delete nil) - (trash (mu4e-get-trash-folder mu4e-compose-parent-message)) - (sent (mu4e-get-sent-folder mu4e-compose-parent-message)) - (otherwise - (mu4e-error "Unsupported value '%S' + ;; Note; we cannot simply use functionp here, since at least + ;; delete is a function, too... + (if (member mu4e-sent-messages-behavior '(delete trash sent)) + mu4e-sent-messages-behavior + (if (functionp mu4e-sent-messages-behavior) + (funcall mu4e-sent-messages-behavior) + mu4e-sent-messages-behavior))) + (mdir + (cl-case sent-behavior + (delete nil) + (trash (mu4e-get-trash-folder mu4e-compose-parent-message)) + (sent (mu4e-get-sent-folder mu4e-compose-parent-message)) + (otherwise + (mu4e-error "Unsupported value '%S' `mu4e-sent-messages-behavior'" - mu4e-sent-messages-behavior)))) - (fccfile (and mdir - (concat (mu4e-root-maildir) mdir "/cur/" - (mu4e~draft-message-filename-construct "S"))))) + mu4e-sent-messages-behavior)))) + (fccfile (and mdir + (concat (mu4e-root-maildir) mdir "/cur/" + (mu4e~draft-message-filename-construct "S"))))) ;; if there's an fcc header, add it to the file (when fccfile (message-add-header (concat "Fcc: " fccfile "\n")) @@ -269,22 +269,22 @@ If needed, set the Fcc header, and register the handler function." ;; etc. if you run it after mu4e so, (hack hack) we reset it to the old ;; handler after we've done our thing. (setq message-fcc-handler-function - (let ((maildir mdir) - (old-handler message-fcc-handler-function)) - (lambda (file) - (setq message-fcc-handler-function old-handler) ;; reset the fcc handler - (let ((mdir-path (concat (mu4e-root-maildir) maildir))) - ;; Create the full maildir structure for the sent folder if it doesn't exist. - ;; `mu4e~proc-mkdir` runs asynchronously but no matter whether it runs before or after - ;; `write-file`, the sent maildir ends up in the correct state. - (unless (file-exists-p mdir-path) - (mu4e~proc-mkdir mdir-path))) - (write-file file) ;; writing maildirs files is easy - (mu4e~proc-add file))))))) ;; update the database + (let ((maildir mdir) + (old-handler message-fcc-handler-function)) + (lambda (file) + (setq message-fcc-handler-function old-handler) ;; reset the fcc handler + (let ((mdir-path (concat (mu4e-root-maildir) maildir))) + ;; Create the full maildir structure for the sent folder if it doesn't exist. + ;; `mu4e~proc-mkdir` runs asynchronously but no matter whether it runs before or after + ;; `write-file`, the sent maildir ends up in the correct state. + (unless (file-exists-p mdir-path) + (mu4e~proc-mkdir mdir-path))) + (write-file file) ;; writing maildirs files is easy + (mu4e~proc-add file))))))) ;; update the database (defvar mu4e-compose-hidden-headers `("^References:" "^Face:" "^X-Face:" - "^X-Draft-From:" "^User-agent:") + "^X-Draft-From:" "^User-agent:") "Hidden headers when composing.") (defun mu4e~compose-hide-headers () @@ -301,25 +301,25 @@ Just after saving we restore it; thus, the separator should never appear on disk. Also update the Date and ensure we have a Message-ID." (add-hook 'before-save-hook - (lambda() - ;; replace the date - (save-excursion - (message-remove-header "Date") - (message-generate-headers '(Date Message-ID)) - (save-match-data - (mu4e~draft-remove-mail-header-separator)))) nil t) + (lambda() + ;; replace the date + (save-excursion + (message-remove-header "Date") + (message-generate-headers '(Date Message-ID)) + (save-match-data + (mu4e~draft-remove-mail-header-separator)))) nil t) (add-hook 'after-save-hook - (lambda () - (save-match-data - (mu4e~compose-set-friendly-buffer-name) - (mu4e~draft-insert-mail-header-separator) - ;; hide some headers again - (mu4e~compose-hide-headers) - (widen) - (set-buffer-modified-p nil) - (mu4e-message "Saved (%d lines)" (count-lines (point-min) (point-max))) - ;; update the file on disk -- ie., without the separator - (mu4e~proc-add (buffer-file-name)))) nil t)) + (lambda () + (save-match-data + (mu4e~compose-set-friendly-buffer-name) + (mu4e~draft-insert-mail-header-separator) + ;; hide some headers again + (mu4e~compose-hide-headers) + (widen) + (set-buffer-modified-p nil) + (mu4e-message "Saved (%d lines)" (count-lines (point-min) (point-max))) + ;; update the file on disk -- ie., without the separator + (mu4e~proc-add (buffer-file-name)))) nil t)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; address completion; inspired by org-contacts.el and @@ -327,37 +327,37 @@ Message-ID." (defun mu4e~compose-complete-handler (str pred action) "Complete address STR with predication PRED for ACTION." (cond - ((eq action nil) - (try-completion str mu4e~contacts pred)) - ((eq action t) - (all-completions str mu4e~contacts pred)) - ((eq action 'metadata) - ;; our contacts are already sorted - just need to tell the - ;; completion machinery not to try to undo that... - '(metadata - (display-sort-function . identity) - (cycle-sort-function . identity))))) + ((eq action nil) + (try-completion str mu4e~contacts pred)) + ((eq action t) + (all-completions str mu4e~contacts pred)) + ((eq action 'metadata) + ;; our contacts are already sorted - just need to tell the + ;; completion machinery not to try to undo that... + '(metadata + (display-sort-function . identity) + (cycle-sort-function . identity))))) (defun mu4e~compose-complete-contact (&optional start) "Complete the text at START with a contact. Ie. either 'name ' or 'email')." (interactive) (let ((mail-abbrev-mode-regexp mu4e~compose-address-fields-regexp) - (eoh ;; end-of-headers - (save-excursion - (goto-char (point-min)) - (search-forward-regexp mail-header-separator nil t)))) + (eoh ;; end-of-headers + (save-excursion + (goto-char (point-min)) + (search-forward-regexp mail-header-separator nil t)))) ;; try to complete only when we're in the headers area, ;; looking at an address field. (when (and eoh (> eoh (point)) (mail-abbrev-in-expansion-header-p)) (let* ((end (point)) - (start - (or start - (save-excursion - (re-search-backward "\\(\\`\\|[\n:,]\\)[ \t]*") - (goto-char (match-end 0)) - (point))))) - (list start end 'mu4e~compose-complete-handler))))) + (start + (or start + (save-excursion + (re-search-backward "\\(\\`\\|[\n:,]\\)[ \t]*") + (goto-char (match-end 0)) + (point))))) + (list start end 'mu4e~compose-complete-handler))))) (defun mu4e~compose-setup-completion () "Set up auto-completion of addresses." @@ -365,7 +365,7 @@ Ie. either 'name ' or 'email')." (set (make-local-variable 'completion-cycle-threshold) 7) (add-to-list (make-local-variable 'completion-styles) 'substring) (add-hook 'completion-at-point-functions - 'mu4e~compose-complete-contact nil t)) + 'mu4e~compose-complete-contact nil t)) (defun mu4e~remove-refs-maybe () "Remove References: if In-Reply-To: is missing. @@ -379,12 +379,12 @@ removing the In-Reply-To header." "Keymap for \"*mu4e-compose*\" buffers.") (unless mu4e-compose-mode-map (setq mu4e-compose-mode-map - (let ((map (make-sparse-keymap))) - (define-key map (kbd "C-S-u") 'mu4e-update-mail-and-index) - (define-key map (kbd "C-c C-u") 'mu4e-update-mail-and-index) - (define-key map (kbd "C-c C-k") 'mu4e-message-kill-buffer) - (define-key map (kbd "M-q") 'mu4e-fill-paragraph) - map))) + (let ((map (make-sparse-keymap))) + (define-key map (kbd "C-S-u") 'mu4e-update-mail-and-index) + (define-key map (kbd "C-c C-u") 'mu4e-update-mail-and-index) + (define-key map (kbd "C-c C-k") 'mu4e-message-kill-buffer) + (define-key map (kbd "M-q") 'mu4e-fill-paragraph) + map))) (defun mu4e-fill-paragraph (&optional region) "Re-layout either the whole message or REGION. @@ -395,11 +395,11 @@ set, this simply executes `fill-paragraph'." ;; Inspired by https://www.emacswiki.org/emacs/UnfillParagraph (interactive (progn (barf-if-buffer-read-only) '(t))) (if mu4e-compose-format-flowed - (let ((fill-column (point-max)) - (use-hard-newlines nil)); rfill "across" hard newlines - (when (use-region-p) - (delete-trailing-whitespace (region-beginning) (region-end))) - (fill-paragraph nil region)) + (let ((fill-column (point-max)) + (use-hard-newlines nil)); rfill "across" hard newlines + (when (use-region-p) + (delete-trailing-whitespace (region-beginning) (region-end))) + (fill-paragraph nil region)) (when (use-region-p) (delete-trailing-whitespace (region-beginning) (region-end))) (fill-paragraph nil region))) @@ -408,7 +408,7 @@ set, this simply executes `fill-paragraph'." (interactive) (setq use-hard-newlines (not use-hard-newlines)) (if use-hard-newlines - (turn-off-auto-fill) + (turn-off-auto-fill) (turn-on-auto-fill))) (defun mu4e~compose-remap-faces () @@ -417,23 +417,23 @@ Our parent `message-mode' uses font-locking for the compose buffers; lets remap its faces so it uses the ones for mu4e." ;; normal headers (face-remap-add-relative 'message-header-name - '((:inherit mu4e-header-key-face))) + '((:inherit mu4e-header-key-face))) (face-remap-add-relative 'message-header-other - '((:inherit mu4e-header-value-face))) + '((:inherit mu4e-header-value-face))) ;; special headers (face-remap-add-relative 'message-header-from - '((:inherit mu4e-contact-face))) + '((:inherit mu4e-contact-face))) (face-remap-add-relative 'message-header-to - '((:inherit mu4e-contact-face))) + '((:inherit mu4e-contact-face))) (face-remap-add-relative 'message-header-cc - '((:inherit mu4e-contact-face))) + '((:inherit mu4e-contact-face))) (face-remap-add-relative 'message-header-bcc - '((:inherit mu4e-contact-face))) + '((:inherit mu4e-contact-face))) (face-remap-add-relative 'message-header-subject - '((:inherit mu4e-special-header-value-face))) + '((:inherit mu4e-special-header-value-face))) ;; citation (face-remap-add-relative 'message-cited-text - '((:inherit mu4e-cited-1-face)))) + '((:inherit mu4e-cited-1-face)))) (define-derived-mode mu4e-compose-mode message-mode "mu4e:compose" "Major mode for the mu4e message composition, derived from `message-mode'. @@ -465,68 +465,68 @@ buffers; lets remap its faces so it uses the ones for mu4e." ;; offer completion for e-mail addresses (when mu4e-compose-complete-addresses (unless mu4e~contacts ;; work-around for https://github.com/djcb/mu/issues/1016 - (mu4e~request-contacts-maybe)) + (mu4e~request-contacts-maybe)) (mu4e~compose-setup-completion)) (if mu4e-compose-format-flowed - (progn - (turn-off-auto-fill) - (setq truncate-lines nil - word-wrap t - mml-enable-flowed t - use-hard-newlines t) - (visual-line-mode t)) + (progn + (turn-off-auto-fill) + (setq truncate-lines nil + word-wrap t + mml-enable-flowed t + use-hard-newlines t) + (visual-line-mode t)) (setq mml-enable-flowed nil)) (let ((keymap (lookup-key message-mode-map [menu-bar text]))) (when keymap - (define-key-after - keymap - [mu4e-hard-newlines] - '(menu-item "Format=flowed" mu4e-toggle-use-hard-newlines - :button (:toggle . use-hard-newlines) - :help "Toggle format=flowed" - :visible (eq major-mode 'mu4e-compose-mode) - :enable mu4e-compose-format-flowed) - 'sep) + (define-key-after + keymap + [mu4e-hard-newlines] + '(menu-item "Format=flowed" mu4e-toggle-use-hard-newlines + :button (:toggle . use-hard-newlines) + :help "Toggle format=flowed" + :visible (eq major-mode 'mu4e-compose-mode) + :enable mu4e-compose-format-flowed) + 'sep) - (define-key-after - keymap - [mu4e-electric-quote-mode] - '(menu-item "Electric quote" electric-quote-local-mode - :button (:toggle . electric-quote-mode) - :help "Toggle Electric quote mode" - :visible (and (eq major-mode 'mu4e-compose-mode) - (functionp 'electric-quote-local-mode))) - 'mu4e-hard-newlines))) + (define-key-after + keymap + [mu4e-electric-quote-mode] + '(menu-item "Electric quote" electric-quote-local-mode + :button (:toggle . electric-quote-mode) + :help "Toggle Electric quote mode" + :visible (and (eq major-mode 'mu4e-compose-mode) + (functionp 'electric-quote-local-mode))) + 'mu4e-hard-newlines))) (when (lookup-key mml-mode-map [menu-bar Attachments]) (define-key-after - (lookup-key mml-mode-map [menu-bar Attachments]) - [mu4e-compose-attach-captured-message] - '(menu-item "Attach captured message" - mu4e-compose-attach-captured-message - :help "Attach message captured in Headers View (with 'a c')" - :visible (eq major-mode 'mu4e-compose-mode)) - (quote Attach\ External...))) + (lookup-key mml-mode-map [menu-bar Attachments]) + [mu4e-compose-attach-captured-message] + '(menu-item "Attach captured message" + mu4e-compose-attach-captured-message + :help "Attach message captured in Headers View (with 'a c')" + :visible (eq major-mode 'mu4e-compose-mode)) + (quote Attach\ External...))) ;; setup the fcc-stuff, if needed (add-hook 'message-send-hook - (lambda () ;; mu4e~compose-save-before-sending - ;; when in-reply-to was removed, remove references as well. - (when (eq mu4e-compose-type 'reply) - (mu4e~remove-refs-maybe)) - (when use-hard-newlines - (mu4e-send-harden-newlines)) - ;; for safety, always save the draft before sending - (set-buffer-modified-p t) - (save-buffer) - (mu4e~compose-setup-fcc-maybe) - (widen)) nil t) + (lambda () ;; mu4e~compose-save-before-sending + ;; when in-reply-to was removed, remove references as well. + (when (eq mu4e-compose-type 'reply) + (mu4e~remove-refs-maybe)) + (when use-hard-newlines + (mu4e-send-harden-newlines)) + ;; for safety, always save the draft before sending + (set-buffer-modified-p t) + (save-buffer) + (mu4e~compose-setup-fcc-maybe) + (widen)) nil t) ;; when the message has been sent. (add-hook 'message-sent-hook - (lambda () ;; mu4e~compose-mark-after-sending - (setq mu4e-sent-func 'mu4e-sent-handler) - (mu4e~proc-sent (buffer-file-name))) nil t)) + (lambda () ;; mu4e~compose-mark-after-sending + (setq mu4e-sent-func 'mu4e-sent-handler) + (mu4e~proc-sent (buffer-file-name))) nil t)) ;; mark these two hooks as permanent-local, so they'll survive mode-changes ;; (put 'mu4e~compose-save-before-sending 'permanent-local-hook t) (put 'mu4e~compose-mark-after-sending 'permanent-local-hook t)) @@ -544,17 +544,17 @@ buffers; lets remap its faces so it uses the ones for mu4e." (defun mu4e~compose-set-friendly-buffer-name (&optional compose-type) "Set some user-friendly buffer name based on the COMPOSE-TYPE." (let* ((subj (message-field-value "subject")) - (subj (unless (and subj (string-match "^[:blank:]*$" subj)) subj)) - (str (or subj - (cl-case compose-type - (reply "*reply*") - (forward "*forward*") - (otherwise "*draft*"))))) + (subj (unless (and subj (string-match "^[:blank:]*$" subj)) subj)) + (str (or subj + (cl-case compose-type + (reply "*reply*") + (forward "*forward*") + (otherwise "*draft*"))))) (rename-buffer (generate-new-buffer-name - (truncate-string-to-width str - mu4e~compose-buffer-max-name-length - nil nil t) - (buffer-name))))) + (truncate-string-to-width str + mu4e~compose-buffer-max-name-length + nil nil t) + (buffer-name))))) (defun mu4e~compose-crypto-reply (parent compose-type) "Possibly encrypt or sign a message based on PARENT and COMPOSE-TYPE. @@ -562,17 +562,17 @@ When composing a reply to an encrypted message, we can automatically encrypt that reply. When the message is unencrypted, we can decide what we want to do." (if (and (eq compose-type 'reply) - (and parent (member 'encrypted (mu4e-message-field parent :flags)))) - (cl-case mu4e-compose-crypto-reply-encrypted-policy - (sign (mml-secure-message-sign)) - (encrypt (mml-secure-message-encrypt)) - (sign-and-encrypt (mml-secure-message-sign-encrypt)) - (message "Do nothing")) - (cl-case mu4e-compose-crypto-reply-plain-policy - (sign (mml-secure-message-sign)) - (encrypt (mml-secure-message-encrypt)) - (sign-and-encrypt (mml-secure-message-sign-encrypt)) - (message "Do nothing"))) + (and parent (member 'encrypted (mu4e-message-field parent :flags)))) + (cl-case mu4e-compose-crypto-reply-encrypted-policy + (sign (mml-secure-message-sign)) + (encrypt (mml-secure-message-encrypt)) + (sign-and-encrypt (mml-secure-message-sign-encrypt)) + (message "Do nothing")) + (cl-case mu4e-compose-crypto-reply-plain-policy + (sign (mml-secure-message-sign)) + (encrypt (mml-secure-message-encrypt)) + (sign-and-encrypt (mml-secure-message-sign-encrypt)) + (message "Do nothing"))) ) @@ -599,21 +599,21 @@ tempfile)." ;; message being forwarded or replied to, otherwise it is nil. (set (make-local-variable 'mu4e-compose-parent-message) original-msg) (put 'mu4e-compose-parent-message 'permanent-local t) - ;; remember the compose-type + ;; remember the compose-type (set (make-local-variable 'mu4e-compose-type) compose-type) (put 'mu4e-compose-type 'permanent-local t) ;; maybe switch the context (mu4e~context-autoswitch mu4e-compose-parent-message - mu4e-compose-context-policy) + mu4e-compose-context-policy) (run-hooks 'mu4e-compose-pre-hook) ;; this opens (or re-opens) a messages with all the basic headers set. (let ((winconf (current-window-configuration))) (condition-case nil - (mu4e-draft-open compose-type original-msg) + (mu4e-draft-open compose-type original-msg) (quit (set-window-configuration winconf) - (mu4e-message "Operation aborted") - (cl-return-from mu4e~compose-handler)))) + (mu4e-message "Operation aborted") + (cl-return-from mu4e~compose-handler)))) ;; insert mail-header-separator, which is needed by message mode to separate ;; headers and body. will be removed before saving to disk (mu4e~draft-insert-mail-header-separator) @@ -625,23 +625,23 @@ tempfile)." (goto-char (point-max)) ;; put attachments at the end (if (and (eq compose-type 'forward) mu4e-compose-forward-as-attachment) - (mu4e-compose-attach-message original-msg) + (mu4e-compose-attach-message original-msg) (dolist (att includes) - (mml-attach-file - (plist-get att :file-name) (plist-get att :mime-type))))) + (mml-attach-file + (plist-get att :file-name) (plist-get att :mime-type))))) (mu4e~compose-set-friendly-buffer-name compose-type) ;; now jump to some useful positions, and start writing that mail! (if (member compose-type '(new forward)) - (message-goto-to) + (message-goto-to) ;; otherwise, it depends... (cl-case message-cite-reply-position ((above traditional) - (message-goto-body)) + (message-goto-body)) (t - (when (message-goto-signature) - (forward-line -2))))) + (when (message-goto-signature) + (forward-line -2))))) ;; bind to `mu4e-compose-parent-message' of compose buffer (set (make-local-variable 'mu4e-compose-parent-message) original-msg) @@ -670,11 +670,11 @@ tempfile)." "Try to go back to some previous buffer, in the order view->headers->main." (unless (eq mu4e-split-view 'single-window) (if (buffer-live-p (mu4e-get-view-buffer)) - (switch-to-buffer (mu4e-get-view-buffer)) + (switch-to-buffer (mu4e-get-view-buffer)) (if (buffer-live-p (mu4e-get-headers-buffer)) - (switch-to-buffer (mu4e-get-headers-buffer)) - ;; if all else fails, back to the main view - (when (fboundp 'mu4e) (mu4e)))))) + (switch-to-buffer (mu4e-get-headers-buffer)) + ;; if all else fails, back to the main view + (when (fboundp 'mu4e) (mu4e)))))) (defun mu4e-sent-handler (docid path) "Handler called with DOCID and PATH for the just-sent message. @@ -687,9 +687,9 @@ appropriate flag at the message forwarded or replied-to." ;; this seems a bit hamfisted... (dolist (buf (buffer-list)) (when (and (buffer-file-name buf) - (string= (buffer-file-name buf) path)) + (string= (buffer-file-name buf) path)) (if message-kill-buffer-on-exit - (kill-buffer buf)))) + (kill-buffer buf)))) (mu4e~switch-back-to-mu4e-buffer) (mu4e-message "Message sent")) @@ -703,8 +703,8 @@ It restores mu4e window layout after killing the compose-buffer." (when (not (equal current-buffer (current-buffer))) ;; Restore mu4e (if mu4e-compose-in-new-frame - (delete-frame) - (mu4e~switch-back-to-mu4e-buffer))))) + (delete-frame) + (mu4e~switch-back-to-mu4e-buffer))))) (defun mu4e~compose-set-parent-flag (path) "Set flags for replied-t and forwarded for the message at PATH. @@ -728,25 +728,25 @@ buffer." (let ((buf (find-file-noselect path))) (when buf (with-current-buffer buf - (message-narrow-to-headers-or-head) - (let ((in-reply-to (message-fetch-field "in-reply-to")) - (forwarded-from) - (references (message-fetch-field "references"))) - (unless in-reply-to - (when references - (with-temp-buffer ;; inspired by `message-shorten-references'. - (insert references) - (goto-char (point-min)) - (let ((refs)) - (while (re-search-forward "<[^ <]+@[^ <]+>" nil t) - (push (match-string 0) refs)) - ;; the last will be the first - (setq forwarded-from (cl-first refs)))))) - ;; remove the <> - (when (and in-reply-to (string-match "<\\(.*\\)>" in-reply-to)) - (mu4e~proc-move (match-string 1 in-reply-to) nil "+R-N")) - (when (and forwarded-from (string-match "<\\(.*\\)>" forwarded-from)) - (mu4e~proc-move (match-string 1 forwarded-from) nil "+P-N"))))))) + (message-narrow-to-headers-or-head) + (let ((in-reply-to (message-fetch-field "in-reply-to")) + (forwarded-from) + (references (message-fetch-field "references"))) + (unless in-reply-to + (when references + (with-temp-buffer ;; inspired by `message-shorten-references'. + (insert references) + (goto-char (point-min)) + (let ((refs)) + (while (re-search-forward "<[^ <]+@[^ <]+>" nil t) + (push (match-string 0) refs)) + ;; the last will be the first + (setq forwarded-from (cl-first refs)))))) + ;; remove the <> + (when (and in-reply-to (string-match "<\\(.*\\)>" in-reply-to)) + (mu4e~proc-move (match-string 1 in-reply-to) nil "+R-N")) + (when (and forwarded-from (string-match "<\\(.*\\)>" forwarded-from)) + (mu4e~proc-move (match-string 1 forwarded-from) nil "+P-N"))))))) (defun mu4e-compose (compose-type) "Start composing a message of COMPOSE-TYPE. @@ -760,31 +760,31 @@ Symbol `edit' is only allowed for draft messages." (unless (member compose-type '(reply forward edit resend new)) (mu4e-error "Invalid compose type '%S'" compose-type)) (when (and (eq compose-type 'edit) - (not (member 'draft (mu4e-message-field msg :flags)))) + (not (member 'draft (mu4e-message-field msg :flags)))) (mu4e-warn "Editing is only allowed for draft messages")) ;; 'new is special, since it takes no existing message as arg; therefore, we ;; don't need to involve the backend, and call the handler *directly* (if (eq compose-type 'new) - (mu4e~compose-handler 'new) + (mu4e~compose-handler 'new) ;; otherwise, we need the doc-id (let* ((docid (mu4e-message-field msg :docid)) - ;; decrypt (or not), based on `mu4e-decryption-policy'. - (decrypt - (and (member 'encrypted (mu4e-message-field msg :flags)) - (if (eq mu4e-decryption-policy 'ask) - (yes-or-no-p (mu4e-format "Decrypt message?")) - mu4e-decryption-policy)))) - ;; if there's a visible view window, select that before starting - ;; composing a new message, so that one will be replaced by the compose - ;; window. The 10-or-so line headers buffer is not a good place to write - ;; it... - (unless (eq mu4e-split-view 'single-window) - (let ((viewwin (get-buffer-window (mu4e-get-view-buffer)))) - (when (window-live-p viewwin) - (select-window viewwin)))) - ;; talk to the backend - (mu4e~proc-compose compose-type decrypt docid))))) + ;; decrypt (or not), based on `mu4e-decryption-policy'. + (decrypt + (and (member 'encrypted (mu4e-message-field msg :flags)) + (if (eq mu4e-decryption-policy 'ask) + (yes-or-no-p (mu4e-format "Decrypt message?")) + mu4e-decryption-policy)))) + ;; if there's a visible view window, select that before starting + ;; composing a new message, so that one will be replaced by the compose + ;; window. The 10-or-so line headers buffer is not a good place to write + ;; it... + (unless (eq mu4e-split-view 'single-window) + (let ((viewwin (get-buffer-window (mu4e-get-view-buffer)))) + (when (window-live-p viewwin) + (select-window viewwin)))) + ;; talk to the backend + (mu4e~proc-compose compose-type decrypt docid))))) (defun mu4e-compose-reply () "Compose a reply for the message at point in the headers buffer." @@ -820,7 +820,7 @@ draft message." ;;;###autoload (defun mu4e~compose-mail (&optional to subject other-headers _continue - _switch-function yank-action _send-actions _return-action) + _switch-function yank-action _send-actions _return-action) "This is mu4e's implementation of `compose-mail'. Quoting its docstring: Start composing a mail message to send. @@ -874,14 +874,14 @@ buffer buried." ;; yank message (if (bufferp yank-action) - (list 'insert-buffer yank-action) + (list 'insert-buffer yank-action) yank-action) ;; try to put the user at some reasonable spot... (if (not to) - (message-goto-to) + (message-goto-to) (if (not subject) - (message-goto-subject) + (message-goto-subject) (message-goto-body)))) ;; happily, we can re-use most things from message mode @@ -933,7 +933,7 @@ is supplied, or Transient Mark mode is enabled and the mark is active." (region-active-p) (push-mark)) (let ((old-position (point)) - (message-position (save-excursion (message-goto-body) (point)))) + (message-position (save-excursion (message-goto-body) (point)))) (goto-char (point-max)) (when (re-search-backward message-signature-separator message-position t) (forward-line -1)) diff --git a/mu4e/mu4e-context.el b/mu4e/mu4e-context.el index d520d6f3..9107daef 100644 --- a/mu4e/mu4e-context.el +++ b/mu4e/mu4e-context.el @@ -1,4 +1,4 @@ -; mu4e-context.el -- part of mu4e, the mu mail user agent -*- lexical-binding: t -*- +;;; mu4e-context.el -- part of mu4e, the mu mail user agent -*- lexical-binding: t -*- ;; ;; Copyright (C) 2015-2020 Dirk-Jan C. Binnema @@ -49,16 +49,16 @@ none." (let ((ctx mu4e~context-current)) (when output (mu4e-message "Current context: %s" - (if ctx (mu4e-context-name ctx) ""))) + (if ctx (mu4e-context-name ctx) ""))) ctx)) (defun mu4e-context-label () "Propertized string with the current context name, or \"\" if there is none." (if (mu4e-context-current) - (concat "[" (propertize (mu4e~quote-for-modeline - (mu4e-context-name (mu4e-context-current))) - 'face 'mu4e-context-face) "]") "")) + (concat "[" (propertize (mu4e~quote-for-modeline + (mu4e-context-name (mu4e-context-current))) + 'face 'mu4e-context-face) "]") "")) (cl-defstruct mu4e-context "A mu4e context object with the following members: @@ -194,9 +194,9 @@ default folders (see `make-mu4e-context' and `mu4e-context'): "Let user choose some context based on its name." (when mu4e-contexts (let* ((names (cl-map 'list (lambda (context) - (cons (mu4e-context-name context) context)) - mu4e-contexts)) - (context (mu4e-read-option prompt names))) + (cons (mu4e-context-name context) context)) + mu4e-contexts)) + (context (mu4e-read-option prompt names))) (or context (mu4e-error "No such context"))))) (defun mu4e-context-switch (&optional force name) @@ -210,25 +210,25 @@ non-nil." (unless mu4e-contexts (mu4e-error "No contexts defined")) (let* ((names (cl-map 'list (lambda (context) - (cons (mu4e-context-name context) context)) - mu4e-contexts)) - (context - (if name - (cdr-safe (assoc name names)) - (mu4e~context-ask-user "Switch to context: ")))) + (cons (mu4e-context-name context) context)) + mu4e-contexts)) + (context + (if name + (cdr-safe (assoc name names)) + (mu4e~context-ask-user "Switch to context: ")))) (unless context (mu4e-error "No such context")) ;; if new context is same as old one one switch with FORCE is set. (when (or force (not (eq context (mu4e-context-current)))) (when (and (mu4e-context-current) - (mu4e-context-leave-func mu4e~context-current)) - (funcall (mu4e-context-leave-func mu4e~context-current))) + (mu4e-context-leave-func mu4e~context-current)) + (funcall (mu4e-context-leave-func mu4e~context-current))) ;; enter the new context (when (mu4e-context-enter-func context) - (funcall (mu4e-context-enter-func context))) + (funcall (mu4e-context-enter-func context))) (when (mu4e-context-vars context) - (mapc (lambda (cell) - (set (car cell) (cdr cell))) - (mu4e-context-vars context))) + (mapc (lambda (cell) + (set (car cell) (cdr cell))) + (mu4e-context-vars context))) (setq mu4e~context-current context) (run-hooks 'mu4e-context-changed-hook) @@ -242,7 +242,7 @@ match, return the first. For MSG and POLICY, see `mu4e-context-determine'." (when (and mu4e-contexts (not mu4e~context-current)) (let ((context (mu4e-context-determine msg policy))) (when context (mu4e-context-switch - nil (mu4e-context-name context)))))) + nil (mu4e-context-name context)))))) (defun mu4e-context-determine (msg &optional policy) "Return the first context with a match-func that returns t. MSG @@ -263,18 +263,18 @@ match, POLICY determines what to do: - otherwise, return nil. Effectively, this leaves the current context as it is." (when mu4e-contexts (if (eq policy 'always-ask) - (mu4e~context-ask-user "Select context: ") + (mu4e~context-ask-user "Select context: ") (or ;; is there a matching one? - (cl-find-if (lambda (context) - (when (mu4e-context-match-func context) - (funcall (mu4e-context-match-func context) msg))) - mu4e-contexts) - ;; no context found yet; consult policy - (cl-case policy - (pick-first (car mu4e-contexts)) - (ask (mu4e~context-ask-user "Select context: ")) - (ask-if-none (or (mu4e-context-current) - (mu4e~context-ask-user "Select context: "))) - (otherwise nil)))))) + (cl-find-if (lambda (context) + (when (mu4e-context-match-func context) + (funcall (mu4e-context-match-func context) msg))) + mu4e-contexts) + ;; no context found yet; consult policy + (cl-case policy + (pick-first (car mu4e-contexts)) + (ask (mu4e~context-ask-user "Select context: ")) + (ask-if-none (or (mu4e-context-current) + (mu4e~context-ask-user "Select context: "))) + (otherwise nil)))))) (provide 'mu4e-context) diff --git a/mu4e/mu4e-contrib.el b/mu4e/mu4e-contrib.el index d102d338..5e1e5787 100644 --- a/mu4e/mu4e-contrib.el +++ b/mu4e/mu4e-contrib.el @@ -61,13 +61,13 @@ ;; Probably this can be moved to mu4e-view.el. (add-hook 'mu4e-view-mode-hook (lambda () - (set (make-local-variable 'bookmark-make-record-function) - 'mu4e-view-bookmark-make-record))) + (set (make-local-variable 'bookmark-make-record-function) + 'mu4e-view-bookmark-make-record))) ;; And this can be moved to mu4e-headers.el. (add-hook 'mu4e-headers-mode-hook (lambda () - (set (make-local-variable 'bookmark-make-record-function) - 'mu4e-view-bookmark-make-record))) + (set (make-local-variable 'bookmark-make-record-function) + 'mu4e-view-bookmark-make-record))) (defun mu4e-view-bookmark-make-record () "Make a bookmark entry for a mu4e buffer. Note that this is an @@ -81,9 +81,9 @@ emacs bookmark, not to be confused with `mu4e-bookmarks'." (subject (or (plist-get msg :subject) "No subject"))) `(,subject ,@(bookmark-make-record-default 'no-file 'no-context) - (location . (,query . ,docid)) - (mode . ,mode) - (handler . mu4e-bookmark-jump)))) + (location . (,query . ,docid)) + (mode . ,mode) + (handler . mu4e-bookmark-jump)))) (defun mu4e-bookmark-jump (bookmark) "Handler function for record returned by `mu4e-view-bookmark-make-record'. @@ -102,8 +102,8 @@ BOOKMARK is a bookmark name or a bookmark record." (run-with-timer 0.1 nil (lambda (bmk) (bookmark-default-handler - `("" (buffer . ,(current-buffer)) . - ,(bookmark-get-bookmark-record bmk)))) + `("" (buffer . ,(current-buffer)) . + ,(bookmark-get-bookmark-record bmk)))) bookmark)))) @@ -132,7 +132,7 @@ For example for bogofile, use \"/usr/bin/bogofilter -Sn < %s\"") (let* ((path (shell-quote-argument (mu4e-message-field msg :path))) (command (format mu4e-register-as-spam-cmd path))) ;; re-register msg as spam (shell-command command)) -(mu4e-mark-at-point 'delete nil)) + (mu4e-mark-at-point 'delete nil)) (defun mu4e-register-msg-as-ham (msg) "Mark message as ham." @@ -140,7 +140,7 @@ For example for bogofile, use \"/usr/bin/bogofilter -Sn < %s\"") (let* ((path (shell-quote-argument(mu4e-message-field msg :path))) (command (format mu4e-register-as-ham-cmd path))) ;; re-register msg as ham (shell-command command)) -(mu4e-mark-at-point 'something nil)) + (mu4e-mark-at-point 'something nil)) ;; (add-to-list 'mu4e-view-actions ;; '("sMark as spam" . mu4e-view-register-msg-as-spam) t) @@ -178,8 +178,8 @@ buffers found, compose a new message and then attach the file." (files-to-attach (delq nil (mapcar (lambda (f) (if (or (not (file-exists-p f)) (file-directory-p f)) - nil - (expand-file-name f))) + nil + (expand-file-name f))) (eshell-flatten-list (reverse args)))))) ;; warn if user tries to attach without any files marked (if (null files-to-attach) @@ -205,7 +205,7 @@ buffers found, compose a new message and then attach the file." ;; if buffer was found, set buffer to destination buffer, and attach files (if (not (eq destination 'nil)) (progn (set-buffer destination) - (goto-char (point-max)) ;attach at end of buffer + (goto-char (point-max)) ; attach at end of buffer (while files-to-attach (mml-attach-file (car files-to-attach) (or (mm-default-file-encoding (car files-to-attach)) diff --git a/mu4e/mu4e-draft.el b/mu4e/mu4e-draft.el index 4381a9d8..22753be3 100644 --- a/mu4e/mu4e-draft.el +++ b/mu4e/mu4e-draft.el @@ -56,9 +56,9 @@ This is the mu4e-specific version of \(i.e. the blob at the bottom of messages). This is the mu4e-specific version of `message-signature'." :type '(choice string - (const :tag "None" nil) - (const :tag "Contents of signature file" t) - function sexp) + (const :tag "None" nil) + (const :tag "Contents of signature file" t) + function sexp) :risky t :group 'mu4e-compose) @@ -68,7 +68,7 @@ mu4e-specific version of `message-signature'." :group 'mu4e-compose) (make-obsolete-variable 'mu4e-compose-auto-include-date - "This is done unconditionally now" "1.3.5") + "This is done unconditionally now" "1.3.5") (defcustom mu4e-compose-in-new-frame nil "Whether to compose messages in a new frame." @@ -95,7 +95,7 @@ its settings apply." ;; set the the signature separator to 'loose', since in the real world, ;; many message don't follow the standard... (let ((message-signature-separator "^-- *$") - (message-signature-insert-empty-line t)) + (message-signature-insert-empty-line t)) (funcall mu4e-compose-cite-function)) (pop-mark) (goto-char (point-min)) @@ -107,8 +107,8 @@ If VAL is nil, return nil." ;; note: the propertize here is currently useless, since gnus sets its own ;; later. (when val (format "%s: %s\n" - (propertize hdr 'face 'mu4e-header-key-face) - (propertize val 'face 'mu4e-header-value-face)))) + (propertize hdr 'face 'mu4e-header-key-face) + (propertize val 'face 'mu4e-header-value-face)))) (defconst mu4e~max-reference-num 21 "Specifies the maximum number of References:. @@ -119,7 +119,7 @@ As suggested by `message-shorten-references'.") Beginning with CUTth one. Code borrowed from `message-shorten-1'." (setcdr (nthcdr (- cut 2) list) - (nthcdr (+ (- cut 2) surplus 1) list))) + (nthcdr (+ (- cut 2) surplus 1) list))) (defun mu4e~draft-references-construct (msg) "Construct the value of the References: header based on MSG. @@ -129,15 +129,15 @@ that :references includes the old in-reply-to as well) and the message-id. If the message-id is empty, returns the old References. If both are empty, return nil." (let* ( ;; these are the ones from the message being replied to / forwarded - (refs (mu4e-message-field msg :references)) - (msgid (mu4e-message-field msg :message-id)) - ;; now, append in - (refs (if (and msgid (not (string= msgid ""))) - (append refs (list msgid)) refs)) - ;; no doubles - (refs (cl-delete-duplicates refs :test #'equal)) - (refnum (length refs)) - (cut 2)) + (refs (mu4e-message-field msg :references)) + (msgid (mu4e-message-field msg :message-id)) + ;; now, append in + (refs (if (and msgid (not (string= msgid ""))) + (append refs (list msgid)) refs)) + ;; no doubles + (refs (cl-delete-duplicates refs :test #'equal)) + (refnum (length refs)) + (cut 2)) ;; remove some refs when there are too many (when (> refnum mu4e~max-reference-num) (let ((surplus (- refnum mu4e~max-reference-num))) @@ -154,13 +154,13 @@ This is specified as a comma-separated list of e-mail addresses. If LST is nil, returns nil." (when lst (mapconcat - (lambda (addrcell) - (let ((name (car addrcell)) - (email (cdr addrcell))) - (if name - (format "%s <%s>" (mu4e~rfc822-quoteit name) email) - (format "%s" email)))) - lst ", "))) + (lambda (addrcell) + (let ((name (car addrcell)) + (email (cdr addrcell))) + (if name + (format "%s <%s>" (mu4e~rfc822-quoteit name) email) + (format "%s" email)))) + lst ", "))) (defun mu4e~draft-address-cell-equal (cell1 cell2) "Return t if CELL1 and CELL2 have the same e-mail address. @@ -168,8 +168,8 @@ The comparison is done case-insensitively. If the cells done match return nil. CELL1 and CELL2 are cons cells of the form (NAME . EMAIL)." (string= - (downcase (or (cdr cell1) "")) - (downcase (or (cdr cell2) "")))) + (downcase (or (cdr cell1) "")) + (downcase (or (cdr cell2) "")))) (defun mu4e~draft-create-to-lst (origmsg) @@ -180,16 +180,16 @@ whatever was in the To: field before, goes to the Cc:-list (if we're doing a reply-to-all). Special case: if we were the sender of the original, we simple copy the list form the original." (let ((reply-to - (or (plist-get origmsg :reply-to) (plist-get origmsg :from)))) + (or (plist-get origmsg :reply-to) (plist-get origmsg :from)))) (cl-delete-duplicates reply-to :test #'mu4e~draft-address-cell-equal) (if mu4e-compose-dont-reply-to-self - (cl-delete-if - (lambda (to-cell) - (cl-member-if + (cl-delete-if + (lambda (to-cell) + (cl-member-if (lambda (addr) (string= (downcase addr) (downcase (cdr to-cell)))) (mu4e-personal-addresses))) - reply-to) + reply-to) reply-to))) @@ -198,24 +198,24 @@ of the original, we simple copy the list form the original." I.e. return all the addresses in ADDRS not matching `mu4e-compose-reply-ignore-address'." (cond - ((null mu4e-compose-reply-ignore-address) - addrs) - ((functionp mu4e-compose-reply-ignore-address) + ((null mu4e-compose-reply-ignore-address) + addrs) + ((functionp mu4e-compose-reply-ignore-address) + (cl-remove-if + (lambda (elt) + (funcall mu4e-compose-reply-ignore-address (cdr elt))) + addrs)) + (t + ;; regexp or list of regexps + (let* ((regexp mu4e-compose-reply-ignore-address) + (regexp (if (listp regexp) + (mapconcat (lambda (elt) (concat "\\(" elt "\\)")) + regexp "\\|") + regexp))) (cl-remove-if - (lambda (elt) - (funcall mu4e-compose-reply-ignore-address (cdr elt))) - addrs)) - (t - ;; regexp or list of regexps - (let* ((regexp mu4e-compose-reply-ignore-address) - (regexp (if (listp regexp) - (mapconcat (lambda (elt) (concat "\\(" elt "\\)")) - regexp "\\|") - regexp))) - (cl-remove-if - (lambda (elt) - (string-match regexp (cdr elt))) - addrs))))) + (lambda (elt) + (string-match regexp (cdr elt))) + addrs))))) (defun mu4e~draft-create-cc-lst (origmsg &optional reply-all include-from) "Create a list of address for the Cc: in a new message. @@ -223,37 +223,37 @@ This is based on the original message ORIGMSG, and whether it's a REPLY-ALL." (when reply-all (let* ((cc-lst ;; get the cc-field from the original, remove dups - (cl-delete-duplicates - (append - (plist-get origmsg :to) - (plist-get origmsg :cc) - (when include-from(plist-get origmsg :from)) - (plist-get origmsg :list-post)) - :test #'mu4e~draft-address-cell-equal)) - ;; now we have the basic list, but we must remove - ;; addresses also in the To: list - (cc-lst - (cl-delete-if - (lambda (cc-cell) - (cl-find-if - (lambda (to-cell) - (mu4e~draft-address-cell-equal cc-cell to-cell)) - (mu4e~draft-create-to-lst origmsg))) - cc-lst)) - ;; remove ignored addresses - (cc-lst (mu4e~strip-ignored-addresses cc-lst)) - ;; finally, we need to remove ourselves from the cc-list - ;; unless mu4e-compose-keep-self-cc is non-nil - (cc-lst - (if (or mu4e-compose-keep-self-cc (null user-mail-address)) + (cl-delete-duplicates + (append + (plist-get origmsg :to) + (plist-get origmsg :cc) + (when include-from(plist-get origmsg :from)) + (plist-get origmsg :list-post)) + :test #'mu4e~draft-address-cell-equal)) + ;; now we have the basic list, but we must remove + ;; addresses also in the To: list + (cc-lst + (cl-delete-if + (lambda (cc-cell) + (cl-find-if + (lambda (to-cell) + (mu4e~draft-address-cell-equal cc-cell to-cell)) + (mu4e~draft-create-to-lst origmsg))) + cc-lst)) + ;; remove ignored addresses + (cc-lst (mu4e~strip-ignored-addresses cc-lst)) + ;; finally, we need to remove ourselves from the cc-list + ;; unless mu4e-compose-keep-self-cc is non-nil + (cc-lst + (if (or mu4e-compose-keep-self-cc (null user-mail-address)) cc-lst - (cl-delete-if - (lambda (cc-cell) - (cl-member-if - (lambda (addr) - (string= (downcase addr) (downcase (cdr cc-cell)))) - (mu4e-personal-addresses))) - cc-lst)))) + (cl-delete-if + (lambda (cc-cell) + (cl-member-if + (lambda (addr) + (string= (downcase addr) (downcase (cdr cc-cell)))) + (mu4e-personal-addresses))) + cc-lst)))) cc-lst))) (defun mu4e~draft-recipients-construct (field origmsg &optional reply-all include-from) @@ -262,13 +262,13 @@ REPLY-ALL." and (optionally) REPLY-ALL which indicates this is a reply-to-all message. Return nil if there are no recipients for the particular field." (mu4e~draft-recipients-list-to-string - (cl-case field - (:to - (mu4e~draft-create-to-lst origmsg)) - (:cc - (mu4e~draft-create-cc-lst origmsg reply-all include-from)) - (otherwise - (mu4e-error "Unsupported field"))))) + (cl-case field + (:to + (mu4e~draft-create-to-lst origmsg)) + (:cc + (mu4e~draft-create-cc-lst origmsg reply-all include-from)) + (otherwise + (mu4e-error "Unsupported field"))))) ;;; RFC2822 handling of phrases in mail-addresses ;;; The optional display-name contains a phrase, it sits before the angle-addr @@ -284,14 +284,14 @@ The reverse of the RFC atext definition is then tested. If it matches, nil is returned, if not, it is an 'rfc822-atom, which is returned." (cond - ((= (length ph) 0) 'rfc822-empty) - ((= (aref ph 0) ?\") - (if (string-match "\"\\([^\"\\\n]\\|\\\\.\\|\\\\\n\\)*\"" ph) + ((= (length ph) 0) 'rfc822-empty) + ((= (aref ph 0) ?\") + (if (string-match "\"\\([^\"\\\n]\\|\\\\.\\|\\\\\n\\)*\"" ph) 'rfc822-quoted-string - 'rfc822-containing-quote)) ; starts with quote, but doesn't end with one - ((string-match-p "[\"]" ph) 'rfc822-containing-quote) - ((string-match-p "[\000-\037()\*<>@,;:\\\.]+" ph) nil) - (t 'rfc822-atom))) + 'rfc822-containing-quote)) ; starts with quote, but doesn't end with one + ((string-match-p "[\"]" ph) 'rfc822-containing-quote) + ((string-match-p "[\000-\037()\*<>@,;:\\\.]+" ph) nil) + (t 'rfc822-atom))) (defun mu4e~rfc822-quoteit (ph) "Quote an RFC822 phrase PH only if necessary. @@ -299,12 +299,12 @@ Atoms and quoted strings don't need quotes. The rest do. In case a phrase contains a quote, it will be escaped." (let ((type (mu4e~rfc822-phrase-type ph))) (cond - ((eq type 'rfc822-atom) ph) - ((eq type 'rfc822-quoted-string) ph) - ((eq type 'rfc822-containing-quote) - (format "\"%s\"" - (replace-regexp-in-string "\"" "\\\\\"" ph))) - (t (format "\"%s\"" ph))))) + ((eq type 'rfc822-atom) ph) + ((eq type 'rfc822-quoted-string) ph) + ((eq type 'rfc822-containing-quote) + (format "\"%s\"" + (replace-regexp-in-string "\"" "\\\\\"" ph))) + (t (format "\"%s\"" ph))))) (defun mu4e~draft-from-construct () @@ -313,7 +313,7 @@ This is based on the variable `user-full-name' and `user-mail-address'; if the latter is nil, function returns nil." (when user-mail-address (if user-full-name - (format "%s <%s>" (mu4e~rfc822-quoteit user-full-name) user-mail-address) + (format "%s <%s>" (mu4e~rfc822-quoteit user-full-name) user-mail-address) (format "%s" user-mail-address)))) @@ -333,23 +333,23 @@ separator is never written to the message file. Also see ;; make sure there's not one already (mu4e~draft-remove-mail-header-separator) (let ((sepa (propertize mail-header-separator - 'intangible t - ;; don't make this read-only, message-mode - ;; seems to require it being writable in some cases - ;;'read-only "Can't touch this" - 'rear-nonsticky t - 'font-lock-face 'mu4e-compose-separator-face))) + 'intangible t + ;; don't make this read-only, message-mode + ;; seems to require it being writable in some cases + ;;'read-only "Can't touch this" + 'rear-nonsticky t + 'font-lock-face 'mu4e-compose-separator-face))) (widen) ;; search for the first empty line (goto-char (point-min)) (if (search-forward-regexp "^$" nil t) - (progn - (replace-match sepa) - ;; `message-narrow-to-headers` searches for a - ;; `mail-header-separator` followed by a new line. Therefore, we - ;; must insert a newline if on the last line of the buffer. - (when (= (point) (point-max)) - (insert "\n"))) + (progn + (replace-match sepa) + ;; `message-narrow-to-headers` searches for a + ;; `mail-header-separator` followed by a new line. Therefore, we + ;; must insert a newline if on the last line of the buffer. + (when (= (point) (point-max)) + (insert "\n"))) (progn ;; no empty line? then prepend one (goto-char (point-max)) (insert "\n" sepa)))))) @@ -372,15 +372,15 @@ never hits the disk. Also see "Ask user whether she wants to reply to *all* recipients. If there is just one recipient of ORIGMSG do nothing." (let* ((recipnum - (+ (length (mu4e~draft-create-to-lst origmsg)) + (+ (length (mu4e~draft-create-to-lst origmsg)) (length (mu4e~draft-create-cc-lst origmsg t)))) - (response - (if (< recipnum 2) + (response + (if (< recipnum 2) 'all ;; with less than 2 recipients, we can reply to 'all' - (mu4e-read-option - "Reply to " - `( (,(format "all %d recipients" recipnum) . all) - ("sender only" . sender-only)))))) + (mu4e-read-option + "Reply to " + `( (,(format "all %d recipients" recipnum) . all) + ("sender only" . sender-only)))))) (eq response 'all))) (defun mu4e~draft-message-filename-construct (&optional flagstr) @@ -389,25 +389,25 @@ It looks something like