diff options
Diffstat (limited to 'custom/jao-custom-notmuch.el')
-rw-r--r-- | custom/jao-custom-notmuch.el | 657 |
1 files changed, 657 insertions, 0 deletions
diff --git a/custom/jao-custom-notmuch.el b/custom/jao-custom-notmuch.el new file mode 100644 index 0000000..3919897 --- /dev/null +++ b/custom/jao-custom-notmuch.el @@ -0,0 +1,657 @@ +;; -*- lexical-binding: t; -*- +;;; minibuffer +(defvar jao-notmuch-minibuffer-string "") + +(defvar jao-notmuch-minibuffer-queries + `((:name "" :query "tag:new and not tag:draft" :face jao-themes-f00) + (:name "B" :query "tag:new and tag:bigml and tag:inbox" :face default) + (:name "A" :query "tag:new and tag:alba" :face default) + (:name "b" :query "tag:new and tag:bigml and tag:bugs" + :face jao-themes-error) + (:name "S" :query "tag:new and tag:bigml and tag:support" :face default) + (:name "W" + :query "tag:new and tag:bigml and not tag:\"/support|bugs|inbox/\"" + :face default) + (:name "I" :query "tag:new and tag:jao and tag:inbox" :face jao-themes-warning) + (:name "W" :query "tag:new and tag:jao and tag:write" :face jao-themes-warning) + (:name "J" + :query ,(concat "tag:new and tag:jao and not " + "tag:\"/local|hacking|draft|inbox|prog|words|write/\"") + :face default) + (:name "H" :query "tag:new and tag:hacking and not tag:\"/emacs/\"") + (:name "E" :query "tag:new and tag:\"/emacs/\"") + (:name "l" :query "tag:new and tag:local") + (:name "F" :query "tag:new and tag:feeds and not tag:\"/emacs/\""))) + +(defun jao-notmuch-notify () + (let ((cnts (notmuch-hello-query-counts jao-notmuch-minibuffer-queries))) + (setq jao-notmuch-minibuffer-string + (mapconcat (lambda (c) + (propertize (format "%s%s" + (plist-get c :name) + (plist-get c :count)) + 'face (or (plist-get c :face) + 'jao-themes-dimm))) + cnts + " ")) + (jao-minibuffer-refresh))) + +(when jao-notmuch-enabled + (jao-minibuffer-add-variable 'jao-notmuch-minibuffer-string -20)) + +;;; saved searches +(defvar jao-notmuch--new "tag:\"/^(unread|new)$/\"") +(defvar jao-notmuch--newa (concat jao-notmuch--new " AND ")) + +(defun jao-notmuch--q (d0 d1 &optional k qs st) + (let ((q (or (when qs (mapconcat #'identity qs " AND ")) + (concat jao-notmuch--newa + (mapconcat (lambda (d) (when d (concat "tag:" d))) + (list d0 d1) " AND "))))) + (list :name (concat d0 (when (and d1 (not (string= "" d1))) "/") d1) + :key k :query q :search-type (or st 'tree) + :sort-order 'oldest-first))) + +(defun jao-notmuch--qn (d0 d1 k qs &optional st) + (jao-notmuch--q d0 d1 k (cons jao-notmuch--new qs) st)) + +(defun jao-notmuch--sq (tag &optional k d0 d1) + (jao-notmuch--qn (or d0 "feeds") (or d1 tag) k (list (concat "tag:" tag)))) + +(defun jao-notmuch-tree-widen-search () + (interactive) + (when-let ((query (notmuch-tree-get-query))) + (let ((notmuch-show-process-crypto (notmuch-tree--message-process-crypto))) + (notmuch-tree-close-message-window) + (notmuch-tree (string-replace jao-notmuch--newa "" query))))) + +(defun jao-notmuch-widen-searches (searches &optional extra) + (mapcar (lambda (s) + (let* ((q (plist-get s :query)) + (qs (string-replace jao-notmuch--newa "" q))) + (plist-put (copy-sequence s) :query (concat qs extra)))) + searches)) + +(defun jao-notmuch-hello--insert-searches (searches title) + (when-let (searches (notmuch-hello-query-counts searches)) + (let* ((cnt (when title + (seq-reduce (lambda (c q) + (+ c (or (plist-get q :count) 0))) + searches + 0))) + (title (if title (format "[ %d %s ]\n\n" cnt title) "\n")) + (notmuch-column-control 1.0)) + (widget-insert (propertize title 'face 'jao-themes-f00)) + (notmuch-hello-insert-buttons searches)))) + +(defmacro jao-notmuch-def-searches (name searches) + (declare (indent 1)) + (let ((name (and name (format "%s" name))) + (id (intern (format "jao-notmuch-%s-searches" (or name (gensym)))))) + `(progn (defvar ,id ,searches) + (defun ,id () (jao-notmuch-hello--insert-searches ,id ,name)) + (setq notmuch-saved-searches (append notmuch-saved-searches ,id)) + (add-to-list 'notmuch-hello-sections ',id t)))) + +(setq notmuch-hello-sections nil notmuch-saved-searches nil) + +(jao-notmuch-def-searches bigml + `(,(jao-notmuch--q "bigml" "inbox" "bi") + ,(jao-notmuch--q "bigml" "alba" "ba") + ,(jao-notmuch--q "bigml" "support" "bs") + ,(jao-notmuch--q "bigml" "bugs" "bb") + ,(jao-notmuch--q "bigml" "drivel" "bd") + ,(jao-notmuch--q "bigml" "lists" "bl"))) + +(jao-notmuch-def-searches inbox + `(,(jao-notmuch--q "jao" "inbox" "ji") + ,(jao-notmuch--qn "jao" "bills" "jb" '("tag:bills")) + ,(jao-notmuch--qn "jao" "write" "jw" '("tag:write")) + ,(jao-notmuch--q "jao" "drivel" "jd") + ,(jao-notmuch--q "jao" "mdk" "jm") + ,(jao-notmuch--qn "jao" "hacking" "jh" '("tag:hacking" "not tag:\"/emacs/\"")) + ,(jao-notmuch--qn "jao" "local" "jl" '("tag:local")))) + +(jao-notmuch-def-searches news + (mapcar #'jao-notmuch--sq '("news" "noticias" "fun" "words" "computers"))) + +(jao-notmuch-def-searches hacking + (mapcar #'jao-notmuch--sq '("xmobar" "geiser" "mdk" "mailutils" "notmuch"))) + +(jao-notmuch-def-searches prog + (append (mapcar #'jao-notmuch--sq + '( "lobsters" "clojure" "lisp" "scheme" + "haskell" "idris" "erlang" "pharo")) + `(,(jao-notmuch--qn "feeds" "prog" "fp" + '("tag:prog" "not tag:\"/emacs/\""))))) + +(jao-notmuch-def-searches emacs + `(,(jao-notmuch--sq "emacs" "ee" "emacs" "feeds") + ,(jao-notmuch--sq "emacs-help" "eh" "emacs" "help") + ,(jao-notmuch--sq "emacs-github" "eg" "emacs" "github") + ,(jao-notmuch--sq "emacs-devel" "ed" "emacs" "devel") + ,(jao-notmuch--sq "emacs-bugs" "eb" "emacs" "bugs") + ,(jao-notmuch--sq "emacs-diffs" "ec" "emacs" "diffs"))) + +(jao-notmuch-def-searches sci + (mapcar #'jao-notmuch--sq + '("philosophy" "math" "physics" "sci" "gr-qc" "quant-ph"))) + +(jao-notmuch-def-searches flags + (jao-notmuch-widen-searches notmuch-saved-searches " AND tag:flagged")) + +(jao-notmuch-def-searches nil + `(,(jao-notmuch--q "bml" "flagged" "rb" '("tag:flagged" "tag:bigml")) + ,(jao-notmuch--q "jao" "flagged" "rj" '("tag:flagged" "tag:jao")) + ,(jao-notmuch--q "feeds" "flagged" "rf" '("tag:flagged" "tag:feeds")))) + +(jao-notmuch-def-searches today + `(,(jao-notmuch--q "new" nil "nn" '("tag:new" "not tag:draft")) + ,(jao-notmuch--q "jao" "drafts" "d" '("tag:draft")) + ,(jao-notmuch--q "bml" "sent" "ts" + '("tag:bigml" "date:1d.." "tag:sent")) + ,(jao-notmuch--q "jao" "sent" "tS" + '("tag:\"/jao|hacking/\"" "date:1d.." "tag:sent")) + ,(jao-notmuch--q "bml" "today" "tb" + '("not tag:sent" "tag:bigml" "date:24h..")) + ,(jao-notmuch--q "jao" "today" "tj" + '("tag:jao" "date:24h.." + "not tag:\"/(sent|feeds|spam|local)/\"")))) + +(jao-notmuch-def-searches trove + (mapcar (lambda (m) (list :query (concat "tag:trove and tag:" m) + :name (concat "trove/" m) + :key (concat "t" (substring m 0 1)) + :search-type 'tree)) + '("jao" "hacking" "feeds" "bills"))) + +(jao-notmuch-def-searches nil + '((:query "not tag:trove and not tag:bigml" :name "jao/untroved" :search-type tree) + (:query "tag:sent and tag:bigml" :name "bigml/sent" :search-type tree) + (:query "tag:sent and not tag:bigml" :name "jao/sent" :search-type tree) + (:query "*" :name "messages" :search-type tree))) + +(defvar jao-notmuch-widened-searches + (jao-notmuch-widen-searches notmuch-saved-searches)) + +(defun jao-notmuch-jump-search (&optional widen) + (interactive "P") + (let ((notmuch-saved-searches + (if widen jao-notmuch-widened-searches notmuch-saved-searches))) + (notmuch-jump-search))) + +;;; tags +(defvar jao-notmuch--shared-tags + '("new" "unread" "flagged" "signed" "sent" "attachment" "forwarded" "inbox" + "encrypted" "gmane" "gnus" "feeds" "rss" "mce" "trove" "prog" "emacs")) + +(defun jao-notmuch--subtags (tag &rest excl) + (let* ((cmd (concat "notmuch search --output=tags tag:" tag)) + (ts (split-string (shell-command-to-string cmd)))) + (seq-difference ts (append jao-notmuch--shared-tags (cons tag excl))))) + +(setq notmuch-archive-tags '("+trove" "-new" "-drivel" "-words" "-inbox") + notmuch-show-mark-read-tags '("-new" "-unread") + notmuch-tag-formats + (let (;; (d `(:foreground ,(face-attribute 'jao-themes-dimm :foreground))) + (e `(:foreground ,(face-attribute 'jao-themes-error :foreground)))) + `(("unread") + ("signed") + ("new" "ยท") + ("replied" "โฉ" (propertize tag 'face '(:family "Fira Code"))) + ("sent" "๐ช") + ("attachment" "๐") + ("deleted" "๐" (propertize tag 'face '(:underline nil ,@e))) + ("flagged" "โ") + ("jao" "j") + ("bigml" "b") + ("feeds" "f") + ("lists" "l") + ("gmane" "g"))) + notmuch-tag-deleted-formats + '(("unread") + ("new") + ("flagged") + ("deleted") + (".*" (notmuch-apply-face tag 'notmuch-tag-deleted)))) + +(with-eval-after-load "notmuch-tag" + (advice-add #'notmuch-read-tag-changes + :filter-return (lambda (x) (mapcar #'string-trim x)))) + +;;; package +;; (add-to-list 'load-path "/usr/local/share/emacs/site-lisp/") +(jao-load-path "notmuch") + +(use-package notmuch + :init + (setq notmuch-address-use-company t + notmuch-address-command 'as-is + notmuch-always-prompt-for-sender t + notmuch-draft-folder "drafts" + notmuch-draft-quoted-tags '("part") + notmuch-fcc-dirs + '(("\\(support\\|education\\)@bigml.com" . nil) + ("mail@jao.io" . nil) + (".*@bigml.com" . "bigml -new -unread +sent +bigml") + (".*" . "jao -new -unread +sent +jao")) + notmuch-maildir-use-notmuch-insert t) + + :custom ((notmuch-address-internal-completion '(sent nil))) + + :config + + (add-hook 'message-send-hook #'notmuch-mua-attachment-check) + + (when jao-notmuch-enabled + (define-key message-mode-map (kbd "C-c C-d") #'notmuch-draft-postpone) + (setq message-directory "~/var/mail/" + message-auto-save-directory "/tmp" + mail-user-agent 'message-user-agent)) + + :bind (:map notmuch-common-keymap + (("E" . jao-notmuch-open-enclosure) + ("B" . notmuch-show-resend-message) + ("b" . jao-notmuch-browse-urls)))) + +(use-package jao-notmuch :demand t) + +;;; hello +(defun jao-notmuch-hello--header () (insert " ")) +(when (display-graphic-p) + (add-to-list 'notmuch-hello-sections 'jao-notmuch-hello--header)) + +(add-to-list 'notmuch-hello-sections 'notmuch-hello-insert-alltags t) + +(defun jao-notmuch-refresh-agenda () + (interactive) + (save-window-excursion (calendar) (jao-org-agenda))) + +(defun jao-notmuch-hello-first () + (interactive) + (let ((inhibit-message t)) + (goto-char (point-min)) + (widget-forward 1))) + +(defun jao-notmuch-refresh-hello (&optional agenda) + (interactive "P") + (ignore-errors + (when (and (string= "mail" (jao-afio-frame-name)) + (derived-mode-p 'notmuch-hello-mode)) + (when (not (string-blank-p jao-notmuch-minibuffer-string)) + (let ((notmuch-hello-auto-refresh nil)) (notmuch-hello))) + (let ((jao-minibuffer-inhibit t)) + (when agenda (jao-notmuch-refresh-agenda))) + (unless (widget-at) (jao-notmuch-hello-first)) + (jao-minibuffer-refresh)))) + +(defvar jao-notmuch-hello--sec-rx "^\\(\\[ [0-9]+\\|All tags:.+\\)") + +(defun jao-notmuch-hello-next-section () + (interactive) + (when (re-search-forward jao-notmuch-hello--sec-rx nil t) + (widget-forward 1))) + +(defun jao-notmuch-hello-prev-section () + (interactive) + (beginning-of-line) + (unless (looking-at-p jao-notmuch-hello--sec-rx) + (re-search-backward jao-notmuch-hello--sec-rx nil t)) + (when (re-search-backward jao-notmuch-hello--sec-rx nil t) + (end-of-line) + (widget-forward 1))) + +(defun jao-notmuch-hello-next () + (interactive) + (if (widget-at) + (widget-button-press (point)) + (jao-notmuch-hello-next-section))) + +(use-package notmuch-hello + :init + (setq notmuch-column-control 1.0 + notmuch-hello-hide-tags nil + notmuch-hello-thousands-separator "," + notmuch-hello-auto-refresh t + notmuch-show-all-tags-list nil + notmuch-show-logo nil + notmuch-show-empty-saved-searches nil) + + (add-to-list 'display-buffer-alist + '("\\*notmuch-hello\\*" + (display-buffer-reuse-window) + (body-function . (lambda (w) (set-window-margins w 1))))) + + :hook ((notmuch-hello-refresh . jao-notmuch-notify)) + + :config + (when jao-notmuch-enabled + (add-hook 'jao-afio-switch-hook #'jao-notmuch-refresh-hello)) + + :bind (:map notmuch-hello-mode-map + (("a" . jao-notmuch-refresh-agenda) + ("g" . jao-notmuch-refresh-hello) + ("j" . jao-notmuch-jump-search) + ("n" . jao-notmuch-hello-next) + ("p" . widget-backward) + ("SPC" . widget-button-press) + ("/" . consult-notmuch) + ("." . jao-notmuch-hello-first) + ("[" . jao-notmuch-hello-prev-section) + ("]" . jao-notmuch-hello-next-section)))) + +;;; show +(defun jao-notmuch-open-enclosure (add) + (interactive "P") + (with-current-notmuch-show-message + (goto-char (point-min)) + (if (not (search-forward "Enclosure:" nil t)) + (user-error "No enclosure in message body") + (re-search-forward "https?://" nil t) + (if-let (url (thing-at-point-url-at-point)) + (progn + (message "%s %s ..." (if add "Adding" "Playing") url) + (unless add (jao-mpc-clear)) + (jao-mpc-add-url url) + (unless add (jao-mpc-play))) + (error "Found an enclosure, but not a link!"))))) + +(defconst jao-mail-clean-rx + (regexp-opt '("ElDiario.es - ElDiario.es: " "The Guardian: " + "The Conversation โ Articles (UK): " + "gr-qc updates on arXiv.org: " + "quant-ph updates on arXiv.org: "))) + +(defun jao-mail-clean-address (args) + (when-let ((address (car args))) + (list (thread-last (replace-regexp-in-string jao-mail-clean-rx "" address) + (replace-regexp-in-string " " ", "))))) + +(use-package notmuch-show + :init + (setq gnus-blocked-images "." + notmuch-message-headers + '("Subject" "To" "Cc" "Date" "Reply-To" "List-Id" "X-RSS-Feed") + notmuch-show-only-matching-messages t + notmuch-show-part-button-default-action 'notmuch-show-view-part + notmuch-wash-signature-lines-max 0 + notmuch-wash-wrap-lines-length 120 + notmuch-wash-citation-lines-prefix 120 + notmuch-wash-citation-lines-suffix 120 + notmuch-show-text/html-blocked-images "." + notmuch-show-header-line nil ;; #'jao-notmuch-message-header-line + jao-notmuch-header-line-format "[%N / %M / %T] %n / %m / %t") + + :config + + (advice-add 'notmuch-clean-address :filter-args #'jao-mail-clean-address) + (add-hook 'notmuch-show-mode-hook (lambda () (setq fill-column 80))) + + :bind + (:map notmuch-show-mode-map + (("h" . jao-notmuch-goto-tree-buffer) + ("r" . notmuch-show-reply) + ("R" . notmuch-show-reply-sender) + ("TAB" . jao-notmuch-show-next-button) + ([backtab] . jao-notmuch-show-previous-button) + ("RET" . jao-notmuch-show-ret)))) + +;;; search +(use-package notmuch-search + :init (setq notmuch-search-result-format + '(("date" . "%12s ") + ("count" . "%-7s ") + ("authors" . "%-35s") + ("subject" . " %-100s") + (jao-notmuch-format-tags . " (%s)")) + notmuch-search-buffer-name-format "*%s*" + notmuch-saved-search-buffer-name-format "*%s*") + :bind (:map notmuch-search-mode-map + (("RET" . notmuch-tree-from-search-thread) + ("M-RET" . notmuch-search-show-thread)))) + +;;; tree +(defun jao-notmuch-tree--forward (&optional prev) + (interactive) + (forward-line (if prev -1 1)) + (when prev (forward-char 2)) + (jao-notmuch-tree-scroll-or-next)) + +(defun jao-notmuch-tree--backward () + (interactive) + (jao-notmuch-tree--forward t)) + +(defun jao-notmuch--via-url () + (when (window-live-p notmuch-tree-message-window) + (with-selected-window notmuch-tree-message-window + (goto-char (point-min)) + (when (re-search-forward "^Via: http" nil t) + (thing-at-point-url-at-point))))) + +(defun jao-notmuch-browse-url (ext) + (interactive "P") + (when-let (url (or (jao-notmuch--via-url) + (car (last (jao-notmuch-message-urls))))) + (funcall (if ext browse-url-secondary-browser-function #'browse-url) + url))) + +(defun jao-notmuch-adjust-tree-fonts (&optional family) + (let ((fg (face-attribute 'jao-themes-dimm :foreground))) + (dolist (f '(notmuch-tree-match-tree-face + notmuch-tree-no-match-tree-face)) + (if family + (set-face-attribute f nil :family family :foreground fg) + (set-face-attribute f nil :foreground fg))))) + +(use-package notmuch-tree + :init + (setq notmuch-tree-result-format + `(("date" . "%12s ") + ("authors" . "%-25s") + ;; (jao-notmuch-format-author . 25) + (jao-notmuch-format-msg-ticks . ,jao-mails-regexp) + (jao-notmuch-format-tree-and-subject . "%>-85s") + (jao-notmuch-format-tags . " (%s)")) + notmuch-unthreaded-result-format notmuch-search-result-format + consult-notmuch-result-format + `((jao-notmuch-format-msg-ticks . ,jao-mails-regexp) + ("date" . "%12s ") + ("authors" . "%-35s") + ("subject" . " %-100s") + (jao-notmuch-format-tags . " (%s)")) + notmuch-tree-thread-symbols + '((prefix . "โ") (top . "โ") (top-tee . "โฌ") + (vertical . "โ") (vertical-tee . "โ") (bottom . "โฐ") + (arrow . "")) + ;; notmuch-tree-thread-symbols + ;; '((prefix . " ") (top . " ") (top-tee . " ") + ;; (vertical . " ") (vertical-tee . " ") (bottom . " ") + ;; (arrow . "")) + notmuch-tree-outline-enabled t + notmuch-tree-outline-visibility 'hide-others + notmuch-tree-outline-auto-close t + notmuch-tree-outline-open-on-next t) + :config + + (when (display-graphic-p) + (jao-notmuch-adjust-tree-fonts + (when (string-prefix-p "Hack" jao-themes-default-face) "Source Code Pro"))) + + (defun jao-notmuch-before-tree (&rest _args) + (when (string= (buffer-name) "*notmuch-hello*") + (window-configuration-to-register ?G) + (split-window-right 40) + (other-window 1))) + + (defvar jao-notmuch--visits 0) + + (defun jao-notmuch-after-tree-quit (&optional _both) + (when (not (derived-mode-p 'notmuch-tree-mode 'notmuch-hello-mode)) + (jump-to-register ?G)) + (jao-notmuch-refresh-hello (= 0 (mod (cl-incf jao-notmuch--visits) 50)))) + + (defun jao-notmuch-tree--sentinel (proc) + (when (eq (process-status proc) 'exit) + (let ((inhibit-read-only t)) + (save-excursion + (goto-char (point-max)) + (when (re-search-backward "^End of search results." nil t) + (delete-line)))) + (jao-notmuch-thread-info-mode))) + + (add-hook 'notmuch-tree-process-exit-functions #'jao-notmuch-tree--sentinel) + + (advice-add 'notmuch-tree :before #'jao-notmuch-before-tree) + (advice-add 'notmuch-tree-quit :after #'jao-notmuch-after-tree-quit) + + :bind (:map notmuch-tree-mode-map + (("b" . jao-notmuch-browse-urls) + ("d" . jao-notmuch-tree-toggle-delete) + ("D" . jao-notmuch-tree-toggle-delete-thread) + ("h" . jao-notmuch-goto-message-buffer) + ("i" . jao-notmuch-toggle-images) + ("k" . jao-notmuch-tree-read-thread) + ("N" . jao-notmuch-tree--forward) + ("O" . notmuch-tree-toggle-order) + ("o" . jao-notmuch-tree-widen-search) + ("P" . jao-notmuch-tree--backward) + ("r" . notmuch-tree-reply) + ("R" . notmuch-tree-reply-sender) + ("s" . jao-notmuch-tree-toggle-spam) + ("u" . jao-notmuch-tree-toggle-flag) + ("v" . notmuch-tree-scroll-message-window) + ("V" . notmuch-tree-scroll-message-window-back) + ("x" . jao-notmuch-arXiv-capture) + ("<" . jao-notmuch-tree-beginning-of-buffer) + (">" . jao-notmuch-tree-end-of-buffer) + ("\\" . notmuch-tree-view-raw-message) + ("." . jao-notmuch-toggle-mime-parts) + (";" . bbdb-mua-display-sender) + ("=" . jao-notmuch-tree-toggle-message) + ("RET" . jao-notmuch-tree-show-or-scroll) + ("SPC" . jao-notmuch-tree-scroll-or-next) + ("M-g" . jao-notmuch-browse-url) + ("M-u" . jao-notmuch-tree-reset-tags)))) + +;;; browse-url +(defvar jao-notmuch-url-rx "^notmuch:\\(/+\\|id:\\)\\(.+\\)") + +(defun jao-notmuch-open-url (url &rest _) + (and (string-match jao-notmuch-url-rx url) + (notmuch-show (concat "id:" (match-string 2 url))))) + +(add-to-list 'browse-url-handlers + (cons jao-notmuch-url-rx 'jao-notmuch-open-url)) + +;;; org mode +(defvar jao-org-notmuch-last-subject nil) +(defun jao-org-notmuch-last-subject () jao-org-notmuch-last-subject) + +(defun jao-notmuch--add-tags (tags) + (if (derived-mode-p 'notmuch-show-mode) + (notmuch-show-add-tag tags) + (notmuch-tree-add-tag tags))) + +(defun org-notmuch-store-link () + "Store a link to a notmuch mail message." + (cl-case major-mode + ((notmuch-show-mode notmuch-tree-mode) + ;; Store link to the current message + (let* ((id (notmuch-show-get-message-id)) + (link (concat "notmuch:" id)) + (subj (notmuch-show-get-subject)) + (description (format "Mail: %s" subj))) + (setq jao-org-notmuch-last-subject subj) + (when (y-or-n-p "Archive message? ") + (jao-notmuch--add-tags '("+trove"))) + (when (y-or-n-p "Flag message? ") + (jao-notmuch--add-tags '("+flagged"))) + (org-link-store-props :type "notmuch" + :link link + :description description))) + (notmuch-search-mode + ;; Store link to the thread on the current line + (let* ((id (notmuch-search-find-thread-id)) + (link (concat "notmuch:" id)) + (subj (notmuch-search-find-subject)) + (description (format "Mail: %s" subj))) + (setq jao-org-notmuch-last-subject subj) + (org-link-store-props + :type "notmuch" + :link link + :description description))))) + +(with-eval-after-load "org" + (org-link-set-parameters "notmuch" + :follow 'notmuch-show + :store 'org-notmuch-store-link)) +;;; arXiv +(use-package org-capture + :config + (add-to-list 'org-capture-templates + '("X" "arXiv" entry (file "notes/physics/arxiv.org") + "* %(jao-org-notmuch-last-subject)\n %i" + :immediate-finish t) + t) + (org-capture-upgrade-templates org-capture-templates)) + +(defun jao-notmuch-arXiv-capture () + (interactive) + (save-window-excursion + (jao-notmuch-goto-message-buffer) + (save-excursion + (goto-char (point-min)) + (re-search-forward "\\[ text/html \\]") + (forward-paragraph) + (setq-local transient-mark-mode 'lambda) + (set-mark (point)) + (goto-char (point-max)) + (org-capture nil "X")))) + +;;; html renderer +(when jao-notmuch-enabled (setq mm-text-html-renderer 'shr)) + +;;; consult +(jao-load-path "consult-notmuch") +(require 'consult-notmuch) +(setq consult-notmuch-newest-first t) +(consult-customize consult-notmuch :preview-key 'any) + +(defvar jao-consult-notmuch-history nil) + +(defvar jao-mailbox-folders '("bigml" "jao")) + +(defun jao-consult-notmuch-folder (&optional tree folder) + (interactive "P") + (let* ((folder (if folder + (file-name-as-directory folder) + (completing-read "Group: " + jao-mailbox-folders + nil nil nil + jao-consult-notmuch-history + "."))) + (folder (replace-regexp-in-string "/\\(.\\)" ".\\1" folder)) + (init (read-string "Initial query: ")) + (init (format "folder:/%s/ %s" folder init))) + (if tree (consult-notmuch-tree init) (consult-notmuch init)))) + +(with-eval-after-load "notmuch-hello" + (define-key notmuch-hello-mode-map "f" #'jao-consult-notmuch-folder)) +;;; recoll +(defun jao-notmuch-open-file (fname &optional _page) + (with-temp-buffer + (insert-file-contents-literally fname) + (goto-char (point-min)) + (and (re-search-forward "^Message-ID: <\\([^>]+\\)>$" nil t) + (notmuch-show (concat "id:" (match-string 1)))))) + +(when jao-notmuch-enabled + (with-eval-after-load "org" + (org-link-set-parameters "message" :follow #'jao-notmuch-open-file)) + + (with-eval-after-load "consult-recoll" + (add-to-list 'consult-recoll-open-fns + '("message/rfc822" . jao-notmuch-open-file)))) + +;;; . +(provide 'jao-custom-notmuch) |