emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[nongnu] elpa/org-drill c27d9035ef 030/251: - Added new example card typ


From: ELPA Syncer
Subject: [nongnu] elpa/org-drill c27d9035ef 030/251: - Added new example card types, more useful than 'spanish_verb':
Date: Mon, 17 Jan 2022 18:58:58 -0500 (EST)

branch: elpa/org-drill
commit c27d9035ef5ba5120157649cbfc8e0587ab4a08c
Author: eeeickythump <devnull@localhost>
Commit: eeeickythump <devnull@localhost>

    - Added new example card types, more useful than 'spanish_verb':
      - 'conjugate': retrieves properties VERB_INFINITIVE and VERB_TRANSLATION
        from parent item, and uses its own property VERB_TENSE to prompt the
        student 'Translate the verb INFINITIVE and conjugate for the TENSE 
tense'
        or 'Give the verb meaning TRANSLATION and conjugate for the TENSE tense'
      - 'translate_number': using third party library spell-number.el,
        prompt the student to translate a random number to or from a non-English
        language (the library can handle numerous languages)
      - examples of both in spanish.org
    - org-drill-card-type-alist can now take a second function name, for
      controlling how the ANSWER is displayed
    - items can have weights (DRILL_CARD_WEIGHT). The interval is divided by
      the weight when scheduling, so eg an item with a weight of 2.0 will be
      tested twice as often as a normal item.
    - New command: org-drill-tree. Same as org-drill using 'tree' argument.
    - New command: org-drill-strip-data: deletes all scheduling data from
      every item in scope. Intended for use if you wish to share your item
      library with someone else.
    - Fixed bug in simple8 algorithm where items failed on their first review
      were not having intervals reset
    - Ensure all markers are freed before starting a new drill session.
---
 README.html  |  74 +++++++--
 README.org   |  52 ++++--
 org-drill.el | 531 ++++++++++++++++++++++++++++++++++++++++++++++-------------
 spanish.org  | 143 +++++++++++++---
 4 files changed, 638 insertions(+), 162 deletions(-)

diff --git a/README.html b/README.html
index 96f0b29258..f5c475600b 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-22 15:27:38 "/>
+<meta name="generated" content="2011-04-30 16:14:35 "/>
 <meta name="author" content="Paul Sexton"/>
 <meta name="description" content=""/>
 <meta name="keywords" content=""/>
@@ -98,6 +98,7 @@ lang="en" xml:lang="en">
 <li><a href="#sec-4_4">Multi-sided cards </a></li>
 <li><a href="#sec-4_5">Multi-cloze cards </a></li>
 <li><a href="#sec-4_6">User-defined card types </a></li>
+<li><a href="#sec-4_7">Empty cards </a></li>
 </ul>
 </li>
 <li><a href="#sec-5">Running the drill session </a></li>
@@ -228,14 +229,16 @@ the topic must have a tag that matches the value of
 will be ignored.
 </p>
 <p>
-You don't need to schedule the topics initially.  However 
<code>org-drill</code> <b>will</b>
-recognise items that have been scheduled previously with
-<code>org-learn</code>. Unscheduled items are considered to be 'new' and ready 
for
-memorisation.
+Drill items can have other drill items as children. When a drill item is being
+tested, the contents of any child drill items will be hidden.
+</p>
+<p>
+You don't need to schedule the topics initially.  Unscheduled items are
+considered to be 'new' and ready for memorisation.
 </p>
 <p>
 How should 'drill topics' be structured? Any org topic is a legal drill topic
-&ndash; it will simply be shown with all subheadings collapsed, so thta only 
the
+&ndash; it will simply be shown with all subheadings collapsed, so that only 
the
 material beneath the main item heading is visible. After pressing a key, any
 hidden subheadings will be revealed, and you will be asked to rate your
 "recall" of the item.
@@ -598,14 +601,56 @@ the [North|North/South] Island and has a population of 
about [400,000].
 Finally, you can write your own emacs lisp functions to define new kinds of
 topics. Any new topic type will need to be added to
 <code>org-drill-card-type-alist</code>, and cards using that topic type will 
need to have
-it as the value of their <code>DRILL_CARD_TYPE</code> property. For an 
example, see the
-function <code>org-drill-present-spanish-verb</code>, which defines the new 
topic type
-<code>spanish_verb</code>, used in 'spanish.org'.
-</p>
+it as the value of their <code>DRILL_CARD_TYPE</code> property. For examples, 
see the
+functions at the end of org-drill.el &ndash; these include:
+</p><ul>
+<li><code>org-drill-present-verb-conjugation</code>, which implements the 
'conjugate'
+  card type. This asks the user to conjugate a verb in a particular tense. It
+  demonstrates how the appearance of an entry can be completely altered during
+  a drill session, both during testing and during the display fo the answer.
+</li>
+<li><code>org-drill-present-translate-number</code>, which uses a third-party 
emacs lisp
+  library (<a 
href="http://www.emacswiki.org/emacs/spell-number.el";>spell-number.el</a>) to 
prompt the user to translate random numbers
+  to and from any language recognised by that library.
+</li>
+<li><code>org-drill-present-spanish-verb</code>, which defines the new topic 
type
+  <code>spanish_verb</code>. This illustrates how a function can control which 
of an
+  item's subheadings are visible during the drill session.
+</li>
+</ul>
+
+
 <p>
-See the file <a href="spanish.html">spanish.org</a> for a full set of example 
material.
+See the file <a href="spanish.html">spanish.org</a> for a full set of example 
material, including examples
+of all the card types discussed above.
 </p>
 
+</div>
+
+</div>
+
+<div id="outline-container-4_7" class="outline-3">
+<h3 id="sec-4_7">Empty cards </h3>
+<div class="outline-text-3" id="text-4_7">
+
+
+
+<p>
+If the body of a drill item is completely empty (ignoring properties and child
+items), then the item will be skipped during drill sessions. The purpose of
+this behaviour is to allow you to paste in 'skeletons' of complex items, then
+fill in missing information later. For example, you may wish to include an
+empty drill item for each tense of a newly learned verb, then paste in the
+actual conjugation later as you learn each tense.
+</p>
+<p>
+Note that if an item is empty, any child drill items will <b>not</b> be 
ignored,
+unless they are empty as well.
+</p>
+<p>
+If you have an item with an empty body, but still want it to be included in a
+drill session, put a brief comment ('# &hellip;')  in the item body.
+</p>
 
 </div>
 </div>
@@ -625,7 +670,10 @@ argument, SCOPE, which allows it to take drill items from 
other
 sources. Possible values for SCOPE are:
 </p>
 <dl>
-<dt>tree</dt><dd>The subtree starting with the entry at the cursor.
+<dt>tree</dt><dd>The subtree starting with the entry at the cursor. 
(Alternatively you
+          can use <code>M-x org=drill-tree</code> to run the drill session 
&ndash; this will
+          behave the same as <code>org-drill</code> if 'tree' was used as the 
value of
+          SCOPE.)
 </dd>
 <dt>file</dt><dd>The current buffer, including both hidden and non-hidden 
items.
 </dd>
@@ -1270,7 +1318,7 @@ or give it different tags or properties, for example.
 </div>
 </div>
 <div id="postamble">
-<p class="date">Date: 2011-04-22 15:27:38 </p>
+<p class="date">Date: 2011-04-30 16:14:35 </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>
diff --git a/README.org b/README.org
index 168182b98e..8e689f8044 100755
--- a/README.org
+++ b/README.org
@@ -1,8 +1,6 @@
 # -*- mode: org; coding: utf-8 -*-
 #+STARTUP: showall
 #+OPTIONS: num:nil
-# Make absolutely sure the emacs lisp examples below don't get spuriously 
evaluated
-#+BABEL: :exports code
 #+TITLE: Org-Drill
 #+AUTHOR: Paul Sexton
 
@@ -66,13 +64,14 @@ the topic must have a tag that matches the value of
 =org-drill-question-tag=. This is =:drill:= by default. Any other org topics
 will be ignored.
 
-You don't need to schedule the topics initially.  However =org-drill= *will*
-recognise items that have been scheduled previously with
-=org-learn=. Unscheduled items are considered to be 'new' and ready for
-memorisation.
+Drill items can have other drill items as children. When a drill item is being
+tested, the contents of any child drill items will be hidden.
+
+You don't need to schedule the topics initially.  Unscheduled items are
+considered to be 'new' and ready for memorisation.
 
 How should 'drill topics' be structured? Any org topic is a legal drill topic
--- it will simply be shown with all subheadings collapsed, so thta only the
+-- it will simply be shown with all subheadings collapsed, so that only the
 material beneath the main item heading is visible. After pressing a key, any
 hidden subheadings will be revealed, and you will be asked to rate your
 "recall" of the item.
@@ -322,12 +321,38 @@ the [North|North/South] Island and has a population of 
about [400,000].
 Finally, you can write your own emacs lisp functions to define new kinds of
 topics. Any new topic type will need to be added to
 =org-drill-card-type-alist=, and cards using that topic type will need to have
-it as the value of their =DRILL_CARD_TYPE= property. For an example, see the
-function =org-drill-present-spanish-verb=, which defines the new topic type
-=spanish_verb=, used in 'spanish.org'.
+it as the value of their =DRILL_CARD_TYPE= property. For examples, see the
+functions at the end of org-drill.el -- these include:
+- =org-drill-present-verb-conjugation=, which implements the 'conjugate'
+  card type. This asks the user to conjugate a verb in a particular tense. It
+  demonstrates how the appearance of an entry can be completely altered during
+  a drill session, both during testing and during the display fo the answer.
+- =org-drill-present-translate-number=, which uses a third-party emacs lisp
+  library 
([[http://www.emacswiki.org/emacs/spell-number.el][spell-number.el]]) to prompt 
the user to translate random numbers
+  to and from any language recognised by that library.
+- =org-drill-present-spanish-verb=, which defines the new topic type
+  =spanish_verb=. This illustrates how a function can control which of an
+  item's subheadings are visible during the drill session.
+
+See the file [[file:spanish.org][spanish.org]] for a full set of example 
material, including examples
+of all the card types discussed above.
+
+
+** Empty cards
+
+
+If the body of a drill item is completely empty (ignoring properties and child
+items), then the item will be skipped during drill sessions. The purpose of
+this behaviour is to allow you to paste in 'skeletons' of complex items, then
+fill in missing information later. For example, you may wish to include an
+empty drill item for each tense of a newly learned verb, then paste in the
+actual conjugation later as you learn each tense.
 
-See the file [[file:spanish.org][spanish.org]] for a full set of example 
material.
+Note that if an item is empty, any child drill items will *not* be ignored,
+unless they are empty as well.
 
+If you have an item with an empty body, but still want it to be included in a
+drill session, put a brief comment ('# ...')  in the item body.
 
 
 * Running the drill session
@@ -338,7 +363,10 @@ non-hidden topics in the current buffer. =org-drill= takes 
an optional
 argument, SCOPE, which allows it to take drill items from other
 sources. Possible values for SCOPE are:
 
-- tree :: The subtree starting with the entry at the cursor.
+- tree :: The subtree starting with the entry at the cursor. (Alternatively you
+          can use =M-x org=drill-tree= to run the drill session -- this will
+          behave the same as =org-drill= if 'tree' was used as the value of
+          SCOPE.)
 - file :: The current buffer, including both hidden and non-hidden items.
 - file-with-archives :: The current buffer, and any archives associated with 
it.
 - agenda :: All agenda files.
diff --git a/org-drill.el b/org-drill.el
index 84b4676b2e..4f8de2215c 100755
--- a/org-drill.el
+++ b/org-drill.el
@@ -1,7 +1,7 @@
 ;;; org-drill.el - Self-testing using spaced repetition
 ;;;
 ;;; Author: Paul Sexton <eeeickythump@gmail.com>
-;;; Version: 2.1.1
+;;; Version: 2.2
 ;;; Repository at http://bitbucket.org/eeeickythump/org-drill/
 ;;;
 ;;;
@@ -180,6 +180,11 @@ during a drill session."
 (setplist 'org-drill-hidden-text-overlay
           '(invisible t))
 
+(setplist 'org-drill-replaced-text-overlay
+          '(display "Replaced text"
+                    face default
+                    window t))
+
 
 (defvar org-drill-cloze-regexp
   ;; ver 1   "[^][]\\(\\[[^][][^]]*\\]\\)"
@@ -204,11 +209,23 @@ during a drill session."
     ("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))
+    ("conjugate" org-drill-present-verb-conjugation
+     org-drill-show-answer-verb-conjugation)
+    ("spanish_verb" . org-drill-present-spanish-verb)
+    ("translate_number" org-drill-present-translate-number
+     org-drill-show-answer-translate-number))
   "Alist associating card types with presentation functions. Each entry in the
-alist takes the form (CARDTYPE . FUNCTION), where CARDTYPE is a string
-or nil, and FUNCTION is a function which takes no arguments and returns a
-boolean value."
+alist takes one of two forms:
+1. (CARDTYPE . QUESTION-FN), where CARDTYPE is a string or nil (for default),
+   and QUESTION-FN is a function which takes no arguments and returns a boolean
+   value.
+2. (CARDTYPE QUESTION-FN ANSWER-FN), where ANSWER-FN is a function that takes
+   one argument -- the argument is a function that itself takes no arguments.
+   ANSWER-FN is called with the point on the active item's
+   heading, just prior to displaying the item's 'answer'. It can therefore be
+   used to modify the appearance of the answer. ANSWER-FN must call its 
argument
+   before returning. (Its argument is a function that prompts the user and
+   performs rescheduling)."
   :group 'org-drill
   :type '(alist :key-type (choice string (const nil)) :value-type function))
 
@@ -914,37 +931,35 @@ See the documentation for `org-drill-get-item-data' for a 
description of these."
                     (/ (+ quality (* meanq totaln 1.0)) (1+ totaln))
                   quality))
     (cond
+     ((<= quality org-drill-failure-quality)
+      (incf failures)
+      (setf repeats 0
+            next-interval -1))
      ((or (zerop repeats)
           (zerop last-interval))
       (setf next-interval (org-drill-simple8-first-interval failures))
       (incf repeats)
       (incf totaln))
      (t
-      (cond
-       ((<= quality org-drill-failure-quality)
-        (incf failures)
-        (setf repeats 0
-              next-interval -1))
-       (t
-        (let* ((use-n
-                (if (and
-                     
org-drill-adjust-intervals-for-early-and-late-repetitions-p
-                     (numberp delta-days) (plusp delta-days)
-                     (plusp last-interval))
-                    (+ repeats (min 1 (/ delta-days last-interval 1.0)))
-                  repeats))
-               (factor (org-drill-simple8-interval-factor
-                        (org-drill-simple8-quality->ease meanq) use-n))
-               (next-int (* last-interval factor)))
-          (when (and 
org-drill-adjust-intervals-for-early-and-late-repetitions-p
-                     (numberp delta-days) (minusp delta-days))
-            ;; The item was reviewed earlier than scheduled.
-            (setf factor (org-drill-early-interval-factor
-                          factor next-int (abs delta-days))
-                  next-int (* last-interval factor)))
-          (setf next-interval next-int)
-          (incf repeats)
-          (incf totaln))))))
+      (let* ((use-n
+              (if (and
+                   org-drill-adjust-intervals-for-early-and-late-repetitions-p
+                   (numberp delta-days) (plusp delta-days)
+                   (plusp last-interval))
+                  (+ repeats (min 1 (/ delta-days last-interval 1.0)))
+                repeats))
+             (factor (org-drill-simple8-interval-factor
+                      (org-drill-simple8-quality->ease meanq) use-n))
+             (next-int (* last-interval factor)))
+        (when (and org-drill-adjust-intervals-for-early-and-late-repetitions-p
+                   (numberp delta-days) (minusp delta-days))
+          ;; The item was reviewed earlier than scheduled.
+          (setf factor (org-drill-early-interval-factor
+                        factor next-int (abs delta-days))
+                next-int (* last-interval factor)))
+        (setf next-interval next-int)
+        (incf repeats)
+        (incf totaln))))
     (list
      (if (and org-drill-add-random-noise-to-intervals-p
               (plusp next-interval))
@@ -962,14 +977,21 @@ See the documentation for `org-drill-get-item-data' for a 
description of these."
 
 
 ;;; Essentially copied from `org-learn.el', but modified to
-;;; optionally call the SM2 function above.
+;;; optionally call the SM2 or simple8 functions.
 (defun org-drill-smart-reschedule (quality &optional days-ahead)
   "If DAYS-AHEAD is supplied it must be a positive integer. The
 item will be scheduled exactly this many days into the future."
   (let ((delta-days (- (time-to-days (current-time))
                    (time-to-days (or (org-get-scheduled-time (point))
                                      (current-time)))))
-        (ofmatrix org-drill-optimal-factor-matrix))
+        (ofmatrix org-drill-optimal-factor-matrix)
+        ;; Entries can have weights, 1 by default. Intervals are divided by the
+        ;; item's weight, so an item with a weight of 2 will have all intervals
+        ;; halved, meaning you will end up reviewing it twice as often.
+        ;; Useful for entries which randomly present any of several facts.
+        (weight (org-entry-get (point) "DRILL_CARD_WEIGHT")))
+    (if (stringp weight)
+        (setq weight (read weight)))
     (destructuring-bind (last-interval repetitions failures
                                        total-repeats meanq ease)
         (org-drill-get-item-data)
@@ -987,10 +1009,16 @@ item will be scheduled exactly this many days into the 
future."
                                                       quality failures meanq
                                                       total-repeats
                                                       delta-days)))
-        (if (integerp days-ahead)
-            (setf next-interval days-ahead))
+        (if (numberp days-ahead)
+            (setq next-interval days-ahead))
+
         (org-drill-store-item-data next-interval repetitions failures
                                    total-repeats meanq ease)
+        (if (and (null days-ahead)
+                 (numberp weight) (plusp weight)
+                 (not (minusp next-interval)))
+            (setq next-interval (max 1.0 (/ next-interval weight))))
+
         (if (eql 'sm5 org-drill-spaced-repetition-algorithm)
             (setq org-drill-optimal-factor-matrix new-ofmatrix))
 
@@ -1005,34 +1033,37 @@ item will be scheduled exactly this many days into the 
future."
                                        (round next-interval))))))))))
 
 
-
 (defun org-drill-hypothetical-next-review-date (quality)
   "Returns an integer representing the number of days into the future
 that the current item would be scheduled, based on a recall quality
 of QUALITY."
-  (destructuring-bind (last-interval repetitions failures
-                                     total-repeats meanq ease)
-      (org-drill-get-item-data)
-    (destructuring-bind (next-interval repetitions ease
-                                       failures meanq total-repeats
-                                       &optional ofmatrix)
-        (case org-drill-spaced-repetition-algorithm
-          (sm5 (determine-next-interval-sm5 last-interval repetitions
-                                            ease quality failures
-                                            meanq total-repeats
-                                            org-drill-optimal-factor-matrix))
-          (sm2 (determine-next-interval-sm2 last-interval repetitions
-                                            ease quality failures
-                                            meanq total-repeats))
-          (simple8 (determine-next-interval-simple8 last-interval repetitions
-                                                    quality failures meanq
-                                                    total-repeats)))
-      (cond
-       ((not (plusp next-interval))
-        0)
-       (t
-        next-interval)))))
-
+  (let ((weight (org-entry-get (point) "DRILL_CARD_WEIGHT")))
+    (destructuring-bind (last-interval repetitions failures
+                                       total-repeats meanq ease)
+        (org-drill-get-item-data)
+      (if (stringp weight)
+          (setq weight (read weight)))
+      (destructuring-bind (next-interval repetitions ease
+                                         failures meanq total-repeats
+                                         &optional ofmatrix)
+          (case org-drill-spaced-repetition-algorithm
+            (sm5 (determine-next-interval-sm5 last-interval repetitions
+                                              ease quality failures
+                                              meanq total-repeats
+                                              org-drill-optimal-factor-matrix))
+            (sm2 (determine-next-interval-sm2 last-interval repetitions
+                                              ease quality failures
+                                              meanq total-repeats))
+            (simple8 (determine-next-interval-simple8 last-interval repetitions
+                                                      quality failures meanq
+                                                      total-repeats)))
+        (cond
+         ((not (plusp next-interval))
+          0)
+         ((and (numberp weight) (plusp weight))
+          (max 1.0 (/ next-interval weight)))
+         (t
+          next-interval))))))
 
 
 (defun org-drill-hypothetical-next-review-dates ()
@@ -1241,21 +1272,25 @@ Consider reformulating the item to make it easier to 
remember.\n"
     (org-in-regexp regexp nlines)))
 
 
-(defun org-drill-hide-region (beg end)
+(defun org-drill-hide-region (beg end &optional text)
   "Hide the buffer region between BEG and END with an 'invisible text'
-visual overlay."
+visual overlay, or with the string TEXT if it is supplied."
   (let ((ovl (make-overlay beg end)))
     (overlay-put ovl 'category
-                 'org-drill-hidden-text-overlay)))
+                 'org-drill-hidden-text-overlay)
+    (when (stringp text)
+      (overlay-put ovl 'invisible nil)
+      (overlay-put ovl 'face 'default)
+      (overlay-put ovl 'display text))))
 
 
-(defun org-drill-hide-heading-at-point ()
+(defun org-drill-hide-heading-at-point (&optional text)
   (unless (org-at-heading-p)
     (error "Point is not on a heading."))
   (save-excursion
     (let ((beg (point)))
       (end-of-line)
-      (org-drill-hide-region beg (point)))))
+      (org-drill-hide-region beg (point) text))))
 
 
 (defun org-drill-hide-comments ()
@@ -1297,6 +1332,54 @@ visual overlay."
                             (1- (length (match-string 0)))))))))
 
 
+(defmacro with-replaced-entry-text (text &rest body)
+  "During the execution of BODY, the entire text of the current entry is
+concealed by an overlay that displays the string TEXT."
+  `(progn
+     (org-drill-replace-entry-text ,text)
+     (unwind-protect
+         (progn
+           ,@body)
+       (org-drill-unreplace-entry-text))))
+
+
+(defun org-drill-replace-entry-text (text)
+  "Make an overlay that conceals the entire text of the item, not
+including properties or the contents of subheadings. The overlay shows
+the string TEXT.
+Note: does not actually alter the item."
+  (let ((ovl (make-overlay (point-min)
+                           (save-excursion
+                             (outline-next-heading)
+                             (point)))))
+    (overlay-put ovl 'category
+                 'org-drill-replaced-text-overlay)
+    (overlay-put ovl 'display text)))
+
+
+(defun org-drill-unreplace-entry-text ()
+  (save-excursion
+    (dolist (ovl (overlays-in (point-min) (point-max)))
+      (when (eql 'org-drill-replaced-text-overlay (overlay-get ovl 'category))
+        (delete-overlay ovl)))))
+
+
+(defmacro with-replaced-entry-heading (heading &rest body)
+  `(progn
+     (org-drill-replace-entry-heading ,heading)
+     (unwind-protect
+         (progn
+           ,@body)
+       (org-drill-unhide-comments))))
+
+
+(defun org-drill-replace-entry-heading (heading)
+  "Make an overlay that conceals the heading of the item. The overlay shows
+the string TEXT.
+Note: does not actually alter the item."
+  (org-drill-hide-heading-at-point heading))
+
+
 (defun org-drill-unhide-clozed-text ()
   (save-excursion
     (dolist (ovl (overlays-in (point-min) (point-max)))
@@ -1304,6 +1387,15 @@ visual overlay."
         (delete-overlay ovl)))))
 
 
+(defun org-drill-get-entry-text ()
+  (substring-no-properties
+   (org-agenda-get-some-entry-text (point-marker) 100)))
+
+
+(defun org-drill-entry-empty-p ()
+  (zerop (length (org-drill-get-entry-text))))
+
+
 
 ;;; Presentation functions ====================================================
 
@@ -1418,47 +1510,15 @@ piece which is chosen at random."
        (org-drill-unhide-clozed-text)))))
 
 
-(defun org-drill-present-spanish-verb ()
-  (let ((prompt nil)
-        (reveal-headings nil))
-    (with-hidden-comments
-     (with-hidden-cloze-text
-      (case (random 6)
-        (0
-         (org-drill-hide-all-subheadings-except '("Infinitive"))
-         (setq prompt
-               (concat "Translate this Spanish verb, and conjugate it "
-                       "for the *present* tense.")
-               reveal-headings '("English" "Present Tense" "Notes")))
-        (1
-         (org-drill-hide-all-subheadings-except '("English"))
-         (setq prompt (concat "For the *present* tense, conjugate the "
-                              "Spanish translation of this English verb.")
-               reveal-headings '("Infinitive" "Present Tense" "Notes")))
-        (2
-         (org-drill-hide-all-subheadings-except '("Infinitive"))
-         (setq prompt (concat "Translate this Spanish verb, and "
-                              "conjugate it for the *past* tense.")
-               reveal-headings '("English" "Past Tense" "Notes")))
-        (3
-         (org-drill-hide-all-subheadings-except '("English"))
-         (setq prompt (concat "For the *past* tense, conjugate the "
-                              "Spanish translation of this English verb.")
-               reveal-headings '("Infinitive" "Past Tense" "Notes")))
-        (4
-         (org-drill-hide-all-subheadings-except '("Infinitive"))
-         (setq prompt (concat "Translate this Spanish verb, and "
-                              "conjugate it for the *future perfect* tense.")
-               reveal-headings '("English" "Future Perfect Tense" "Notes")))
-        (5
-         (org-drill-hide-all-subheadings-except '("English"))
-         (setq prompt (concat "For the *future perfect* tense, conjugate the "
-                              "Spanish translation of this English verb.")
-               reveal-headings '("Infinitive" "Future Perfect Tense" 
"Notes"))))
-      (org-cycle-hide-drawers 'all)
-      (prog1
-          (org-drill-presentation-prompt prompt)
-        (org-drill-hide-all-subheadings-except reveal-headings))))))
+(defun org-drill-present-card-using-text (question &optional answer)
+  "Present the string QUESTION as the only visible content of the card."
+  (with-hidden-comments
+   (with-replaced-entry-text
+    question
+    (org-drill-hide-all-subheadings-except nil)
+    (org-cycle-hide-drawers 'all)
+    (prog1 (org-drill-presentation-prompt)
+      (org-drill-hide-subheadings-if 'org-drill-entry-p)))))
 
 
 ;;; The following macro is necessary because `org-save-outline-visibility'
@@ -1496,7 +1556,8 @@ See `org-drill' for more details."
   ;;(unless (org-at-heading-p)
   ;;  (org-back-to-heading))
   (let ((card-type (org-entry-get (point) "DRILL_CARD_TYPE"))
-        (cont nil))
+        (cont nil)
+        (answer-fn nil))
     (org-drill-save-visibility
      (save-restriction
        (org-narrow-to-subtree)
@@ -1504,6 +1565,9 @@ See `org-drill' for more details."
        (org-cycle-hide-drawers 'all)
 
        (let ((presentation-fn (cdr (assoc card-type 
org-drill-card-type-alist))))
+         (if (listp presentation-fn)
+             (psetq answer-fn (second presentation-fn)
+                    presentation-fn (first presentation-fn)))
          (cond
           (presentation-fn
            (setq cont (funcall presentation-fn)))
@@ -1520,7 +1584,11 @@ See `org-drill' for more details."
          'skip)
         (t
          (save-excursion
-           (org-drill-reschedule))))))))
+           (cond
+            (answer-fn
+             (funcall answer-fn (lambda () (org-drill-reschedule))))
+            (t
+             (org-drill-reschedule))))))))))
 
 
 (defun org-drill-entries-pending-p ()
@@ -1737,6 +1805,19 @@ order to make items appear more frequently over time."
          ))))
 
 
+
+(defun org-drill-free-all-markers ()
+  (dolist (m (append  *org-drill-done-entries*
+                      *org-drill-new-entries*
+                      *org-drill-failed-entries*
+                      *org-drill-again-entries*
+                      *org-drill-overdue-entries*
+                      *org-drill-young-mature-entries*
+                      *org-drill-old-mature-entries*))
+    (free-marker m)))
+
+
+
 (defun org-drill (&optional scope resume-p)
   "Begin an interactive 'drill session'. The user is asked to
 review a series of topics (headers). Each topic is initially
@@ -1784,6 +1865,7 @@ than starting a new one."
         (cnt 0))
     (block org-drill
       (unless resume-p
+        (org-drill-free-all-markers)
         (setq *org-drill-current-item* nil
               *org-drill-done-entries* nil
               *org-drill-dormant-entry-count* 0
@@ -1817,6 +1899,8 @@ than starting a new one."
                      (cond
                       ((not (org-drill-entry-p))
                        nil)             ; skip
+                      ((org-drill-entry-empty-p)
+                       nil)             ; skip -- item body is empty
                       ((or (null due)   ; unscheduled - usually a skipped leech
                            (minusp due)) ; scheduled in the future
                        (incf *org-drill-dormant-entry-count*)
@@ -1854,14 +1938,7 @@ than starting a new one."
               (message "Drill session finished!"))))
         (progn
           (unless end-pos
-            (dolist (m (append  *org-drill-done-entries*
-                                *org-drill-new-entries*
-                                *org-drill-failed-entries*
-                                *org-drill-again-entries*
-                                *org-drill-overdue-entries*
-                                *org-drill-young-mature-entries*
-                                *org-drill-old-mature-entries*))
-              (free-marker m))))))
+            (org-drill-free-all-markers)))))
     (cond
      (end-pos
       (when (markerp end-pos)
@@ -1875,6 +1952,7 @@ than starting a new one."
       ))))
 
 
+
 (defun org-drill-save-optimal-factor-matrix ()
   (message "Saving optimal factor matrix...")
   (customize-save-variable 'org-drill-optimal-factor-matrix
@@ -1891,6 +1969,13 @@ hours."
     (org-drill scope)))
 
 
+(defun org-drill-tree ()
+  "Run an interactive drill session using drill items within the
+subtree at point."
+  (interactive)
+  (org-drill 'tree))
+
+
 (defun org-drill-resume ()
   "Resume a suspended drill session. Sessions are suspended by
 exiting them with the `edit' option."
@@ -1898,6 +1983,30 @@ exiting them with the `edit' option."
   (org-drill nil t))
 
 
+(defun org-drill-strip-data (&optional scope)
+  "Delete scheduling data from every drill entry in scope. This
+function may be useful if you want to give your collection of
+entries to someone else.  Scope defaults to the current buffer,
+and is specified by the argument SCOPE, which accepts the same
+values as `org-drill'."
+  (interactive)
+  (when (yes-or-no-p
+         "Delete scheduling data from ALL items in scope: are you sure?")
+    (org-map-entries (lambda ()
+                       (org-delete-property "DRILL_LAST_INTERVAL")
+                       (org-delete-property "DRILL_REPEATS_SINCE_FAIL")
+                       (org-delete-property "DRILL_TOTAL_REPEATS")
+                       (org-delete-property "DRILL_FAILURE_COUNT")
+                       (org-delete-property "DRILL_AVERAGE_QUALITY")
+                       (org-delete-property "DRILL_EASE")
+                       (org-delete-property "DRILL_LAST_QUALITY")
+                       (org-delete-property "DRILL_LAST_REVIEWED")
+                       (org-schedule t))
+                     "" scope)
+    (message "Done.")))
+
+
+
 (add-hook 'org-mode-hook
           (lambda ()
             (if org-drill-use-visible-cloze-face-p
@@ -1907,5 +2016,197 @@ exiting them with the `edit' option."
                  nil))))
 
 
-
 (provide 'org-drill)
+
+;;; Card types for learning languages =========================================
+
+;;; Get spell-number.el from:
+;;; http://www.emacswiki.org/emacs/spell-number.el
+(autoload 'spelln-integer-in-words "spell-number")
+
+
+;;; `conjugate' card type =====================================================
+;;; See spanish.org for usage
+
+(defvar org-drill-verb-tense-alist
+  '(("present" "tomato")
+    ("simple present" "tomato")
+    ("present indicative" "tomato")
+    ;; past tenses
+    ("past" "purple")
+    ("simple past" "purple")
+    ("preterite" "purple")
+    ("imperfect" "darkturquoise")
+    ("present perfect" "royalblue")
+    ;; future tenses
+    ("future" "green"))
+  "Alist where each entry has the form (TENSE COLOUR), where
+TENSE is a string naming a tense in which verbs can be
+conjugated, and COLOUR is a string specifying a foreground colour
+which will be used by `org-drill-present-verb-conjugation' and
+`org-drill-show-answer-verb-conjugation' to fontify the verb and
+the name of the tense.")
+
+
+(defun org-drill-get-verb-conjugation-info ()
+  "Auxiliary function used by `org-drill-present-verb-conjugation' and
+`org-drill-show-answer-verb-conjugation'."
+  (let ((infinitive (org-entry-get (point) "VERB_INFINITIVE" t))
+        (translation (org-entry-get (point) "VERB_TRANSLATION" t))
+        (tense (org-entry-get (point) "VERB_TENSE" nil))
+        (highlight-face nil))
+    (unless (and infinitive translation tense)
+      (error "Missing information for verb conjugation card (%s, %s, %s) at %s"
+             infinitive translation tense (point)))
+    (setq tense (downcase (car (read-from-string tense)))
+          infinitive (car (read-from-string infinitive))
+          translation (car (read-from-string translation)))
+    (setq highlight-face
+          (list :foreground
+                (or (second (assoc-string tense org-drill-verb-tense-alist t))
+                    "red")))
+    (setq infinitive (propertize infinitive 'face highlight-face))
+    (setq translation (propertize translation 'face highlight-face))
+    (setq tense (propertize tense 'face highlight-face))
+    (list infinitive translation tense)))
+
+
+(defun org-drill-present-verb-conjugation ()
+  "Present a drill entry whose card type is 'conjugate'."
+  (destructuring-bind (infinitive translation tense)
+      (org-drill-get-verb-conjugation-info)
+    (org-drill-present-card-using-text
+     (cond
+      ((zerop (random 2))
+       (format "\nTranslate the verb\n\n%s\n\nand conjugate for the %s 
tense.\n\n"
+               infinitive tense))
+      (t
+       (format "\nGive the verb that means\n\n%s\n\nand conjugate for the %s 
tense.\n\n"
+               translation tense))))))
+
+
+(defun org-drill-show-answer-verb-conjugation (reschedule-fn)
+  "Show the answer for a drill item whose card type is 'conjugate'.
+RESCHEDULE-FN must be a function that calls `org-drill-reschedule' and
+returns its return value."
+  (destructuring-bind (infinitive translation tense)
+      (org-drill-get-verb-conjugation-info)
+    (with-replaced-entry-heading
+     (format "%s tense of %s ==> %s\n\n"
+             (capitalize tense)
+             infinitive translation)
+     (funcall reschedule-fn))))
+
+
+;;; `translate_number' card type ==============================================
+;;; See spanish.org for usage
+
+(defvar *drilled-number* 0)
+(defvar *drilled-number-direction* 'to-english)
+
+(defun org-drill-present-translate-number ()
+  (let ((num-min (read (org-entry-get (point) "DRILL_NUMBER_MIN")))
+        (num-max (read (org-entry-get (point) "DRILL_NUMBER_MAX")))
+        (language (read (org-entry-get (point) "DRILL_LANGUAGE" t)))
+        (highlight-face 'font-lock-warning-face))
+    (cond
+     ((not (fboundp 'spelln-integer-in-words))
+      (message "`spell-number.el' not loaded, skipping 'translate_number' 
card...")
+      (sit-for 0.5)
+      'skip)
+     ((not (and (numberp num-min) (numberp num-max) language))
+      (error "Missing language or minimum or maximum numbers for number card"))
+     (t
+      (if (> num-min num-max)
+          (psetf num-min num-max
+                 num-max num-min))
+      (setq *drilled-number*
+            (+ num-min (random (abs (1+ (- num-max num-min))))))
+      (setq *drilled-number-direction*
+            (if (zerop (random 2)) 'from-english 'to-english))
+      (org-drill-present-card-using-text
+       (if (eql 'to-english *drilled-number-direction*)
+           (format "\nTranslate into English:\n\n%s\n"
+                   (let ((spelln-language language))
+                     (propertize
+                      (spelln-integer-in-words *drilled-number*)
+                      'face highlight-face)))
+         (format "\nTranslate into %s:\n\n%s\n"
+                 (capitalize (format "%s" language))
+                 (let ((spelln-language 'english-gb))
+                   (propertize
+                    (spelln-integer-in-words *drilled-number*)
+                    'face highlight-face)))))))))
+
+
+(defun org-drill-show-answer-translate-number (reschedule-fn)
+  (let* ((language (read (org-entry-get (point) "DRILL_LANGUAGE" t)))
+         (highlight-face 'font-lock-warning-face)
+         (non-english
+          (let ((spelln-language language))
+            (propertize (spelln-integer-in-words *drilled-number*)
+                        'face highlight-face)))
+         (english
+          (let ((spelln-language 'english-gb))
+            (propertize (spelln-integer-in-words *drilled-number*)
+                        'face 'highlight-face))))
+    (with-replaced-entry-text
+     (cond
+      ((eql 'to-english *drilled-number-direction*)
+       (format "\nThe English translation of %s is:\n\n%s\n"
+               non-english english))
+      (t
+       (format "\nThe %s translation of %s is:\n\n%s\n"
+               (capitalize (format "%s" language))
+               english non-english)))
+     (funcall reschedule-fn))))
+
+
+;;; `spanish_verb' card type ==================================================
+;;; Not very interesting, but included to demonstrate how a presentation
+;;; function can manipulate which subheading are hidden versus shown.
+
+
+(defun org-drill-present-spanish-verb ()
+  (let ((prompt nil)
+        (reveal-headings nil))
+    (with-hidden-comments
+     (with-hidden-cloze-text
+      (case (random 6)
+        (0
+         (org-drill-hide-all-subheadings-except '("Infinitive"))
+         (setq prompt
+               (concat "Translate this Spanish verb, and conjugate it "
+                       "for the *present* tense.")
+               reveal-headings '("English" "Present Tense" "Notes")))
+        (1
+         (org-drill-hide-all-subheadings-except '("English"))
+         (setq prompt (concat "For the *present* tense, conjugate the "
+                              "Spanish translation of this English verb.")
+               reveal-headings '("Infinitive" "Present Tense" "Notes")))
+        (2
+         (org-drill-hide-all-subheadings-except '("Infinitive"))
+         (setq prompt (concat "Translate this Spanish verb, and "
+                              "conjugate it for the *past* tense.")
+               reveal-headings '("English" "Past Tense" "Notes")))
+        (3
+         (org-drill-hide-all-subheadings-except '("English"))
+         (setq prompt (concat "For the *past* tense, conjugate the "
+                              "Spanish translation of this English verb.")
+               reveal-headings '("Infinitive" "Past Tense" "Notes")))
+        (4
+         (org-drill-hide-all-subheadings-except '("Infinitive"))
+         (setq prompt (concat "Translate this Spanish verb, and "
+                              "conjugate it for the *future perfect* tense.")
+               reveal-headings '("English" "Future Perfect Tense" "Notes")))
+        (5
+         (org-drill-hide-all-subheadings-except '("English"))
+         (setq prompt (concat "For the *future perfect* tense, conjugate the "
+                              "Spanish translation of this English verb.")
+               reveal-headings '("Infinitive" "Future Perfect Tense" 
"Notes"))))
+      (org-cycle-hide-drawers 'all)
+      (prog1
+          (org-drill-presentation-prompt prompt)
+        (org-drill-hide-all-subheadings-except reveal-headings))))))
+
+
diff --git a/spanish.org b/spanish.org
index 387b37ab28..3e6fcb511c 100755
--- a/spanish.org
+++ b/spanish.org
@@ -49,7 +49,7 @@ llamar = to be named
 # that character is considered to be a `hint', and will remain visible when the
 # rest of the clozed text is hidden.
 
-# Set the variable `org-drill-use-visible-cloze-face-p' to `t' if you want 
+# Set the variable `org-drill-use-visible-cloze-face-p' to `t' if you want
 # cloze-deleted text to be shown in a special face when you are editing org
 # mode buffers.
 
@@ -59,27 +59,27 @@ To form the plural of a noun ending in a consonant, add 
[-es] to the end.
 
 *** Grammar Rule                                     :drill:
 
-To make the plural of an adjective ending in [a stressed vowel or a consonant 
+To make the plural of an adjective ending in [a stressed vowel or a consonant
 other than -z], add /-es/.
 
 ** Grammar rules 2
 
-# An example of a 'multicloze' card. One of the areas marked with square
+# An example of a 'hide1cloze' card. One of the areas marked with square
 # brackets will be hidden (chosen at random), the others will remain visible.
 
 *** Grammar Rule                                     :drill:
     :PROPERTIES:
-    :DRILL_CARD_TYPE: multicloze
+    :DRILL_CARD_TYPE: hide1cloze
     :END:
 
-To form [an adverb] from an adjective, add [-mente] to the [feminine|gender] 
+To form [an adverb] from an adjective, add [-mente] to the [feminine|gender]
 form of the adjective.
 
 ** Vocabulary
 
 # Examples of 'twosided' cards. These are 'flip cards' where one of the
 # first 2 'sides' (subheadings) is presented at random, while all others stay
-# hidden. 
+# hidden.
 
 # There is another builtin card type called 'multisided'. These are like
 # 'twosided' cards, but can have any number of sides. So we could extend the
@@ -110,22 +110,15 @@ the cat
 
 *** Noun                                             :drill:
     :PROPERTIES:
-    :DRILL_CARD_TYPE: twosided
+    :DRILL_CARD_TYPE: hide1cloze
     :END:
 
-Translate this word.
-
-**** Spanish
-
-el perro
-
-**** English
-
-the dog
+Sp: [el perro]
+En: [the dog]
 
 **** Example sentence
 
-Cuidado con *el perro*. 
+Cuidado con *el perro*.
 Beware of *the dog*.
 
 
@@ -160,7 +153,7 @@ Translate this word.
 
 caliente
 
-**** English 
+**** English
 
 hot
 
@@ -172,11 +165,90 @@ The water is very hot.
 
 ** Verbs
 
-# An example of a special card type. The information in "spanish_verb" topics
-# can be presented in any of several different ways -- see the function
-# `org-drill-present-spanish-verb'.
+[[Regular Verb: bailar][Below]] is an example of a complex drill item. The 
main item is itself a drill
+item which tests your ability to translate 'bailar' to and from English (which
+direction is chosen at random).
+
+The item has several child items, some of which contain notes about the verb,
+others of which are separate drill items relating to the verb. In this example,
+all the child drill items test verb conjugation, and have the 'conjugate' card
+type. Which tense to test is specified by the =VERB_TENSE= property in each 
item,
+and the information about the verb is retrieved from the parent's
+=VERB_INFINITIVE= and =VERB_TRANSLATION= properties.
+
+Some of the conjugation items are empty -- this allows the user to past in
+conjugations as they are learned.
+
+Following this item is an [[Old Style Verb][example]] of the "spanish_verb" 
card type. This is not
+as sophisticated or useful as the above example, but is intended to demonstrate
+how a function can control which subheadings are visible when an item is
+tested.
+
+
+*** Regular Verb: bailar                                            
:verb:drill:
+  :PROPERTIES:
+  :VERB_INFINITIVE: "bailar"
+  :VERB_TRANSLATION: "to dance"
+  :DRILL_CARD_TYPE: hide1cloze
+  :DATE_ADDED: [2011-04-30 Sat]
+  :END:
 
-*** Verb                                             :drill:
+Sp:  [bailar]
+En:  [to dance] (verb)
+
+**** Notes
+
+This is a regular verb.
+
+**** Examples
+
+Bailé con mi novia.
+I danced with my girlfriend.
+
+**** Present Indicative tense                                       
:verb:drill:
+     :PROPERTIES:
+     :VERB_TENSE: "present indicative"
+     :DRILL_CARD_TYPE: conjugate
+     :END:
+
+| yo            | bailo    |
+| tú            | bailas   |
+| él/usted      | baila    |
+| nosotros      | bailamos |
+| vosotros      | bailáis  |
+| ellos/ustedes | bailan   |
+
+**** Participles                                                    
:verb:drill:
+Present participle of bailar:  [bailando]
+Past participle of bailar:     [bailado]
+
+**** Preterite tense                                                
:verb:drill:
+     :PROPERTIES:
+     :VERB_TENSE: "preterite"
+     :DRILL_CARD_TYPE: conjugate
+     :END:
+
+| yo            | bailé      |
+| tú            | bailaste   |
+| él/usted      | bailó      |
+| nosotros      | bailamos   |
+| vosotros      | bailasteis |
+| ellos/ustedes | bailaron   |
+
+**** Imperfect tense                                                
:verb:drill:
+     :PROPERTIES:
+     :VERB_TENSE: "imperfect"
+     :DRILL_CARD_TYPE: conjugate
+     :END:
+
+**** Future tense                                                   
:verb:drill:
+    :PROPERTIES:
+    :VERB_TENSE: "future"
+    :DRILL_CARD_TYPE: conjugate
+    :END:
+
+
+*** Old Style Verb                                                       
:drill:
     :PROPERTIES:
     :DRILL_CARD_TYPE: spanish_verb
     :END:
@@ -212,3 +284,30 @@ to sing
 
 Regular verb.
 
+
+** Random Numbers
+
+Below is an example of a card that tests the user's ability to translate random
+whole numbers to and from a non-English language. For it to work correctly, you
+must have the third party library 
[[http://www.emacswiki.org/emacs/spell-number.el][spell-number.el]] installed 
and loaded.
+
+The meaning of the item's properties is as follows:
+- =DRILL_LANGUAGE=: any language recognised by spell-number.el. At the time of
+  writing these include: catalan, danish, dutch, english-eur, english-gb,
+  english-us, esperanto, finnish, french-fr, french-ch, german, italian,
+  japanese, norwegian, portuguese-br, portuguese-pt, spanish and swedish.
+- =DRILL_NUMBER_MIN= and =DRILL_NUMBER_MAX=: the range between which the random
+  number will fall.
+
+
+*** Random Number 20-99                                                  
:drill:
+  :PROPERTIES:
+  :DRILL_NUMBER_MIN: 20
+  :DRILL_NUMBER_MAX: 99
+  :DRILL_LANGUAGE: spanish
+  :DRILL_CARD_TYPE: translate_number
+  :END:
+
+# This comment is included so that the item body is non-empty. Items with
+# empty bodies are skipped during drill sessions.
+



reply via email to

[Prev in Thread] Current Thread [Next in Thread]