diff options
| author | Craig Jennings <c@cjennings.net> | 2026-07-09 16:08:47 -0500 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-07-09 16:08:47 -0500 |
| commit | ce3a1014d929b94bd90cbc565608655d10d843bc (patch) | |
| tree | 029d13d83241fd5f6259f052aadcf0d429c9f46f | |
| parent | ad21a480cb4b833fba94339e8b9e13401e7c8873 (diff) | |
| download | chime-ce3a1014d929b94bd90cbc565608655d10d843bc.tar.gz chime-ce3a1014d929b94bd90cbc565608655d10d843bc.zip | |
fix: drop nil day counts before taking the minimum
chime--days-until-event maps over every timestamp on an event and keeps a day count only for the all-day ones. A timed timestamp maps to nil. An event carrying both kinds handed -min a list with a nil in it, which signals wrong-type-argument. An event with no all-day timestamp handed it an empty list, which signals too.
Both crash on every tick once chime-day-wide-advance-notice is on. The recurring failure walks the async counter up to the persistent-failure warning.
The map now runs through -non-nil, and an empty result returns nil, which the docstring already promised. I added a nil branch to chime--day-wide-notification-text so a nil count can't reach the = comparisons. The advance-notice window should already exclude an event with no all-day timestamp, so that branch is a guard rather than a live path.
| -rw-r--r-- | chime.el | 38 |
1 files changed, 24 insertions, 14 deletions
@@ -1310,20 +1310,26 @@ For timed events, checks if the time is today (past or future)." (defun chime--days-until-event (all-times) "Calculate minimum days until the soonest all-day timestamp in ALL-TIMES. ALL-TIMES is a list of (TIMESTAMP-STR . TIME-OBJECT) cons cells. -Returns integer days (ceiling), or nil if no all-day timestamps found." - (let ((now (current-time))) - (-min - (--map - (when-let* ((timestamp-str (car it)) - (is-all-day (not (chime--has-timestamp timestamp-str))) - (parsed (org-parse-time-string timestamp-str)) - (year (nth 5 parsed)) - (month (nth 4 parsed)) - (day (nth 3 parsed))) - (let* ((event-time (encode-time 0 0 0 day month year)) - (seconds-until (time-subtract event-time now))) - (ceiling (/ (float-time seconds-until) 86400.0)))) - all-times)))) +Returns integer days (ceiling), or nil if no all-day timestamps found. + +A timed timestamp contributes no day count, so an event mixing timed and +all-day timestamps yields nils that must be dropped before `-min' sees +them. An event with no all-day timestamp at all leaves nothing to +minimize, hence the nil return the docstring promises." + (let* ((now (current-time)) + (days (-non-nil + (--map + (when-let* ((timestamp-str (car it)) + (is-all-day (not (chime--has-timestamp timestamp-str))) + (parsed (org-parse-time-string timestamp-str)) + (year (nth 5 parsed)) + (month (nth 4 parsed)) + (day (nth 3 parsed))) + (let* ((event-time (encode-time 0 0 0 day month year)) + (seconds-until (time-subtract event-time now))) + (ceiling (/ (float-time seconds-until) 86400.0)))) + all-times)))) + (when days (-min days)))) (defun chime--day-wide-notification-text (event) "Generate notification text for day-wide EVENT. @@ -1338,6 +1344,10 @@ Handles both same-day events and advance notices." (is-advance-notice (let ((days-until (chime--days-until-event (chime--event-times event)))) (cond + ;; No all-day timestamp means no day count to report. The + ;; advance-notice window should have excluded such an event, so + ;; this is a belt-and-braces guard against a nil reaching `='. + ((null days-until) (format "%s is due or scheduled today" title)) ((= days-until 1) (format "%s is tomorrow" title)) ((= days-until 2) (format "%s is in 2 days" title)) (t (format "%s is in %d days" title days-until))))) |
