aboutsummaryrefslogtreecommitdiff
path: root/chime.el
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-05-05 12:20:29 -0500
committerCraig Jennings <c@cjennings.net>2026-05-05 12:20:29 -0500
commit68877f04c2ceb569ae5cd74b8303b84b36ced1c5 (patch)
tree6ca0e67785c759bae0687728798e8c7c4b164841 /chime.el
parent44831f8587947212f2df8c38e81a3c1b6fa588fc (diff)
downloadchime-68877f04c2ceb569ae5cd74b8303b84b36ced1c5.tar.gz
chime-68877f04c2ceb569ae5cd74b8303b84b36ced1c5.zip
fix: validate numeric defcustoms at customize-time
Six numeric settings are declared as integers but were read straight into arithmetic and timer math. A bad value (string, negative number, nil where nil isn't supported) used to slip past the defcustom and surface as a timer error or `arith-error' deep in a callback, instead of as a configuration problem at the moment the user set it. I added `chime--validate-integer-setting' as a small shared helper and wired a `:set' on each of the affected defcustoms: - `chime-modeline-lookahead-minutes' — integer >= 0 (0 disables) - `chime-tooltip-lookahead-hours' — integer >= 1 - `chime-modeline-tooltip-max-events' — integer >= 1 or nil (show all) - `chime-day-wide-advance-notice' — integer >= 0 or nil (same-day only) - `chime-max-consecutive-failures' — integer >= 0 (0 disables warnings) - `chime-validation-max-retries' — integer >= 0 (0 = fail immediately) The constraints follow each docstring's stated intent. The helper signals `user-error', so `customize-set-variable' surfaces it as a config problem rather than a generic error trace. Tests: 22 cases in `tests/test-chime-numeric-defcustom-setters.el' — five direct on the helper plus each defcustom's accept/reject paths through `customize-set-variable'.
Diffstat (limited to 'chime.el')
-rw-r--r--chime.el48
1 files changed, 42 insertions, 6 deletions
diff --git a/chime.el b/chime.el
index 3dafc48..ee08f69 100644
--- a/chime.el
+++ b/chime.el
@@ -78,6 +78,24 @@
"Chime customization options."
:group 'org)
+(defun chime--validate-integer-setting (symbol value min allow-nil)
+ "Reject bad integer values for SYMBOL at customize time.
+VALUE is what the user is trying to set. MIN is the inclusive floor.
+When ALLOW-NIL is non-nil, nil is accepted; otherwise nil fails like any
+other non-integer. Returns VALUE on success so the caller can chain into
+`set-default'. The error is a `user-error' so `customize-set-variable'
+surfaces it as a configuration problem rather than a generic error."
+ (cond
+ ((and allow-nil (null value)) value)
+ ((not (integerp value))
+ (user-error "%s must be %s, got: %S"
+ symbol
+ (if allow-nil "nil or an integer" "an integer")
+ value))
+ ((< value min)
+ (user-error "%s must be >= %d, got: %d" symbol min value))
+ (t value)))
+
(defcustom chime-alert-intervals '((10 . medium) (0 . high))
"Alert intervals with severity levels for upcoming events.
Each element is a cons cell (MINUTES . SEVERITY) where:
@@ -311,7 +329,10 @@ Example: With value 1 and alert times \\='(\"08:00\"), you'll get:
:package-version '(chime . "0.6.0")
:group 'chime
:type '(choice (const :tag "Same day only" nil)
- (integer :tag "Days in advance")))
+ (integer :tag "Days in advance"))
+ :set (lambda (symbol value)
+ (chime--validate-integer-setting symbol value 0 t)
+ (set-default symbol value)))
(defcustom chime-tooltip-show-all-day-events t
"Whether to show all-day events in the tooltip.
@@ -350,7 +371,10 @@ Set to 0 to disable modeline display.
This setting only takes effect when `chime-enable-modeline' is non-nil."
:package-version '(chime . "0.6.0")
:group 'chime
- :type '(integer :tag "Minutes"))
+ :type '(integer :tag "Minutes")
+ :set (lambda (symbol value)
+ (chime--validate-integer-setting symbol value 0 nil)
+ (set-default symbol value)))
(defcustom chime-modeline-format " ⏰ %s"
"Format string for modeline display.
@@ -388,7 +412,10 @@ Note: larger values increase the `org-agenda-list' span in the async
subprocess, which may slow event checks for large org collections."
:package-version '(chime . "0.6.0")
:group 'chime
- :type '(integer :tag "Hours"))
+ :type '(integer :tag "Hours")
+ :set (lambda (symbol value)
+ (chime--validate-integer-setting symbol value 1 nil)
+ (set-default symbol value)))
(defcustom chime-modeline-tooltip-max-events 5
"Maximum number of events to show in modeline tooltip.
@@ -396,7 +423,10 @@ Set to nil to show all events within tooltip lookahead window."
:package-version '(chime . "0.6.0")
:group 'chime
:type '(choice (integer :tag "Maximum events")
- (const :tag "Show all" nil)))
+ (const :tag "Show all" nil))
+ :set (lambda (symbol value)
+ (chime--validate-integer-setting symbol value 1 t)
+ (set-default symbol value)))
(defcustom chime-modeline-no-events-text " ⏰"
"Text to display in modeline when no events are within lookahead window.
@@ -536,7 +566,10 @@ via `display-warning'. The counter resets on any successful check.
Set to 0 to disable failure warnings."
:package-version '(chime . "0.6.0")
:group 'chime
- :type 'integer)
+ :type 'integer
+ :set (lambda (symbol value)
+ (chime--validate-integer-setting symbol value 0 nil)
+ (set-default symbol value)))
(defcustom chime-debug nil
"Enable debug functions for troubleshooting chime behavior.
@@ -616,7 +649,10 @@ Set to 0 to show errors immediately without retrying.
Default is 3 retries (with 30-60s check intervals, this gives ~1.5-3 minutes
for org-agenda-files to be populated)."
:type 'integer
- :group 'chime)
+ :group 'chime
+ :set (lambda (symbol value)
+ (chime--validate-integer-setting symbol value 0 nil)
+ (set-default symbol value)))
(defvar chime-modeline-string nil
"Modeline string showing next upcoming event.")