From 3019a33d391912120a78cad43a49eb34c4a1d044 Mon Sep 17 00:00:00 2001 From: Craig Jennings Date: Tue, 5 May 2026 12:39:55 -0500 Subject: refactor!: collapse six filter defcustoms into include/exclude alists MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Six per-axis filter variables (keyword/tags/predicate × whitelist/blacklist) were carrying parallel structure for what's really one decision: include events that look like X, exclude events that look like Y. I merged them into two alists, `chime-include-filters' and `chime-exclude-filters', each keyed by axis (`keywords', `tags', `predicates'). Default for `chime-exclude-filters' keeps the same out-of-the-box behavior — done items and declined Google Calendar invites stay filtered: ((predicates . (chime-done-keywords-predicate chime-declined-events-predicate))) Implementation: one shared `chime--filter-predicates' helper that walks the alist and emits a marker-taking predicate per non-empty axis. The public callers — now `chime--apply-include-filters' and `chime--apply-exclude-filters' — wrap that helper with `-orfn'-then-`-filter' and `-orfn'-then-`-remove' respectively. The async-environment regex injection list shrank from six names to two, and the debug config dump in chime-debug.el follows. The terminology shift (whitelist/blacklist → include/exclude) drops loaded language for descriptive intent. The internal helpers and the public function names all moved together. Tests: 700-ish lines across five test files (test-chime-apply-whitelist, test-chime-apply-blacklist, test-chime-whitelist-blacklist-conflicts, test-chime-environment-regex, test-chime-declined-events-predicate) were rewritten to bind the new alists. The dedup-conflict tests still exercise the same precedence rule (exclude wins on overlap). README's filtering section was rewritten end-to-end with new examples. Migration: (setq chime-keyword-whitelist '("TODO")) ;; -> (setq chime-include-filters '((keywords . ("TODO")))) (setq chime-predicate-blacklist '(my-pred)) ;; -> (setq chime-exclude-filters '((predicates . (my-pred)))) This brings the consolidation pass to 37 -> 29 defcustoms, the target from .ai/settings-consolidation.org. --- README.org | 113 +++++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 68 insertions(+), 45 deletions(-) (limited to 'README.org') diff --git a/README.org b/README.org index fd8081c..1a30644 100644 --- a/README.org +++ b/README.org @@ -79,13 +79,14 @@ The quickest way to try it out: ;; Notification settings (setq chime-notification-title "Reminder") - ;; Don't filter by TODO keywords - notify for all events - (setq chime-keyword-whitelist nil) - (setq chime-keyword-blacklist nil) + ;; Filtering — leave nil to notify for everything that isn't excluded + (setq chime-include-filters nil) - ;; Only notify for non-done items - (setq chime-predicate-blacklist - '(chime-done-keywords-predicate)) + ;; Default exclude rules: skip done items and declined invitations. + ;; (Both predicates ship with chime; this is the package default.) + (setq chime-exclude-filters + '((predicates . (chime-done-keywords-predicate + chime-declined-events-predicate)))) ;; Enable chime-mode automatically (chime-mode 1)) @@ -570,70 +571,94 @@ For maximum modeline space savings: *** Filtering -#+BEGIN_SRC elisp -;; Only notify for specific TODO keywords -(setq chime-keyword-whitelist '("TODO" "NEXT")) +Two alists control which events trigger notifications: +=chime-include-filters= (must match) and =chime-exclude-filters= (must +not match). Each takes the same shape: -;; Never notify for these keywords -(setq chime-keyword-blacklist '("DONE" "CANCELLED")) +#+BEGIN_SRC elisp +'((keywords . ("TODO" "NEXT")) ; org TODO keywords + (tags . ("work" "urgent")) ; org tags + (predicates . (my-predicate-fn))) ; functions taking a marker +#+END_SRC -;; Only notify for specific org tags -(setq chime-tags-whitelist '("important")) +When =chime-include-filters= is nil (the default), every event passes the +include phase. When it's set, an event must match at least one listed +value in any one entry. =chime-exclude-filters= then drops anything +matching any of its entries. -;; Never notify for these org-tags -(setq chime-tags-blacklist '("someday")) +#+BEGIN_SRC elisp +;; Only notify for specific TODO keywords and tags +(setq chime-include-filters + '((keywords . ("TODO" "NEXT")) + (tags . ("important")))) + +;; Never notify for these keywords or tags +(setq chime-exclude-filters + '((keywords . ("DONE" "CANCELLED")) + (tags . ("someday")) + (predicates . (chime-done-keywords-predicate + chime-declined-events-predicate)))) #+END_SRC -**** Whitelist and Blacklist Precedence +**** Include and Exclude Precedence -If the same keyword or tag appears in both a whitelist and blacklist, the *blacklist wins* and the item is filtered out. +If the same keyword or tag appears in both filters, the *exclude wins* +and the item is filtered out. Examples: -- Item with =TODO= keyword when =TODO= is in both ~chime-keyword-whitelist~ and ~chime-keyword-blacklist~ → *filtered out* (blacklist wins) -- Item with =:urgent:= tag when =urgent= is in both ~chime-tags-whitelist~ and ~chime-tags-blacklist~ → *filtered out* (blacklist wins) -- Item with whitelisted keyword but blacklisted tag → *filtered out* (blacklist wins) +- Item with =TODO= keyword when =TODO= appears under =keywords= in both filters → *filtered out* +- Item with =:urgent:= tag when =urgent= appears under =tags= in both filters → *filtered out* +- Item with an included keyword but an excluded tag → *filtered out* -Most users configure either whitelists or blacklists, not both. If you use both, ensure they don't overlap to avoid confusion. +Most users set one or the other, not both. If you set both, ensure +they don't overlap to avoid confusion. **** Custom Predicate Filtering -Keywords and tags cover most filtering needs, but sometimes you want logic they can't express — like silencing work events on weekends, or only getting notified about events in a specific file. +Keywords and tags cover most filtering needs, but sometimes you want +logic they can't express — like silencing work events on weekends, or +only getting notified about events in a specific file. -For filtering logic that goes beyond keywords and tags, you can write custom predicate functions. Each predicate receives an org marker (POM) and should return non-nil to match. Whitelisted predicates include events that match; blacklisted predicates exclude them. +For filtering logic that goes beyond keywords and tags, you can write +custom predicate functions. Each predicate receives an org marker +(POM) and should return non-nil to match. Predicates listed under the +=predicates= key in =chime-include-filters= include events that match; +predicates under =predicates= in =chime-exclude-filters= drop them. #+BEGIN_SRC elisp -;; Whitelist: only notify for events in work.org +;; Include: only notify for events in work.org (defun my-work-file-predicate (marker) "Match events that live in work.org." (string-match-p "work\\.org" (or (buffer-file-name (marker-buffer marker)) ""))) -(setq chime-predicate-whitelist '(my-work-file-predicate)) +(setq chime-include-filters + '((predicates . (my-work-file-predicate)))) -;; Blacklist: silence work events on weekends +;; Exclude: silence work events on weekends (defun my-weekend-work-silencer (marker) "Match work.org events on Saturday or Sunday." (and (memq (nth 6 (decode-time)) '(0 6)) (string-match-p "work\\.org" (or (buffer-file-name (marker-buffer marker)) "")))) -;; Blacklist: exclude events with a NO_NOTIFY property +;; Exclude: drop events with a NO_NOTIFY property (defun my-no-notify-predicate (marker) "Match events with a NO_NOTIFY property set." (org-entry-get marker "NO_NOTIFY")) -;; Whitelist: only notify for high-priority items -(defun my-priority-a-only (marker) - "Match events with a [#A] priority cookie." - (string= (org-entry-get marker "PRIORITY") "A")) - -(setq chime-predicate-blacklist - '(chime-done-keywords-predicate - my-weekend-work-silencer - my-no-notify-predicate)) +;; Compose multiple exclude predicates with chime's defaults +(setq chime-exclude-filters + '((predicates . (chime-done-keywords-predicate + chime-declined-events-predicate + my-weekend-work-silencer + my-no-notify-predicate)))) #+END_SRC -The built-in =chime-done-keywords-predicate= is in the blacklist by default, filtering out DONE items. +The built-in =chime-done-keywords-predicate= and +=chime-declined-events-predicate= ship in =chime-exclude-filters= by +default, filtering out done items and declined Google Calendar +invitations. *** All-Day Events @@ -856,13 +881,11 @@ If you have custom variables that need to be available in chime's async subproce ;; Notification settings (setq chime-notification-title "Reminder") - ;; Don't filter by TODO keywords - notify for all events - (setq chime-keyword-whitelist nil) - (setq chime-keyword-blacklist nil) - - ;; Only notify for non-done items - (setq chime-predicate-blacklist - '(chime-done-keywords-predicate)) + ;; Filtering — leave nil to notify for everything that isn't excluded + (setq chime-include-filters nil) + (setq chime-exclude-filters + '((predicates . (chime-done-keywords-predicate + chime-declined-events-predicate)))) ;; Enable chime-mode automatically (chime-mode 1)) @@ -1055,7 +1078,7 @@ It also monitors event loading timing and async process performance in the backg 1. Ensure files are in =org-agenda-files= 2. Verify timestamps have time components: =<2025-10-25 Sat 14:00>= not =<2025-10-25 Sat>= -3. Check filtering settings (keyword/tag whitelist/blacklist) +3. Check filtering settings (`chime-include-filters' / `chime-exclude-filters') 4. Timestamps support both 24-hour (=14:00=) and 12-hour (=2:00pm=, =2:00 PM=) formats *** Multiple Emacs Instances Producing Duplicate Notifications -- cgit v1.2.3