aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-05-26 17:10:55 -0500
committerCraig Jennings <c@cjennings.net>2026-05-26 18:09:28 -0500
commit5c8d908a943470e3e4738c090cf8eaa1deee5a1f (patch)
tree2c5d4d7d390013b32768321389dce6419191715b /tests
parent1338b2ae757b7143fe4d211fc5a354c73cee526b (diff)
downloadorg-drill-5c8d908a943470e3e4738c090cf8eaa1deee5a1f.tar.gz
org-drill-5c8d908a943470e3e4738c090cf8eaa1deee5a1f.zip
fix: scope cloze fontification to drill buffers via org-drill-mode
org-drill-add-cloze-fontification ran on org-font-lock-set-keywords-hook, which fires in every org buffer, and pushed the cloze rule into org's global org-font-lock-extra-keywords. The cloze regexp is built from the [ and ] delimiters, so an org priority cookie like [#A] matched the cloze pattern and got fontified as a cloze in every org buffer, colliding with org's headline fontification and stripping the heading's org-level-N face. I replaced the global install with org-drill-mode, a buffer-local minor mode that adds the cloze keywords only to its own buffer via font-lock-add-keywords. org-drill-auto-enable-mode (default on) turns the mode on from org-mode-hook in buffers that hold drill cards, so existing drill files keep their cloze highlighting while plain org buffers stay clean. Highlighting still respects org-drill-use-visible-cloze-face-p. The cloze regexp itself is unchanged, so the single-line cloze constraint from #38 is preserved.
Diffstat (limited to 'tests')
-rw-r--r--tests/test-org-drill-mode.el136
-rw-r--r--tests/test-org-drill-queue-and-misc.el13
-rw-r--r--tests/test-org-drill-small-branch-coverage.el28
3 files changed, 157 insertions, 20 deletions
diff --git a/tests/test-org-drill-mode.el b/tests/test-org-drill-mode.el
new file mode 100644
index 0000000..2050feb
--- /dev/null
+++ b/tests/test-org-drill-mode.el
@@ -0,0 +1,136 @@
+;;; test-org-drill-mode.el --- Tests for org-drill-mode minor mode -*- lexical-binding: t; -*-
+
+;;; Commentary:
+;; `org-drill-mode' scopes cloze fontification to buffers that hold drill
+;; cards instead of installing it globally via `org-font-lock-set-keywords-hook'.
+;;
+;; Regression target: the global hook caused org priority cookies ([#A]..[#D])
+;; to match the cloze `[...]' pattern in EVERY org buffer, colliding with org's
+;; headline fontification and stripping the heading's `org-level-N' face. With
+;; the mode, plain org buffers carry no cloze rule at all, so the collision
+;; cannot happen there.
+
+;;; Code:
+
+(require 'ert)
+(require 'org-drill)
+
+;;;; Helpers
+
+(defun tdm--face-prop-has (face prop)
+ "Return non-nil if FACE is, or is a member of, the face PROP."
+ (or (eq prop face)
+ (and (listp prop) (memq face prop))))
+
+(defun tdm--face-at-string (s)
+ "Fontify the buffer and return the `face' text property at the first
+character of the first occurrence of literal string S."
+ (font-lock-ensure)
+ (goto-char (point-min))
+ (when (search-forward s nil t)
+ (get-text-property (match-beginning 0) 'face)))
+
+;;;; Minor mode definition
+
+(ert-deftest test-org-drill-mode-is-buffer-local-minor-mode ()
+ "`org-drill-mode' exists and is buffer-local."
+ (should (fboundp 'org-drill-mode))
+ (should (local-variable-if-set-p 'org-drill-mode)))
+
+(ert-deftest test-org-drill-mode-toggle-adds-and-removes-cloze-keyword ()
+ "Enabling the mode highlights a cloze; disabling stops highlighting it."
+ (let ((org-drill-use-visible-cloze-face-p t))
+ (with-temp-buffer
+ (insert "Question [answer] tail\n")
+ (org-mode)
+ (org-drill-mode 1)
+ (should org-drill-mode)
+ (should (tdm--face-prop-has 'org-drill-visible-cloze-face
+ (tdm--face-at-string "answer")))
+ (org-drill-mode -1)
+ (should-not org-drill-mode)
+ (should-not (tdm--face-prop-has 'org-drill-visible-cloze-face
+ (tdm--face-at-string "answer"))))))
+
+;;;; Drill-buffer predicate
+
+(ert-deftest test-org-drill-buffer-has-cards-p-true-for-drill-tag ()
+ "A heading tagged with the question tag counts as a drill buffer."
+ (with-temp-buffer
+ (insert "* A card :drill:\nbody\n")
+ (org-mode)
+ (should (org-drill-buffer-has-cards-p))))
+
+(ert-deftest test-org-drill-buffer-has-cards-p-true-for-leitner-tag ()
+ "A heading tagged with the leitner tag counts as a drill buffer."
+ (with-temp-buffer
+ (insert "* A card :leitner:\nbody\n")
+ (org-mode)
+ (should (org-drill-buffer-has-cards-p))))
+
+(ert-deftest test-org-drill-buffer-has-cards-p-false-for-plain-org ()
+ "An org buffer with no drill/leitner tag is not a drill buffer."
+ (with-temp-buffer
+ (insert "* Just notes :work:\n** TODO [#A] A heading\nbody [bracketed] text\n")
+ (org-mode)
+ (should-not (org-drill-buffer-has-cards-p))))
+
+;;;; Auto-enable on org-mode-hook
+
+(ert-deftest test-org-drill-mode-auto-enables-in-drill-buffer ()
+ "With auto-enable on, opening a drill buffer turns the mode on."
+ (let ((org-drill-auto-enable-mode t))
+ (with-temp-buffer
+ (insert "* A card :drill:\nQ [answer] A\n")
+ (org-mode)
+ (should org-drill-mode))))
+
+(ert-deftest test-org-drill-mode-does-not-auto-enable-in-plain-buffer ()
+ "With auto-enable on, a plain org buffer does NOT turn the mode on."
+ (let ((org-drill-auto-enable-mode t))
+ (with-temp-buffer
+ (insert "* Notes\n** TODO [#A] With cookie\n")
+ (org-mode)
+ (should-not org-drill-mode))))
+
+(ert-deftest test-org-drill-mode-auto-enable-respects-defcustom-off ()
+ "When `org-drill-auto-enable-mode' is nil, drill buffers do not auto-enable."
+ (let ((org-drill-auto-enable-mode nil))
+ (with-temp-buffer
+ (insert "* A card :drill:\nQ [answer] A\n")
+ (org-mode)
+ (should-not org-drill-mode))))
+
+(ert-deftest test-org-drill-auto-enable-mode-defaults-on ()
+ "The auto-enable defcustom ships on so existing drill files keep highlighting."
+ (should (eq t (default-value 'org-drill-auto-enable-mode))))
+
+;;;; Regression — the bug
+
+(ert-deftest test-org-drill-no-global-font-lock-keywords-hook ()
+ "Cloze fontification is no longer installed globally on
+`org-font-lock-set-keywords-hook' — that was the every-buffer pollution that
+made priority cookies collide with the cloze pattern."
+ (should-not (memq 'org-drill-add-cloze-fontification
+ (if (boundp 'org-font-lock-set-keywords-hook)
+ org-font-lock-set-keywords-hook
+ nil))))
+
+(ert-deftest test-org-drill-priority-cookie-not-clozed-in-plain-buffer ()
+ "In a plain org buffer (no drill cards) a priority cookie must not be
+fontified as a cloze, regardless of `org-drill-use-visible-cloze-face-p'."
+ (let ((org-drill-use-visible-cloze-face-p t)
+ (org-drill-auto-enable-mode t))
+ (with-temp-buffer
+ (insert "* Notes\n** TODO [#A] With cookie\n")
+ (org-mode)
+ (should-not org-drill-mode)
+ (goto-char (point-min))
+ (search-forward "#A")
+ (should-not (tdm--face-prop-has
+ 'org-drill-visible-cloze-face
+ (get-text-property (match-beginning 0) 'face))))))
+
+(provide 'test-org-drill-mode)
+
+;;; test-org-drill-mode.el ends here
diff --git a/tests/test-org-drill-queue-and-misc.el b/tests/test-org-drill-queue-and-misc.el
index d8cc3fa..81a7844 100644
--- a/tests/test-org-drill-queue-and-misc.el
+++ b/tests/test-org-drill-queue-and-misc.el
@@ -194,26 +194,27 @@ warned-about-id-creation slot flips to t and a fresh ID is returned."
(org-drill-id-get-create-with-warning session)
(should (oref session warned-about-id-creation))))))
-;;;; org-drill-add-cloze-fontification
+;;;; org-drill-mode (cloze fontification)
-(ert-deftest test-org-drill-add-cloze-fontification-sets-buffer-local-regex ()
- "Sets buffer-local `org-drill-cloze-regexp' built from the current delimiters."
+(ert-deftest test-org-drill-mode-sets-buffer-local-regex ()
+ "Enabling `org-drill-mode' sets buffer-local `org-drill-cloze-regexp' built
+from the current delimiters."
(with-temp-buffer
(let ((org-startup-folded nil))
(org-mode)
(let ((org-drill-left-cloze-delimiter "{{")
(org-drill-right-cloze-delimiter "}}"))
- (org-drill-add-cloze-fontification)
+ (org-drill-mode 1)
(should (local-variable-p 'org-drill-cloze-regexp))
;; The buffer-local regex matches the new delimiters.
(should (string-match-p org-drill-cloze-regexp "test {{x}} more"))
(should-not (string-match-p org-drill-cloze-regexp "test [x] more"))))))
-(ert-deftest test-org-drill-add-cloze-fontification-sets-buffer-local-keywords ()
+(ert-deftest test-org-drill-mode-sets-buffer-local-keywords ()
(with-temp-buffer
(let ((org-startup-folded nil))
(org-mode)
- (org-drill-add-cloze-fontification)
+ (org-drill-mode 1)
(should (local-variable-p 'org-drill-cloze-keywords))
(should (listp org-drill-cloze-keywords)))))
diff --git a/tests/test-org-drill-small-branch-coverage.el b/tests/test-org-drill-small-branch-coverage.el
index db1a2e9..21b67c6 100644
--- a/tests/test-org-drill-small-branch-coverage.el
+++ b/tests/test-org-drill-small-branch-coverage.el
@@ -105,24 +105,24 @@ read and re-activates it on the way out."
(should hook-ran)
(should key-read)))
-;;;; org-drill-add-cloze-fontification
+;;;; org-drill-mode cloze-face flag branches
-(ert-deftest test-add-cloze-fontification-with-flag-extends-keywords ()
- "When `org-drill-use-visible-cloze-face-p' is t, the cloze keyword spec is
-added to `org-font-lock-extra-keywords'."
+(ert-deftest test-org-drill-mode-with-flag-installs-cloze-keywords ()
+ "When `org-drill-use-visible-cloze-face-p' is t, enabling `org-drill-mode'
+installs the cloze keyword spec buffer-locally."
(with-temp-buffer
- (let ((org-drill-use-visible-cloze-face-p t)
- (org-font-lock-extra-keywords nil))
- (org-drill-add-cloze-fontification)
- (should org-font-lock-extra-keywords))))
+ (org-mode)
+ (let ((org-drill-use-visible-cloze-face-p t))
+ (org-drill-mode 1)
+ (should org-drill--installed-cloze-keywords))))
-(ert-deftest test-add-cloze-fontification-without-flag-leaves-keywords-untouched ()
- "When the flag is nil, no entry is added to `org-font-lock-extra-keywords'."
+(ert-deftest test-org-drill-mode-without-flag-installs-nothing ()
+ "When the flag is nil, enabling `org-drill-mode' installs no cloze keywords."
(with-temp-buffer
- (let ((org-drill-use-visible-cloze-face-p nil)
- (org-font-lock-extra-keywords nil))
- (org-drill-add-cloze-fontification)
- (should (null org-font-lock-extra-keywords)))))
+ (org-mode)
+ (let ((org-drill-use-visible-cloze-face-p nil))
+ (org-drill-mode 1)
+ (should (null org-drill--installed-cloze-keywords)))))
(provide 'test-org-drill-small-branch-coverage)
;;; test-org-drill-small-branch-coverage.el ends here