123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786 |
- ;; gnus configuration -*- lexical-binding: t -*-
- ;;; features
- (defvar jao-gnus-use-local-imap nil)
- (defvar jao-gnus-use-leafnode nil)
- (defvar jao-gnus-use-gandi-imap nil)
- (defvar jao-gnus-use-pm-imap nil)
- (defvar jao-gnus-use-gmane nil)
- (defvar jao-gnus-use-nnml nil)
- (defvar jao-gnus-use-maildirs nil)
- (defvar jao-notmuch-enabled nil)
- (defvar jao-gnus-nnml-group-params nil)
- ;;; directories
- (defun jao-gnus-dir (dir)
- (expand-file-name dir gnus-home-directory))
- (setq smtpmail-queue-dir (jao-gnus-dir "Mail/queued-mail/"))
- (setq mail-source-directory (jao-gnus-dir "Mail/")
- message-directory (jao-gnus-dir "Mail/"))
- (setq gnus-default-directory (expand-file-name "~")
- gnus-startup-file (jao-gnus-dir "newsrc")
- gnus-agent-directory (jao-gnus-dir "News/agent")
- gnus-home-score-file (jao-gnus-dir "scores")
- gnus-article-save-directory (jao-gnus-dir "saved/")
- nntp-authinfo-file (jao-gnus-dir "authinfo")
- nnmail-message-id-cache-file (jao-gnus-dir "nnmail-cache")
- nndraft-directory (jao-gnus-dir "drafts")
- nnrss-directory (jao-gnus-dir "rss"))
- ;;; looks
- ;;;; verbosity
- (setq gnus-verbose 4)
- ;;;; geometry
- (defvar jao-gnus-use-three-panes t)
- (defvar jao-gnus-groups-width 50)
- (defvar jao-gnus-wide-width 190)
- (setq gnus-use-trees nil
- gnus-generate-tree-function 'gnus-generate-horizontal-tree
- gnus-tree-minimize-window nil)
- (when jao-gnus-use-three-panes
- ;; (dolist (m '(calendar-mode org-agenda-mode gnus-group-mode))
- ;; (add-to-list 'display-buffer-alist `((major-mode . ,m) (dedicated t))))
- (setq calendar-left-margin 6)
- (let ((side-bar '(vertical 1.0
- ("inbox.org" 0.4)
- ("*Org Agenda*" 1.0)
- ("*Calendar*" 8)))
- (wide-len jao-gnus-wide-width)
- (groups-len jao-gnus-groups-width)
- (summary-len (- jao-gnus-wide-width jao-gnus-groups-width)))
- (gnus-add-configuration
- `(article
- (horizontal 1.0
- (vertical ,groups-len (group 1.0))
- (vertical ,summary-len
- (summary 0.25 point)
- (article 1.0))
- ,side-bar)))
- (gnus-add-configuration
- `(group (horizontal 1.0 (group ,wide-len point) ,side-bar)))
- (gnus-add-configuration
- `(message (horizontal 1.0 (message ,wide-len point) ,side-bar)))
- (gnus-add-configuration
- `(reply-yank (horizontal 1.0 (message ,wide-len point) ,side-bar)))
- (gnus-add-configuration
- `(summary
- (horizontal 1.0
- (vertical ,groups-len (group 1.0))
- (vertical ,summary-len (summary 1.0 point))
- ,side-bar)))
- (gnus-add-configuration
- `(reply
- (horizontal 1.0
- (message ,(- wide-len 100) point)
- (article 100)
- ,side-bar)))))
- ;;;; no blue icon
- (advice-add 'gnus-mode-line-buffer-identification :override #'identity)
- (setq gnus-mode-line-image-cache nil)
- ;;; search
- (setq gnus-search-use-parsed-queries nil
- gnus-search-notmuch-raw-queries-p nil
- gnus-permanently-visible-groups "^nnselect:.*"
- gnus-search-ignored-newsgroups "nndraft.*\\|nnselect.*")
- (with-eval-after-load "gnus-search"
- (defclass gnus-search-recoll (gnus-search-indexed)
- ((separator :type string :initform ".")
- (program :initform "recoll")
- (raw-queries-p :initform t)))
- (cl-defmethod gnus-search-indexed-extract ((_engine gnus-search-recoll))
- (prog1 (and (looking-at "^file://\\(.+\\)$") (list (match-string 1) 100))
- (forward-line 1)))
- (cl-defmethod gnus-search-transform-expression ((_engine gnus-search-recoll)
- expr)
- expr)
- (cl-defmethod gnus-search-indexed-search-command ((engine gnus-search-recoll)
- (qstring string)
- query
- &optional groups)
- (let* ((subdir (slot-value engine 'remove-prefix))
- (sep (slot-value engine 'separator))
- (gdirs (mapcar (lambda (g)
- (let ((g (gnus-group-short-name g)))
- (replace-regexp-in-string "\\." sep g)))
- (or groups
- (and (not (string= "" subdir)) (list subdir)))))
- (dirsq (and gdirs
- (concat "("
- (mapconcat (lambda (d) (format "dir:%s" d))
- gdirs " OR ")
- ")")))
- (qstring (if (string-prefix-p "id:" qstring)
- (replace-regexp-in-string "<\\|>" "\"" qstring)
- qstring))
- (qstring (if (cdr (assoc 'thread query))
- (concat qstring " OR "
- (replace-regexp-in-string "id:\"" "ref:\""
- qstring))
- qstring))
- (qstring (replace-regexp-in-string " or " " OR " qstring))
- (qstring (replace-regexp-in-string " and " " AND " qstring))
- (q (format "mime:message %s (%s)" dirsq qstring)))
- ;; (message "query is: %s -- %S" q query)
- `("-b" "-t" "-q" ,q))))
- ;; (add-to-list 'gnus-parameters '("^nnselect:.*" (nnselect-rescan . t)))
- ;;; news
- (defvar jao-gnus-leafnode-spool "/var/spool/news/")
- (setq gnus-select-method
- (cond
- (jao-gnus-use-leafnode
- `(nntp "localhost"
- (gnus-search-engine gnus-search-recoll
- (remove-prefix ,jao-gnus-leafnode-spool)
- (separator "/"))))
- (jao-gnus-use-gmane '(nntp "news.gmane.io"))
- (t '(nnnil ""))))
- (setq gnus-secondary-select-methods '())
- (setq nnheader-read-timeout 0.02
- gnus-save-newsrc-file nil) ; .newsrc only needed by other newsreaders
- ;; leafnode articles group parameters
- (defvar jao-gnus-image-groups '("xkcd"))
- (defvar jao-gnus-leafnode-group-params
- `((,(format "gwene\\..*%s.*" (regexp-opt jao-gnus-image-groups))
- (mm-html-inhibit-images nil)
- (mm-html-blocked-images nil))
- ("\\(gmane\\|gwene\\)\\..*"
- (jao-gnus--archiving-group "nnml:feeds.trove")
- (posting-style (address "jao@gnu.org")))))
- (when jao-gnus-use-leafnode
- (dolist (p jao-gnus-leafnode-group-params)
- (add-to-list 'gnus-parameters p t)))
- ;;; mail
- ;;;; nnmail
- (setq nnmail-treat-duplicates 'delete
- nnmail-scan-directory-mail-source-once nil
- nnmail-cache-accepted-message-ids t
- nnmail-message-id-cache-length 100000
- nnmail-split-fancy-with-parent-ignore-groups nil
- nnmail-use-long-file-names t
- nnmail-crosspost t
- nnmail-resplit-incoming t
- nnmail-mail-splitting-decodes t
- nnmail-split-methods 'nnmail-split-fancy)
- ;;;; nnml
- (setq gnus-message-archive-group nil
- nnml-get-new-mail t
- nnml-directory message-directory)
- (setq mail-sources
- (let* ((pwd (auth-source-pick-first-password :host "proton-bridge"))
- (mds (mapcar (lambda (f)
- `(maildir :path ,(expand-file-name f "~/var/mail/")))
- '("local/" "feeds/")))
- (ims (mapcar (lambda (b)
- `(imap :server "127.0.0.1" :port 1143
- :user "mail@jao.io" :password ,pwd
- :stream starttls :predicate "1:*"
- :fetchflag "\\Deleted \\Seen"
- :mailbox ,(concat "Labels/#" b)))
- '("inbox" "drivel" "hacking" "bills"
- "bigml" "prog" "words"))))
- (append mds ims)))
- (when jao-gnus-use-nnml
- (add-to-list
- 'gnus-secondary-select-methods
- `(nnml "" (gnus-search-engine gnus-search-recoll
- (remove-prefix ,(jao-gnus-dir "Mail/"))))))
- (when jao-gnus-use-nnml
- (dolist (p jao-gnus-nnml-group-params)
- (add-to-list 'gnus-parameters p t)))
- ;;;; imap
- (setq nnimap-quirks nil)
- (when jao-gnus-use-local-imap
- (add-to-list 'gnus-secondary-select-methods
- `(nnimap "" (nnimap-address "localhost"))))
- (when jao-gnus-use-pm-imap
- (add-to-list 'gnus-secondary-select-methods
- '(nnimap "pm"
- (nnimap-address "127.0.0.1")
- (nnimap-stream network)
- (nnimap-server-port 1143))))
- (when jao-gnus-use-gandi-imap
- (add-to-list 'gnus-secondary-select-methods
- '(nnimap "gandi" (nnimap-address "mail.gandi.net"))))
- ;;; groups
- (setq gnus-group-line-format
- " %m%S%p%3y%P%* %~(pad-right 30)G %B\n"
- ;; " %m%S%p%P:%~(pad-right 35)c %3y %B\n"
- ;; " %m%S%p%3y%P%* %~(pad-right 30)C %B\n"
- gnus-topic-line-format "%i[ %(%{%n%}%) -- %A ]%v\n"
- gnus-group-uncollapsed-levels 2
- gnus-auto-select-subject 'unread
- gnus-large-newsgroup 2000)
- (add-hook 'gnus-select-group-hook 'gnus-group-set-timestamp)
- (add-hook 'gnus-group-mode-hook 'gnus-topic-mode)
- ;;; rss
- (setq nnrss-use-local t ;; M-x nnrss-generate-download-script
- nnrss-ignore-article-fields '(category
- dc:creator
- dc:date
- enclosure
- guid
- link
- media:content
- media:thumbnail
- media:title
- post-id
- pubDate
- slash:comments))
- (add-to-list 'gnus-parameters `(,(format "nnrss:%s.*"
- (regexp-opt jao-gnus-image-groups t))
- (mm-html-inhibit-images nil)
- (mm-html-blocked-images nil)))
- ;;; summary
- ;;;; configuration
- (setq gnus-summary-ignore-duplicates t
- gnus-suppress-duplicates t
- ;; gnus-summary-ignored-from-addresses jao-mails-regexp
- gnus-process-mark-toggle t
- gnus-auto-select-next 'almost-quietly)
- ;;;; threading
- (setq gnus-face-1 'jao-gnus-face-tree
- gnus-show-threads t
- gnus-thread-hide-subtree t
- gnus-build-sparse-threads nil
- gnus-refer-thread-use-search t
- gnus-summary-make-false-root 'adopt
- gnus-summary-gather-subject-limit nil ;; 120
- gnus-summary-thread-gathering-function #'gnus-gather-threads-by-subject
- gnus-sort-gathered-threads-function 'gnus-thread-sort-by-date
- gnus-thread-sort-functions '(gnus-thread-sort-by-date))
- (defun jao-fix-protonmail-references (header)
- (let ((references (mail-header-references header)))
- (setf (mail-header-references header)
- (mapconcat #'(lambda (x)
- (if (string-match "protonmail.internalid" x) "" x))
- (gnus-split-references references)
- " "))
- header))
- (setq gnus-alter-header-function 'jao-fix-protonmail-references)
- ;;;; search on enter nnselect
- (defun jao-gnus--maybe-reselect (&rest _i)
- (when (string-match-p "^nnselect" (or (gnus-group-name-at-point) ""))
- (save-excursion (gnus-group-get-new-news-this-group))))
- (advice-add 'gnus-group-select-group :before #'jao-gnus--maybe-reselect)
- ;;;; summary line
- (setq gnus-not-empty-thread-mark ?↓) ; ↓) ?·
- (setq jao-gnus--summary-line-fmt
- (concat "%%U %%*%%R %%uj "
- "[ %%~(max-right 23)~(pad-right 23)uf "
- " %%I%%~(pad-left 2)t ] %%s"
- "%%-%s="
- "%%~(max-right 8)~(pad-left 8)&user-date;"
- "\n"))
- (defun jao-gnus--set-summary-line (&optional w)
- (let* ((d (if jao-gnus-use-three-panes (+ jao-gnus-groups-width 11) 12))
- (w (- (or w (window-width)) d)))
- (setq gnus-summary-line-format (format jao-gnus--summary-line-fmt w))))
- (add-hook 'gnus-select-group-hook 'jao-gnus--set-summary-line)
- ;; (jao-gnus--set-summary-line 187)
- (add-to-list 'nnmail-extra-headers 'Cc)
- (add-to-list 'nnmail-extra-headers 'BCc)
- (use-package gnus-sum
- :config
- (add-to-list 'gnus-extra-headers 'Cc)
- (add-to-list 'gnus-extra-headers 'BCc))
- (defun gnus-user-format-function-j (headers)
- (let ((to (gnus-extra-header 'To headers)))
- (if (string-match jao-mails-regexp to)
- (if (string-match "," to) "¬" "»") ;; "~" "=")
- (if (or (string-match jao-mails-regexp
- (gnus-extra-header 'Cc headers))
- (string-match jao-mails-regexp
- (gnus-extra-header 'BCc headers)))
- "¬" ;; "~"
- " "))))
- (defconst jao-gnus--news-rx
- (concat (regexp-opt '("ElDiaro.es "
- "ElDiario.es - ElDiario.es: "
- "The Guardian: "
- "Aeon | a world of ideas: "
- "Planet Debian: "))
- "\\|The Conversation – Articles (.+): "
- "\\|unofficial mirror of [^:]+: "
- "\\|[gq].+ updates on arXiv.org: "))
- (defun gnus-user-format-function-f (headers)
- (let* ((from (gnus-header-from headers))
- (from (gnus-summary-extract-address-component from))
- (from (replace-regexp-in-string jao-gnus--news-rx "" from)))
- from))
- (setq gnus-user-date-format-alist
- '(((gnus-seconds-today) . "%H:%M")
- ((+ 86400 (gnus-seconds-today)) . "'%H:%M")
- ;; (604800 . "%a %H:%M") ;; that's one week
- ((gnus-seconds-month) . "%a %d")
- ((gnus-seconds-year) . "%b %d")
- (t . "%b '%y")))
- ;;;; moving messages around
- (defvar-local jao-gnus--spam-group nil)
- (defvar-local jao-gnus--archiving-group nil)
- (defvar-local jao-gnus--archive-as-copy-p nil)
- (defvar jao-gnus--last-move nil)
- (defun jao-gnus-move-hook (a headers c to d)
- (setq jao-gnus--last-move (cons to (mail-header-id headers))))
- (defun jao-gnus-goto-last-moved ()
- (interactive)
- (when jao-gnus--last-move
- (when (eq major-mode 'gnus-summary-mode) (gnus-summary-exit))
- (gnus-group-goto-group (car jao-gnus--last-move))
- (gnus-group-select-group)
- (gnus-summary-goto-article (cdr jao-gnus--last-move) nil t)))
- (add-hook 'gnus-summary-article-move-hook 'jao-gnus-move-hook)
- (defun jao-gnus-archive (follow)
- (interactive "P")
- (if jao-gnus--archiving-group
- (progn
- (if (or jao-gnus--archive-as-copy-p
- (not (gnus-check-backend-function
- 'request-move-article gnus-newsgroup-name)))
- (gnus-summary-copy-article nil jao-gnus--archiving-group)
- (gnus-summary-move-article nil jao-gnus--archiving-group))
- (when follow (jao-gnus-goto-last-moved)))
- (gnus-summary-mark-as-read)
- (gnus-summary-delete-article)))
- (defun jao-gnus-archive-tickingly ()
- (interactive)
- (gnus-summary-tick-article)
- (jao-gnus-archive)
- (when jao-gnus--archive-as-copy-p
- (gnus-summary-mark-as-read)))
- (defun jao-gnus-show-tickled ()
- (interactive)
- (gnus-summary-limit-to-marks "!"))
- (make-variable-buffer-local
- (defvar jao-gnus--trash-group nil))
- (defun jao-gnus-trash ()
- (interactive)
- (gnus-summary-mark-as-read)
- (if jao-gnus--trash-group
- (gnus-summary-move-article nil jao-gnus--trash-group)
- (gnus-summary-delete-article)))
- (defun jao-gnus-move-to-spam ()
- (interactive)
- (gnus-summary-mark-as-read)
- (gnus-summary-move-article nil jao-gnus--spam-group))
- (define-key gnus-summary-mode-map "Ba" 'jao-gnus-archive)
- (define-key gnus-summary-mode-map "BA" 'jao-gnus-archive-tickingly)
- (define-key gnus-summary-mode-map "Bl" 'jao-gnus-goto-last-moved)
- (define-key gnus-summary-mode-map (kbd "B DEL") 'jao-gnus-trash)
- (define-key gnus-summary-mode-map (kbd "B <backspace>") 'jao-gnus-trash)
- (define-key gnus-summary-mode-map "Bs" 'jao-gnus-move-to-spam)
- (define-key gnus-summary-mode-map "/!" 'jao-gnus-show-tickled)
- (define-key gnus-summary-mode-map [f7] 'gnus-summary-force-verify-and-decrypt)
- ;;;; saving emails
- (setq gnus-default-article-saver 'gnus-summary-save-article-mail)
- (defvar jao-gnus-file-save-directory (expand-file-name "~/tmp"))
- (defun jao-gnus-file-save (newsgroup headers &optional last-file)
- (expand-file-name (format "%s.eml" (mail-header-subject headers))
- jao-gnus-file-save-directory))
- (setq gnus-mail-save-name 'jao-gnus-file-save)
- ;;;; arXiv capture
- (use-package org-capture
- :config
- (add-to-list 'org-capture-templates
- '("X" "arXiv" entry (file "notes/physics/arxiv.org")
- "* %:subject\n\n(jao-gnus-org-paragraph \"%i\")"
- :immediate-finish t)
- t)
- (org-capture-upgrade-templates org-capture-templates))
- (defvar jao-gnus-org-url nil)
- (defun jao-gnus-org-paragraph (x)
- (with-temp-buffer
- (insert " " (string-trim (or x "")) "\n ")
- (goto-char 0)
- (fill-paragraph)
- (goto-char (point-max))
- (open-rectangle 0 (point))
- (concat (buffer-string) "\n " (or jao-gnus-org-url ""))))
- (defun jao-gnus-arXiv-capture ()
- (interactive)
- (unless (derived-mode-p '(gnus-summary-mode)) (gnus-article-show-summary))
- (setq jao-subject (gnus-summary-article-subject))
- (gnus-summary-select-article-buffer)
- (gnus-article-goto-part 0)
- (setq-local transient-mark-mode 'lambda)
- (set-mark (point))
- (forward-paragraph)
- (save-excursion
- (when (re-search-forward "^Link" nil t)
- (beginning-of-line)
- (setq jao-gnus-org-url (org-eww-url-below-point))))
- (org-capture nil "X")
- (set-mark (point))
- (gnus-article-show-summary))
- ;;; article
- ;;;; config, headers
- (setq mail-source-delete-incoming t)
- (setq gnus-gcc-mark-as-read t)
- (setq gnus-treat-display-smileys nil)
- (setq gnus-treat-fill-long-lines nil)
- (setq gnus-treat-fill-article 120)
- (setq gnus-treat-fold-headers nil)
- (setq gnus-treat-strip-leading-blank-lines t)
- (setq gnus-article-auto-eval-lisp-snippets nil)
- (setq gnus-posting-styles '((".*" (name "Jose A. Ortega Ruiz"))))
- (setq gnus-single-article-buffer nil)
- (setq gnus-article-update-lapsed-header 60)
- (setq gnus-article-update-date-headers 60)
- (with-eval-after-load "gnus-art"
- (setq gnus-visible-headers
- (concat
- gnus-visible-headers
- "\\|^List-[iI][Dd]:\\|^X-Newsreader:\\|^X-Mailer:"
- "\\|^User-Agent:\\|^X-User-Agent:\\|^X-RSS-Feed:")))
- ;;;; html and images
- (setq gnus-button-url 'browse-url-generic
- gnus-inhibit-images t
- mm-discouraged-alternatives nil ;; '("text/html" "text/richtext")
- mm-inline-large-images 'resize)
- (defvar-local jao-gnus--images nil)
- (defun jao-gnus--init-images ()
- (with-current-buffer gnus-article-buffer
- (setq jao-gnus--images nil)))
- (add-hook 'gnus-select-article-hook #'jao-gnus--init-images)
- (defun jao-gnus-browse-html ()
- (interactive)
- (let ((browse-url-browser-function jao-browse-url-external-function)
- (browse-url-handlers nil)
- (browse-url-default-handlers nil))
- (gnus-article-browse-html-article)))
- (defun jao-gnus-show-images ()
- (interactive)
- (if window-system
- (save-window-excursion
- (gnus-summary-select-article-buffer)
- (save-excursion
- (if (and jao-afio-use-w3m (fboundp 'w3m-toggle-inline-images))
- (w3m-toggle-inline-images)
- (setq jao-gnus--images (not jao-gnus--images))
- (if jao-gnus--images
- (gnus-article-show-images)
- (gnus-article-remove-images)))))
- (jao-gnus-browse-html)))
- ;;;; format from:
- (defvar jao-gnus--from-rx
- (concat "From: \\\"?\\( *" jao-gnus--news-rx "\\)"))
- (defun jao-gnus-format-from ()
- (save-excursion
- (goto-char (point-min))
- (when (re-search-forward jao-gnus--from-rx nil t)
- (replace-match "" nil nil nil 1))))
- (add-hook 'gnus-part-display-hook 'jao-gnus-format-from)
- ;;;; follow links and enclosures
- (defun jao-gnus-follow-link (&optional external)
- (interactive "P")
- (when (eq major-mode 'gnus-summary-mode)
- (gnus-summary-select-article-buffer))
- (save-excursion
- (goto-char (point-min))
- (when (or (search-forward-regexp "^Via: h" nil t)
- (search-forward-regexp "^URL: h" nil t)
- (and (search-forward-regexp "^Link$" nil t)
- (not (beginning-of-line))))
- (cond (external (jao-browse-with-external-browser))
- ((featurep 'jao-custom-eww) (eww (jao-url-around-point)))
- (t (browse-url (jao-url-around-point)))))))
- (defun jao-gnus-from-eww (keep-eww-buffer)
- (interactive "P")
- (unless keep-eww-buffer (jao-eww-close))
- (jao-afio-goto-mail)
- (gnus-article-show-summary))
- (with-eval-after-load 'eww
- (define-key eww-mode-map (kbd "h") #'jao-gnus-from-eww))
- (defun jao-gnus-open-enclosure ()
- (interactive)
- (save-window-excursion
- (gnus-summary-select-article-buffer)
- (save-excursion
- (goto-char (point-min))
- (let ((offset (or (and (search-forward-regexp "^Enclosure: " nil t) 2)
- (and (search-forward-regexp "^Enclosure$" nil t) -2))))
- (when offset (forward-char offset))
- (if-let ((url (jao-url-around-point)))
- (jao-mpc-add-or-play-url url)
- (error "No enclosure found"))))))
- ;;;; delayed messages
- (require 'gnus-util)
- (gnus-delay-initialize)
- (setq gnus-delay-default-delay "3h")
- (eval-after-load "message"
- '(setq message-draft-headers (remove 'Date message-draft-headers)))
- ;;; daemon and exit
- (setq gnus-interactive-exit t)
- (defun jao-quit-gnus () (gnus-group-exit) t)
- (add-hook 'kill-emacs-query-functions #'jao-quit-gnus)
- ;; daemon config
- (setq mail-user-agent 'gnus-user-agent)
- (setq gnus-asynchronous t)
- (setq gnus-use-article-prefetch nil)
- (setq gnus-save-killed-list nil)
- (setq gnus-check-new-newsgroups nil)
- (require 'gnus-demon)
- (defun jao-gnus--scan ()
- (let ((inhibit-message t))
- (gnus-demon-scan-news)
- (jao-gnus--notify)))
- (defun jao-gnus-add-demon ()
- (interactive)
- (gnus-demon-add-handler 'jao-gnus--scan 5 1))
- (jao-gnus-add-demon)
- (gnus-demon-init)
- ;; this is, in theory, not needed; but at some point in the way to emacs
- ;; version 31 this idle timers have ceased to work after a sleep/awake cycle
- (add-to-list 'jao-sleep-awake-functions #'jao-gnus-add-demon)
- ;;; add-ons
- ;;;; notifications
- ;;;;; minibuffer
- (defvar jao-gnus-tracked-groups
- (let ((feeds (thread-first
- (directory-files mail-source-directory nil "feeds\\.[^e]")
- (seq-difference '("feeds.trove")))))
- `(("nnml:bigml\\.inbox" "B" jao-themes-f00)
- ("nnml:bigml\\.alba" "A" jao-themes-f00)
- ("nnml:bigml\\.bugs" "b" jao-themes-error)
- ("nnml:bigml\\.support" "S" default)
- ("nnml:jao\\.\\(inbox\\|trove\\)" "I" jao-themes-f01)
- ("nnml:bigml\\.[^aibs]" "W" jao-themes-dimm)
- ("nnml:jao.hacking" "H" jao-themes-dimm)
- ("nnml:jao.write" "W" jao-themes-warning)
- ("nnml:jao.[^isthw]" "J" jao-themes-dimm)
- (,(format "^nnml:%s" (regexp-opt feeds)) "F" jao-themes-dimm)
- ("feeds\\.e" "E" jao-themes-dimm)
- ("nnml:local" "l" jao-themes-dimm)
- ("nnrss:.*" "R" jao-themes-dimm)
- ("^\\(gwene\\|gmane\\)\\." "N" jao-themes-dimm))))
- (defun jao-gnus--unread-counts ()
- (seq-reduce (lambda (r g)
- (let ((n (gnus-group-unread (car g))))
- (if (and (numberp n) (> n 0)) (cons (cons (car g) n) r) r)))
- gnus-newsrc-alist
- ()))
- (defun jao-gnus--unread-label (counts rx label face)
- (let ((n (seq-reduce (lambda (n c)
- (if (string-match-p rx (car c)) (+ n (cdr c)) n))
- counts
- 0)))
- (when (> n 0) `(:propertize ,(format "%s%d " label n) face ,face))))
- (defvar jao-gnus--notify-strs ())
- (defun jao-gnus--notify-strs ()
- (let ((counts (jao-gnus--unread-counts)))
- (seq-filter #'identity
- (seq-map (lambda (args)
- (apply 'jao-gnus--unread-label counts args))
- jao-gnus-tracked-groups))))
- (defun jao-gnus--notify ()
- (setq jao-gnus--notify-strs (jao-gnus--notify-strs))
- (jao-minibuffer-refresh))
- (with-eval-after-load "jao-minibuffer"
- (jao-minibuffer-add-variable 'jao-gnus--notify-strs -20))
- (add-hook 'gnus-started-hook #'jao-gnus--notify)
- ;; (add-hook 'gnus-summary-exit-hook #'jao-gnus--notify)
- (add-hook 'gnus-after-getting-new-news-hook #'jao-gnus--notify)
- ;;;;; agenda and other updates on summary exit
- (let ((exit-count 0))
- (defun jao-gnus--on-summary-exit ()
- (when (> (setq exit-count (+ 1 exit-count)) 20)
- (setq exit-count 0)
- (jao-org-agenda))
- (jao-gnus--notify)))
- (add-hook 'gnus-summary-exit-hook #'jao-gnus--on-summary-exit)
- ;;;; open mail file in gnus
- (defun jao-gnus-file-to-group (file &optional maildir newsdir m-server n-server)
- "Compute the Gnus group name from the given file name.
- IN: /home/jao/.emacs.d/gnus/Mail/jao.trove/32, /home/jao/.emacs.d/gnus/Mail/
- OUT: nnml:jao.trove "
- (let* ((maildir (or maildir message-directory))
- (newsdir (or newsdir jao-gnus-leafnode-spool))
- (m-server (or m-server "nnml"))
- (n-server (or n-server "nntp+localhost"))
- (nntp (and newsdir (string-match-p newsdir file)))
- (g (directory-file-name (file-name-directory file)))
- (g (replace-regexp-in-string (file-name-as-directory maildir) "" g))
- (g (replace-regexp-in-string (file-name-as-directory newsdir) "" g))
- (g (cond (nntp (concat n-server ":" g))
- ((file-name-directory g)
- (replace-regexp-in-string "^\\([^/]+\\)/"
- (concat m-server ":\\1/")
- (file-name-directory g) t))
- (t (concat m-server ":" g))))
- (g (replace-regexp-in-string "/" "." g))
- (g (replace-regexp-in-string "[/.]$" "" g)))
- (cond ((string-match ":$" g) (concat g "inbox"))
- (nntp g)
- (t (replace-regexp-in-string ":\\." ":" g)))))
- (defun jao-gnus-goto-file (filename &optional _page)
- (let ((group (jao-gnus-file-to-group filename))
- (id (file-name-nondirectory filename)))
- (if (and group id)
- (org-gnus-follow-link group id)
- (message "Couldn't get relevant info for switching to Gnus."))))
- ;;;; afio
- (defun jao-gnus--on-afio-switch ()
- (when (derived-mode-p 'gnus-group-mode)
- (let ((no (or (gnus-group-unread (gnus-group-group-name)) 0)))
- (unless (> no 0) (gnus-group-first-unread-group)))))
- (add-hook 'jao-afio-switch-hook #'jao-gnus--on-afio-switch)
- (defun jao-gnus-refresh-workspace ()
- (interactive)
- (save-window-excursion (calendar) (jao-org-agenda)))
- ;;;; gnus-icalendar
- (require 'ol-gnus)
- (use-package gnus-icalendar
- :demand t
- :init (setq gnus-icalendar-org-capture-file
- (expand-file-name "inbox.org" org-directory)
- gnus-icalendar-org-capture-headline '("Appointments"))
- :config (gnus-icalendar-org-setup))
- ;;;; bbdb
- (with-eval-after-load "bbdb"
- ;; (bbdb-initialize 'gnus 'message 'pgp)
- (bbdb-mua-auto-update-init 'gnus)
- (with-eval-after-load "gnus-sum"
- (define-key gnus-summary-mode-map ":" 'bbdb-mua-annotate-sender)
- (define-key gnus-summary-mode-map ";" 'bbdb-mua-annotate-recipients)))
- ;;;; randomsig
- (with-eval-after-load "randomsig"
- (with-eval-after-load "gnus-sum"
- (define-key gnus-summary-save-map "-" 'gnus/randomsig-summary-read-sig)))
- ;;;; recoll
- (unless jao-notmuch-enabled
- (with-eval-after-load "org"
- (org-link-set-parameters "message" :follow #'jao-gnus-goto-file))
- (with-eval-after-load "consult-recoll"
- (add-to-list 'consult-recoll-open-fns
- '("message/rfc822" . jao-gnus-goto-file))))
- ;;;; notmuch
- (use-package jao-notmuch-gnus
- :demand t)
- (jao-load-path "consult-notmuch")
- (use-package consult-notmuch
- :bind (:map gnus-group-mode-map ("S" . #'jao-gnus-consult-notmuch)))
- ;;; keyboard shortcuts
- (define-key gnus-article-mode-map "i" 'jao-gnus-show-images)
- (define-key gnus-summary-mode-map "i" 'jao-gnus-show-images)
- (define-key gnus-article-mode-map "\M-g" 'jao-gnus-follow-link)
- (define-key gnus-summary-mode-map "\M-g" 'jao-gnus-follow-link)
- (define-key gnus-summary-mode-map "v" 'scroll-other-window)
- (define-key gnus-summary-mode-map "V" 'scroll-other-window-down)
- (define-key gnus-summary-mode-map "X" 'jao-gnus-arXiv-capture)
- (define-key gnus-summary-mode-map "e" 'jao-gnus-open-enclosure)
- (define-key gnus-summary-mode-map "\C-l" nil)
- (define-key gnus-group-mode-map "a" 'jao-gnus-refresh-workspace)
|