aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-05-05 12:39:55 -0500
committerCraig Jennings <c@cjennings.net>2026-05-05 12:39:55 -0500
commit3019a33d391912120a78cad43a49eb34c4a1d044 (patch)
tree4941d154529ce988bbdeb5e1929fa6cdea35f94a
parent26fabb22edfea51e8a686c179ab91d00a2ff0bc3 (diff)
downloadchime-3019a33d391912120a78cad43a49eb34c4a1d044.tar.gz
chime-3019a33d391912120a78cad43a49eb34c4a1d044.zip
refactor!: collapse six filter defcustoms into include/exclude alists
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.
-rw-r--r--README.org113
-rw-r--r--chime-debug.el6
-rw-r--r--chime.el169
-rw-r--r--tests/test-chime-apply-blacklist.el54
-rw-r--r--tests/test-chime-apply-whitelist.el50
-rw-r--r--tests/test-chime-declined-events-predicate.el12
-rw-r--r--tests/test-chime-environment-regex.el6
-rw-r--r--tests/test-chime-whitelist-blacklist-conflicts.el64
8 files changed, 228 insertions, 246 deletions
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
diff --git a/chime-debug.el b/chime-debug.el
index 5fe4c4e..cab4462 100644
--- a/chime-debug.el
+++ b/chime-debug.el
@@ -115,10 +115,8 @@ Shows all relevant settings, agenda files, and current state."
(chime--log-silently " chime-alert-intervals: %s" chime-alert-intervals)
(chime--log-silently " chime-notification-title: %s" chime-notification-title)
(chime--log-silently "\nFilters:")
- (chime--log-silently " chime-keyword-blacklist: %s" chime-keyword-blacklist)
- (chime--log-silently " chime-keyword-whitelist: %s" chime-keyword-whitelist)
- (chime--log-silently " chime-tags-blacklist: %s" chime-tags-blacklist)
- (chime--log-silently " chime-tags-whitelist: %s" chime-tags-whitelist)
+ (chime--log-silently " chime-include-filters: %s" chime-include-filters)
+ (chime--log-silently " chime-exclude-filters: %s" chime-exclude-filters)
(chime--log-silently "\nOrg agenda files (%d):" (length org-agenda-files))
(dolist (file org-agenda-files)
(chime--log-silently " - %s %s"
diff --git a/chime.el b/chime.el
index 9de2e72..de603ef 100644
--- a/chime.el
+++ b/chime.el
@@ -49,8 +49,8 @@
;; Notification intervals and severity can be customized globally via
;; `chime-alert-intervals'.
;;
-;; Filter notifications using `chime-keyword-whitelist' and
-;; `chime-keyword-blacklist' variables.
+;; Filter notifications using `chime-include-filters' and
+;; `chime-exclude-filters' alists (keys: keywords, tags, predicates).
;;
;; See README.org for complete documentation.
@@ -173,31 +173,22 @@ Note: Changes take effect after restarting chime-mode."
:type '(choice (const :tag "No icon" nil)
(file :tag "Icon file path")))
-(defcustom chime-keyword-whitelist nil
- "Receive notifications for these keywords only.
-Leave this variable blank if you do not want to filter anything."
- :package-version '(chime . "0.2.2")
- :group 'chime
- :type '(repeat string))
+(defcustom chime-include-filters nil
+ "Filters that INCLUDE events for notifications.
+An alist where each entry is (TYPE . VALUES):
-(defcustom chime-keyword-blacklist nil
- "Never receive notifications for these keywords."
- :package-version '(chime . "0.2.2")
- :group 'chime
- :type '(repeat string))
+ (keywords . (\"TODO\" \"MEETING\")) - org TODO keywords
+ (tags . (\"work\" \"urgent\")) - org tags
+ (predicates . (my-custom-predicate)) - functions taking a marker
-(defcustom chime-tags-whitelist nil
- "Receive notifications for these tags only.
-Leave this variable blank if you do not want to filter anything."
- :package-version '(chime . "0.3.1")
+When nil, all events pass. When set, an event must match at least one
+listed value in any one filter type to pass."
+ :package-version '(chime . "0.8.0")
:group 'chime
- :type '(repeat string))
-
-(defcustom chime-tags-blacklist nil
- "Never receive notifications for these tags."
- :package-version '(chime . "0.3.1")
- :group 'chime
- :type '(repeat string))
+ :type '(alist :key-type (choice (const keywords)
+ (const tags)
+ (const predicates))
+ :value-type (repeat sexp)))
(defcustom chime-display-time-format-string "%I:%M %p"
"Format string for displaying event times.
@@ -259,15 +250,6 @@ Examples for long:
(const long))
:value-type string))
-(defcustom chime-predicate-whitelist nil
- "Receive notifications for events matching these predicates only.
-Each function should take an event POM and return non-nil iff that event should
-trigger a notification. Leave this variable blank if you do not want to filter
-anything."
- :package-version '(chime . "0.5.0")
- :group 'chime
- :type '(repeat function))
-
(defcustom chime-additional-environment-regexes nil
"Additional regular expressions for async environment injection.
These regexes are provided to `async-inject-environment' before
@@ -276,15 +258,22 @@ running the async command to check notifications."
:group 'chime
:type '(repeat string))
-(defcustom chime-predicate-blacklist
- '(chime-done-keywords-predicate
- chime-declined-events-predicate)
- "Never receive notifications for events matching these predicates.
-Each function should take an event POM and return non-nil iff that event should
-not trigger a notification."
- :package-version '(chime . "0.5.0")
+(defcustom chime-exclude-filters
+ '((predicates . (chime-done-keywords-predicate
+ chime-declined-events-predicate)))
+ "Filters that EXCLUDE events from notifications.
+Same structure as `chime-include-filters'. An event matching ANY value
+in ANY filter type is suppressed.
+
+Defaults to excluding entries with a done keyword (DONE, CANCELLED, etc.
+per `org-done-keywords') and Google Calendar invitations the user has
+declined."
+ :package-version '(chime . "0.8.0")
:group 'chime
- :type '(repeat function))
+ :type '(alist :key-type (choice (const keywords)
+ (const tags)
+ (const predicates))
+ :value-type (repeat sexp)))
(defcustom chime-extra-alert-plist nil
"Additional arguments that should be passed to invocations of `alert'."
@@ -1256,43 +1245,39 @@ Tooltip shows events within `chime-tooltip-lookahead-hours' hours."
(when-let* ((tags-str (org-entry-get marker "TAGS")))
(org-split-string tags-str ":")))
-(defun chime--whitelist-predicates ()
- "Return list of whitelist predicate functions.
-Combines keyword, tag, and custom predicate whitelists."
- (->> `([,chime-keyword-whitelist
- (lambda (it)
- (-contains-p chime-keyword-whitelist
- (org-with-point-at it (org-get-todo-state))))]
-
- [,chime-tags-whitelist
- (lambda (it)
- (-intersection chime-tags-whitelist
- (chime--get-tags it)))]
-
- [,chime-predicate-whitelist
- (lambda (marker)
- (--some? (funcall it marker) chime-predicate-whitelist))])
- (--filter (aref it 0))
- (--map (aref it 1))))
-
-(defun chime--blacklist-predicates ()
- "Return list of blacklist predicate functions.
-Combines keyword, tag, and custom predicate blacklists."
- (->> `([,chime-keyword-blacklist
- (lambda (it)
- (-contains-p chime-keyword-blacklist
- (org-with-point-at it (org-get-todo-state))))]
-
- [,chime-tags-blacklist
- (lambda (it)
- (-intersection chime-tags-blacklist
- (chime--get-tags it)))]
-
- [,chime-predicate-blacklist
- (lambda (marker)
- (--some? (funcall it marker) chime-predicate-blacklist))])
- (--filter (aref it 0))
- (--map (aref it 1))))
+(defun chime--filter-predicates (filters)
+ "Build a list of predicate functions from a FILTERS alist.
+FILTERS is in the shape used by `chime-include-filters' and
+`chime-exclude-filters' — `(keywords . VALUES)', `(tags . VALUES)',
+`(predicates . FUNCTIONS)'. Each non-empty entry contributes one
+marker-taking predicate. An empty FILTERS list returns nil so callers
+can short-circuit the filter pass."
+ (let ((keywords (alist-get 'keywords filters))
+ (tags (alist-get 'tags filters))
+ (predicates (alist-get 'predicates filters))
+ (preds nil))
+ (when keywords
+ (push (lambda (marker)
+ (-contains-p keywords
+ (org-with-point-at marker (org-get-todo-state))))
+ preds))
+ (when tags
+ (push (lambda (marker)
+ (-intersection tags (chime--get-tags marker)))
+ preds))
+ (when predicates
+ (push (lambda (marker)
+ (--some? (funcall it marker) predicates))
+ preds))
+ (nreverse preds)))
+
+(defun chime--include-filter-predicates ()
+ "Predicates derived from `chime-include-filters'."
+ (chime--filter-predicates chime-include-filters))
+
+(defun chime--exclude-filter-predicates ()
+ "Predicates derived from `chime-exclude-filters'."
+ (chime--filter-predicates chime-exclude-filters))
(defun chime-done-keywords-predicate (marker)
"Check if entry at MARKER has a done keyword."
@@ -1309,17 +1294,17 @@ because that is what real org-gcal exports use."
(let ((status (org-entry-get marker "STATUS")))
(and status (string= status "declined"))))
-(defun chime--apply-whitelist (markers)
- "Apply whitelist to MARKERS."
- (-if-let (whitelist-predicates (chime--whitelist-predicates))
- (-> (apply '-orfn whitelist-predicates)
+(defun chime--apply-include-filters (markers)
+ "Keep MARKERS that match any predicate in `chime-include-filters'."
+ (-if-let (preds (chime--include-filter-predicates))
+ (-> (apply '-orfn preds)
(-filter markers))
markers))
-(defun chime--apply-blacklist (markers)
- "Apply blacklist to MARKERS."
- (-if-let (blacklist-predicates (chime--blacklist-predicates))
- (-> (apply '-orfn blacklist-predicates)
+(defun chime--apply-exclude-filters (markers)
+ "Drop MARKERS that match any predicate in `chime-exclude-filters'."
+ (-if-let (preds (chime--exclude-filter-predicates))
+ (-> (apply '-orfn preds)
(-remove markers))
markers))
@@ -1336,12 +1321,8 @@ because that is what real org-gcal exports use."
"load-path"
"org-todo-keywords"
"chime-alert-intervals"
- "chime-keyword-whitelist"
- "chime-keyword-blacklist"
- "chime-tags-whitelist"
- "chime-tags-blacklist"
- "chime-predicate-whitelist"
- "chime-predicate-blacklist")))
+ "chime-include-filters"
+ "chime-exclude-filters")))
string-end)))
(defun chime--environment-regex ()
@@ -1390,8 +1371,8 @@ because that is what real org-gcal exports use."
(org-fix-agenda-info (text-properties-at 0 it))
'org-marker))
(-non-nil)
- (chime--apply-whitelist)
- (chime--apply-blacklist)
+ (chime--apply-include-filters)
+ (chime--apply-exclude-filters)
(-map 'chime--gather-info))))
;;;; Notification Dispatch
diff --git a/tests/test-chime-apply-blacklist.el b/tests/test-chime-apply-blacklist.el
index 036f2a4..df2f317 100644
--- a/tests/test-chime-apply-blacklist.el
+++ b/tests/test-chime-apply-blacklist.el
@@ -1,4 +1,4 @@
-;;; test-chime-apply-blacklist.el --- Tests for chime--apply-blacklist -*- lexical-binding: t; -*-
+;;; test-chime-apply-blacklist.el --- Tests for chime--apply-exclude-filters -*- lexical-binding: t; -*-
;; Copyright (C) 2024-2026 Craig Jennings
@@ -19,7 +19,7 @@
;;; Commentary:
-;; Unit tests for chime--apply-blacklist function.
+;; Unit tests for chime--apply-exclude-filters function.
;; Tests use real org-mode buffers with real org syntax.
;; Tests cover normal cases, boundary cases, and error cases.
@@ -36,16 +36,12 @@
"Setup function run before each test."
(chime-create-test-base-dir)
;; Reset blacklist settings
- (setq chime-keyword-blacklist nil)
- (setq chime-tags-blacklist nil)
- (setq chime-predicate-blacklist nil))
+ (setq chime-exclude-filters nil))
(defun test-chime-apply-blacklist-teardown ()
"Teardown function run after each test."
(chime-delete-test-base-dir)
- (setq chime-keyword-blacklist nil)
- (setq chime-tags-blacklist nil)
- (setq chime-predicate-blacklist nil))
+ (setq chime-exclude-filters nil))
;;; Normal Cases
@@ -53,10 +49,9 @@
"Test that nil blacklist returns all markers unchanged."
(test-chime-apply-blacklist-setup)
(unwind-protect
- (let* ((chime-keyword-blacklist nil)
- (chime-tags-blacklist nil)
+ (let* ((chime-exclude-filters nil)
(markers (list (make-marker) (make-marker) (make-marker)))
- (result (chime--apply-blacklist markers)))
+ (result (chime--apply-exclude-filters markers)))
;; Should return all markers when blacklist is nil
(should (equal (length result) 3)))
(test-chime-apply-blacklist-teardown)))
@@ -76,8 +71,8 @@
(let ((marker2 (point-marker)))
(forward-line 1)
(let ((marker3 (point-marker))
- (chime-keyword-blacklist '("DONE")))
- (let ((result (chime--apply-blacklist (list marker1 marker2 marker3))))
+ (chime-exclude-filters `((keywords . ,'("DONE")))))
+ (let ((result (chime--apply-exclude-filters (list marker1 marker2 marker3))))
;; Should filter out DONE marker
(should (= (length result) 2))
(should (member marker1 result))
@@ -100,8 +95,8 @@
(let ((marker2 (point-marker)))
(forward-line 1)
(let ((marker3 (point-marker))
- (chime-tags-blacklist '("personal")))
- (let ((result (chime--apply-blacklist (list marker1 marker2 marker3))))
+ (chime-exclude-filters `((tags . ,'("personal")))))
+ (let ((result (chime--apply-exclude-filters (list marker1 marker2 marker3))))
;; Should filter out marker with "personal" tag
(should (= (length result) 2))
(should (member marker1 result))
@@ -124,9 +119,8 @@
(let ((marker2 (point-marker)))
(forward-line 1)
(let ((marker3 (point-marker))
- (chime-keyword-blacklist '("DONE"))
- (chime-tags-blacklist '("archive")))
- (let ((result (chime--apply-blacklist (list marker1 marker2 marker3))))
+ (chime-exclude-filters `((keywords . ,'("DONE")) (tags . ,'("archive")))))
+ (let ((result (chime--apply-exclude-filters (list marker1 marker2 marker3))))
;; Should filter out marker2 (DONE) and marker3 (archive tag)
(should (= (length result) 1))
(should (member marker1 result))
@@ -149,8 +143,8 @@
(let ((marker2 (point-marker)))
(forward-line 1)
(let ((marker3 (point-marker))
- (chime-keyword-blacklist '("DONE")))
- (let ((result (chime--apply-blacklist (list marker1 marker2 marker3))))
+ (chime-exclude-filters `((keywords . ,'("DONE")))))
+ (let ((result (chime--apply-exclude-filters (list marker1 marker2 marker3))))
;; Should only keep TODO marker, filter out both DONE markers
(should (= (length result) 1))
(should (member marker1 result)))))))
@@ -162,8 +156,8 @@
"Test that empty markers list returns empty."
(test-chime-apply-blacklist-setup)
(unwind-protect
- (let ((chime-keyword-blacklist '("DONE"))
- (result (chime--apply-blacklist '())))
+ (let ((chime-exclude-filters `((keywords . ,'("DONE"))))
+ (result (chime--apply-exclude-filters '())))
(should (equal result '())))
(test-chime-apply-blacklist-teardown)))
@@ -179,8 +173,8 @@
(let ((marker1 (point-marker)))
(forward-line 1)
(let ((marker2 (point-marker))
- (chime-keyword-blacklist '("DONE")))
- (let ((result (chime--apply-blacklist (list marker1 marker2))))
+ (chime-exclude-filters `((keywords . ,'("DONE")))))
+ (let ((result (chime--apply-exclude-filters (list marker1 marker2))))
(should (= (length result) 1))
(should (member marker1 result))))))
(test-chime-apply-blacklist-teardown)))
@@ -195,8 +189,8 @@
(let ((marker1 (point-marker)))
(insert "* DONE Task 2\n")
(let ((marker2 (point-marker))
- (chime-keyword-blacklist '("DONE")))
- (let ((result (chime--apply-blacklist (list marker1 marker2))))
+ (chime-exclude-filters `((keywords . ,'("DONE")))))
+ (let ((result (chime--apply-exclude-filters (list marker1 marker2))))
(should (equal result '()))))))
(test-chime-apply-blacklist-teardown)))
@@ -210,8 +204,8 @@
(org-mode)
(insert "* Entry without TODO keyword\n")
(let ((marker1 (point-marker))
- (chime-keyword-blacklist '("DONE")))
- (let ((result (chime--apply-blacklist (list marker1))))
+ (chime-exclude-filters `((keywords . ,'("DONE")))))
+ (let ((result (chime--apply-exclude-filters (list marker1))))
;; Should keep marker with nil keyword (not in blacklist)
(should (= (length result) 1)))))
(test-chime-apply-blacklist-teardown)))
@@ -224,8 +218,8 @@
(org-mode)
(insert "* Entry without tags\n")
(let ((marker1 (point-marker))
- (chime-tags-blacklist '("archive")))
- (let ((result (chime--apply-blacklist (list marker1))))
+ (chime-exclude-filters `((tags . ,'("archive")))))
+ (let ((result (chime--apply-exclude-filters (list marker1))))
;; Should keep marker with nil tags (not in blacklist)
(should (= (length result) 1)))))
(test-chime-apply-blacklist-teardown)))
diff --git a/tests/test-chime-apply-whitelist.el b/tests/test-chime-apply-whitelist.el
index e61f3c3..1552ee2 100644
--- a/tests/test-chime-apply-whitelist.el
+++ b/tests/test-chime-apply-whitelist.el
@@ -1,4 +1,4 @@
-;;; test-chime-apply-whitelist.el --- Tests for chime--apply-whitelist -*- lexical-binding: t; -*-
+;;; test-chime-apply-whitelist.el --- Tests for chime--apply-include-filters -*- lexical-binding: t; -*-
;; Copyright (C) 2024-2026 Craig Jennings
@@ -19,7 +19,7 @@
;;; Commentary:
-;; Unit tests for chime--apply-whitelist function.
+;; Unit tests for chime--apply-include-filters function.
;; Tests use real org-mode buffers with real org syntax.
;; Tests cover normal cases, boundary cases, and error cases.
@@ -36,16 +36,12 @@
"Setup function run before each test."
(chime-create-test-base-dir)
;; Reset whitelist settings
- (setq chime-keyword-whitelist nil)
- (setq chime-tags-whitelist nil)
- (setq chime-predicate-whitelist nil))
+ (setq chime-include-filters nil))
(defun test-chime-apply-whitelist-teardown ()
"Teardown function run after each test."
(chime-delete-test-base-dir)
- (setq chime-keyword-whitelist nil)
- (setq chime-tags-whitelist nil)
- (setq chime-predicate-whitelist nil))
+ (setq chime-include-filters nil))
;;; Normal Cases
@@ -53,10 +49,9 @@
"Test that nil whitelist returns all markers unchanged."
(test-chime-apply-whitelist-setup)
(unwind-protect
- (let* ((chime-keyword-whitelist nil)
- (chime-tags-whitelist nil)
+ (let* ((chime-include-filters nil)
(markers (list (make-marker) (make-marker) (make-marker)))
- (result (chime--apply-whitelist markers)))
+ (result (chime--apply-include-filters markers)))
;; Should return all markers when whitelist is nil
(should (equal (length result) 3)))
(test-chime-apply-whitelist-teardown)))
@@ -76,8 +71,8 @@
(let ((marker2 (point-marker)))
(forward-line 1)
(let ((marker3 (point-marker))
- (chime-keyword-whitelist '("TODO")))
- (let ((result (chime--apply-whitelist (list marker1 marker2 marker3))))
+ (chime-include-filters `((keywords . ,'("TODO")))))
+ (let ((result (chime--apply-include-filters (list marker1 marker2 marker3))))
;; Should only keep TODO markers
(should (= (length result) 2))
(should (member marker1 result))
@@ -100,8 +95,8 @@
(let ((marker2 (point-marker)))
(forward-line 1)
(let ((marker3 (point-marker))
- (chime-tags-whitelist '("urgent")))
- (let ((result (chime--apply-whitelist (list marker1 marker2 marker3))))
+ (chime-include-filters `((tags . ,'("urgent")))))
+ (let ((result (chime--apply-include-filters (list marker1 marker2 marker3))))
;; Should only keep markers with "urgent" tag
(should (= (length result) 2))
(should (member marker1 result))
@@ -124,9 +119,8 @@
(let ((marker2 (point-marker)))
(forward-line 1)
(let ((marker3 (point-marker))
- (chime-keyword-whitelist '("TODO"))
- (chime-tags-whitelist '("urgent")))
- (let ((result (chime--apply-whitelist (list marker1 marker2 marker3))))
+ (chime-include-filters `((keywords . ,'("TODO")) (tags . ,'("urgent")))))
+ (let ((result (chime--apply-include-filters (list marker1 marker2 marker3))))
;; Should keep marker1 (TODO) and marker3 (urgent tag)
(should (= (length result) 2))
(should (member marker1 result))
@@ -140,8 +134,8 @@
"Test that empty markers list returns empty."
(test-chime-apply-whitelist-setup)
(unwind-protect
- (let ((chime-keyword-whitelist '("TODO"))
- (result (chime--apply-whitelist '())))
+ (let ((chime-include-filters `((keywords . ,'("TODO"))))
+ (result (chime--apply-include-filters '())))
(should (equal result '())))
(test-chime-apply-whitelist-teardown)))
@@ -157,8 +151,8 @@
(let ((marker1 (point-marker)))
(forward-line 1)
(let ((marker2 (point-marker))
- (chime-keyword-whitelist '("TODO")))
- (let ((result (chime--apply-whitelist (list marker1 marker2))))
+ (chime-include-filters `((keywords . ,'("TODO")))))
+ (let ((result (chime--apply-include-filters (list marker1 marker2))))
(should (= (length result) 1))
(should (member marker1 result))))))
(test-chime-apply-whitelist-teardown)))
@@ -175,8 +169,8 @@
(let ((marker1 (point-marker)))
(forward-line 1)
(let ((marker2 (point-marker))
- (chime-keyword-whitelist '("TODO")))
- (let ((result (chime--apply-whitelist (list marker1 marker2))))
+ (chime-include-filters `((keywords . ,'("TODO")))))
+ (let ((result (chime--apply-include-filters (list marker1 marker2))))
(should (equal result '()))))))
(test-chime-apply-whitelist-teardown)))
@@ -191,8 +185,8 @@
(insert "* Entry without TODO keyword\n")
(goto-char (point-min))
(let ((marker1 (point-marker))
- (chime-keyword-whitelist '("TODO")))
- (let ((result (chime--apply-whitelist (list marker1))))
+ (chime-include-filters `((keywords . ,'("TODO")))))
+ (let ((result (chime--apply-include-filters (list marker1))))
;; Should filter out marker with nil keyword (not in whitelist)
(should (= (length result) 0)))))
(test-chime-apply-whitelist-teardown)))
@@ -206,8 +200,8 @@
(insert "* Entry without tags\n")
(goto-char (point-min))
(let ((marker1 (point-marker))
- (chime-tags-whitelist '("urgent")))
- (let ((result (chime--apply-whitelist (list marker1))))
+ (chime-include-filters `((tags . ,'("urgent")))))
+ (let ((result (chime--apply-include-filters (list marker1))))
;; Should filter out marker with nil tags (not in whitelist)
(should (= (length result) 0)))))
(test-chime-apply-whitelist-teardown)))
diff --git a/tests/test-chime-declined-events-predicate.el b/tests/test-chime-declined-events-predicate.el
index ca25faa..5f8c4b8 100644
--- a/tests/test-chime-declined-events-predicate.el
+++ b/tests/test-chime-declined-events-predicate.el
@@ -144,13 +144,15 @@ than treating it as declined."
(let ((marker (point-marker)))
(should-not (chime-declined-events-predicate marker)))))
-;;;; Integration with the default predicate-blacklist
+;;;; Integration with the default exclude filters
-(ert-deftest test-chime-declined-events-predicate-on-default-blacklist ()
- "Normal: the predicate ships in the default `chime-predicate-blacklist'
-so out-of-the-box installs hide declined events without extra config."
+(ert-deftest test-chime-declined-events-predicate-on-default-exclude-filters ()
+ "Normal: the predicate ships in the default `chime-exclude-filters'
+under the predicates key, so out-of-the-box installs hide declined
+events without extra config."
(should (memq 'chime-declined-events-predicate
- (default-value 'chime-predicate-blacklist))))
+ (alist-get 'predicates
+ (default-value 'chime-exclude-filters)))))
(provide 'test-chime-declined-events-predicate)
;;; test-chime-declined-events-predicate.el ends here
diff --git a/tests/test-chime-environment-regex.el b/tests/test-chime-environment-regex.el
index 2179198..3b67877 100644
--- a/tests/test-chime-environment-regex.el
+++ b/tests/test-chime-environment-regex.el
@@ -34,10 +34,8 @@
(let ((regex (chime--environment-regex))
(chime-additional-environment-regexes nil))
(dolist (var '("org-agenda-files" "load-path" "org-todo-keywords"
- "chime-alert-intervals" "chime-keyword-whitelist"
- "chime-keyword-blacklist" "chime-tags-whitelist"
- "chime-tags-blacklist" "chime-predicate-whitelist"
- "chime-predicate-blacklist"))
+ "chime-alert-intervals"
+ "chime-include-filters" "chime-exclude-filters"))
(should (string-match-p regex var)))))
(ert-deftest test-chime--environment-regex-includes-additional-regexes ()
diff --git a/tests/test-chime-whitelist-blacklist-conflicts.el b/tests/test-chime-whitelist-blacklist-conflicts.el
index f79bffd..5becfe0 100644
--- a/tests/test-chime-whitelist-blacklist-conflicts.el
+++ b/tests/test-chime-whitelist-blacklist-conflicts.el
@@ -39,22 +39,14 @@
"Setup function run before each test."
(chime-create-test-base-dir)
;; Reset all whitelist/blacklist settings
- (setq chime-keyword-whitelist nil)
- (setq chime-tags-whitelist nil)
- (setq chime-predicate-whitelist nil)
- (setq chime-keyword-blacklist nil)
- (setq chime-tags-blacklist nil)
- (setq chime-predicate-blacklist nil))
+ (setq chime-include-filters nil)
+ (setq chime-exclude-filters nil))
(defun test-chime-conflicts-teardown ()
"Teardown function run after each test."
(chime-delete-test-base-dir)
- (setq chime-keyword-whitelist nil)
- (setq chime-tags-whitelist nil)
- (setq chime-predicate-whitelist nil)
- (setq chime-keyword-blacklist nil)
- (setq chime-tags-blacklist nil)
- (setq chime-predicate-blacklist nil))
+ (setq chime-include-filters nil)
+ (setq chime-exclude-filters nil))
;;; Keyword Conflict Tests
@@ -74,11 +66,11 @@ Current behavior: blacklist wins (item is filtered out)."
(let ((marker2 (point-marker)))
(forward-line 1)
(let ((marker3 (point-marker))
- (chime-keyword-whitelist '("TODO" "DONE"))
- (chime-keyword-blacklist '("DONE"))) ; DONE in both lists
+ (chime-include-filters `((keywords . ,'("TODO" "DONE"))))
+ (chime-exclude-filters `((keywords . ,'("DONE"))))) ; DONE in both lists
;; Apply both filters (simulating what happens in chime--gather-timestamps)
- (let* ((after-whitelist (chime--apply-whitelist (list marker1 marker2 marker3)))
- (after-blacklist (chime--apply-blacklist after-whitelist)))
+ (let* ((after-whitelist (chime--apply-include-filters (list marker1 marker2 marker3)))
+ (after-blacklist (chime--apply-exclude-filters after-whitelist)))
;; Whitelist should keep all three (all are TODO or DONE)
(should (= (length after-whitelist) 3))
(should (member marker1 after-whitelist))
@@ -105,10 +97,10 @@ Current behavior: blacklist wins, all items filtered out."
(let ((marker1 (point-marker)))
(forward-line 1)
(let ((marker2 (point-marker))
- (chime-keyword-whitelist '("TODO" "DONE"))
- (chime-keyword-blacklist '("TODO" "DONE")))
- (let* ((after-whitelist (chime--apply-whitelist (list marker1 marker2)))
- (after-blacklist (chime--apply-blacklist after-whitelist)))
+ (chime-include-filters `((keywords . ,'("TODO" "DONE"))))
+ (chime-exclude-filters `((keywords . ,'("TODO" "DONE")))))
+ (let* ((after-whitelist (chime--apply-include-filters (list marker1 marker2)))
+ (after-blacklist (chime--apply-exclude-filters after-whitelist)))
;; Whitelist should keep both
(should (= (length after-whitelist) 2))
;; Blacklist should remove both
@@ -133,10 +125,10 @@ Current behavior: blacklist wins (item is filtered out)."
(let ((marker2 (point-marker)))
(forward-line 1)
(let ((marker3 (point-marker))
- (chime-tags-whitelist '("urgent" "important"))
- (chime-tags-blacklist '("urgent"))) ; urgent in both lists
- (let* ((after-whitelist (chime--apply-whitelist (list marker1 marker2 marker3)))
- (after-blacklist (chime--apply-blacklist after-whitelist)))
+ (chime-include-filters `((tags . ,'("urgent" "important"))))
+ (chime-exclude-filters `((tags . ,'("urgent"))))) ; urgent in both lists
+ (let* ((after-whitelist (chime--apply-include-filters (list marker1 marker2 marker3)))
+ (after-blacklist (chime--apply-exclude-filters after-whitelist)))
;; Whitelist should keep urgent and important (markers 1 and 3)
(should (= (length after-whitelist) 2))
(should (member marker1 after-whitelist))
@@ -163,10 +155,10 @@ Current behavior: blacklist wins (OR logic means tag match filters it out)."
(let ((marker1 (point-marker)))
(forward-line 1)
(let ((marker2 (point-marker))
- (chime-keyword-whitelist '("TODO"))
- (chime-tags-blacklist '("urgent")))
- (let* ((after-whitelist (chime--apply-whitelist (list marker1 marker2)))
- (after-blacklist (chime--apply-blacklist after-whitelist)))
+ (chime-include-filters `((keywords . ,'("TODO"))))
+ (chime-exclude-filters `((tags . ,'("urgent")))))
+ (let* ((after-whitelist (chime--apply-include-filters (list marker1 marker2)))
+ (after-blacklist (chime--apply-exclude-filters after-whitelist)))
;; Whitelist should keep TODO (marker1)
(should (= (length after-whitelist) 1))
(should (member marker1 after-whitelist))
@@ -187,10 +179,10 @@ Current behavior: blacklist wins (OR logic means keyword match filters it out)."
(let ((marker1 (point-marker)))
(forward-line 1)
(let ((marker2 (point-marker))
- (chime-tags-whitelist '("urgent"))
- (chime-keyword-blacklist '("TODO")))
- (let* ((after-whitelist (chime--apply-whitelist (list marker1 marker2)))
- (after-blacklist (chime--apply-blacklist after-whitelist)))
+ (chime-include-filters `((tags . ,'("urgent"))))
+ (chime-exclude-filters `((keywords . ,'("TODO")))))
+ (let* ((after-whitelist (chime--apply-include-filters (list marker1 marker2)))
+ (after-blacklist (chime--apply-exclude-filters after-whitelist)))
;; Whitelist should keep urgent tag (marker1)
(should (= (length after-whitelist) 1))
(should (member marker1 after-whitelist))
@@ -219,10 +211,10 @@ Current behavior: only items with conflicts are filtered out."
(let ((marker3 (point-marker)))
(forward-line 1)
(let ((marker4 (point-marker))
- (chime-keyword-whitelist '("TODO"))
- (chime-tags-blacklist '("urgent")))
- (let* ((after-whitelist (chime--apply-whitelist (list marker1 marker2 marker3 marker4)))
- (after-blacklist (chime--apply-blacklist after-whitelist)))
+ (chime-include-filters `((keywords . ,'("TODO"))))
+ (chime-exclude-filters `((tags . ,'("urgent")))))
+ (let* ((after-whitelist (chime--apply-include-filters (list marker1 marker2 marker3 marker4)))
+ (after-blacklist (chime--apply-exclude-filters after-whitelist)))
;; Whitelist should keep TODO (markers 1, 3, 4)
(should (= (length after-whitelist) 3))
(should (member marker1 after-whitelist))