branch: externals/calibre
commit ac4c02aeb9b9454ed206a0f72ad7c2bed53a6571
Author: Kjartan Óli Ágústsson <[email protected]>
Commit: Kjartan Óli Ágústsson <[email protected]>
Add support for composite filters
* calibre-db.el (calibre-composite-filter-p): Create
(calibre--get-filter-items): Handle composite filters.
* calibre-search.el (calibre-search): Add docstring.
Add binding to compose composite filters
(calibre-search-composing-filter, calibre-search-compose-apply,
calibre-search-compose-cleanup,
calibre-search--composition-function, calibre-search-compose-author,
calibre-search-compose-publisher, calibre-search-compose-tag,
calibre-search-compose-series, calibre-search-compose-format,
calibre-search-compose): Create
* calibre-virtual-library.el (calibre-virtual-libraries): Change type
to support composite filters.
---
calibre-db.el | 26 ++++++++++++++++-------
calibre-search.el | 52 ++++++++++++++++++++++++++++++++++++++++++++--
calibre-virtual-library.el | 24 ++++++++++++++-------
3 files changed, 85 insertions(+), 17 deletions(-)
diff --git a/calibre-db.el b/calibre-db.el
index 313d6e18ff..3f6c42bdb1 100644
--- a/calibre-db.el
+++ b/calibre-db.el
@@ -176,15 +176,27 @@ WHERE s.name = ?" `[,series])))
FROM data
WHERE format = ?" `[,format])))
+(defun calibre-composite-filter-p (object)
+ "Return t if OBJECT is a composite filter."
+ (and (vectorp object) (length= object 2) (listp (elt object 1))))
+
(defun calibre--get-filter-items (filter)
"Return the id's of books matching FILTER."
- (seq-let (_ field value) filter
- (cl-case field
- (author (calibre-db--get-author-books value))
- (tag (calibre-db--get-tag-books value))
- (publisher (calibre-db--get-publisher-books value))
- (series (calibre-db--get-series-books value))
- (format (calibre-db--get-format-books value)))))
+ (if (calibre-composite-filter-p filter)
+ (seq-let (op filters) filter
+ (cl-reduce (if (eq op '+)
+ #'cl-union
+ #'cl-intersection)
+ (mapcar (lambda (f)
+ (calibre--get-filter-items (vconcat `[,op] f)))
+ filters)))
+ (seq-let (_ field value) filter
+ (cl-case field
+ (author (calibre-db--get-author-books value))
+ (tag (calibre-db--get-tag-books value))
+ (publisher (calibre-db--get-publisher-books value))
+ (series (calibre-db--get-series-books value))
+ (format (calibre-db--get-format-books value))))))
(defun calibre-library--filter (filters books)
"Return those books in BOOKS that match FILTERS.
diff --git a/calibre-search.el b/calibre-search.el
index 8e2fb187a1..4f8e402737 100644
--- a/calibre-search.el
+++ b/calibre-search.el
@@ -82,7 +82,7 @@ ARGS is the argument list of a transient command."
(calibre-library--refresh))
(transient-define-prefix calibre-search ()
- ""
+ "Filter the library view."
:transient-suffix 'transient--do-call
["Arguments"
("-e" "Exclude" "--exclude")]
@@ -92,9 +92,57 @@ ARGS is the argument list of a transient command."
("t" "Tag" calibre-library-search-tag)
("s" "Series" calibre-library-search-series)
("f" "Format" calibre-library-search-format)]
- ["Misc"
+ ["Actions"
+ ("C" "Compose" calibre-search-compose)
("u" "Undo" calibre-library-clear-last-search)
("c" "Clear" calibre-library-clear-filters)
("q" "Exit" transient-quit-one)])
+
+(defvar calibre-search-composing-filter nil)
+(defun calibre-search-compose-apply (&optional args)
+ "Apply the composite filter under construction."
+ (interactive (list (transient-args 'calibre-search-compose)))
+ (if (not calibre-search-composing-filter)
+ (error "Can not apply an empty composite filter")
+ (let ((filter (vector (calibre-search--operation args)
+ calibre-search-composing-filter)))
+ (setf calibre-library--filters (cons filter calibre-library--filters)
+ calibre-search-composing-filter nil)
+ (calibre-library--refresh))))
+
+(defun calibre-search-compose-cleanup ()
+ "Clear any filter currently being composed."
+ (interactive)
+ (setf calibre-search-composing-filter nil))
+
+(defmacro calibre-search--composition-function (field)
+ "Create a function adding a filter for FIELD to a composite filter."
+ `(defun ,(intern (format "calibre-search-compose-%s" field)) ()
+ ,(format "Add a filter for %s to the composite filter under
construction." field)
+ (interactive)
+ (setf calibre-search-composing-filter
+ (cons (vector ',(intern field) (,(intern (format
"calibre-search-chose-%s" field)))) calibre-search-composing-filter))))
+
+(calibre-search--composition-function "author")
+(calibre-search--composition-function "publisher")
+(calibre-search--composition-function "tag")
+(calibre-search--composition-function "series")
+(calibre-search--composition-function "format")
+
+(transient-define-prefix calibre-search-compose ()
+ "Create a composite filter."
+ :transient-suffix 'transient--do-call
+ ["Arguments"
+ ("-e" "Exclude" "--exclude")]
+ ["Compose"
+ ("a" "Author" calibre-search-compose-author)
+ ("p" "Publisher" calibre-search-compose-publisher)
+ ("t" "Tag" calibre-search-compose-tag)
+ ("s" "Series" calibre-search-compose-series)
+ ("f" "Format" calibre-search-compose-format)]
+ ["Actions"
+ ("A" "Apply" calibre-search-compose-apply :transient transient--do-return)
+ ("q" "Quit" calibre-search-compose-cleanup :transient
transient--do-return)])
+
(provide 'calibre-search)
diff --git a/calibre-virtual-library.el b/calibre-virtual-library.el
index 70f55357f4..ad60178eb9 100644
--- a/calibre-virtual-library.el
+++ b/calibre-virtual-library.el
@@ -28,7 +28,13 @@
"A list of predefined filters, i.e. Virtual Libraries.
Each element is a cons cell (name . filters) where name is a
string, and filters is a list of vectors [op field value]"
- :type '(repeat :tag "Virtual Libraries"
+ :type (let ((fields '(choice :tag "Field"
+ (const :tag "Author" author)
+ (const :tag "Publisher" publisher)
+ (const :tag "Series" series)
+ (const :tag "Tag" tag)
+ (const :tag "Format" format))))
+ `(repeat :tag "Virtual Libraries"
(cons :tag "Virtual Library"
(string :tag "Name")
(repeat :tag "Filters"
@@ -36,13 +42,15 @@ string, and filters is a list of vectors [op field value]"
(choice :tag "Operation"
(const :tag "Include" +)
(const :tag "Exclude" -))
- (choice :tag "Field"
- (const :tag "Author" author)
- (const :tag "Publisher"
publisher)
- (const :tag "Series" series)
- (const :tag "Tag" tag)
- (const :tag "Format" format))
- (string :tag "Value")))))
+ (choice :tag "Type"
+ (list :tag "Basic"
+ :inline t
+ ,fields
+ (string :tag "Value"))
+ (repeat :tag "Composite"
+ (vector :tag "Filter"
+ ,fields
+ (string :tag
"Value")))))))))
:group 'calibre
:package-version '("calibre" . "1.1.0"))