diff options
| author | Craig Jennings <c@cjennings.net> | 2026-05-26 17:10:55 -0500 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-05-26 18:09:28 -0500 |
| commit | 5c8d908a943470e3e4738c090cf8eaa1deee5a1f (patch) | |
| tree | 2c5d4d7d390013b32768321389dce6419191715b /tests | |
| parent | 1338b2ae757b7143fe4d211fc5a354c73cee526b (diff) | |
| download | org-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.el | 136 | ||||
| -rw-r--r-- | tests/test-org-drill-queue-and-misc.el | 13 | ||||
| -rw-r--r-- | tests/test-org-drill-small-branch-coverage.el | 28 |
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 |
