Lisp:遍历函数

时间:2015-12-29 05:50:22

标签: emacs elisp

我使用elfeed来阅读emacs中的RSS,并希望创建一个循环浏览不同视图的函数:news,9gag,nonnews等。

我试图通过快速研究制作一些代码。当我按下ctrl +右箭头键时,它循环浏览视图。它工作正常,但我不认为这是最方便的代码。

按ctrl +左箭头键时,我也想让它反向浏览视图。

;;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)

2 个答案:

答案 0 :(得分:1)

您应该将数据放在一个单独的变量中,并让您的代码只是在该结构中维护一个全局索引变量。也许是这样的:

(defvar elfeed-views-list "List of views for `elfeed-cycle-views'.
Each member should be a cons of a label string and a function.
`elfeed-views--index' is a pointer into this structure."
  (("default" . #'elfeed-read-defaultnews)
   ("news" . #'elfeed-read-news)
   ("nonnews" . #'elfeed-read-nonnews)
   ("9gag" . #'elfeed-read-9gag)))

添加新视图不再需要更改代码 - 只需将另一个项目推送到此列表的末尾即可。

现在所有循环功能需要做的是将索引增加或减少到这个结构中,如果你超越了结束,请注意包装:

;; The double dash in the name suggests a private variable
(defvar elfeed-views--index "Index into `elfeed-views-list' for `elfeed-cycle-views'.
Use that function to manipulate the index." 0)

(defun elfeed-cycle-views (&optional skip)
  "Update `elfeed-views--index' by adding SKIP (default 1) and
wrapping if necessary, then call the function at this index in
`elfeed-views-list'."
  (interactive)
  (setq elfeed-views--index (+ elfeed-views-index (or skip 1)))
   ;; BUG: skips with an absolute value bigger than 1 don't wrap properly.
  (if (>= elfeed-views--index (length elfeed-views-list))
    (setq elfeed-views--index 0)
   (when (< elfeed-views--index 0)
     (setq elfeed-views--index (1- (length elfeed-views-list))) ))
  (eval (cdr (nth elfeed-views--index elfeed-views-list))) )

现在可以通过将-1作为SKIP参数传递来实现相反的循环。

(未经测试,但至少这应该会给你一些想法。)

除了风格之外,您还想了解cond而不是if语句的可怕序列。您显然必须强制执行您的代码的不直观的反向排序顺序,因为您不知道此控制结构。

答案 1 :(得分:0)

看起来triee的答案适用于您提出的一般性问题(关于如何循环查看函数列表)。对于具体问题(通过Elfeed过滤器循环),我在一段时间后为自己写了一个这样的实现,并认为我会在这里发布它,以防它对你有用。

如果没有看到您正在调用的代码(例如,elfeed-read-news),很难说这与您的实现有何不同,但我猜您不需要将所有视图都写成单独的函数(除非您还希望命令直接跳转到特定视图)。

另外,我应该注意我的实现使用了dash库,你可以在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)))))

我没有使用“循环向后”命令,但是很容易找到一个:

(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)))