diff options
Diffstat (limited to '.emacs.d/rul-lisp')
| -rw-r--r-- | .emacs.d/rul-lisp/packages/rul-mail.el | 105 |
1 files changed, 54 insertions, 51 deletions
diff --git a/.emacs.d/rul-lisp/packages/rul-mail.el b/.emacs.d/rul-lisp/packages/rul-mail.el index a16614e..12846a0 100644 --- a/.emacs.d/rul-lisp/packages/rul-mail.el +++ b/.emacs.d/rul-lisp/packages/rul-mail.el @@ -4,6 +4,13 @@ ;; Use sender to find GPG key. (setq mml-secure-openpgp-sign-with-sender t) +;; Keep HTML mail readable without sender-defined styling. +(setq shr-use-colors nil + shr-use-fonts nil) + +(with-eval-after-load 'shr + (set-face-attribute 'shr-link nil :inherit 'default :underline t)) + (use-package notmuch :ensure t :config @@ -19,6 +26,53 @@ (setq notmuch-draft-folder "current/Drafts") + (defvar-local rul/notmuch-show-refreshing-for-olivetti nil) + + (defun rul/notmuch-show-enable-olivetti () + "Enable Olivetti before notmuch renders message HTML." + (setq-local olivetti-body-width 100 + shr-width nil + shr-max-width olivetti-body-width) + (olivetti-mode 1)) + + (defun rul/notmuch-show-refresh-after-olivetti () + "Refresh an already-rendered notmuch buffer after Olivetti changes width." + (when (and (derived-mode-p 'notmuch-show-mode) + olivetti-mode + notmuch-show-thread-id + (not rul/notmuch-show-refreshing-for-olivetti)) + (setq rul/notmuch-show-refreshing-for-olivetti t) + (run-at-time + 0 nil + (lambda (buffer) + (when (buffer-live-p buffer) + (with-current-buffer buffer + (unwind-protect + (when (and (derived-mode-p 'notmuch-show-mode) + olivetti-mode + notmuch-show-thread-id) + (notmuch-refresh-this-buffer)) + (setq rul/notmuch-show-refreshing-for-olivetti nil))))) + (current-buffer)))) + + (add-hook 'notmuch-show-mode-hook #'rul/notmuch-show-enable-olivetti) + + (with-eval-after-load 'olivetti + (add-hook 'olivetti-mode-on-hook + #'rul/notmuch-show-refresh-after-olivetti + t)) + + (defun rul/notmuch-inline-override-images (types) + "Treat standalone image MIME parts as attachments in notmuch." + (if (member "image/.*" types) + types + (append types '("image/.*")))) + + (unless (advice-member-p #'rul/notmuch-inline-override-images + 'notmuch--inline-override-types) + (advice-add 'notmuch--inline-override-types :filter-return + #'rul/notmuch-inline-override-images)) + ;; Keymaps (defun rul/capture-mail() "Capture mail to org mode." @@ -51,57 +105,6 @@ (interactive (notmuch-search-interactive-region)) (notmuch-search-tag (list "+spam" "-inbox" "-unread") beg end))) - ;; Unspam: restore false-positives back to INBOX. Unlike archive, the file - ;; move has to happen inline — the hook's path:current/Spam/** rule would - ;; otherwise re-tag +spam on the next post-new, reverting the user's action. - ;; Move the file BEFORE changing tags so an interleaved post-new from mbsync - ;; can't re-apply +spam between our tag change and our rename. - (defun rul/notmuch-move-to-inbox (query) - "Move files matching QUERY that live under spam/trash maildirs into -~/mail/INBOX/cur/ with fresh uuid names. Reindex if any moved." - (let ((inbox-cur (expand-file-name "~/mail/INBOX/cur/")) - (spam-paths "(path:current/Spam/** or path:current/spam/** or path:current/Trash/** or path:current/trash/**)") - (count 0)) - ;; Spam/trash are in search.exclude_tags, so include excluded files here. - (dolist (f (process-lines "notmuch" "search" "--exclude=false" "--output=files" - (concat "(" query ") and " spam-paths))) - (when (file-exists-p f) - (let* ((base (file-name-nondirectory f)) - (colon (cl-position ?: base :from-end t)) - (suffix (if colon (substring base colon) "")) - (uuid (string-trim (shell-command-to-string "uuidgen")))) - (rename-file f (concat inbox-cur uuid suffix)) - (cl-incf count)))) - (when (> count 0) - (call-process "notmuch" nil nil nil "new" "--no-hooks")) - count)) - - (defun rul/notmuch-search-unspam (&optional beg end) - "Restore threads from spam/trash: move files back to INBOX first (so a -racing post-new can't re-tag +spam based on path), then tag -spam -trash --killed +inbox +unread, then refresh." - (interactive (notmuch-search-interactive-region)) - (let ((tids (save-excursion - (goto-char beg) - (cl-loop while (< (point) end) - collect (notmuch-search-find-thread-id) - do (forward-line 1))))) - (dolist (tid tids) - (rul/notmuch-move-to-inbox (concat "thread:" tid))) - (notmuch-search-tag (list "-spam" "-trash" "-killed" "+inbox" "+unread") beg end)) - (notmuch-refresh-this-buffer)) - - (defun rul/notmuch-show-unspam () - "Restore current message from spam/trash back to INBOX." - (interactive) - (let ((mid (notmuch-show-get-message-id))) - (rul/notmuch-move-to-inbox mid) - (notmuch-show-tag (list "-spam" "-trash" "-killed" "+inbox" "+unread"))) - (notmuch-refresh-this-buffer)) - - (define-key notmuch-search-mode-map "U" 'rul/notmuch-search-unspam) - (define-key notmuch-show-mode-map "U" 'rul/notmuch-show-unspam) - ;; Archive ;; Stock `a` applies notmuch-archive-tags but doesn't re-run the search, so ;; the thread stays visible in the tag:inbox buffer with stale results. Wrap |
