I use elfeed to read RSS in emacs and want to make a function that cycle through different views: news, 9gag, nonnews etc.
I have tried to make some code via quick research. When I press ctrl + right arrow key it cycle through the views. It works fine, but I don't think it is the most convenient code.
I also want to make it go reverse through the views when pressing ctrl + left arrow key.
;;cycle through views
(setq a 0)
(defun cycle-list-view ()
(interactive)
(if (= a 3)
(progn
(elfeed-read-9gag)
(setq a 4)
))
(if (= a 2)
(progn
(elfeed-read-nonnews)
(setq a 3)
))
(if (= a 1)
(progn
(elfeed-read-news)
(setq a 2)
))
(if (= a 0)
(progn
(elfeed-read-defaultnews)
(setq a 1)
))
(if (= a 4)
(progn
(setq a 0)
))
)
(global-set-key (kbd "<C-right>") 'cycle-list-view)
It looks like tripleee's answer will work for the general question you asked (regarding how to cycle through a list of functions). For the specific question (cycling through Elfeed filters), I wrote an implementation of this for myself a while back, and thought I'd post it here in case it's of use to you.
Without seeing the code you're calling (e.g., elfeed-read-news
) it's hard to say how this differs from your implementation, but I'm guessing you don't need to have all of your views written up as separate functions (unless you also want a command to jump straight to a particular view).
Also, I should note that my implementation uses the dash
library, which you can find on MELPA.
(defvar my/elfeed-favorite-filters
'("@6-months-ago +unread"
"+todo")
"A list of commonly-used filters for Elfeed.
Use `my/elfeed-search-next-favorite-filter' to cycle through
these.")
(defun my/elfeed-search-next-favorite-filter (&optional verbose)
"Apply the next filter in `my/elfeed-favorite-filters'.
If the current search filter is an element of
`my/elfeed-favorite-filters', apply the filter immediately
following that one in the list, looping back to the beginning if
necessary.
If the current search filter is not an element of
`my/elfeed-favorite-filters', apply the first filter in the
list.
If `my/elfeed-favorite-filters' is empty, just apply the default
filter.
Return the filter applied. When called interactively or the optional
VERBOSE parameter is non-nil, also print a message informing the user
of the newly applied filter."
(interactive "p")
(let ((new-filter
(my/successor-in-list my/elfeed-favorite-filters
elfeed-search-filter :cyclical)))
(elfeed-search-set-filter new-filter)
(when verbose (message "Filter applied: %s" elfeed-search-filter))
elfeed-search-filter))
(defun my/successor-in-list (list elt &optional cycle)
"Return the element in LIST following ELT.
If ELT is not an element of LIST, return nil.
If ELT is the last element in LIST, return (car LIST) if the
optional parameter CYCLE is non-nil; otherwise, return nil."
(require 'dash) ; For `-drop-while'
(let ((found (-drop-while (lambda (x) (not (equal x elt)))
list)))
(cond
((null found) nil)
((or (cdr found) (null cycle)) (cadr found))
(:else (car list)))))
I don't use a "cycle backward" command, but it's pretty easy to tack one on:
(defun my/elfeed-search-prev-favorite-filter (&optional verbose)
"Apply the previous filter in `my/elfeed-favorite-filters'.
As `my/elfeed-search-next-favorite-filter', but cycle backwards."
(interactive "p")
(let ((my/elfeed-favorite-filters (reverse my/elfeed-favorite-filters)))
(my/elfeed-search-next-favorite-filter verbose)))