diff options
| -rw-r--r-- | org-drill.el | 37 | ||||
| -rw-r--r-- | tests/test-org-drill-mode.el | 52 |
2 files changed, 79 insertions, 10 deletions
diff --git a/org-drill.el b/org-drill.el index 2680113..2ad00f0 100644 --- a/org-drill.el +++ b/org-drill.el @@ -3782,19 +3782,36 @@ non-nil; otherwise the mode is a no-op for fontification." (defun org-drill-buffer-has-cards-p () "Return non-nil if the current buffer contains a drill card — a heading -tagged with `org-drill-question-tag' or `org-drill-leitner-tag'." +tagged with `org-drill-question-tag' or `org-drill-leitner-tag'. + +The tag may sit on the heading itself, on an ancestor heading (the +ancestor line carries the literal tag, so the per-heading scan still +matches), or be applied file-wide via `#+FILETAGS:'. The file-tag case +is checked separately because the tag never appears on a heading line +there — the upstream bug where filetag-only decks failed to auto-enable +`org-drill-mode'." (save-excursion (save-restriction (widen) - (goto-char (point-min)) - (let ((case-fold-search t)) - (re-search-forward - (concat "^\\*+ .*:\\(?:" - (regexp-quote org-drill-question-tag) - "\\|" - (regexp-quote org-drill-leitner-tag) - "\\):") - nil t))))) + (let ((case-fold-search t) + (tags (concat "\\(?:" + (regexp-quote org-drill-question-tag) + "\\|" + (regexp-quote org-drill-leitner-tag) + "\\)"))) + (or + ;; Per-heading tag (also catches inheritance from a tagged ancestor). + (progn + (goto-char (point-min)) + (re-search-forward (concat "^\\*+ .*:" tags ":") nil t)) + ;; File-wide tag via #+FILETAGS:, in either the space-separated or + ;; colon-delimited syntax. The [: \t] boundaries keep a value like + ;; `drilldown' from matching `drill'. + (progn + (goto-char (point-min)) + (re-search-forward + (concat "^#\\+FILETAGS:.*[: \t]" tags "\\(?:[: \t]\\|$\\)") + nil t))))))) (defun org-drill-maybe-enable-mode () "Enable `org-drill-mode' when appropriate for the current buffer. diff --git a/tests/test-org-drill-mode.el b/tests/test-org-drill-mode.el index 2050feb..2760b31 100644 --- a/tests/test-org-drill-mode.el +++ b/tests/test-org-drill-mode.el @@ -75,6 +75,48 @@ character of the first occurrence of literal string S." (org-mode) (should-not (org-drill-buffer-has-cards-p)))) +;;;; Drill-buffer predicate — file-level tags (#+FILETAGS), upstream bug + +(ert-deftest test-org-drill-buffer-has-cards-p-true-for-filetags-space () + "A deck that tags its cards via `#+FILETAGS: drill' (space syntax, no +per-heading tag) counts as a drill buffer." + (with-temp-buffer + (insert "#+FILETAGS: drill\n* A card\nQ [answer] A\n") + (org-mode) + (should (org-drill-buffer-has-cards-p)))) + +(ert-deftest test-org-drill-buffer-has-cards-p-true-for-filetags-colon () + "A deck tagged via the colon syntax `#+FILETAGS: :spanish:drill:verbs:' +counts as a drill buffer even when the tag sits among others." + (with-temp-buffer + (insert "#+FILETAGS: :spanish:drill:verbs:\n* A card\nQ [answer] A\n") + (org-mode) + (should (org-drill-buffer-has-cards-p)))) + +(ert-deftest test-org-drill-buffer-has-cards-p-true-for-filetags-leitner () + "A deck tagged via `#+FILETAGS: leitner' counts as a drill buffer." + (with-temp-buffer + (insert "#+FILETAGS: leitner\n* A card\nQ [answer] A\n") + (org-mode) + (should (org-drill-buffer-has-cards-p)))) + +(ert-deftest test-org-drill-buffer-has-cards-p-true-for-inherited-top-level-tag () + "A deck whose cards inherit the tag from a tagged top-level heading counts +as a drill buffer. The ancestor heading line carries the literal tag, so the +per-heading scan already matches it — this locks that in." + (with-temp-buffer + (insert "* Deck :drill:\n** Card 1\nQ [answer] A\n** Card 2\nQ2 [answer2] A2\n") + (org-mode) + (should (org-drill-buffer-has-cards-p)))) + +(ert-deftest test-org-drill-buffer-has-cards-p-false-for-filetags-substring () + "A `#+FILETAGS:' value that merely contains the tag as a substring +\(e.g. `drilldown') must NOT count as a drill buffer." + (with-temp-buffer + (insert "#+FILETAGS: drilldown\n* Notes\nbody\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 () @@ -85,6 +127,16 @@ character of the first occurrence of literal string S." (org-mode) (should org-drill-mode)))) +(ert-deftest test-org-drill-mode-auto-enables-in-filetags-buffer () + "With auto-enable on, opening a deck tagged only via `#+FILETAGS: drill' +turns the mode on. This is the user-facing bug: filetag-only decks were +left without cloze highlighting." + (let ((org-drill-auto-enable-mode t)) + (with-temp-buffer + (insert "#+FILETAGS: drill\n* A card\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)) |
