[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
-– 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.
@@ -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 – 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 ('# …') 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
– 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.
+
- [nongnu] elpa/org-drill 3cf59ccba6 226/251: Update documentation, (continued)
- [nongnu] elpa/org-drill 3cf59ccba6 226/251: Update documentation, ELPA Syncer, 2022/01/17
- [nongnu] elpa/org-drill ecf4bae5ce 237/251: Fix typo "Eaqch" to "Each", ELPA Syncer, 2022/01/17
- [nongnu] elpa/org-drill 64d878afe3 212/251: Update README's installation instructions, ELPA Syncer, 2022/01/17
- [nongnu] elpa/org-drill fca357cad8 220/251: Add blank line between authors in README, ELPA Syncer, 2022/01/17
- [nongnu] elpa/org-drill f5b7472de1 204/251: Remove unused variable, ELPA Syncer, 2022/01/17
- [nongnu] elpa/org-drill 4307a3a387 233/251: Show latex overlays in simple card's answer, ELPA Syncer, 2022/01/17
- [nongnu] elpa/org-drill 2d7ea5d00b 245/251: add helper fn to check cards without killing emacs, ELPA Syncer, 2022/01/17
- [nongnu] elpa/org-drill fee727e76e 023/251: Added tag 2.0 for changeset 16cafa21aef0, ELPA Syncer, 2022/01/17
- [nongnu] elpa/org-drill 8b72dfbded 024/251: - Can now resume drill sessions after exiting with (e)dit or (q)uit commands!, ELPA Syncer, 2022/01/17
- [nongnu] elpa/org-drill 2d039d0429 027/251: Added tag 2.1.1 for changeset 60b0a80ce97a, ELPA Syncer, 2022/01/17
- [nongnu] elpa/org-drill c27d9035ef 030/251: - Added new example card types, more useful than 'spanish_verb':,
ELPA Syncer <=
- [nongnu] elpa/org-drill ce3e540b00 035/251: Added tag 2.3.1 for changeset 566cf446fdae, ELPA Syncer, 2022/01/17
- [nongnu] elpa/org-drill 0aeff8516d 032/251: - All drill items now receive unique IDs (using the org-id module). This allows, ELPA Syncer, 2022/01/17
- [nongnu] elpa/org-drill 1c77d6cf3a 041/251: Removed old doc files (renamed)., ELPA Syncer, 2022/01/17
- [nongnu] elpa/org-drill ca5231b9b4 043/251: Cloze text is now correctly identified in items whose bodies contain [[bracketed links]]., ELPA Syncer, 2022/01/17
- [nongnu] elpa/org-drill 8133a8c566 044/251: Added tag 2.3.3 for changeset e68b52fe88ac, ELPA Syncer, 2022/01/17
- [nongnu] elpa/org-drill c410f8dcb0 042/251: Added tag 2.3.2 for changeset 4e43f149ea97, ELPA Syncer, 2022/01/17
- [nongnu] elpa/org-drill 7301c9ea71 073/251: Fixed calculation of 'org-drill-entry-days-since-creation' for cases where 'org-drill-entry-days-overdue' returns NIL., ELPA Syncer, 2022/01/17
- [nongnu] elpa/org-drill 361aa53a14 069/251: Very overdue items are considered "lapsed" and are presented in the order they, ELPA Syncer, 2022/01/17
- [nongnu] elpa/org-drill 612848a840 068/251: Added tag 2.4.1 for changeset 97f51d64df45, ELPA Syncer, 2022/01/17
- [nongnu] elpa/org-drill d987e8d734 081/251: Added tag 2.5.0 for changeset 9b098bf2648d, ELPA Syncer, 2022/01/17