diff options
| -rw-r--r-- | modules/calibredb-epub-config.el | 85 | ||||
| -rw-r--r-- | tests/test-calibredb-epub-config--menu.el | 52 |
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 |
