Skip to content

Commit

Permalink
Work with regular completing-read (e.g. selectrum) + embark
Browse files Browse the repository at this point in the history
bump version
  • Loading branch information
unhammer committed Jan 7, 2021
1 parent a7b131c commit 6f13a00
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 59 deletions.
61 changes: 22 additions & 39 deletions README.org
Expand Up @@ -10,63 +10,46 @@ Or hit a key while reading one article to pop back through the stack
of previously read articles, even if they were in a different Group.

Or insert a link to a recently read e-mail in an org-mode buffer by
just picking one with [[https://github.com/abo-abo/swiper/][ivy]]:
just picking one with completion:

#+ATTR_HTML: :alt demo of gnus-recent inserting link with ivy in org-mode
[[file:gnus-recent-org-mode.gif][file:gnus-recent-org-mode.gif]]

* Installation

** MELPA
If you use [[https://melpa.org/][MELPA]], you can just do =M-x list-packages=, find
=gnus-recent= in the list and hit =i x=.

The Melpa packages doesn't include the ivy/helm stuff, you'll have to
add those manually for now.
clone the repo if you want those.

** Manual
Just put =gnus-recent.el= (and optionally =gnus-recent-ivy.el= /
=gnus-recent-helm.el=) somewhere in =load-path=.
* Configuration

Require and bind whatever keys you prefer to the interactive function:

* Usage

After reading some articles in Gnus and then doing whatever, doing
=gnus-recent-goto-previous= will open the last read article and rotate
the list, so you can keep calling it to go further back.

Doing =gnus-recent-ivy= will let you pick an article to
re-open. Hitting =M-o l= will insert an =org-mode= link to the article
instead.

** Manual, loading on startup:
#+BEGIN_SRC emacs-lisp
(use-package gnus-recent
:ensure t ; if you want it from MELPA
; :load-path "~/src/gnus-recent" ; if you're running from a git clone
:after gnus
:bind (("<f3>" . gnus-recent)
:map gnus-summary-mode-map ("l" . gnus-recent-goto-previous)
:map gnus-group-mode-map ("C-c L" . gnus-recent-goto-previous)))
#+END_SRC

To use, require and bind whatever keys you prefer to the
interactive function:
If you use [[https://github.com/oantolin/embark][Embark]], add the following to be able to insert org links on =l=:

#+BEGIN_SRC emacs-lisp
(require 'gnus-recent)
(define-key gnus-summary-mode-map (kbd "l") #'gnus-recent-goto-previous) ;
(define-key gnus-group-mode-map (kbd "C-c L") #'gnus-recent-goto-previous)

(require 'gnus-recent-ivy)
(global-set-key (kbd "<f3>") #'gnus-recent-ivy)
(add-hook 'minibuffer-setup-hook #'gnus-recent-embark-minibuffer-hook)
#+END_SRC

** With use-package, enabled after org:
* Usage

If you prefer =use-package=, the above settings would be:
After reading some articles in Gnus and then doing whatever, doing
=gnus-recent-goto-previous= will open the last read article and rotate
the list, so you can keep calling it to go further back.

#+BEGIN_SRC emacs-lisp
(use-package gnus-recent
:load-path "~/src/gnus-recent" ; wherever you checked this out
:after gnus
:config
(define-key gnus-summary-mode-map (kbd "l") #'gnus-recent-goto-previous)
(define-key gnus-group-mode-map (kbd "C-c L") #'gnus-recent-goto-previous))
Doing =gnus-recent= will let you pick an article to re-open.

(use-package gnus-recent-ivy
:load-path "~/src/gnus-recent" ; wherever you checked this out
:after gnus
:bind (("<f3>" . gnus-recent-ivy)))
#+END_SRC
If you use =gnus-recent-ivy=, you can hit =M-o l= to insert an
=org-mode= link to the article instead.
6 changes: 3 additions & 3 deletions gnus-recent-helm.el
Expand Up @@ -48,14 +48,14 @@
(candidates . ,(mapcar (lambda (item)
(cons (car item) item))
gnus-recent--articles-list))
(action . (("Open article" . gnus-recent--open-article)
(action . (("Open article" . gnus-recent-open-article)
("Copy org link to kill ring" . gnus-recent-kill-new-org-link)
("Insert org link" . gnus-recent-insert-org-link)
("Remove article" . gnus-recent-helm-forget)
("Remove article" . gnus-recent--helm-forget)
("Clear all" . gnus-recent-forget-all)))))
:buffer "*helm gnus recent*"))

(defun gnus-recent-helm-forget (_recent)
(defun gnus-recent--helm-forget (_recent)
"Remove Gnus articles from `gnus-recent--articles-list' using `helm'.
Helm allows for marked articles or current selection. See
function `helm-marked-candidates'. Argument _recent is not used."
Expand Down
56 changes: 39 additions & 17 deletions gnus-recent.el
@@ -1,9 +1,9 @@
;;; gnus-recent.el --- article breadcrumbs for Gnus -*- lexical-binding: t -*-
;;; gnus-recent.el --- Article breadcrumbs for Gnus -*- lexical-binding: t -*-

;; Copyright (C) 2018-2020 Kevin Brubeck Unhammer
;; Copyright (C) 2018-2021 Kevin Brubeck Unhammer

;; Author: Kevin Brubeck Unhammer <unhammer@fsfe.org>
;; Version: 0.3.0
;; Version: 0.4.0
;; URL: https://github.com/unhammer/gnus-recent
;; Package-Requires: ((emacs "25.3.2"))
;; Keywords: convenience, mail
Expand Down Expand Up @@ -31,23 +31,17 @@
;;; To use, require and bind whatever keys you prefer to the
;;; interactive functions:
;;;
;;; (require 'gnus-recent)
;;; (define-key gnus-summary-mode-map (kbd "l") #'gnus-recent-goto-previous)
;;; (define-key gnus-group-mode-map (kbd "C-c L") #'gnus-recent-goto-previous)

;;; If you prefer `use-package', the above settings would be:
;;;
;;; (use-package gnus-recent
;;; :after gnus
;;; :config
;;; (define-key gnus-summary-mode-map (kbd "l") #'gnus-recent-goto-previous)
;;; (define-key gnus-group-mode-map (kbd "C-c L") #'gnus-recent-goto-previous))
;;; :bind (("<f3>" . gnus-recent)
;;; :map gnus-summary-mode-map ("l" . gnus-recent-goto-previous)
;;; :map gnus-group-mode-map ("C-c L" . gnus-recent-goto-previous)))

;;; Code:

(require 'gnus-sum)
(unless (require 'org-gnus nil 'noerror)
(require 'ol-gnus))
(require 'ol-gnus)) ; for org-gnus-follow-link

(defvar gnus-recent--articles-list nil
"The list of articles read in this Emacs session.")
Expand Down Expand Up @@ -127,7 +121,7 @@ article data in `gnus-recent--articles-list', but only if the
moved article was already tracked. For use by
`gnus-summary-article-move-hook'."
(when (eq action 'move)
(gnus-recent-update (gnus-recent--get-article-data) to-group)))
(gnus-recent--update (gnus-recent--get-article-data) to-group)))

(defun gnus-recent--track-delete-article (action _article _from-group &rest _rest)
"Track interactive user deletion of articles.
Expand All @@ -147,7 +141,7 @@ For use by `gnus-summary-article-expire-hook'."
(let ((article-data (gnus-recent--get-article-data)))
(when (member article-data gnus-recent--articles-list)
(if to-group ; article moves to the expiry-target group
(gnus-recent-update article-data to-group)
(gnus-recent--update article-data to-group)
(gnus-recent-forget article-data)))))) ; article is deleted

;; Activate the hooks (should be named -functions)
Expand Down Expand Up @@ -190,14 +184,17 @@ Warn if RECENT can't be deconstructed as expected."
(_
(message "Couldn't parse recent message: %S" recent))))

(defun gnus-recent--open-article (recent)
(defun gnus-recent (recent)
"Open RECENT gnus article using `org-gnus'."
(interactive (list (gnus-recent--completing-read)))
(gnus-recent--action
recent
(lambda (message-id group from to subject)
(let ((gnus-recent--showing-recent t))
(org-gnus-follow-link group message-id)))))

(defalias 'gnus-recent--open-article 'gnus-recent)

(defun gnus-recent--create-org-link (recent)
"Return an `org-mode' link to RECENT Gnus article."
(gnus-recent--action
Expand All @@ -220,14 +217,16 @@ Warn if RECENT can't be deconstructed as expected."

(defun gnus-recent-kill-new-org-link (recent)
"Add to the `kill-ring' an `org-mode' link to RECENT Gnus article."
(interactive (list (gnus-recent--completing-read)))
(kill-new (gnus-recent--create-org-link recent))
(message "Added org-link to kill-ring"))

(defun gnus-recent-insert-org-link (recent)
"Insert an `org-mode' link to RECENT Gnus article."
(interactive (list (gnus-recent--completing-read)))
(insert (gnus-recent--create-org-link recent)))

(defun gnus-recent-update (recent to-group)
(defun gnus-recent--update (recent to-group)
"Update RECENT Gnus article in `gnus-recent--articles-list'.
The Gnus article has moved to group TO-GROUP."
(cl-nsubstitute (list (cl-first recent) (cl-second recent) to-group)
Expand All @@ -238,6 +237,7 @@ The Gnus article has moved to group TO-GROUP."
(defun gnus-recent-forget (recent &optional print-msg)
"Remove RECENT Gnus article from `gnus-recent--articles-list'.
When PRINT-MSG is non-nil, show a message about it."
(interactive (list (gnus-recent--completing-read)))
(setq gnus-recent--articles-list
(cl-delete recent gnus-recent--articles-list :test 'equal :count 1))
(when print-msg
Expand All @@ -249,5 +249,27 @@ When PRINT-MSG is non-nil, show a message about it."
(setq gnus-recent--articles-list nil)
(message "Cleared all gnus-recent article entries"))

(defvar gnus-recent--actions
(let ((map (make-sparse-keymap)))
(define-key map "l" #'gnus-recent-insert-org-link)
(define-key map "c" #'gnus-recent-kill-new-org-link)
(define-key map "k" #'gnus-recent-forget)
(define-key map "K" #'gnus-recent-forget-all)
map))

(defun gnus-recent-embark-minibuffer-hook ()
"Use as `minibuffer-setup-hook' if using Embark."
(when (eq this-command 'gnus-recent)
(setq-local embark-overriding-keymap gnus-recent--actions)))

(defun gnus-recent--completing-read ()
"Pick an article using `completing-read'."
(when-let ((match (completing-read "Recent article: "
gnus-recent--articles-list
nil
'require-match)))
(assoc match gnus-recent--articles-list)))


(provide 'gnus-recent)
;;; gnus-recent.el ends here

0 comments on commit 6f13a00

Please sign in to comment.