aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-07-10 06:37:44 -0500
committerCraig Jennings <c@cjennings.net>2026-07-10 06:37:44 -0500
commit326ec0198b57855ed61523ea2f476b8e88cd3d50 (patch)
tree99fcfbc0f871c5eb63f577ff133f565988b77665
parent216e10b4df8ce93aa42f005033ed07210d38a929 (diff)
downloaddotemacs-326ec0198b57855ed61523ea2f476b8e88cd3d50.tar.gz
dotemacs-326ec0198b57855ed61523ea2f476b8e88cd3d50.zip
fix(auto-dim): dim the remaining org faces, and test for the next one
Four rounds of this bug had one shape: a face nobody enumerated, sitting ahead of a mapped face in a face list and outranking it. A table header renders as (org-table-header org-table), so the mapped org-table underneath never got a say. So this round adds a test instead of another guess. It fontifies a representative org buffer, collects every face the buffer actually uses (including the line-prefix and wrap-prefix that org-indent hangs its faces on), and fails on anything neither mapped nor deliberately excluded. It caught org-checkbox while I was writing it. Newly dimmed: org-table-header, org-formula, org-checkbox, org-checkbox-statistics-done, org-headline-done, org-drill-visible-cloze-face. org-indent joins org-hide and org-superstar-leading on the -hide face. All three resolve to the background colour, which is what makes folded text, leading stars and indent prefixes invisible. Flat-dimming any of them reveals what I hid. bold, italic and underline stay unmapped on purpose. They carry no foreground even through inheritance, so they take their colour from default and dim for free.
-rw-r--r--modules/auto-dim-config.el14
-rw-r--r--tests/test-auto-dim-config.el73
2 files changed, 87 insertions, 0 deletions
diff --git a/modules/auto-dim-config.el b/modules/auto-dim-config.el
index fae00b48..faa4101c 100644
--- a/modules/auto-dim-config.el
+++ b/modules/auto-dim-config.el
@@ -83,6 +83,20 @@ focus cue on a split-displayed dashboard, accepted as a fair trade."
(font-lock-builtin-face . (auto-dim-other-buffers . nil))
(font-lock-preprocessor-face . (auto-dim-other-buffers . nil))
(font-lock-warning-face . (auto-dim-other-buffers . nil))
+ ;; Faces that sit AHEAD of a mapped face in a face list and outrank it, so
+ ;; the text under them stayed lit until each was named here: a table header
+ ;; renders as (org-table-header org-table), a TODO line as
+ ;; (org-faces-todo org-level-3). tests/test-auto-dim-config.el walks a
+ ;; fontified org buffer and fails when a built-in org face is left out.
+ (org-table-header . (auto-dim-other-buffers . nil))
+ (org-formula . (auto-dim-other-buffers . nil))
+ (org-checkbox . (auto-dim-other-buffers . nil))
+ (org-checkbox-statistics-done . (auto-dim-other-buffers . nil))
+ (org-headline-done . (auto-dim-other-buffers . nil))
+ (org-drill-visible-cloze-face . (auto-dim-other-buffers . nil))
+ ;; org-indent inherits org-hide, so its foreground IS the background: that
+ ;; is what makes indent prefixes invisible. -hide face, never the flat dim.
+ (org-indent . (auto-dim-other-buffers-hide . nil))
;; org-superstar draws heading stars and list bullets, and puts its own face
;; ahead of the org face beneath, so a star renders as
;; (org-superstar-header-bullet org-level-1) and outranks the dimmed level.
diff --git a/tests/test-auto-dim-config.el b/tests/test-auto-dim-config.el
index 869eb409..12435fa0 100644
--- a/tests/test-auto-dim-config.el
+++ b/tests/test-auto-dim-config.el
@@ -71,6 +71,19 @@ dimmed org-level-1. Without these, bullets stay lit in an unfocused window
even though every face under them dims.
`org-superstar-leading' is excluded on purpose -- see the test below.")
+(defconst test-auto-dim--hide-class-faces
+ '(org-hide org-superstar-leading org-indent)
+ "Faces whose foreground IS the background colour.
+That is what makes them invisible. They take `auto-dim-other-buffers-hide',
+never the flat dim, which would paint them visible grey.")
+
+(defconst test-auto-dim--no-foreground-faces
+ '(bold italic underline)
+ "Faces that carry no foreground, even through inheritance.
+They set weight, slant or underline only, so text wearing them takes its
+colour from `default', which is already remapped. They need no entry and
+must not gain one, or the alist grows entries that do nothing.")
+
(defconst test-auto-dim--keyword-dim-variants
'((org-faces-todo . org-faces-todo-dim)
(org-faces-doing . org-faces-doing-dim)
@@ -135,6 +148,66 @@ and reveal stars the user chose to hide. Same contract as `org-hide'."
(should entry)
(should (eq 'auto-dim-other-buffers-hide (car (cdr entry))))))
+(ert-deftest test-auto-dim-config-hide-class-faces-use-hide-face ()
+ "Error: every background-coloured face takes the -hide face.
+`org-hide', `org-superstar-leading' and `org-indent' all resolve to the
+background colour, which is what keeps folded text, leading stars and indent
+prefixes invisible. Flat-dimming any of them reveals what the user hid."
+ (skip-unless (file-directory-p test-auto-dim--fork))
+ (require 'auto-dim-config)
+ (dolist (face test-auto-dim--hide-class-faces)
+ (let ((entry (assq face auto-dim-other-buffers-affected-faces)))
+ (should entry)
+ (should (eq 'auto-dim-other-buffers-hide (car (cdr entry)))))))
+
+(ert-deftest test-auto-dim-config-no-org-face-left-unmapped ()
+ "Boundary: a fontified org buffer uses no face we forgot to handle.
+Four rounds of this bug all had the same shape: a face nobody enumerated,
+sitting ahead of a mapped face in a face list and outranking it. This walks
+a representative buffer, collects every face it actually uses (including the
+`line-prefix' and `wrap-prefix' org-indent hangs its faces on), and fails on
+anything that is neither mapped nor deliberately excluded.
+
+Built-in org only. org-superstar and org-drill are elpa packages, and the
+test run has no `package-initialize', so their faces are pinned by name in
+the tests above instead."
+ (skip-unless (file-directory-p test-auto-dim--fork))
+ (require 'auto-dim-config)
+ (require 'org)
+ (let ((used (make-hash-table :test #'eq))
+ (allowed (append test-auto-dim--no-foreground-faces
+ ;; Keyword class: deliberately unmapped so status stays
+ ;; readable in an unfocused window. Pinned by
+ ;; test-auto-dim-config-todo-priority-faces-not-flat-dimmed.
+ '(org-todo org-priority)
+ (mapcar #'car auto-dim-other-buffers-affected-faces))))
+ (with-temp-buffer
+ (insert "#+TITLE: T\n#+AUTHOR: A\n\n* H1 :tag:\n** TODO [#A] task\n"
+ "DEADLINE: <2026-07-10 Fri>\n:PROPERTIES:\n:K: v\n:END:\n"
+ "Body ~verbatim~ =code= [[https://x.org][link]].\n"
+ "| a | b |\n|---+---|\n| 1 | 2 |\n"
+ "#+begin_src sh\necho hi\n#+end_src\n"
+ "- [X] done item\n")
+ (org-mode)
+ (font-lock-ensure)
+ (let ((p (point-min)))
+ (while (< p (point-max))
+ (dolist (f (let ((v (get-text-property p 'face)))
+ (if (listp v) v (list v))))
+ (when (and f (symbolp f)) (puthash f t used)))
+ (dolist (prop '(line-prefix wrap-prefix))
+ (let ((s (get-text-property p prop)))
+ (when (stringp s)
+ (dolist (f (let ((v (get-text-property 0 'face s)))
+ (if (listp v) v (list v))))
+ (when (and f (symbolp f)) (puthash f t used))))))
+ (setq p (1+ p)))))
+ (let (unmapped)
+ (maphash (lambda (face _v)
+ (unless (memq face allowed) (push face unmapped)))
+ used)
+ (should (equal nil (sort unmapped #'string<))))))
+
(ert-deftest test-auto-dim-config-keyword-faces-keep-dim-variants ()
"Boundary: org TODO-keyword faces keep dedicated -dim variants, not flat dim.
Keyword status is scanned across unfocused windows, so it earns a variant;