diff options
| author | Craig Jennings <c@cjennings.net> | 2026-05-16 02:35:38 -0500 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-05-16 02:35:38 -0500 |
| commit | 1c5a2ebab7c721d795ed9331afdb305fd683e172 (patch) | |
| tree | f3c1756585b8f0590a0f381adbb23aedb2be957c | |
| parent | 9325ca00173a03f282e74b6a86c4083fa88977d5 (diff) | |
| download | dotemacs-1c5a2ebab7c721d795ed9331afdb305fd683e172.tar.gz dotemacs-1c5a2ebab7c721d795ed9331afdb305fd683e172.zip | |
refactor(foundation): hygiene pass across early-init, user-constants, system-defaults, chrono-tools
Six small fixes the 2026-05-15 module-by-module re-review surfaced:
- Consolidate `user-home-dir` -- canonical defconst stays in
early-init.el (package-archive bootstrap needs it before normal
modules load); user-constants.el switches to a `defvar` with the
identical `(getenv "HOME")` expression so the module still loads /
byte-compiles standalone, but at runtime early-init's defconst
wins.
- Drop the redundant `(autoload 'env-bsd-p ...)` line in
system-defaults.el. The `(eval-when-compile (require
'host-environment))` already exposes the symbol to the byte
compiler, and at runtime host-environment is loaded earlier in
init.el. Added a comment documenting the boundary.
- Convert `cj/debug-modules` and `cj/use-online-repos` from `defvar`
to `defcustom`, with `:type`, `:group 'cj`, and a top-level
`(defgroup cj ...)` so both show up in M-x customize.
- Name the package-archive priorities in early-init.el. Nine new
defconsts replace the magic numbers (200 / 125 / 120 / 115 / 100 /
25 / 20 / 15 / 5) with one constant each, plus a header comment
explaining the local-first ordering and the gnu > nongnu > melpa >
melpa-stable trust ranking within each tier.
- Delete the 19-line commented-out `use-package time` world-clock
block in chrono-tools.el. `time-zones` immediately above is the
active replacement; git history preserves the old config if anyone
needs it.
- Add coverage for `cj/tmr-select-sound-file`. Collapsed the
prefix-arg branch into a delegation to
`cj/tmr-reset-sound-to-default` (single reset source) and
extracted `cj/tmr--available-sound-files` as a pure helper that
tests directly. 9 ERT tests across Normal / Boundary / Error
cover the available-sounds helper, the reset path, the prefix-arg
delegation (no prompt), the normal selection path, and the
empty-dir / missing-dir / cancel boundaries.
| -rw-r--r-- | early-init.el | 67 | ||||
| -rw-r--r-- | modules/chrono-tools.el | 109 | ||||
| -rw-r--r-- | modules/system-defaults.el | 9 | ||||
| -rw-r--r-- | modules/user-constants.el | 24 | ||||
| -rw-r--r-- | tests/test-chrono-tools-tmr-sound.el | 130 | ||||
| -rw-r--r-- | todo.org | 112 |
6 files changed, 310 insertions, 141 deletions
diff --git a/early-init.el b/early-init.el index 49a9da92..50a1de1d 100644 --- a/early-init.el +++ b/early-init.el @@ -81,10 +81,18 @@ ;; --------------------------- Use Online Repos Flag --------------------------- ;; set to nil to only use localrepo and local elpa-mirrors (see script directory) -(defvar cj/use-online-repos t +(defgroup cj nil + "Craig's personal Emacs configuration." + :group 'convenience + :prefix "cj/") + +(defcustom cj/use-online-repos t "Whether to use online package repositories in addition to local repos. -When t, online repos are added but .localrepo has highest priority (200). -Set to nil to use only local repos.") +When non-nil, online repos are added but .localrepo has highest priority +(see `cj/package-priority-localrepo' below). Set to nil to use only +local repos." + :type 'boolean + :group 'cj) ;; ---------------------------- Startup Performance ---------------------------- ;; increases garbage collection threshold and turns off file-name-handler @@ -144,40 +152,73 @@ early-init.el.") (setq package-archives nil) ;; package-archives will be added below +;; Named priorities for package archives. Local-first: project-pinned +;; .localrepo wins outright, then the local ELPA mirrors (kept on disk +;; via the elpa-mirror scripts), then the online archives in fallback +;; positions. Within each tier the order is gnu > nongnu > melpa > +;; melpa-stable, matching the trust ranking we want for resolution. +(defconst cj/package-priority-localrepo 200 + "Priority for the project-pinned .localrepo archive (highest).") +(defconst cj/package-priority-mirror-gnu 125 + "Priority for the local GNU ELPA mirror.") +(defconst cj/package-priority-mirror-nongnu 120 + "Priority for the local NonGNU ELPA mirror.") +(defconst cj/package-priority-mirror-melpa 115 + "Priority for the local MELPA mirror.") +(defconst cj/package-priority-mirror-melpa-stable 100 + "Priority for the local stable MELPA mirror.") +(defconst cj/package-priority-online-gnu 25 + "Priority for the online GNU ELPA archive.") +(defconst cj/package-priority-online-nongnu 20 + "Priority for the online NonGNU ELPA archive.") +(defconst cj/package-priority-online-melpa 15 + "Priority for the online MELPA archive.") +(defconst cj/package-priority-online-melpa-stable 5 + "Priority for the online stable MELPA archive (lowest).") + ;; LOCAL REPOSITORY (packages in version control) (when (file-accessible-directory-p localrepo-location) (add-to-list 'package-archives (cons "localrepo" localrepo-location) t) - (add-to-list 'package-archive-priorities '("localrepo" . 200))) + (add-to-list 'package-archive-priorities + (cons "localrepo" cj/package-priority-localrepo))) ;; LOCAL REPOSITORY ELPA MIRRORS (when (file-accessible-directory-p elpa-mirror-gnu-location) (add-to-list 'package-archives (cons "gnu-local" elpa-mirror-gnu-location) t) - (add-to-list 'package-archive-priorities '("gnu-local" . 125))) + (add-to-list 'package-archive-priorities + (cons "gnu-local" cj/package-priority-mirror-gnu))) (when (file-accessible-directory-p elpa-mirror-nongnu-location) (add-to-list 'package-archives (cons "nongnu-local" elpa-mirror-nongnu-location) t) - (add-to-list 'package-archive-priorities '("nongnu-local" . 120))) + (add-to-list 'package-archive-priorities + (cons "nongnu-local" cj/package-priority-mirror-nongnu))) (when (file-accessible-directory-p elpa-mirror-melpa-location) (add-to-list 'package-archives (cons "melpa-local" elpa-mirror-melpa-location) t) - (add-to-list 'package-archive-priorities '("melpa-local" . 115))) + (add-to-list 'package-archive-priorities + (cons "melpa-local" cj/package-priority-mirror-melpa))) (when (file-accessible-directory-p elpa-mirror-stable-melpa-location) (add-to-list 'package-archives (cons "melpa-stable-local" elpa-mirror-stable-melpa-location) t) - (add-to-list 'package-archive-priorities '("melpa-stable-local" . 100))) + (add-to-list 'package-archive-priorities + (cons "melpa-stable-local" cj/package-priority-mirror-melpa-stable))) ;; ONLINE REPOSITORIES ;; Added regardless of network status. If offline, package operations fail gracefully. -;; .localrepo has highest priority (200), so reproducible installs work offline. +;; .localrepo has highest priority, so reproducible installs work offline. (when cj/use-online-repos (add-to-list 'package-archives '("gnu" . "https://elpa.gnu.org/packages/") t) - (add-to-list 'package-archive-priorities '("gnu" . 25)) + (add-to-list 'package-archive-priorities + (cons "gnu" cj/package-priority-online-gnu)) (add-to-list 'package-archives '("nongnu" . "https://elpa.nongnu.org/nongnu/") t) - (add-to-list 'package-archive-priorities '("nongnu" . 20)) + (add-to-list 'package-archive-priorities + (cons "nongnu" cj/package-priority-online-nongnu)) (add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t) - (add-to-list 'package-archive-priorities '("melpa" . 15)) + (add-to-list 'package-archive-priorities + (cons "melpa" cj/package-priority-online-melpa)) (add-to-list 'package-archives '("melpa-stable" . "https://stable.melpa.org/packages/") t) - (add-to-list 'package-archive-priorities '("melpa-stable" . 5))) + (add-to-list 'package-archive-priorities + (cons "melpa-stable" cj/package-priority-online-melpa-stable))) ;; Initialize package system (package-initialize) diff --git a/modules/chrono-tools.el b/modules/chrono-tools.el index 37a065f2..8b8c2072 100644 --- a/modules/chrono-tools.el +++ b/modules/chrono-tools.el @@ -20,26 +20,6 @@ :commands time-zones :bind ("M-S-c" . time-zones)) ;; was M-C, overrides capitalize-word -;; Commented out old world-clock config while testing time-zone package above -;; (use-package time -;; :ensure nil ;; built-in -;; :defer 0.5 -;; :bind ("C-x c" . world-clock) -;; :config -;; (setq world-clock-list -;; '(("Pacific/Honolulu" " Honolulu") -;; ("America/Los_Angeles" " San Francisco, LA") -;; ("America/Chicago" " Chicago, New Orleans") -;; ("America/New_York" " New York, Boston") -;; ("Etc/UTC" " UTC =================") -;; ("Europe/London" " London, Lisbon") -;; ("Europe/Paris" " Paris, Berlin, Rome") -;; ("Europe/Athens" " Athens, Istanbul, Moscow") -;; ("Asia/Kolkata" " India") -;; ("Asia/Shanghai" " Shanghai, Singapore") -;; ("Asia/Tokyo" " Tokyo, Seoul"))) -;; (setq world-clock-time-format " %a, %d %b @ %I:%M %p %Z")) - (use-package calendar :ensure nil ;; built-in :defer 0.5 @@ -56,50 +36,16 @@ ;; ------------------------------------ TMR ------------------------------------ -(defun cj/tmr-select-sound-file () - "Select a sound file from `sounds-dir' to use for tmr timers. +(defconst cj/tmr--audio-extensions + '("mp3" "m4a" "ogg" "opus" "wav" "flac" "aac") + "Audio file extensions offered to `cj/tmr-select-sound-file'.") -Present all audio files in the sounds directory and set the chosen file as -`tmr-sound-file'. Use \\[universal-argument] to reset to the default sound." - (interactive) - (if current-prefix-arg - ;; With prefix arg, reset to default - (progn - (setq tmr-sound-file notification-sound) - (message "Timer sound reset to default: %s" - (file-name-nondirectory notification-sound))) - ;; Otherwise, select a new sound - (let* ((audio-extensions '("mp3" "m4a" "ogg" "opus" "wav" "flac" "aac")) - (extension-regex (concat "\\." (regexp-opt audio-extensions t) "$")) - (sound-files (when (file-directory-p sounds-dir) - (directory-files sounds-dir nil extension-regex))) - (current-file (when (and tmr-sound-file (file-exists-p tmr-sound-file)) - (file-name-nondirectory tmr-sound-file))) - (selected-file (when sound-files - (completing-read - (format "Select timer sound%s: " - (if current-file - (format " (current: %s)" current-file) - "")) - sound-files - nil - t - nil - nil - current-file)))) ; Default to current file - (cond - ((not (file-directory-p sounds-dir)) - (message "Sounds directory does not exist: %s" sounds-dir)) - ((null sound-files) - (message "No audio files found in %s" sounds-dir)) - (selected-file - (setq tmr-sound-file (expand-file-name selected-file sounds-dir)) - (when (equal tmr-sound-file notification-sound) - (message "Timer sound set to default: %s" selected-file)) - (unless (equal tmr-sound-file notification-sound) - (message "Timer sound set to: %s" selected-file))) - (t - (message "No file selected")))))) +(defun cj/tmr--available-sound-files () + "Return a list of audio filenames in `sounds-dir', or nil if none. +Returns nil if `sounds-dir' does not exist." + (when (and (boundp 'sounds-dir) (file-directory-p sounds-dir)) + (let ((regex (concat "\\." (regexp-opt cj/tmr--audio-extensions t) "$"))) + (directory-files sounds-dir nil regex)))) (defun cj/tmr-reset-sound-to-default () "Reset the tmr sound file to the default notification sound." @@ -108,6 +54,43 @@ Present all audio files in the sounds directory and set the chosen file as (message "Timer sound reset to default: %s" (file-name-nondirectory notification-sound))) +(defun cj/tmr-select-sound-file () + "Select a sound file from `sounds-dir' to use for tmr timers. + +Present all audio files in the sounds directory and set the chosen file as +`tmr-sound-file'. Use \\[universal-argument] to reset to the default sound." + (interactive) + (cond + (current-prefix-arg + (cj/tmr-reset-sound-to-default)) + ((not (and (boundp 'sounds-dir) (file-directory-p sounds-dir))) + (message "Sounds directory does not exist: %s" + (if (boundp 'sounds-dir) sounds-dir "<unset>"))) + (t + (let ((sound-files (cj/tmr--available-sound-files))) + (cond + ((null sound-files) + (message "No audio files found in %s" sounds-dir)) + (t + (let* ((current-file (when (and tmr-sound-file + (file-exists-p tmr-sound-file)) + (file-name-nondirectory tmr-sound-file))) + (selected-file + (completing-read + (format "Select timer sound%s: " + (if current-file + (format " (current: %s)" current-file) + "")) + sound-files nil t nil nil current-file))) + (cond + ((or (null selected-file) (string-empty-p selected-file)) + (message "No file selected")) + (t + (setq tmr-sound-file (expand-file-name selected-file sounds-dir)) + (if (equal tmr-sound-file notification-sound) + (message "Timer sound set to default: %s" selected-file) + (message "Timer sound set to: %s" selected-file))))))))))) + (use-package tmr :defer 0.5 :init diff --git a/modules/system-defaults.el b/modules/system-defaults.el index 6fbec003..d0b9f835 100644 --- a/modules/system-defaults.el +++ b/modules/system-defaults.el @@ -16,13 +16,14 @@ (require 'server) (require 'bookmark) -;; Loaded earlier in init.el +;; `host-environment' and `user-constants' are loaded earlier in init.el, +;; so they are available at runtime when this module loads. The +;; `eval-when-compile' forms here are byte-compile hints to silence +;; free-variable / free-function warnings when this module is compiled +;; in isolation; no runtime requires are needed. (eval-when-compile (require 'host-environment)) (eval-when-compile (require 'user-constants)) -;; Function in system-utils.el; autoload to avoid requiring it here. -(autoload 'env-bsd-p "host-environment" nil t) - ;; -------------------------- Native Comp Preferences -------------------------- (with-eval-after-load 'comp-run diff --git a/modules/user-constants.el b/modules/user-constants.el index 21e141a5..2cc4a50c 100644 --- a/modules/user-constants.el +++ b/modules/user-constants.el @@ -22,12 +22,15 @@ ;; -------------------------------- Debug Toggle ------------------------------- -(defvar cj/debug-modules nil +(defcustom cj/debug-modules nil "List of modules with debug functions enabled. -Possible values: org-agenda, mail, chime, etc. Set to t to enable all debug modules. -Example: (setq cj/debug-modules '(org-agenda mail)) - (setq cj/debug-modules t) ; Enable all") +Set to a list of module symbols (e.g. \\='(org-agenda mail)) to enable +debug output for those modules only. Possible values: org-agenda, +mail, chime, etc." + :type '(choice (const :tag "All modules" t) + (repeat :tag "Specific modules" symbol)) + :group 'cj) ;; -------------------------------- Contact Info ------------------------------- @@ -71,8 +74,17 @@ the regular transcription pipeline.") (defconst emacs-early-init-file (expand-file-name "early-init.el" user-emacs-directory) "The location of Emacs's early init file.") -(defconst user-home-dir (getenv "HOME") - "The user's home directory per the environment variable.") +;; Canonical definition of `user-home-dir' lives in `early-init.el' so +;; the package-archive paths there can reference it during package +;; bootstrap. The `defvar' below is a no-op at runtime (early-init's +;; defconst wins, defvar doesn't reassign a bound symbol) -- it exists +;; only so this module loads / byte-compiles standalone, when +;; early-init hasn't run. If you ever change the expression here, keep +;; it identical to early-init.el's. +(defvar user-home-dir (getenv "HOME") + "The user's home directory per the environment variable. +Canonical definition in early-init.el; this form is a standalone-load +fallback only.") (defconst books-dir (expand-file-name "sync/books/" user-home-dir) "The location of book files for CalibreDB.") diff --git a/tests/test-chrono-tools-tmr-sound.el b/tests/test-chrono-tools-tmr-sound.el new file mode 100644 index 00000000..2f7dbbab --- /dev/null +++ b/tests/test-chrono-tools-tmr-sound.el @@ -0,0 +1,130 @@ +;;; test-chrono-tools-tmr-sound.el --- Tests for tmr sound selection -*- lexical-binding: t; -*- + +;;; Commentary: +;; Tests for `cj/tmr-select-sound-file' and its helpers in chrono-tools.el. +;; The prefix-arg branch delegates to `cj/tmr-reset-sound-to-default' so +;; there's no duplicated reset logic to test twice. + +;;; Code: + +(require 'ert) +(require 'cl-lib) + +(add-to-list 'load-path (expand-file-name "modules" user-emacs-directory)) + +;; Stub vars that chrono-tools.el assumes are bound at runtime. +(defvar sounds-dir nil) +(defvar tmr-sound-file nil) +(defvar notification-sound "/tmp/notify.mp3") + +(require 'chrono-tools) + +;; -------------------------------- helpers + +(defun test-chrono-tools--with-sounds-dir (files fn) + "Create a temp `sounds-dir' containing FILES, call FN, clean up." + (let* ((dir (make-temp-file "test-chrono-tools-tmr-" t)) + (sounds-dir dir)) + (unwind-protect + (progn + (dolist (f files) + (with-temp-file (expand-file-name f dir) (insert "x"))) + (funcall fn dir)) + (when (file-exists-p dir) (delete-directory dir t))))) + +;; -------------------------------- available-sound-files + +(ert-deftest test-chrono-tools-available-sounds-normal () + "Normal: returns audio files in `sounds-dir' matching the extension list." + (test-chrono-tools--with-sounds-dir + '("a.mp3" "b.opus" "readme.txt") + (lambda (_dir) + (let ((files (cj/tmr--available-sound-files))) + (should (member "a.mp3" files)) + (should (member "b.opus" files)) + (should-not (member "readme.txt" files)))))) + +(ert-deftest test-chrono-tools-available-sounds-empty-dir () + "Boundary: empty `sounds-dir' returns nil." + (test-chrono-tools--with-sounds-dir + '() + (lambda (_dir) + (should-not (cj/tmr--available-sound-files))))) + +(ert-deftest test-chrono-tools-available-sounds-no-dir () + "Boundary: missing `sounds-dir' returns nil." + (let ((sounds-dir (expand-file-name (format "missing-%s" (random)) "/tmp"))) + (should-not (cj/tmr--available-sound-files)))) + +;; -------------------------------- reset-sound-to-default + +(ert-deftest test-chrono-tools-reset-sets-default () + "Reset assigns `notification-sound' to `tmr-sound-file'." + (let ((tmr-sound-file "/tmp/other.mp3") + (notification-sound "/tmp/the-default.mp3")) + (cj/tmr-reset-sound-to-default) + (should (equal tmr-sound-file "/tmp/the-default.mp3")))) + +;; -------------------------------- select-sound-file + +(ert-deftest test-chrono-tools-select-with-prefix-arg-resets () + "Prefix arg delegates to reset, no completing-read prompt." + (let ((current-prefix-arg '(4)) + (tmr-sound-file "/tmp/other.mp3") + (notification-sound "/tmp/the-default.mp3") + (prompted nil)) + (cl-letf (((symbol-function 'completing-read) + (lambda (&rest _) (setq prompted t) ""))) + (cj/tmr-select-sound-file)) + (should-not prompted) + (should (equal tmr-sound-file "/tmp/the-default.mp3")))) + +(ert-deftest test-chrono-tools-select-normal-sets-selected-file () + "Normal: pick a file, `tmr-sound-file' updates to its full path." + (test-chrono-tools--with-sounds-dir + '("alpha.mp3" "beta.opus") + (lambda (dir) + (let ((current-prefix-arg nil) + (tmr-sound-file nil) + (notification-sound "/tmp/the-default.mp3")) + (cl-letf (((symbol-function 'completing-read) + (lambda (&rest _) "alpha.mp3"))) + (cj/tmr-select-sound-file)) + (should (equal tmr-sound-file + (expand-file-name "alpha.mp3" dir))))))) + +(ert-deftest test-chrono-tools-select-boundary-empty-dir () + "Boundary: empty sounds dir leaves `tmr-sound-file' unchanged." + (test-chrono-tools--with-sounds-dir + '() + (lambda (_dir) + (let ((current-prefix-arg nil) + (tmr-sound-file "/tmp/keep-me.mp3") + (notification-sound "/tmp/the-default.mp3")) + (cj/tmr-select-sound-file) + (should (equal tmr-sound-file "/tmp/keep-me.mp3")))))) + +(ert-deftest test-chrono-tools-select-boundary-missing-dir () + "Boundary: missing sounds dir leaves `tmr-sound-file' unchanged." + (let ((current-prefix-arg nil) + (sounds-dir (expand-file-name (format "missing-%s" (random)) "/tmp")) + (tmr-sound-file "/tmp/keep-me.mp3") + (notification-sound "/tmp/the-default.mp3")) + (cj/tmr-select-sound-file) + (should (equal tmr-sound-file "/tmp/keep-me.mp3")))) + +(ert-deftest test-chrono-tools-select-boundary-cancel-returns-no-change () + "Boundary: empty completion result leaves `tmr-sound-file' unchanged." + (test-chrono-tools--with-sounds-dir + '("alpha.mp3") + (lambda (_dir) + (let ((current-prefix-arg nil) + (tmr-sound-file "/tmp/keep-me.mp3") + (notification-sound "/tmp/the-default.mp3")) + (cl-letf (((symbol-function 'completing-read) + (lambda (&rest _) ""))) + (cj/tmr-select-sound-file)) + (should (equal tmr-sound-file "/tmp/keep-me.mp3")))))) + +(provide 'test-chrono-tools-tmr-sound) +;;; test-chrono-tools-tmr-sound.el ends here @@ -1022,32 +1022,36 @@ Expected outcome: - Add a small test or validation helper around the computed package policy if package bootstrap is extracted. -**** TODO [#C] Consolidate duplicate =user-home-dir= constant :cleanup: - -=user-home-dir= is defined identically in =early-init.el:116-117= and -=modules/user-constants.el:74-75=. early-init.el defines it first -because =package-archive= paths reference it, then user-constants.el -redefines it. Both definitions silently drift if one is edited. -Consolidate: keep early-init.el's definition (load-order requirement) -and reference it from user-constants.el with a comment explaining why -the constant lives in early-init. - -**** TODO [#C] Drop redundant =eval-when-compile= alongside autoload in =system-defaults.el= :cleanup: - -=modules/system-defaults.el:20-24= wraps host-environment and -user-constants under =eval-when-compile= require forms, then line 24 -also declares =(autoload 'env-bsd-p "host-environment" nil t)=. The -=eval-when-compile= is redundant given the autoload; the mixed pattern -suggests one of the two requires was added without removing the other. -Pick one boundary and document it. - -**** TODO [#C] Convert =cj/debug-modules= and =cj/use-online-repos= to =defcustom= :refactor: - -These are user-facing toggles defined as =defvar= in -=modules/user-constants.el:25-30= and =early-init.el:84-87=. Users -cannot discover or change them through =M-x customize=. Convert to -=defcustom= with =:type=, =:group=, and a docstring so they show up in -the customization UI alongside other config knobs. +**** 2026-05-16 Sat @ 02:34:22 -0500 Consolidated user-home-dir into early-init as canonical + +Canonical defconst in =early-init.el= kept (the package-archive paths +need it during package bootstrap, before normal modules load). +=modules/user-constants.el= switched to a `defvar` with the identical +=(getenv "HOME")= expression and a comment explaining the pattern: +defvar is a no-op at runtime (early-init's defconst wins, defvar +doesn't reassign a bound symbol), but it lets the module load / +byte-compile standalone when early-init hasn't run. Drift risk is +mitigated by both expressions being =(getenv "HOME")= literally; the +comment flags the requirement to keep them identical. + +**** 2026-05-16 Sat @ 02:34:22 -0500 Dropped redundant autoload alongside compile-time require in system-defaults.el + +Kept the =eval-when-compile= requires for =host-environment= and +=user-constants= (they silence free-variable / free-function warnings +during byte-compile in isolation) and dropped the +=(autoload 'env-bsd-p ...)= line — both modules are loaded earlier in +init.el at runtime, and the eval-when-compile already exposes +=env-bsd-p= to the byte-compiler. Added a comment documenting the +chosen boundary. + +**** 2026-05-16 Sat @ 02:34:22 -0500 Converted cj/debug-modules and cj/use-online-repos to defcustom + +Both toggles now live as =defcustom= with explicit =:type= and +=:group 'cj=. =cj/debug-modules='s type is the natural choice form: +either =t= (all modules) or a list of module symbols. +=cj/use-online-repos='s type is boolean. Added a top-level +=(defgroup cj ...)= in early-init.el so the group exists for both, +plus the package-priority constants below it. **** TODO [#B] Surface custom-file redirection so accidental Customize use isn't silent :safety: @@ -1061,35 +1065,33 @@ Customize buffer loses those changes on Emacs exit. Either surface a =custom-file= to a versioned path under =data/= so the discard is at least durable for the session. -**** TODO [#C] Name and document package archive priorities :refactor: - -=early-init.el:149-180= assigns priorities as magic numbers -(localrepo=200, gnu-local=125, melpa-local=115, online gnu=25, -melpa=15, melpa-stable=5). Future maintainers cannot answer "why is -gnu-local 125 but melpa-local 115?" without re-deriving the -hierarchy. Define named constants -(=cj/package-priority-local-mirror=, =cj/package-priority-online=, -etc.) at the top of early-init.el with a short comment explaining the -local-first ordering. - -**** TODO [#C] Remove dead world-clock block in =chrono-tools.el= :cleanup: - -Lines 23-41 carry a 19-line commented-out =use-package time= block -("old world-clock config while testing time-zone package above") left -over from the time-zones migration. Either delete it or replace with -a one-line breadcrumb noting that =time-zones= superseded it. Dead -commented code lengthens the file with no value to future readers. - -**** TODO [#C] Add coverage for =cj/tmr-select-sound-file= in =chrono-tools.el= :tests: - -The two TMR sound-selection helpers (=cj/tmr-select-sound-file= and -=cj/tmr-reset-sound-to-default=) currently have no tests. The select -function has nontrivial branching across the prefix-arg path, the -missing-directory path, the empty-directory path, the cancel path, -and the "default selected" message variant. Refactor the -prefix-arg branch to call =cj/tmr-reset-sound-to-default= directly -so the duplication collapses, then add Normal/Boundary/Error tests -against the resulting helper. +**** 2026-05-16 Sat @ 02:34:22 -0500 Named the package archive priorities in early-init.el + +Nine =defconst= entries replace the magic numbers: +=cj/package-priority-localrepo= (200) for the project-pinned repo, +four =cj/package-priority-mirror-*= entries for the local ELPA +mirrors (125 / 120 / 115 / 100), four =cj/package-priority-online-*= +entries for the online archives (25 / 20 / 15 / 5). A header comment +above the block explains the local-first ordering and the +gnu > nongnu > melpa > melpa-stable trust ranking within each tier. + +**** 2026-05-16 Sat @ 02:34:22 -0500 Deleted dead world-clock block in chrono-tools.el + +The 19-line commented-out =use-package time= block is gone. The +=time-zones= use-package directly above it is the active replacement; +git history preserves the old config if anyone needs to dig it back up. + +**** 2026-05-16 Sat @ 02:34:22 -0500 Added coverage for cj/tmr-select-sound-file with a pre-test refactor + +The prefix-arg branch now delegates to =cj/tmr-reset-sound-to-default= +directly (single source for the reset path). Extracted a pure helper +=cj/tmr--available-sound-files= so the directory scan is testable +without driving =completing-read=. =tests/test-chrono-tools-tmr-sound.el= +covers Normal / Boundary / Error: available-sounds against a populated +dir, empty dir, missing dir; reset path; select with prefix-arg +(delegates to reset, no prompt); select normal (picks a file); select +boundary paths for empty dir, missing dir, cancel (empty completion). +9 tests, all green. *** DOING [#B] Harden custom editing utility modules :harden: |
