diff options
| author | Craig Jennings <c@cjennings.net> | 2026-05-05 12:39:55 -0500 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-05-05 12:39:55 -0500 |
| commit | 3019a33d391912120a78cad43a49eb34c4a1d044 (patch) | |
| tree | 4941d154529ce988bbdeb5e1929fa6cdea35f94a | |
| parent | 26fabb22edfea51e8a686c179ab91d00a2ff0bc3 (diff) | |
| download | chime-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.org | 113 | ||||
| -rw-r--r-- | chime-debug.el | 6 | ||||
| -rw-r--r-- | chime.el | 169 | ||||
| -rw-r--r-- | tests/test-chime-apply-blacklist.el | 54 | ||||
| -rw-r--r-- | tests/test-chime-apply-whitelist.el | 50 | ||||
| -rw-r--r-- | tests/test-chime-declined-events-predicate.el | 12 | ||||
| -rw-r--r-- | tests/test-chime-environment-regex.el | 6 | ||||
| -rw-r--r-- | tests/test-chime-whitelist-blacklist-conflicts.el | 64 |
8 files changed, 228 insertions, 246 deletions
@@ -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" @@ -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)) |
