feat: add searches to settings

This commit is contained in:
Pavel Korytov 2022-03-17 21:31:07 +03:00
parent e9d4d59b41
commit 2d21f978c1

View file

@ -27,10 +27,13 @@
;; TODO ;; TODO
;;; Code: ;;; Code:
(require 'cl-lib)
(require 'elfeed) (require 'elfeed)
(require 'elfeed-db) (require 'elfeed-db)
(require 'widget) (require 'elfeed-search)
(require 'magit-section)
(require 'seq) (require 'seq)
(require 'widget)
(define-widget 'elfeed-summary-query 'lazy (define-widget 'elfeed-summary-query 'lazy
"A query to extract a subset of elfeed feeds." "A query to extract a subset of elfeed feeds."
@ -61,56 +64,76 @@
(const :tag "OR" or) (const :tag "OR" or)
(repeat elfeed-summary-query)))) (repeat elfeed-summary-query))))
(define-widget 'elfeed-summary-group 'lazy (define-widget 'elfeed-summary-setting-elements 'lazy
"A group of `elfeed-summary-query'" "Type widget for `elfeed-summary-settings'"
:offset 4 :offset 4
:tag "Group" :tag "Settings list"
:type '(repeat :type '(repeat
(choice (choice
(cons :tag "Group" (cons :tag "Group"
(const group) (const group)
(list :tag "Group params" (repeat :tag "Group params"
(cons (choice
(const :tag "Title" :title) (cons
(string :tag "Title")) (const :tag "Title" :title)
(cons (string :tag "Title"))
(const :tag "Sort function" :sort-fn) (cons
(choice (const :tag "Sort function" :sort-fn)
function (choice
(const :tag "None" nil))) function
(cons (const :tag "None" nil)))
(const :tag "Elements" :elements) (cons
elfeed-summary-group))) (const :tag "Elements" :elements)
elfeed-summary-query))) elfeed-summary-setting-elements))))
(cons :tag "Query"
(const query)
elfeed-summary-query)
(cons :tag "Search"
(const search)
(repeat :tag "Search params"
(choice
(cons :tag "Filter"
(const :tag "Filter" :filter)
(string :tag "Filter string"))
(cons :tag "Title"
(const :tag "Title" :title)
(string :tag "Filter title")))))
(const :tag "Misc feeds" :misc))))
(defgroup elfeed-summary () (defgroup elfeed-summary ()
"Feed summary inteface for elfeed." "Feed summary inteface for elfeed."
:group 'elfeed) :group 'elfeed)
(defcustom elfeed-summary-settings '((group (:title . "All feeds") (defcustom elfeed-summary-settings
(:sort-fn . string-lessp) '((group (:title . "All feeds")
(:elements :all))) (:sort-fn . string-lessp)
(:elements (query . :all)))
(group (:title . "Searches")
(:elements (search
(:filter . "@7-days-ago +unread")
(:title . "Unread entries this week"))
(search
(:filter . "@6-months-ago emacs")
(:title . "Something about Emacs")))))
"Elfeed summary buffer settings. "Elfeed summary buffer settings.
This is a list of these possible items: This is a list of these possible items:
- group - Group `(group . <group-params>)'
- query Groups are used to group elements under collapsible sections.
- Query `(query . <query-params>)'
Query extracts a subset of elfeed feeds based on the given criteria.
Each found feed will be represented as a line.
- Search `(search . <search-params>)'
Elfeed search, as defined by `elfeed-search-set-filter'.
- a few special forms - a few special forms
Groups are used to group queries under collapsible sections. `<group-params>' is an alist with the following keys:
A group is a cons cell like (group . <params>), where params are an
alist with the following attributes:
- `:title' (mandatory) - `:title' (mandatory)
- `:elements' (mandatory) - also a list of groups and queries - `:elements' (mandatory) - also a list of groups and queries
- `:sort-fn' - function used to sort titles of feeds, found by queries - `:sort-fn' - function used to sort titles of feeds, found by queries
in `:elements'. E.g. `string-greaterp' for alphabetical order. in `:elements'. E.g. `string-greaterp' for alphabetical order.
Query is a form that extract a subset of elfeed feeds based on `<query-params>' can be:
some criteria. In the summary buffer, each feed found by the
query will be represented as a line.
Query can be:
- A symbol of a tag. - A symbol of a tag.
A feed will be matched if it has that tag. A feed will be matched if it has that tag.
- `:all'. Will match anything. - `:all'. Will match anything.
@ -125,22 +148,27 @@ Query can be:
Match if any of the conditions 1, 2, ..., n match. Match if any of the conditions 1, 2, ..., n match.
- `(not <query>)' - `(not <query>)'
Feed tags are taken from `elfeed-feeds'. Feed tags for query are taken from `elfeed-feeds'.
Query examples: Query examples:
- `(emacs lisp)' - `(emacs lisp)'
Return all feeds that have either \"emacs\" or \"lisp\" tags. Return all feeds that have either \"emacs\" or \"lisp\" tags.
- `(and emacs lisp)' - `(and emacs lisp)'
Return all feeds that have both \"emacs\" and \"lisp\" tags. Return all feeds that have both \"emacs\" and \"lisp\" tags.
- `(and (title . \"Emacs\") (not planets)) - `(and (title . \"Emacs\") (not planets))'
Return all feeds that have \"Emacs\" in their title and don't have Return all feeds that have \"Emacs\" in their title and don't have
the \"planets\" tag. the \"planets\" tag.
`<search-params>` is an alist with the following keys:
- `:filter' (mandatory) filter string, as defined by
`elfeed-search-set-filter'
- `:title' (mandatory) title
Available special forms: Available special forms:
- `:misc' - print out feeds, not found by any query above. - `:misc' - print out feeds, not found by any query above.
- `:unread' - a special feed of all unread entries." - `:unread' - a special feed of all unread entries."
:group 'elfeed-summary :group 'elfeed-summary
:type 'elfeed-summary-group) :type 'elfeed-summary-setting-elements)
(defcustom elfeed-summary-look-back (* 60 60 24 180) (defcustom elfeed-summary-look-back (* 60 60 24 180)
"TODO" "TODO"
@ -157,6 +185,8 @@ Available special forms:
"Default face for the elfeed-summary group." "Default face for the elfeed-summary group."
:group 'elfeed-summary) :group 'elfeed-summary)
;;; Logic
(cl-defun elfeed-summary--match-tag (query &key tags title url author title-meta) (cl-defun elfeed-summary--match-tag (query &key tags title url author title-meta)
"Check if attributes of elfeed feed match QUERY. "Check if attributes of elfeed feed match QUERY.
@ -261,7 +291,8 @@ QUERY is described in `elfeed-summary-settings'."
if (and (listp param) (eq (car param) 'group)) if (and (listp param) (eq (car param) 'group))
append (elfeed-summary--extract-feeds append (elfeed-summary--extract-feeds
(cdr (assoc :elements (cdr param)))) (cdr (assoc :elements (cdr param))))
else append (elfeed-summary--get-feeds param))) else if (and (listp param) (eq (car param) 'query))
append (elfeed-summary--get-feeds (cdr param))))
(defun elfeed-summary--build-tree-feed (feed unread-count total-count) (defun elfeed-summary--build-tree-feed (feed unread-count total-count)
(let* ((unread (or (gethash (elfeed-feed-id feed) unread-count) 0)) (let* ((unread (or (gethash (elfeed-feed-id feed) unread-count) 0))
@ -284,6 +315,33 @@ QUERY is described in `elfeed-summary-settings'."
(unread . ,unread) (unread . ,unread)
(total . ,unread)))) (total . ,unread))))
(defun elfeed-summary--build-search (search)
"TODO
Implented the same way as `elfeed-search--update-list'."
(let* ((filter (elfeed-search-parse-filter (alist-get :filter search)))
(head (list nil))
(tail head)
(count 0))
(if elfeed-search-compile-filter
;; Force lexical bindings regardless of the current
;; buffer-local value. Lexical scope uses the faster
;; stack-ref opcode instead of the traditional varref opcode.
(let ((lexical-binding t)
(func (byte-compile (elfeed-search-compile-filter filter))))
(with-elfeed-db-visit (entry feed)
(when (funcall func entry feed count)
(setf (cdr tail) (list entry)
tail (cdr tail)
count (1+ count)))))
(with-elfeed-db-visit (entry feed)
(when (elfeed-search-filter filter entry feed count)
(setf (cdr tail) (list entry)
tail (cdr tail)
count (1+ count)))))
`((search . ,search)
(count . ,count))))
(defun elfeed-summary--build-tree (params unread-count total-count misc-feeds) (defun elfeed-summary--build-tree (params unread-count total-count misc-feeds)
(cl-loop for param in params (cl-loop for param in params
if (and (listp param) (eq (car param) 'group)) if (and (listp param) (eq (car param) 'group))
@ -291,16 +349,19 @@ QUERY is described in `elfeed-summary-settings'."
(children . ,(elfeed-summary--build-tree (children . ,(elfeed-summary--build-tree
(cdr (assoc :elements (cdr param))) (cdr (assoc :elements (cdr param)))
unread-count total-count misc-feeds))) unread-count total-count misc-feeds)))
else if (and (listp param) (eq (car param) 'search))
collect (elfeed-summary--build-search param)
else if (and (listp param) (eq (car param) 'query))
append (cl-loop for feed in (elfeed-summary--get-feeds (cdr param))
collect (elfeed-summary--build-tree-feed
feed unread-count total-count))
else if (eq param :misc) else if (eq param :misc)
append (cl-loop for feed in misc-feeds append (cl-loop for feed in misc-feeds
collect (elfeed-summary--build-tree-feed collect (elfeed-summary--build-tree-feed
feed unread-count total-count)) feed unread-count total-count))
else if (eq param :unread) else if (eq param :unread)
collect (elfeed-summary--build-tree-unread unread-count) collect (elfeed-summary--build-tree-unread unread-count)
else else do (error "Can't parse: %s" (prin1-to-string param))))
append (cl-loop for feed in (elfeed-summary--get-feeds param)
collect (elfeed-summary--build-tree-feed
feed unread-count total-count))))
(defun elfeed-summary--get-data () (defun elfeed-summary--get-data ()
(let* ((feeds (elfeed-summary--extract-feeds (let* ((feeds (elfeed-summary--extract-feeds
@ -328,5 +389,10 @@ QUERY is described in `elfeed-summary-settings'."
(elfeed-summary--build-tree elfeed-summary-settings (elfeed-summary--build-tree elfeed-summary-settings
unread-count total-count misc-feeds))) unread-count total-count misc-feeds)))
;;; View
(defun elfeed-summary--render (tree)
"TODO")
(provide 'elfeed-summary) (provide 'elfeed-summary)
;;; elfeed-summary.el ends here ;;; elfeed-summary.el ends here