diff options
| author | Craig Jennings <c@cjennings.net> | 2026-06-12 10:49:39 -0500 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-06-12 10:49:39 -0500 |
| commit | 2032c13811a9d5f39301085ca70f476ca6813529 (patch) | |
| tree | 5ed64f2faffba1d49ddc3cc0f12f4774635385b0 | |
| parent | 27453b4faa9dcd6a672dabd06b2a1fb300fedeef (diff) | |
| download | dotemacs-2032c13811a9d5f39301085ca70f476ca6813529.tar.gz dotemacs-2032c13811a9d5f39301085ca70f476ca6813529.zip | |
fix(org-drill): route drill-refile targets through the validated helper
The prior fix listed drill files with a raw directory-files call, bypassing cj/--drill-files-or-error, the shared validated entry point the other drill commands use. That skipped the missing/unreadable-dir user-error, fell through silently on an empty dir, and included leading-dot .org files the module otherwise excludes. Route through cj/--drill-files-or-error + expand-file-name, keeping the let binding so the session-wide org-refile-targets still survives. The test is rewritten into three: validated-helper targets, no global clobber, and a user-error on a missing drill dir.
| -rw-r--r-- | modules/org-drill-config.el | 4 | ||||
| -rw-r--r-- | tests/test-org-drill-config-commands.el | 42 | ||||
| -rw-r--r-- | todo.org | 2 |
3 files changed, 34 insertions, 14 deletions
diff --git a/modules/org-drill-config.el b/modules/org-drill-config.el index b2d2a5099..2c6e400e0 100644 --- a/modules/org-drill-config.el +++ b/modules/org-drill-config.el @@ -97,7 +97,9 @@ With a prefix arg OTHER-DIR, prompt for the directory instead of `drill-dir'." (interactive) (let ((org-refile-targets `((nil :maxlevel . 1) - (,(directory-files drill-dir t "\\.org$") :maxlevel . 1)))) + (,(mapcar (lambda (f) (expand-file-name f drill-dir)) + (cj/--drill-files-or-error drill-dir)) + :maxlevel . 1)))) (call-interactively 'org-refile))) ;; ------------------------------- Drill Keymap -------------------------------- diff --git a/tests/test-org-drill-config-commands.el b/tests/test-org-drill-config-commands.el index 37d1f5c46..c35bd6cd4 100644 --- a/tests/test-org-drill-config-commands.el +++ b/tests/test-org-drill-config-commands.el @@ -71,12 +71,19 @@ ;;; cj/drill-refile -(ert-deftest test-org-drill-refile-delegates-with-file-targets () - "Normal: drill-refile dispatches to `org-refile' with current buffer + -the list of drill .org files (not the `drill-dir' variable symbol)." - (let (seen-targets called-fn) - (cl-letf (((symbol-function 'directory-files) - (lambda (&rest _) '("/tmp/cj-drill/a.org" "/tmp/cj-drill/b.org"))) +(ert-deftest test-org-drill-refile-targets-from-validated-helper () + "Normal: drill-refile builds its drill targets from the shared +`cj/--drill-files-or-error' helper, expanded against `drill-dir' — not from +a raw `directory-files' call (so it inherits the helper's dot-file exclusion +and validation)." + (let ((drill-dir "/tmp/cj-drill/") + seen-targets called-fn) + (cl-letf (((symbol-function 'cj/--drill-files-or-error) + (lambda (_dir) '("a.org" "b.org"))) + ;; If the old raw path were still in use it would call + ;; `directory-files'; a sentinel here keeps it from masquerading. + ((symbol-function 'directory-files) + (lambda (&rest _) '("/WRONG/raw.org"))) ((symbol-function 'call-interactively) (lambda (fn) (setq called-fn fn @@ -85,20 +92,29 @@ the list of drill .org files (not the `drill-dir' variable symbol)." (should (eq called-fn 'org-refile)) (should (= 2 (length seen-targets))) (should (assoc nil seen-targets)) - ;; The drill entry's car is a real list of .org files, never the - ;; `drill-dir' symbol (org reads a bound symbol as the directory string). - (let ((files (car (nth 1 seen-targets)))) - (should (equal files '("/tmp/cj-drill/a.org" "/tmp/cj-drill/b.org"))) - (should-not (eq files 'drill-dir))))) + (should (equal (car (nth 1 seen-targets)) + '("/tmp/cj-drill/a.org" "/tmp/cj-drill/b.org"))))) (ert-deftest test-org-drill-refile-does-not-clobber-global-targets () "Error: drill-refile let-binds `org-refile-targets'; the session-wide value survives the call instead of being permanently replaced." - (let ((org-refile-targets '((sentinel :maxlevel . 9)))) - (cl-letf (((symbol-function 'directory-files) (lambda (&rest _) nil)) + (let ((drill-dir "/tmp/cj-drill/") + (org-refile-targets '((sentinel :maxlevel . 9)))) + (cl-letf (((symbol-function 'cj/--drill-files-or-error) (lambda (_dir) '("a.org"))) ((symbol-function 'call-interactively) (lambda (_fn) nil))) (cj/drill-refile)) (should (equal org-refile-targets '((sentinel :maxlevel . 9)))))) +(ert-deftest test-org-drill-refile-errors-on-missing-drill-dir () + "Error: a missing or unreadable drill dir signals a clear `user-error' via +the shared validated helper, instead of a low-level error, and never reaches +`org-refile'." + (let ((drill-dir (expand-file-name "cj-drill-nonexistent-XYZ/" + temporary-file-directory)) + (called nil)) + (cl-letf (((symbol-function 'call-interactively) (lambda (_fn) (setq called t)))) + (should-error (cj/drill-refile) :type 'user-error)) + (should-not called))) + (provide 'test-org-drill-config-commands) ;;; test-org-drill-config-commands.el ends here @@ -818,6 +818,8 @@ From the 2026-06 config audit, =modules/calendar-sync.el=: CLOSED: [2026-06-12 Fri] Fixed in =modules/org-drill-config.el=: =cj/drill-refile= now =let=-binds =org-refile-targets= (the session-wide value survives) and supplies =(directory-files drill-dir t "\\.org$")= as the file list instead of the bound =drill-dir= symbol (org reads a bound symbol as a directory string, which yielded nothing). Rewrote the stale test (it asserted the buggy =(assoc 'drill-dir ...)=) into two: targets are a real .org file list, and the global is not clobbered. Both red before, green after. Live-reloaded into the daemon. +Follow-up 2026-06-12 (Codex review): the first fix reinvented file-listing with a raw =directory-files= call, bypassing the shared validated entry point =cj/--drill-files-or-error= — no missing/unreadable-dir =user-error=, silent fall-through on an empty dir, and it included leading-dot =.org= files the rest of the module excludes. Re-routed through =cj/--drill-files-or-error= + =expand-file-name=; the test was rewritten into three (validated-helper targets, no global clobber, =user-error= on a missing dir). + ** TODO [#B] ERC: double mention notifications + tautological server list :bug:quick:solo: From the 2026-06 config audit, =modules/erc-config.el=: - =:281= — =erc-modules= includes the built-in =notifications= module AND :config adds =cj/erc-notify-on-mention= to the same hook — every mention fires two desktop notifications. Pick one path (keep the custom one, slated for messenger unification). |
