Anonymous avatar Anonymous committed f1e6be8

- 'multicloze' card type renamed to 'hide1cloze' (though 'multicloze' is
still recognised as a synonym, for backwards compatibility)
- new card type 'show1cloze' -- like hide1cloze, but only reveals one
of the areas of clozed text in the item.
- when 'revealing' an item during a drill session, do not show contents
of any subheadings which are themselves tagged as drill items. This means
you can have drill items inside drill items, without giving their answers
away when you review the parent item.
- better ensure visibility state of the org buffer is restored after the
drill session.
- syntax highlighting of [clozed text] now works if other faces are applied
inside the clozed text area, eg [the *largest* city]

Comments (0)

Files changed (3)

 <title>Org-Drill</title>
 <meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
 <meta name="generator" content="Org-mode"/>
-<meta name="generated" content="2011-04-15 08:42:23 "/>
+<meta name="generated" content="2011-04-22 15:27:38 "/>
 <meta name="author" content="Paul Sexton"/>
 <meta name="description" content=""/>
 <meta name="keywords" content=""/>
 </li>
 <li><a href="#sec-4_4">Multi-sided cards</a>
 </li>
-<li><a href="#Multicloze-cards">Multicloze cards</a>
+<li><a href="#sec-4_5">Multi-cloze cards</a>
 </li>
 <li><a href="#sec-4_6">User-defined card types</a>
 </li>
 
 
 <p>
-However, this is really cumbersome. The 'multicloze' card type exists for this
+However, this is really cumbersome. Multicloze card types exist for this
 situation. Multicloze cards behave like 'simple' cards, except that when there
-is more than one area marked as cloze text, only one of the marked areas will
-be hidden during review &ndash; the others all remain visible. The hidden text area
-is chosen randomly at each review.
+is more than one area marked as cloze text, some but not all of the areas
+are hidden. There are two types of multicloze card:
 </p>
+<ol>
+<li><code>hide1cloze</code> &ndash; one of the marked areas is hidden during review; the others
+   all remain visible. The hidden text area is chosen randomly at each review.
+   (Note: this type used to be called 'multicloze', and that card type is
+   retained as a synonym for 'hide1cloze'.)
+</li>
+<li><code>show1cloze</code> &ndash; only one of the marked areas is visible during review; all
+   the others are hidden. The hidden text area is chosen randomly at each
+   review.
+</li>
+</ol>
+
+
 <p>
 So, for the above example, we can actually use the original 'bad' simple card,
-but change its card type to 'multicloze'. Each time the card is presented for
+but change its card type to 'hide1cloze'. Each time the card is presented for
 review, one of 'New Zealand', 'Wellington', 'the South Island' or '400,000'
 will be hidden.
 </p>
 </div>
 </div>
 <div id="postamble">
-<p class="date">Date: 2011-04-15 08:42:23 </p>
+<p class="date">Date: 2011-04-22 15:27:38 </p>
 <p class="author">Author: Paul Sexton</p>
 <p class="creator">Org version 7.5 with Emacs version 23</p>
 <a href="http://validator.w3.org/check?uri=referer">Validate XHTML 1.0</a>
 recall purposes. For this reason, some other card types are defined, including:
 - [[Two-sided cards]]
 - [[Multi-sided cards]]
-- [[Multicloze cards]]
+- [[Multi-cloze cards]]
 - [[User-defined card types]]
 
 *A note about comments:* In org mode, comment lines start with '#'. The rest of
 the [North|North/South] Island.
 #+END_EXAMPLE
 
-However, this is really cumbersome. The 'multicloze' card type exists for this
+However, this is really cumbersome. Multicloze card types exist for this
 situation. Multicloze cards behave like 'simple' cards, except that when there
-is more than one area marked as cloze text, only one of the marked areas will
-be hidden during review -- the others all remain visible. The hidden text area
-is chosen randomly at each review.
+is more than one area marked as cloze text, some but not all of the areas
+are hidden. There are two types of multicloze card:
+
+1. =hide1cloze= -- one of the marked areas is hidden during review; the others
+   all remain visible. The hidden text area is chosen randomly at each review.
+   (Note: this type used to be called 'multicloze', and that card type is
+   retained as a synonym for 'hide1cloze'.)
+2. =show1cloze= -- only one of the marked areas is visible during review; all
+   the others are hidden. The hidden text area is chosen randomly at each
+   review.
 
 So, for the above example, we can actually use the original 'bad' simple card,
-but change its card type to 'multicloze'. Each time the card is presented for
+but change its card type to 'hide1cloze'. Each time the card is presented for
 review, one of 'New Zealand', 'Wellington', 'the South Island' or '400,000'
 will be hidden.
 
     ("simple" . org-drill-present-simple-card)
     ("twosided" . org-drill-present-two-sided-card)
     ("multisided" . org-drill-present-multi-sided-card)
-    ("multicloze" . org-drill-present-multicloze)
+    ("hide1cloze" . org-drill-present-multicloze-hide1)
+    ("show1cloze" . org-drill-present-multicloze-show1)
+    ("multicloze" . org-drill-present-multicloze-hide1)
     ("spanish_verb" . org-drill-present-spanish-verb))
   "Alist associating card types with presentation functions. Each entry in the
 alist takes the form (CARDTYPE . FUNCTION), where CARDTYPE is a string
       nil))))
 
 
-(defun org-drill-hide-all-subheadings-except (heading-list)
-  "Returns a list containing the position of each immediate subheading of
+;; (defun org-drill-hide-all-subheadings-except (heading-list)
+;;   "Returns a list containing the position of each immediate subheading of
+;; the current topic."
+;;   (let ((drill-entry-level (org-current-level))
+;;         (drill-sections nil)
+;;         (drill-heading nil))
+;;     (org-show-subtree)
+;;     (save-excursion
+;;       (org-map-entries
+;;        (lambda ()
+;;          (when (and (not (outline-invisible-p))
+;;                     (> (org-current-level) drill-entry-level))
+;;            (setq drill-heading (org-get-heading t))
+;;            (unless (and (= (org-current-level) (1+ drill-entry-level))
+;;                         (member drill-heading heading-list))
+;;              (hide-subtree))
+;;            (push (point) drill-sections)))
+;;        "" 'tree))
+;;     (reverse drill-sections)))
+
+
+
+(defun org-drill-hide-subheadings-if (test)
+  "TEST is a function taking no arguments. TEST will be called for each
+of the immediate subheadings of the current drill item, with the point
+on the relevant subheading. TEST should return nil if the subheading is
+to be revealed, non-nil if it is to be hidden.
+Returns a list containing the position of each immediate subheading of
 the current topic."
   (let ((drill-entry-level (org-current-level))
-        (drill-sections nil)
-        (drill-heading nil))
+        (drill-sections nil))
     (org-show-subtree)
     (save-excursion
       (org-map-entries
        (lambda ()
          (when (and (not (outline-invisible-p))
                     (> (org-current-level) drill-entry-level))
-           (setq drill-heading (org-get-heading t))
-           (unless (and (= (org-current-level) (1+ drill-entry-level))
-                        (member drill-heading heading-list))
+           (when (or (/= (org-current-level) (1+ drill-entry-level))
+                        (funcall test))
              (hide-subtree))
            (push (point) drill-sections)))
        "" 'tree))
     (reverse drill-sections)))
 
 
+(defun org-drill-hide-all-subheadings-except (heading-list)
+  (org-drill-hide-subheadings-if
+   (lambda () (let ((drill-heading (org-get-heading t)))
+           (not (member drill-heading heading-list))))))
+
+
 (defun org-drill-presentation-prompt (&rest fmt-and-args)
   (let* ((item-start-time (current-time))
          (input nil)
     (org-display-inline-images t)
     (org-cycle-hide-drawers 'all)
     (prog1 (org-drill-presentation-prompt)
-      (org-show-subtree)))))
+      (org-drill-hide-subheadings-if 'org-drill-entry-p)))))
 
 
 (defun org-drill-present-two-sided-card ()
       (org-cycle-hide-drawers 'all)
       (prog1
           (org-drill-presentation-prompt)
-        (org-show-subtree))))))
+        (org-drill-hide-subheadings-if 'org-drill-entry-p))))))
 
 
 
       (org-cycle-hide-drawers 'all)
       (prog1
           (org-drill-presentation-prompt)
-        (org-show-subtree))))))
+        (org-drill-hide-subheadings-if 'org-drill-entry-p))))))
 
 
-(defun org-drill-present-multicloze ()
+(defun org-drill-present-multicloze-hide1 ()
+  "Hides one of the pieces of text that are marked for cloze deletion,
+chosen at random."
   (with-hidden-comments
    (let ((item-end nil)
          (match-count 0)
      (org-display-inline-images t)
      (org-cycle-hide-drawers 'all)
      (prog1 (org-drill-presentation-prompt)
-       (org-show-subtree)
+       (org-drill-hide-subheadings-if 'org-drill-entry-p)
+       (org-drill-unhide-clozed-text)))))
+
+
+(defun org-drill-present-multicloze-show1 ()
+  "Similar to `org-drill-present-multicloze-hide1', but hides all
+the pieces of text that are marked for cloze deletion, except for one
+piece which is chosen at random."
+  (with-hidden-comments
+   (let ((item-end nil)
+         (match-count 0)
+         (body-start (or (cdr (org-get-property-block))
+                         (point))))
+     (org-drill-hide-all-subheadings-except nil)
+     (save-excursion
+       (outline-next-heading)
+       (setq item-end (point)))
+     (save-excursion
+       (goto-char body-start)
+       (while (re-search-forward org-drill-cloze-regexp item-end t)
+         (incf match-count)))
+     (when (plusp match-count)
+       (let ((match-to-hide (random match-count)))
+         (save-excursion
+           (goto-char body-start)
+           (dotimes (n match-count)
+             (re-search-forward org-drill-cloze-regexp
+                                item-end t)
+             (unless (= n match-to-hide)
+               (org-drill-hide-matched-cloze-text))))))
+     (org-display-inline-images t)
+     (org-cycle-hide-drawers 'all)
+     (prog1 (org-drill-presentation-prompt)
+       (org-drill-hide-subheadings-if 'org-drill-entry-p)
        (org-drill-unhide-clozed-text)))))
 
 
         (org-drill-hide-all-subheadings-except reveal-headings))))))
 
 
+;;; The following macro is necessary because `org-save-outline-visibility'
+;;; currently discards the value returned by its body and returns a garbage
+;;; value instead. (as at org mode v 7.5)
+
+(defmacro org-drill-save-visibility (&rest body)
+  "Store the current visibility state of the org buffer, and restore it
+after executing BODY. Return the value of the last expression
+in BODY."
+  (let ((retval (gensym)))
+    `(let ((,retval nil))
+       (org-save-outline-visibility t
+         (setq ,retval
+               (progn
+                 ,@body)))
+       ,retval)))
+
 
 (defun org-drill-entry ()
   "Present the current topic for interactive review, as in `org-drill'.
   ;;  (org-back-to-heading))
   (let ((card-type (org-entry-get (point) "DRILL_CARD_TYPE"))
         (cont nil))
-    (save-restriction
-      (org-narrow-to-subtree)
-      (org-show-subtree)
-      (org-cycle-hide-drawers 'all)
+    (org-drill-save-visibility
+     (save-restriction
+       (org-narrow-to-subtree)
+       (org-show-subtree)
+       (org-cycle-hide-drawers 'all)
 
-      (let ((presentation-fn (cdr (assoc card-type org-drill-card-type-alist))))
-        (cond
-         (presentation-fn
-          (setq cont (funcall presentation-fn)))
-         (t
-          (error "Unknown card type: '%s'" card-type))))
+       (let ((presentation-fn (cdr (assoc card-type org-drill-card-type-alist))))
+         (cond
+          (presentation-fn
+           (setq cont (funcall presentation-fn)))
+          (t
+           (error "Unknown card type: '%s'" card-type))))
 
-      (cond
-       ((not cont)
-        (message "Quit")
-        nil)
-       ((eql cont 'edit)
-        'edit)
-       ((eql cont 'skip)
-        'skip)
-       (t
-        (save-excursion
-          (org-drill-reschedule)))))))
+       (cond
+        ((not cont)
+         (message "Quit")
+         nil)
+        ((eql cont 'edit)
+         'edit)
+        ((eql cont 'skip)
+         'skip)
+        (t
+         (save-excursion
+           (org-drill-reschedule))))))))
 
 
 (defun org-drill-entries-pending-p ()
                               (make-string (ceiling cnt 50) ?.)))
                    (let ((due (org-drill-entry-days-overdue))
                          (last-int (org-drill-entry-last-interval 1)))
-                   (cond
-                    ((not (org-drill-entry-p))
-                     nil)               ; skip
-                    ((or (null due)     ; unscheduled - usually a skipped leech
-                         (minusp due))  ; scheduled in the future
-                     (incf *org-drill-dormant-entry-count*)
-                     (if (eq -1 due)
-                         (incf *org-drill-due-tomorrow-count*)))
-                    ((org-drill-entry-new-p)
-                     (push (point-marker) *org-drill-new-entries*))
-                    ((<= (org-drill-entry-last-quality 9999)
-                         org-drill-failure-quality)
-                     ;; Mature entries that were failed last time are FAILED,
-                     ;; regardless of how young, old or overdue they are.
-                     (push (point-marker) *org-drill-failed-entries*))
-                    ((org-drill-entry-overdue-p due last-int)
-                     ;; Overdue status overrides young versus old distinction.
-                     (push (point-marker) *org-drill-overdue-entries*))
-                    ((<= (org-drill-entry-last-interval 9999)
-                         org-drill-days-before-old)
-                     ;; Item is 'young'.
-                     (push (point-marker) *org-drill-young-mature-entries*))
-                    (t
-                     (push (point-marker) *org-drill-old-mature-entries*)))))
+                     (cond
+                      ((not (org-drill-entry-p))
+                       nil)             ; skip
+                      ((or (null due)   ; unscheduled - usually a skipped leech
+                           (minusp due)) ; scheduled in the future
+                       (incf *org-drill-dormant-entry-count*)
+                       (if (eq -1 due)
+                           (incf *org-drill-due-tomorrow-count*)))
+                      ((org-drill-entry-new-p)
+                       (push (point-marker) *org-drill-new-entries*))
+                      ((<= (org-drill-entry-last-quality 9999)
+                           org-drill-failure-quality)
+                       ;; Mature entries that were failed last time are FAILED,
+                       ;; regardless of how young, old or overdue they are.
+                       (push (point-marker) *org-drill-failed-entries*))
+                      ((org-drill-entry-overdue-p due last-int)
+                       ;; Overdue status overrides young versus old distinction.
+                       (push (point-marker) *org-drill-overdue-entries*))
+                      ((<= (org-drill-entry-last-interval 9999)
+                           org-drill-days-before-old)
+                       ;; Item is 'young'.
+                       (push (point-marker) *org-drill-young-mature-entries*))
+                      (t
+                       (push (point-marker) *org-drill-old-mature-entries*)))))
                  (concat "+" org-drill-question-tag) scope)))
             (setq *org-drill-due-entry-count* (org-drill-pending-entry-count))
             (setq *org-drill-overdue-entry-count*
                 (font-lock-add-keywords
                  'org-mode
                  org-drill-cloze-keywords
-                 t))))
+                 nil))))
 
 
 
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.