diff options
| -rwxr-xr-x | README.html | 30 | ||||
| -rwxr-xr-x | README.org | 19 | ||||
| -rwxr-xr-x | org-drill.el | 204 |
3 files changed, 178 insertions, 75 deletions
diff --git a/README.html b/README.html index a04d8c3..96f0b29 100755 --- a/README.html +++ b/README.html @@ -7,7 +7,7 @@ lang="en" xml:lang="en"> <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=""/> @@ -249,7 +249,7 @@ recall purposes. For this reason, some other card types are defined, including: </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> @@ -545,15 +545,27 @@ the [North|North/South] Island. <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 – the others all remain visible. The hidden text area -is chosen randomly at each review. -</p> +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> – 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> – 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> @@ -1258,7 +1270,7 @@ or give it different tags or properties, for example. </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> @@ -82,7 +82,7 @@ where you have more control over what information is hidden from the user for 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 @@ -286,14 +286,21 @@ The capital city of New Zealand is Wellington, which is located in 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. diff --git a/org-drill.el b/org-drill.el index 832afc0..84b4676 100755 --- a/org-drill.el +++ b/org-drill.el @@ -201,7 +201,9 @@ during a drill session." ("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 @@ -1117,27 +1119,57 @@ How well did you do? (0-5, ?=help, e=edit, t=tags, q=quit)" 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) @@ -1289,7 +1321,7 @@ visual overlay." (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 () @@ -1305,7 +1337,7 @@ visual overlay." (org-cycle-hide-drawers 'all) (prog1 (org-drill-presentation-prompt) - (org-show-subtree)))))) + (org-drill-hide-subheadings-if 'org-drill-entry-p)))))) @@ -1321,10 +1353,12 @@ visual overlay." (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) @@ -1347,7 +1381,40 @@ visual overlay." (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))))) @@ -1394,6 +1461,22 @@ visual overlay." (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'. @@ -1414,29 +1497,30 @@ See `org-drill' for more details." ;; (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) - - (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)))) + (org-drill-save-visibility + (save-restriction + (org-narrow-to-subtree) + (org-show-subtree) + (org-cycle-hide-drawers 'all) - (cond - ((not cont) - (message "Quit") - nil) - ((eql cont 'edit) - 'edit) - ((eql cont 'skip) - 'skip) - (t - (save-excursion - (org-drill-reschedule))))))) + (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)))))))) (defun org-drill-entries-pending-p () @@ -1730,30 +1814,30 @@ than starting a new one." (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* @@ -1820,7 +1904,7 @@ exiting them with the `edit' option." (font-lock-add-keywords 'org-mode org-drill-cloze-keywords - t)))) + nil)))) |
