aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--modules/calibredb-epub-config.el85
-rw-r--r--tests/test-calibredb-epub-config--menu.el52
2 files changed, 136 insertions, 1 deletions
diff --git a/modules/calibredb-epub-config.el b/modules/calibredb-epub-config.el
index 9f09e392..a17bf8c9 100644
--- a/modules/calibredb-epub-config.el
+++ b/modules/calibredb-epub-config.el
@@ -51,6 +51,7 @@
(require 'user-constants) ;; for books-dir
(require 'subr-x)
+(require 'transient) ;; cj/calibredb-menu is a transient prefix
;; Declare functions from lazy-loaded packages
(declare-function calibredb-find-create-search-buffer "calibredb" ())
@@ -59,6 +60,24 @@
(declare-function nov-render-document "nov" ())
(defvar nov-text-width) ; from nov.el; set buffer-local here
+;; calibredb commands the curated menu drives (all autoloaded by calibredb)
+(declare-function calibredb-switch-library "calibredb" ())
+(declare-function calibredb-filter-by-book-format "calibredb" ())
+(declare-function calibredb-filter-by-author-sort "calibredb" ())
+(declare-function calibredb-search-clear-filter "calibredb" ())
+(declare-function calibredb-sort-by-author "calibredb" ())
+(declare-function calibredb-sort-by-title "calibredb" ())
+(declare-function calibredb-sort-by-pubdate "calibredb" ())
+(declare-function calibredb-sort-by-format "calibredb" ())
+(declare-function calibredb-find-file "calibredb" ())
+(declare-function calibredb-dispatch "calibredb" ())
+(declare-function calibredb-show-entry "calibredb" (entry &optional switch))
+(declare-function calibredb-find-candidate-at-point "calibredb" ())
+(declare-function calibredb-search-refresh-or-resume "calibredb" (&optional begin position))
+(defvar calibredb-show-entry-switch) ; from calibredb-show.el
+(defvar calibredb-sort-by) ; from calibredb-core.el
+(defvar calibredb-search-filter) ; from calibredb-search.el
+
;; -------------------------- CalibreDB Ebook Manager --------------------------
(defun cj/calibredb-clear-filters ()
@@ -73,6 +92,23 @@
;; empty string resets keyword filter and refreshes listing
(calibredb-search-keyword-filter ""))
+(defun cj/calibredb-describe-at-point ()
+ "Show the book at point in the docked *calibredb-entry* buffer.
+Displays the entry without switching focus back to the list, so it lands
+in the bottom-docked window (see the `display-buffer-alist' entry below)
+and q (`calibredb-entry-quit') dismisses it."
+ (interactive)
+ (calibredb-show-entry (car (calibredb-find-candidate-at-point))))
+
+(defun cj/--calibredb-sort-preserving-filter (field)
+ "Set `calibredb-sort-by' to FIELD and refresh, keeping the active filter.
+calibredb's own `calibredb-sort-by-*' commands refresh with
+`calibredb-search-refresh-and-clear-filter', which drops the active filter
+on every sort. This refreshes with `calibredb-search-refresh-or-resume',
+which re-applies `calibredb-search-filter' instead."
+ (setq calibredb-sort-by field)
+ (calibredb-search-refresh-or-resume))
+
(use-package calibredb
:commands calibredb
:bind
@@ -80,7 +116,10 @@
;; use built-in filter by tag, add clear-filters
(:map calibredb-search-mode-map
("l" . calibredb-filter-by-tag)
- ("L" . cj/calibredb-clear-filters))
+ ("L" . cj/calibredb-clear-filters)
+ ;; "?" -> curated menu of frequent workflows; "H" -> the full dispatch
+ ("?" . cj/calibredb-menu)
+ ("H" . calibredb-dispatch))
:config
;; basic config
(setq calibredb-root-dir books-dir)
@@ -88,6 +127,50 @@
(setq calibredb-program "/usr/bin/calibredb")
(setq calibredb-preferred-format "epub")
(setq calibredb-search-page-max-rows 500)
+ ;; Dock the book-detail buffer to the bottom 30%; q dismisses it.
+ ;; `pop-to-buffer' honours `display-buffer-alist' (the default
+ ;; `switch-to-buffer-other-window' would not).
+ (setq calibredb-show-entry-switch #'pop-to-buffer)
+ (add-to-list 'display-buffer-alist
+ '("\\`\\*calibredb-entry\\*\\'"
+ (display-buffer-at-bottom)
+ (window-height . 0.3)))
+ ;; A curated menu of the frequent calibredb workflows, bound to `?' in the
+ ;; search buffer; calibredb's own full dispatch (the wall of every command)
+ ;; moves to `H'. Defined here in `:config' so it only builds once calibredb
+ ;; (and its matching transient) is loaded. This is the "? brings up a
+ ;; discoverable help menu" convention.
+ (transient-define-prefix cj/calibredb-menu ()
+ "Frequent calibredb workflows."
+ [["Library"
+ ("l" "switch library" calibredb-switch-library)]
+ ["Filter"
+ ("f" "format" calibredb-filter-by-book-format)
+ ("a" "author" calibredb-filter-by-author-sort)
+ ("x" "reset filter" calibredb-search-clear-filter)]
+ ["Sort"
+ ("A" "author (last name)" calibredb-sort-by-author)
+ ("t" "title" calibredb-sort-by-title)
+ ("p" "pubdate" calibredb-sort-by-pubdate)
+ ("g" "group by format" calibredb-sort-by-format)]
+ ["Book"
+ ("o" "open" calibredb-find-file)
+ ("d" "describe" cj/calibredb-describe-at-point)
+ ("H" "full calibredb menu" calibredb-dispatch)]]
+ [("q" "quit" transient-quit-one)])
+
+ ;; Keep the active filter when sorting. calibredb's macro-generated
+ ;; `calibredb-sort-by-*' commands refresh-and-clear-filter, dropping the
+ ;; filter on every sort; override each to refresh-or-resume so the filter
+ ;; survives. Named advice keeps the override idempotent across reloads.
+ (dolist (field '(id title author format date pubdate tag size language))
+ (let ((cmd (intern (format "calibredb-sort-by-%s" field)))
+ (adv (intern (format "cj/--calibredb-sort-keep-filter-%s" field)))
+ (f field))
+ (defalias adv
+ (lambda (&rest _) (interactive) (cj/--calibredb-sort-preserving-filter f))
+ (format "Sort by %s, keeping the active filter (override)." field))
+ (advice-add cmd :override adv)))
;; search window display
(setq calibredb-size-show nil)
diff --git a/tests/test-calibredb-epub-config--menu.el b/tests/test-calibredb-epub-config--menu.el
new file mode 100644
index 00000000..4860efc3
--- /dev/null
+++ b/tests/test-calibredb-epub-config--menu.el
@@ -0,0 +1,52 @@
+;;; test-calibredb-epub-config--menu.el --- calibredb curated-menu tests -*- lexical-binding: t; -*-
+
+;;; Commentary:
+;; Tests for the docked book-description command bound into the curated calibredb
+;; menu. The transient itself, its `?'/`H' keybindings, and the
+;; display-buffer-alist dock live in calibredb's deferred `use-package' config
+;; (they need the elpa transient, which batch does not load) and are verified
+;; live in the daemon; here we cover the describe command, which has no transient
+;; dependency.
+
+;;; Code:
+
+(require 'ert)
+(require 'cl-lib)
+(add-to-list 'load-path (expand-file-name "modules" user-emacs-directory))
+(require 'calibredb-epub-config)
+
+;; calibredb vars (defvar'd here so the tests' `let' bindings are dynamic; the
+;; module's bare defvars are file-local to its own compilation unit).
+(defvar calibredb-sort-by)
+(defvar calibredb-search-filter)
+(defvar calibredb-format-filter-p)
+
+(ert-deftest test-calibredb-describe-at-point-shows-entry-without-switch ()
+ "Normal: describe calls `calibredb-show-entry' on the entry at point with no
+switch argument, so the entry lands in the docked window with focus (q quits)."
+ (let (call)
+ (cl-letf (((symbol-function 'calibredb-find-candidate-at-point)
+ (lambda () '(the-entry extra)))
+ ((symbol-function 'calibredb-show-entry)
+ (lambda (&rest args) (setq call args))))
+ (cj/calibredb-describe-at-point)
+ ;; one argument only -- the entry -- and switch is therefore nil
+ (should (equal call '(the-entry))))))
+
+(ert-deftest test-calibredb-sort-preserving-filter-keeps-filter ()
+ "Normal: the filter-preserving sort sets the field and refreshes via
+`calibredb-search-refresh-or-resume' without touching the active filter."
+ (let ((calibredb-sort-by 'id)
+ (calibredb-search-filter "epub")
+ (calibredb-format-filter-p t)
+ (refreshed nil))
+ (cl-letf (((symbol-function 'calibredb-search-refresh-or-resume)
+ (lambda (&rest _) (setq refreshed t))))
+ (cj/--calibredb-sort-preserving-filter 'author)
+ (should (eq calibredb-sort-by 'author)) ; field updated
+ (should refreshed) ; refreshed
+ (should (equal calibredb-search-filter "epub")) ; filter kept
+ (should calibredb-format-filter-p)))) ; filter flag kept
+
+(provide 'test-calibredb-epub-config--menu)
+;;; test-calibredb-epub-config--menu.el ends here