;; -*- 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 (when jao-notmuch-enabled (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)