diff options
| -rw-r--r-- | README.html | 764 | ||||
| -rw-r--r-- | README.org | 410 | ||||
| -rw-r--r-- | org-drill.el | 352 | ||||
| -rw-r--r-- | spanish.org | 86 |
4 files changed, 1482 insertions, 130 deletions
diff --git a/README.html b/README.html new file mode 100644 index 0000000..d3291be --- /dev/null +++ b/README.html @@ -0,0 +1,764 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" +lang="en" xml:lang="en"> +<head> +<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="2010-08-22 09:45:05 NZST"/> +<meta name="author" content="Paul Sexton"/> +<meta name="description" content=""/> +<meta name="keywords" content=""/> +<style type="text/css"> + <!--/*--><![CDATA[/*><!--*/ + html { font-family: Times, serif; font-size: 12pt; } + .title { text-align: center; } + .todo { color: red; } + .done { color: green; } + .tag { background-color: #add8e6; font-weight:normal } + .target { } + .timestamp { color: #bebebe; } + .timestamp-kwd { color: #5f9ea0; } + p.verse { margin-left: 3% } + pre { + border: 1pt solid #AEBDCC; + background-color: #F3F5F7; + padding: 5pt; + font-family: courier, monospace; + font-size: 90%; + overflow:auto; + } + table { border-collapse: collapse; } + td, th { vertical-align: top; } + dt { font-weight: bold; } + div.figure { padding: 0.5em; } + div.figure p { text-align: center; } + textarea { overflow-x: auto; } + .linenr { font-size:smaller } + .code-highlighted {background-color:#ffff00;} + .org-info-js_info-navigation { border-style:none; } + #org-info-js_console-label { font-size:10px; font-weight:bold; + white-space:nowrap; } + .org-info-js_search-highlight {background-color:#ffff00; color:#000000; + font-weight:bold; } + /*]]>*/--> +</style> +<script type="text/javascript"> +<!--/*--><![CDATA[/*><!--*/ + function CodeHighlightOn(elem, id) + { + var target = document.getElementById(id); + if(null != target) { + elem.cacheClassElem = elem.className; + elem.cacheClassTarget = target.className; + target.className = "code-highlighted"; + elem.className = "code-highlighted"; + } + } + function CodeHighlightOff(elem, id) + { + var target = document.getElementById(id); + if(elem.cacheClassElem) + elem.className = elem.cacheClassElem; + if(elem.cacheClassTarget) + target.className = elem.cacheClassTarget; + } +/*]]>*///--> +</script> +</head> +<body> +<div id="content"> + +<h1 class="title">Org-Drill</h1> + + +<div id="table-of-contents"> +<h2>Table of Contents</h2> +<div id="text-table-of-contents"> +<ul> +<li><a href="#sec-1">1 Synopsis </a></li> +<li><a href="#sec-2">2 Installation </a></li> +<li><a href="#sec-3">3 Demonstration </a></li> +<li><a href="#sec-4">4 Writing the questions </a> +<ul> +<li><a href="#sec-4_1">4.1 Simple topics </a></li> +<li><a href="#sec-4_2">4.2 Cloze deletion </a></li> +<li><a href="#sec-4_3">4.3 Two-sided cards </a></li> +<li><a href="#sec-4_4">4.4 Multi-sided cards </a></li> +<li><a href="#sec-4_5">4.5 User-defined topic types </a></li> +</ul> +</li> +<li><a href="#sec-5">5 Running the drill session </a></li> +<li><a href="#sec-6">6 Leeches </a></li> +<li><a href="#sec-7">7 Incremental reading </a></li> +<li><a href="#sec-8">8 Still to do </a></li> +</ul> +</div> +</div> + +<div id="outline-container-1" class="outline-2"> +<h2 id="sec-1"><span class="section-number-2">1</span> Synopsis </h2> +<div class="outline-text-2" id="text-1"> + + + +<p> +Org-Drill uses the spaced repetition algorithm in <code>org-learn</code> to conduct +interactive "drill sessions", using org files as sources of facts to be +memorised. The material to be remembered is presented to the student in random +order. The student rates his or her recall of each item, and this information +is fed back to <code>org-learn</code> to schedule the item for later revision. +</p> +<p> +Each drill session can be restricted to topics in the current buffer +(default), one or several files, all agenda files, or a subtree. A single +topic can also be drilled. +</p> +<p> +Different "topic types" can be defined, which present their information to the +student in different ways. +</p> +<p> +For more on the spaced repetition algorithm, and examples of other programs +that use it, see: +</p><ul> +<li> +<a href="http://supermemo.com/index.htm">SuperMemo</a> (the SM5 algorithm is discussed <a href="http://www.supermemo.com/english/ol/sm5.htm">here</a>) +</li> +<li> +<a href="http://ichi2.net/anki/">Anki</a> +</li> +<li> +<a href="http://mnemosyne-proj.org/index.php">Mnemosyne</a> + + +</li> +</ul> +</div> + +</div> + +<div id="outline-container-2" class="outline-2"> +<h2 id="sec-2"><span class="section-number-2">2</span> Installation </h2> +<div class="outline-text-2" id="text-2"> + + + +<p> +Put the following in your <code>.emacs</code>. You will also need to make sure that Org's +"contrib/lisp" directory is in the emacs load-path. +</p> + + + +<pre class="src src-emacs-lisp"><span style="color: #696969;">(</span><span style="color: #8b4789;">require</span> '<span style="color: #698b22; font-weight: bold;">org-drill</span><span style="color: #696969;">)</span> +</pre> + + + +<p> +I also recommend the following, so that items are always eventually retested, +even when you remember them very well. +</p> + + + +<pre class="src src-emacs-lisp"><span style="color: #696969;">(</span>setq org-learn-always-reschedule t<span style="color: #696969;">)</span> +</pre> + + + +<p> +If you want cloze-deleted text to show up in a special font within Org mode +buffers, also add: +</p> + + + +<pre class="src src-emacs-lisp"><span style="color: #696969;">(</span>setq org-drill-use-visible-cloze-face-p t<span style="color: #696969;">)</span> +</pre> + + + + +</div> + +</div> + +<div id="outline-container-3" class="outline-2"> +<h2 id="sec-3"><span class="section-number-2">3</span> Demonstration </h2> +<div class="outline-text-2" id="text-3"> + + + +<p> +Load the file <a href="spanish.html">spanish.org</a>. Press <code>M-x</code> and run the function <code>org-drill</code>. Follow +the prompts at the bottom of the screen. +</p> +<p> +When the drill finishes, you can look at <code>spanish.org</code> to get some idea of how +drill topics are written. +</p> + +</div> + +</div> + +<div id="outline-container-4" class="outline-2"> +<h2 id="sec-4"><span class="section-number-2">4</span> Writing the questions </h2> +<div class="outline-text-2" id="text-4"> + + + +<p> +Org-Drill uses org mode topics as 'drill items'. To be used as a drill item, +the topic must have a tag that matches <code>org-drill-question-tag</code>. This is +<code>:drill:</code> by default. Any other org topics 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. +</p> +<p> +How should 'drill topics' be structured? Any org topic is a legal drill topic +– it will simply be shown with subheadings collapsed. After pressing a +key, any hidden subheadings will be revealed, and you will be asked to rate +your "recall" of the item. +</p> +<p> +This will be adequate for some items, but usually you will want to write items +where you have more control over what information is hidden from the user for +recall purposes. +</p> + +</div> + +<div id="outline-container-4_1" class="outline-3"> +<h3 id="sec-4_1"><span class="section-number-3">4.1</span> Simple topics </h3> +<div class="outline-text-3" id="text-4_1"> + + +<p> +The simplest drill topic has no special structure. When such a topic is +presented during a drill session, any subheadings are "collapsed" with their +contents hidden. So, you could include the question as text beneath the main +heading, and the answer within a subheading. For example: +</p> + + + +<pre class="example">* Item :drill: +What is the capital city of Estonia? + +** The Answer +Tallinn. +</pre> + + + +<p> +When this item is presented for review, the text beneath the main heading will +be visible, but the contents of the subheading ("The Answer") will be hidden. +</p> + +</div> + +</div> + +<div id="outline-container-4_2" class="outline-3"> +<h3 id="sec-4_2"><span class="section-number-3">4.2</span> Cloze deletion </h3> +<div class="outline-text-3" id="text-4_2"> + + +<p> +Cloze deletion can be used in any drill topic regardless of whether it is +otherwise 'simple', or one of the specialised topic types discussed below. To +use cloze deletion, part of the body of the topic is marked as <i>cloze text</i> by +surrounding it with single square brackets, [like so]. When the topic is +presented for review, the text within square brackets will be obscured. The +text is then revealed after the user presses a key. For example: +</p> + + + +<pre class="example">* Item :drill: +The capital city of Estonia is [Tallinn]. +</pre> + + + +<p> +During review, the user will see: +</p> +<blockquote> + +<p>The capital city of Estonia is <font style="background-color: blue;" color="blue"> +XXXXXXX</font>. +</p> +</blockquote> + + +<p> +When the user presses a key, the text "Tallinn" will become visible. +</p> + +</div> + +</div> + +<div id="outline-container-4_3" class="outline-3"> +<h3 id="sec-4_3"><span class="section-number-3">4.3</span> Two-sided cards </h3> +<div class="outline-text-3" id="text-4_3"> + + +<p> +The remaining topic types all use the topic property, <code>DRILL_CARD_TYPE</code>. This +property tells <code>org-drill</code> which function to use to present the topic during +review. If this property has the value <code>twosided</code> then the topic is treated as +a "two sided card". When a two sided card is reviewed, <i>one of the first two</i> +subheadings within the topic will be visible – all other +subheadings will be hidden. +</p> +<p> +Two-sided cards are meant to emulate the type of flipcard where either side is +useful as test material (for example, a card with a word in a foreign language +on one side, and its translation on the other). +</p> +<p> +A two sided card can have more than 2 subheadings, but all subheadings after +the first two are considered as "notes" and will always be hidden during topic +review. +</p> + + + +<pre class="example">* Noun :drill: + :PROPERTIES: + :DRILL_CARD_TYPE: twosided + :END: + +Translate this word. + +** Spanish +la mujer + +** English +the woman + +** Example sentence +¿Quién fue esa mujer? +Who was that woman? +</pre> + + + +<p> +In this example, the user will be shown the main text – "Translate this word" +– and either 'la mujer', <i>or</i> 'the woman', at random. The section 'Example +sentence' will never be shown until after the user presses a key, because it is +not one of the first two 'sides' of the topic. +</p> + +</div> + +</div> + +<div id="outline-container-4_4" class="outline-3"> +<h3 id="sec-4_4"><span class="section-number-3">4.4</span> Multi-sided cards </h3> +<div class="outline-text-3" id="text-4_4"> + + +<p> +The <code>multisided</code> card type is similar to <code>twosided</code>, except that any +subheading has a chance of being presented during the topic review. One +subheading is always shown and all others are always hidden. +</p> + + + +<pre class="example">* Noun :drill: + :PROPERTIES: + :DRILL_CARD_TYPE: multisided + :END: + +Translate. + +** Spanish +la mesa + +** English +the table + +** Picture +[[file:table.jpg][PICTURE]] +</pre> + + + +<p> +The user will be shown the main text and either 'la mujer', <i>or</i> 'the woman', +<i>or</i> a picture of a table. +</p> + +</div> + +</div> + +<div id="outline-container-4_5" class="outline-3"> +<h3 id="sec-4_5"><span class="section-number-3">4.5</span> User-defined topic types </h3> +<div class="outline-text-3" id="text-4_5"> + + +<p> +Finally, you can write your own elisp 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> +<p> +See the file <a href="spanish.html">spanish.org</a> for a full set of example material. +</p> + +</div> +</div> + +</div> + +<div id="outline-container-5" class="outline-2"> +<h2 id="sec-5"><span class="section-number-2">5</span> Running the drill session </h2> +<div class="outline-text-2" id="text-5"> + + + +<p> +Start a drill session with <code>M-x org-drill</code>. By default, this includes all +non-hidden topics in the current buffer. <code>org-drill</code> takes an optional +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. +</dd> +<dt>file</dt><dd> +The current buffer, including both hidden and non-hidden items. +</dd> +<dt>file-with-archives</dt><dd> +The current buffer, and any archives associated with it. +</dd> +<dt>agenda</dt><dd> +All agenda files. +</dd> +<dt>agenda-with-archives</dt><dd> +All agenda files with any archive files associated +with them. +</dd> +<dt>(file1 file2 …)</dt><dd> +A list of filenames. All files in the list will be +scanned. + +</dd> +</dl> + +<p>During a drill session, you will be presented with each item, then asked to +rate your recall of it by pressing a key between 0 and 5. The meaning of these +numbers is (taken from <code>org-learn</code>): +</p> +<dl> +<dt>0</dt><dd> +Completely forgot. +</dd> +<dt>1</dt><dd> +Even after seeing the answer, it still took a bit to sink in. +</dd> +<dt>2</dt><dd> +After seeing the answer, you remembered it. +</dd> +<dt>3</dt><dd> +It took you awhile, but you finally remembered. +</dd> +<dt>4</dt><dd> +After a little bit of thought you remembered. +</dd> +<dt>5</dt><dd> +You remembered the item really easily. + +</dd> +</dl> + +<p>You can press '?' at the prompt if you have trouble remembering what the +numbers 0–5 signify. At any time you can press 'q' to finish the drill early +(your progress will be saved), or 'e' to finish the drill and jump to the +current topic for editing (your progress up to that point will be saved). +</p> + +</div> + +</div> + +<div id="outline-container-6" class="outline-2"> +<h2 id="sec-6"><span class="section-number-2">6</span> Leeches </h2> +<div class="outline-text-2" id="text-6"> + + + +<p> +From the Anki website, <a href="http://ichi2.net/anki/wiki/Leeches">http://ichi2.net/anki/wiki/Leeches</a>: +</p> +<blockquote> + +<p>Leeches are cards that you keep on forgetting. Because they require so many +reviews, they take up a lot more of your time than other cards. +</p> +</blockquote> + + +<p> +Like Anki, Org-Drill defines leeches as cards that you have "failed" many +times. The number of times an item must be failed before it is considered a +leech is set by the variable <code>org-drill-leech-failure-threshold</code> (15 by +default). When you fail to remember an item more than this many times, the item +will be given the <code>:leech:</code> tag. +</p> +<p> +Leech items can be handled in one of three ways. You can choose how Org-Drill +handles leeches by setting the variable <code>org-drill-leech-method</code> to one of the +following values: +</p><dl> +<dt>nil</dt><dd> +Leech items are tagged with the <code>leech</code> tag, but otherwise treated the +same as normal items. +</dd> +<dt>skip</dt><dd> +Leech items are not included in drill sessions. +</dd> +<dt>warn</dt><dd> +Leech items are still included in drill sessions, but a warning +message is printed when each leech item is presented. + +</dd> +</dl> + +<p>The best way to deal with a leech is either to delete it, or reformulate it so +that it is easier to remember, for example by splitting it into more than one +card. +</p> +<p> +See <a href="http://www.supermemo.com/help/leech.htm">the SuperMemo website</a> for more on leeches. +</p> + +</div> + +</div> + +<div id="outline-container-7" class="outline-2"> +<h2 id="sec-7"><span class="section-number-2">7</span> Incremental reading </h2> +<div class="outline-text-2" id="text-7"> + + + +<p> +An innovative feature of the program SuperMemo is so-called "incremental +reading". This refers to the ability to quickly and easily make drill items +from selected portions of text as you read an article (a web page for +example). See <a href="http://www.supermemo.com/help/read.htm">the SuperMemo website</a> for more on incremental reading. +</p> +<p> +Much of the infrastructure for incremental reading is already provided by Org +Mode, with the help of some other emacs packages. You can provide yourself with +an incremental reading facility by using 'org-capture' alongside a package that +allows you to browse web pages in emacs – e.g. w3 or <a href="http://www.emacswiki.org/emacs/emacs-w3m">emacs-w3m</a>. There is a +large variety of bookmarking packages for emacs which allow you to save your +place in webpages (another important component of incremental reading). See the +<a href="http://www.emacswiki.org/emacs/BookMarks">Emacs Wiki</a> for details. +</p> +<p> +An example of using Org-Drill for incremental reading is given below. First, +and most importantly, we need to define an <code>org-capture</code> template for captured +facts: +</p> + + + +<pre class="src src-emacs-lisp"><span style="color: #696969;">(</span>setq org-capture-templates + `<span style="color: #696969;">((</span><span style="color: #008b00;">"f"</span> <span style="color: #008b00;">"Fact"</span> entry + <span style="color: #696969;">(</span>file+headline <span style="color: #008b00;">"my_new_facts.org"</span> <span style="color: #008b00;">"Incoming"</span><span style="color: #696969;">)</span> + <span style="color: #696969;">(</span>concat <span style="color: #008b00;">"* Fact #%(format \"%s\" (float-time)) :"</span> + org-drill-question-tag + <span style="color: #008b00;">":%^g\n + :PROPERTIES: + :DATE_ADDED: %t + :SOURCE_URL: %a + :END:\n +%i%?\n\n"</span><span style="color: #696969;">)</span> + <span style="color: #4169e1;">:empty-lines</span> 1 + <span style="color: #4169e1;">:immediate-finish</span> nil<span style="color: #696969;">)</span> + <span style="color: #db7093;">;; </span><span style="color: #db7093;">...other capture templates... +</span> <span style="color: #696969;">))</span> +</pre> + + + +<p> +Using this template, you can select a region of text which contains a fact you +want to remember, for example while reading a web page. You then invoke the +capture template above, and the selected text will be turned into a new fact +and saved to whichever file and heading you nominate in the template. You will +be given the opportunity to edit the fact – you should make sure that the fact +makes sense independent of its context, as that is how it will be presented to +you. The easiest way to turn the text into a 'question' is by cloze +deletion. All you need to do is surround the 'hidden' parts of the text with +square brackets. +</p> +<p> +Next, you start reading a web page within Emacs. For example, suppose you are +reading the Wikipedia entry on tuberculosis <a href="http://en.wikipedia.org/wiki/Tuberculosis">here</a>. +</p> +<p> +You read the following: +</p> +<blockquote> + +<p>The classic symptoms of tuberculosis are a chronic cough with blood-tinged +sputum, fever, night sweats, and weight loss. Infection of other organs causes +a wide range of symptoms. Treatment is difficult and requires long courses of +multiple antibiotics. Antibiotic resistance is a growing problem in +(extensively) multi-drug-resistant tuberculosis. Prevention relies on screening +programs and vaccination, usually with Bacillus Calmette-Guérin vaccine. +</p> +</blockquote> + + +<p> +You decide you want to remember that "Bacillus Calmette-Guérin vaccine" is the +name of the vaccine against tuberculosis. First, you select the relevant +portion of the text as the active region: +</p> +<blockquote> + +<p>The classic symptoms of tuberculosis are a chronic cough with blood-tinged +sputum, fever, night sweats, and weight loss. Infection of other organs causes +a wide range of symptoms. Treatment is difficult and requires long courses of +multiple antibiotics. Antibiotic resistance is a growing problem in +(extensively) multi-drug-resistant tuberculosis. +<font style="background-color: yellow;">Prevention relies +on screening programs and vaccination, usually with Bacillus Calmette-Guérin +vaccine.</font> +</p> +</blockquote> + + +<p> +Then you press a key to "capture" this piece of text (whatever key you have +bound to <code>org-capture</code>), followed by "f" to use the "Fact" template shown +above. +</p> +<p> +A temporary buffer will be created, containing something like: +</p> + + + +<pre class="example">** Fact #1282372386.671655 :drill: + + :PROPERTIES: + :DATE_ADDED: <2010-08-21 Sat> + :SOURCE_URL: [[http://en.wikipedia.org/wiki/Tuberculosis][Tuberculosis - Wikipedia, the free encyclopedia]] + :END: + +Prevention relies on screening programs and vaccination, usually with Bacillus +Calmette-Guérin vaccine. +</pre> + + + +<p> +Note that the fact's properties automatically contain the date of its creation, +and a URL linking back to the origin of the fact – the web page you were +browsing, in this case. Because fact "titles" are seldom necessary, the title +of the fact contains a meaningless but unique number (the number of seconds +elapsed since 1/1/1970). +</p> +<p> +Next, you edit the sentence so that it makes sense when you are presented with +it out of context, and you also mark the key fact you want to remember by +surrounding it with single square brackets. +</p> +<pre class="example"> +Prevention of tuberculosis relies on screening programs and vaccination, +usually with [Bacillus Calmette-Guérin vaccine]. +</pre> + + +<p> +You then press <code>C-c C-c</code>, and the new fact is saved. You continue reading the +web page, adding other facts if you wish. +</p> +<p> +Points to note: +</p><ul> +<li> +You can of course define several different "fact" templates, each of which +might send its fact to a different file or subheading, or give it different +tags or properties, for example. +</li> +<li> +You don't have to use a web browser within Emacs. The "fact" template above +will work if you do not have text selected – the new fact will be empty. You +could read a web page (or PDF document, etc) in a program of your choice, +copy some text to the clipboard, then switch to Emacs and paste it into a new +empty fact. +</li> +<li> +Alternatively, you could define a template that takes its text from the +clipboard rather than from the selected region. You can do this by changing +the <code>%i</code> in the fact template to <code>%x</code> or <code>%^C</code>. See the documentation for the +variable <code>org-capture-templates</code> for more details. + + +</li> +</ul> +</div> + +</div> + +<div id="outline-container-8" class="outline-2"> +<h2 id="sec-8"><span class="section-number-2">8</span> Still to do </h2> +<div class="outline-text-2" id="text-8"> + + + +<ul> +<li> +hide drawers. +</li> +<li> +<code>org-drill-question-tag</code> should use a tag match string, rather than a +single tag +</li> +<li> +progress indicator during drill session: cumulative time, time spent thinking +about this card +</li> +<li> +perhaps take account of item priorities, showing high priority items first + +</li> +</ul> +</div> +</div> +<div id="postamble"> +<p class="author"> Author: Paul Sexton +</p> +<p class="date"> Date: 2010-08-22 09:45:05 NZST</p> +<p class="creator">HTML generated by org-mode 7.01trans in emacs 23</p> +</div> +</div> +</body> +</html> diff --git a/README.org b/README.org new file mode 100644 index 0000000..7faf0c2 --- /dev/null +++ b/README.org @@ -0,0 +1,410 @@ +# -*- mode: org; coding: utf-8 -*- +#+TITLE: Org-Drill +#+AUTHOR: Paul Sexton + +* Synopsis + + +Org-Drill uses the spaced repetition algorithm in =org-learn= to conduct +interactive "drill sessions", using org files as sources of facts to be +memorised. The material to be remembered is presented to the student in random +order. The student rates his or her recall of each item, and this information +is fed back to =org-learn= to schedule the item for later revision. + +Each drill session can be restricted to topics in the current buffer +(default), one or several files, all agenda files, or a subtree. A single +topic can also be drilled. + +Different "topic types" can be defined, which present their information to the +student in different ways. + +For more on the spaced repetition algorithm, and examples of other programs +that use it, see: +- [[http://supermemo.com/index.htm][SuperMemo]] (the SM5 algorithm is discussed [[http://www.supermemo.com/english/ol/sm5.htm][here]]) +- [[http://ichi2.net/anki/][Anki]] +- [[http://mnemosyne-proj.org/index.php][Mnemosyne]] + + +* Installation + + +Put the following in your =.emacs=. You will also need to make sure that Org's +"contrib/lisp" directory is in the emacs load-path. + +#+BEGIN_SRC emacs-lisp +(require 'org-drill) +#+END_SRC + +I also recommend the following, so that items are always eventually retested, +even when you remember them very well. + +#+BEGIN_SRC emacs-lisp +(setq org-learn-always-reschedule t) +#+END_SRC + +If you want cloze-deleted text to show up in a special font within Org mode +buffers, also add: + +#+BEGIN_SRC emacs-lisp +(setq org-drill-use-visible-cloze-face-p t) +#+END_SRC + + +* Demonstration + + +Load the file [[file:spanish.org][spanish.org]]. Press =M-x= and run the function =org-drill=. Follow +the prompts at the bottom of the screen. + +When the drill finishes, you can look at =spanish.org= to get some idea of how +drill topics are written. + + +* Writing the questions + + +Org-Drill uses org mode topics as 'drill items'. To be used as a drill item, +the topic must have a tag that matches =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. + +How should 'drill topics' be structured? Any org topic is a legal drill topic +-- it will simply be shown with subheadings collapsed. After pressing a +key, any hidden subheadings will be revealed, and you will be asked to rate +your "recall" of the item. + +This will be adequate for some items, but usually you will want to write items +where you have more control over what information is hidden from the user for +recall purposes. + +** Simple topics + +The simplest drill topic has no special structure. When such a topic is +presented during a drill session, any subheadings are "collapsed" with their +contents hidden. So, you could include the question as text beneath the main +heading, and the answer within a subheading. For example: + +#+BEGIN_EXAMPLE +* Item :drill: +What is the capital city of Estonia? + +** The Answer +Tallinn. +#+END_EXAMPLE + +When this item is presented for review, the text beneath the main heading will +be visible, but the contents of the subheading ("The Answer") will be hidden. + + +** Cloze deletion + +Cloze deletion can be used in any drill topic regardless of whether it is +otherwise 'simple', or one of the specialised topic types discussed below. To +use cloze deletion, part of the body of the topic is marked as /cloze text/ by +surrounding it with single square brackets, [like so]. When the topic is +presented for review, the text within square brackets will be obscured. The +text is then revealed after the user presses a key. For example: + +#+BEGIN_EXAMPLE +* Item :drill: +The capital city of Estonia is [Tallinn]. +#+END_EXAMPLE + +During review, the user will see: + +#+BEGIN_QUOTE +The capital city of Estonia is @<font style="background-color: blue;" color="blue"> +XXXXXXX@</font>. +#+END_QUOTE + +When the user presses a key, the text "Tallinn" will become visible. + + +** Two-sided cards + +The remaining topic types all use the topic property, =DRILL_CARD_TYPE=. This +property tells =org-drill= which function to use to present the topic during +review. If this property has the value =twosided= then the topic is treated as +a "two sided card". When a two sided card is reviewed, /one of the first two/ +subheadings within the topic will be visible -- all other +subheadings will be hidden. + +Two-sided cards are meant to emulate the type of flipcard where either side is +useful as test material (for example, a card with a word in a foreign language +on one side, and its translation on the other). + +A two sided card can have more than 2 subheadings, but all subheadings after +the first two are considered as "notes" and will always be hidden during topic +review. + +#+BEGIN_EXAMPLE +* Noun :drill: + :PROPERTIES: + :DRILL_CARD_TYPE: twosided + :END: + +Translate this word. + +** Spanish +la mujer + +** English +the woman + +** Example sentence +¿Quién fue esa mujer? +Who was that woman? +#+END_EXAMPLE + +In this example, the user will be shown the main text -- "Translate this word" +-- and either 'la mujer', /or/ 'the woman', at random. The section 'Example +sentence' will never be shown until after the user presses a key, because it is +not one of the first two 'sides' of the topic. + + +** Multi-sided cards + +The =multisided= card type is similar to =twosided=, except that any +subheading has a chance of being presented during the topic review. One +subheading is always shown and all others are always hidden. + +#+BEGIN_EXAMPLE +* Noun :drill: + :PROPERTIES: + :DRILL_CARD_TYPE: multisided + :END: + +Translate. + +** Spanish +la mesa + +** English +the table + +** Picture +[[file:table.jpg][PICTURE]] +#+END_EXAMPLE + +The user will be shown the main text and either 'la mujer', /or/ 'the woman', +/or/ a picture of a table. + + +** User-defined topic types + +Finally, you can write your own elisp 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'. + +See the file [[file:spanish.org][spanish.org]] for a full set of example material. + + +* Running the drill session + + +Start a drill session with =M-x org-drill=. By default, this includes all +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. +- 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. +- agenda-with-archives :: All agenda files with any archive files associated + with them. +- (file1 file2 ...) :: A list of filenames. All files in the list will be + scanned. + +During a drill session, you will be presented with each item, then asked to +rate your recall of it by pressing a key between 0 and 5. The meaning of these +numbers is (taken from =org-learn=): + +- 0 :: Completely forgot. +- 1 :: Even after seeing the answer, it still took a bit to sink in. +- 2 :: After seeing the answer, you remembered it. +- 3 :: It took you awhile, but you finally remembered. +- 4 :: After a little bit of thought you remembered. +- 5 :: You remembered the item really easily. + +You can press '?' at the prompt if you have trouble remembering what the +numbers 0--5 signify. At any time you can press 'q' to finish the drill early +(your progress will be saved), or 'e' to finish the drill and jump to the +current topic for editing (your progress up to that point will be saved). + + +* Leeches + + +From the Anki website, http://ichi2.net/anki/wiki/Leeches: + +#+BEGIN_QUOTE +Leeches are cards that you keep on forgetting. Because they require so many +reviews, they take up a lot more of your time than other cards. +#+END_QUOTE + +Like Anki, Org-Drill defines leeches as cards that you have "failed" many +times. The number of times an item must be failed before it is considered a +leech is set by the variable =org-drill-leech-failure-threshold= (15 by +default). When you fail to remember an item more than this many times, the item +will be given the =:leech:= tag. + +Leech items can be handled in one of three ways. You can choose how Org-Drill +handles leeches by setting the variable =org-drill-leech-method= to one of the +following values: +- nil :: Leech items are tagged with the =leech= tag, but otherwise treated the + same as normal items. +- skip :: Leech items are not included in drill sessions. +- warn :: Leech items are still included in drill sessions, but a warning + message is printed when each leech item is presented. + +The best way to deal with a leech is either to delete it, or reformulate it so +that it is easier to remember, for example by splitting it into more than one +card. + +See [[http://www.supermemo.com/help/leech.htm][the SuperMemo website]] for more on leeches. + + +* Incremental reading + + +An innovative feature of the program SuperMemo is so-called "incremental +reading". This refers to the ability to quickly and easily make drill items +from selected portions of text as you read an article (a web page for +example). See [[http://www.supermemo.com/help/read.htm][the SuperMemo website]] for more on incremental reading. + +Much of the infrastructure for incremental reading is already provided by Org +Mode, with the help of some other emacs packages. You can provide yourself with +an incremental reading facility by using 'org-capture' alongside a package that +allows you to browse web pages in emacs -- e.g. w3 or [[http://www.emacswiki.org/emacs/emacs-w3m][emacs-w3m]]. There is a +large variety of bookmarking packages for emacs which allow you to save your +place in webpages (another important component of incremental reading). See the +[[http://www.emacswiki.org/emacs/BookMarks][Emacs Wiki]] for details. + +An example of using Org-Drill for incremental reading is given below. First, +and most importantly, we need to define an =org-capture= template for captured +facts: + +#+BEGIN_SRC emacs-lisp +(setq org-capture-templates + `(("f" "Fact" entry + (file+headline "my_new_facts.org" "Incoming") + (concat "* Fact #%(format \"%s\" (float-time)) :" + org-drill-question-tag + ":%^g\n + :PROPERTIES: + :DATE_ADDED: %t + :SOURCE_URL: %a + :END:\n +%i%?\n\n") + :empty-lines 1 + :immediate-finish nil) + ;; ...other capture templates... + )) +#+END_SRC + +Using this template, you can select a region of text which contains a fact you +want to remember, for example while reading a web page. You then invoke the +capture template above, and the selected text will be turned into a new fact +and saved to whichever file and heading you nominate in the template. You will +be given the opportunity to edit the fact -- you should make sure that the fact +makes sense independent of its context, as that is how it will be presented to +you. The easiest way to turn the text into a 'question' is by cloze +deletion. All you need to do is surround the 'hidden' parts of the text with +square brackets. + +Next, you start reading a web page within Emacs. For example, suppose you are +reading the Wikipedia entry on tuberculosis [[http://en.wikipedia.org/wiki/Tuberculosis][here]]. + +You read the following: + +#+BEGIN_QUOTE +The classic symptoms of tuberculosis are a chronic cough with blood-tinged +sputum, fever, night sweats, and weight loss. Infection of other organs causes +a wide range of symptoms. Treatment is difficult and requires long courses of +multiple antibiotics. Antibiotic resistance is a growing problem in +(extensively) multi-drug-resistant tuberculosis. Prevention relies on screening +programs and vaccination, usually with Bacillus Calmette-Guérin vaccine. +#+END_QUOTE + +You decide you want to remember that "Bacillus Calmette-Guérin vaccine" is the +name of the vaccine against tuberculosis. First, you select the relevant +portion of the text as the active region: + +#+BEGIN_QUOTE +The classic symptoms of tuberculosis are a chronic cough with blood-tinged +sputum, fever, night sweats, and weight loss. Infection of other organs causes +a wide range of symptoms. Treatment is difficult and requires long courses of +multiple antibiotics. Antibiotic resistance is a growing problem in +(extensively) multi-drug-resistant tuberculosis. +@<font style="background-color: yellow;">Prevention relies +on screening programs and vaccination, usually with Bacillus Calmette-Guérin +vaccine.@</font> +#+END_QUOTE + +Then you press a key to "capture" this piece of text (whatever key you have +bound to =org-capture=), followed by "f" to use the "Fact" template shown +above. + +A temporary buffer will be created, containing something like: + +#+BEGIN_EXAMPLE +** Fact #1282372386.671655 :drill: + + :PROPERTIES: + :DATE_ADDED: <2010-08-21 Sat> + :SOURCE_URL: [[http://en.wikipedia.org/wiki/Tuberculosis][Tuberculosis - Wikipedia, the free encyclopedia]] + :END: + +Prevention relies on screening programs and vaccination, usually with Bacillus +Calmette-Guérin vaccine. +#+END_EXAMPLE + +Note that the fact's properties automatically contain the date of its creation, +and a URL linking back to the origin of the fact -- the web page you were +browsing, in this case. Because fact "titles" are seldom necessary, the title +of the fact contains a meaningless but unique number (the number of seconds +elapsed since 1/1/1970). + +Next, you edit the sentence so that it makes sense when you are presented with +it out of context, and you also mark the key fact you want to remember by +surrounding it with single square brackets. + +: Prevention of tuberculosis relies on screening programs and vaccination, +: usually with [Bacillus Calmette-Guérin vaccine]. + +You then press =C-c C-c=, and the new fact is saved. You continue reading the +web page, adding other facts if you wish. + +Points to note: +- You can of course define several different "fact" templates, each of which + might send its fact to a different file or subheading, or give it different + tags or properties, for example. +- You don't have to use a web browser within Emacs. The "fact" template above + will work if you do not have text selected -- the new fact will be empty. You + could read a web page (or PDF document, etc) in a program of your choice, + copy some text to the clipboard, then switch to Emacs and paste it into a new + empty fact. +- Alternatively, you could define a template that takes its text from the + clipboard rather than from the selected region. You can do this by changing + the =%i= in the fact template to =%x= or =%^C=. See the documentation for the + variable =org-capture-templates= for more details. + + +* Still to do + + +- hide drawers. +- =org-drill-question-tag= should use a tag match string, rather than a + single tag +- progress indicator during drill session: cumulative time, time spent thinking + about this card +- perhaps take account of item priorities, showing high priority items first + diff --git a/org-drill.el b/org-drill.el index 89c3124..b92a39d 100644 --- a/org-drill.el +++ b/org-drill.el @@ -21,77 +21,8 @@ ;;; Different "card types" can be defined, which present their information to ;;; the student in different ways. ;;; -;;; -;;; Installation -;;; ============ -;;; -;;; Put the following in your .emacs: -;;; -;;; (add-to-list 'load-path "/path/to/org-drill/") -;;; (require 'org-drill) -;;; -;;; -;;; Writing the questions -;;; ===================== -;;; -;;; See the file "spanish.org" for an example set of material. -;;; -;;; Tag all items you want to be asked about with a tag that matches -;;; `org-drill-question-tag'. This is :drill: by default. -;;; -;;; You don't need to schedule the topics initially. However org-drill *will* -;;; recognise items that have been scheduled previously with `org-learn'. -;;; -;;; Within each question, the answer can be included in the following ways: -;;; -;;; - Question in the main body text, answer in subtopics. This is the -;;; default. All subtopics will be shown collapsed, while the text under -;;; the main heading will stay visible. -;;; -;;; - Each subtopic contains a piece of information related to the topic. ONE -;;; of these will revealed at random, and the others hidden. To define a -;;; topic of this type, give the topic a property `DRILL_CARD_TYPE' with -;;; value `multisided'. -;;; -;;; - Cloze deletion -- any pieces of text in the body of the card that are -;;; surrounded with [SINGLE square brackets] will be hidden when the card is -;;; presented to the user, and revealed once they press a key. Cloze deletion -;;; is automatically applied to all topics. -;;; -;;; - No explicit answer -- the user judges whether they recalled the -;;; fact adequately. -;;; -;;; - Other methods of your own devising, provided you write a function to -;;; handle selective display of the topic. See the function -;;; `org-drill-present-spanish-verb', which handles topics of type "spanish_verb", -;;; for an example. -;;; -;;; -;;; Running the drill session -;;; ========================= -;;; -;;; Start a drill session with `M-x org-drill'. This will include all eligible -;;; topics in the current buffer. `org-drill' can also be targeted at a particular -;;; subtree or particular files or sets of files; see the documentation of -;;; the function `org-drill' for details. -;;; -;;; During the drill session, you will be presented with each item, then asked -;;; to rate your recall of it by pressing a key between 0 and 5. At any time you -;;; can press 'q' to finish the drill early (your progress will be saved), or -;;; 'e' to finish the drill and jump to the current topic for editing. -;;; -;;; -;;; TODO -;;; ==== -;;; -;;; - encourage org-learn to reschedule "4" and "5" items. -;;; - nicer "cloze face" which does not hide the space preceding the cloze, -;;; and behaves more nicely across line breaks -;;; - hide drawers. -;;; - org-drill-question-tag should use a tag match string, rather than a -;;; single tag -;;; - when finished, display a message showing how many items reviewed, -;;; how many still pending, numbers in each recall category +;;; See the file README.org for more detailed documentation. + (eval-when-compile (require 'cl)) (eval-when-compile (require 'hi-lock)) @@ -132,6 +63,41 @@ Nil means unlimited." :type '(choice integer (const nil))) +(defcustom org-drill-leech-failure-threshold + 15 + "If an item is forgotten more than this many times, it is tagged +as a 'leech' item." + :group 'org-drill + :type '(choice integer (const nil))) + + +(defcustom org-drill-leech-method + 'skip + "How should 'leech items' be handled during drill sessions? +Possible values: +- nil :: Leech items are treated the same as normal items. +- skip :: Leech items are not included in drill sessions. +- warn :: Leech items are still included in drill sessions, + but a warning message is printed when each leech item is + presented." + :group 'org-drill + :type '(choice (const 'warn) (const 'skip) (const nil))) + + +(defface org-drill-visible-cloze-face + '((t (:foreground "dark slate blue"))) + "The face used to hide the contents of cloze phrases." + :group 'org-drill) + + +(defcustom org-drill-use-visible-cloze-face-p + nil + "Use a special face to highlight cloze-deleted text in org mode +buffers?" + :group 'org-drill + :type 'boolean) + + (defface org-drill-hidden-cloze-face '((t (:foreground "blue" :background "blue"))) @@ -140,12 +106,14 @@ Nil means unlimited." (defvar org-drill-cloze-regexp - "[^][]\\(\\[[^][][^]]*\\]\\)") + ;; old "[^][]\\(\\[[^][][^]]*\\]\\)" + "\\(\\[.*?\\]\\|^[^[[:cntrl:]]*?\\]\\|\\[.*?$\\)") (defcustom org-drill-card-type-alist '((nil . org-drill-present-simple-card) ("simple" . org-drill-present-simple-card) + ("twosided" . org-drill-present-two-sided-card) ("multisided" . org-drill-present-multi-sided-card) ("spanish_verb" . org-drill-present-spanish-verb)) "Alist associating card types with presentation functions. Each entry in the @@ -156,6 +124,11 @@ boolean value." :type '(alist :key-type (choice string (const nil)) :value-type function)) +(defvar *org-drill-done-entry-count* 0) +(defvar *org-drill-pending-entry-count* 0) +(defvar *org-drill-session-qualities* nil) +(defvar *org-drill-start-time* 0) + (defun shuffle-list (list) "Randomly permute the elements of LIST (all permutations equally likely)." @@ -174,19 +147,46 @@ boolean value." +(defun org-drill-entry-p () + "Is the current entry a 'drill item'?" + (or (assoc "LEARN_DATA" (org-entry-properties nil)) + (member org-drill-question-tag (org-get-local-tags)))) + + +(defun org-drill-entry-leech-p () + "Is the current entry a 'leech item'?" + (and (org-drill-entry-p) + (member "leech" (org-get-local-tags)))) + + (defun org-drill-entry-due-p () (let ((item-time (org-get-scheduled-time (point)))) - (and (or (assoc "LEARN_DATA" (org-entry-properties nil)) - (member org-drill-question-tag (org-get-local-tags))) + (and (org-drill-entry-p) + (or (not (eql 'skip org-drill-leech-method)) + (not (org-drill-entry-leech-p))) (or (null item-time) - (not (minusp ; scheduled for today/in - ; future + (not (minusp ; scheduled for today/in future (- (time-to-days (current-time)) (time-to-days item-time)))))))) +(defun org-drill-entry-new-p () + (let ((item-time (org-get-scheduled-time (point)))) + (and (org-drill-entry-p) + (null item-time)))) + + + +(defun org-drill-entry-last-quality () + (let ((quality (cdr (assoc "DRILL_LAST_QUALITY" (org-entry-properties nil))))) + (if quality + (string-to-number quality) + nil))) + + (defun org-drill-reschedule () + "Returns quality rating (0-5), or nil if the user quit." (let ((ch nil)) (while (not (memq ch '(?q ?0 ?1 ?2 ?3 ?4 ?5))) (setq ch (read-char @@ -205,9 +205,21 @@ How well did you do? (0-5, ?=help, q=quit)" "How well did you do? (0-5, ?=help, q=quit)")))) (cond ((and (>= ch ?0) (<= ch ?5)) - (save-excursion - (org-smart-reschedule (- ch 48))) - ch) + (let ((quality (- ch ?0)) + (failures (cdr (assoc "DRILL_FAILURE_COUNT" (org-entry-properties nil))))) + (save-excursion + (org-smart-reschedule quality)) + (push quality *org-drill-session-qualities*) + (cond + ((< quality 3) + (when org-drill-leech-failure-threshold + (setq failures (if failures (string-to-number failures) 0)) + (org-set-property "DRILL_FAILURE_COUNT" + (format "%d" (1+ failures))) + (if (> (1+ failures) org-drill-leech-failure-threshold) + (org-toggle-tag "leech" 'on))))) + (org-set-property "DRILL_LAST_QUALITY" (format "%d" quality)) + quality)) (t nil)))) @@ -231,12 +243,23 @@ the current topic." (reverse drill-sections))) + (defun org-drill-presentation-prompt (&rest fmt-and-args) - (let ((ch (read-char (if fmt-and-args - (apply 'format - (first fmt-and-args) - (rest fmt-and-args)) - "Press any key to see the answer, 'e' to edit, 'q' to quit.")))) + (let ((ch nil) + (prompt + (if fmt-and-args + (apply 'format + (first fmt-and-args) + (rest fmt-and-args)) + "Press any key to see the answer, 'e' to edit, 'q' to quit."))) + (setq prompt + (format "(%d) %s" *org-drill-pending-entry-count* prompt)) + (if (and (eql 'warn org-drill-leech-method) + (org-drill-entry-leech-p)) + (setq prompt (concat "!!! LEECH ITEM !!! +You seem to be having a lot of trouble memorising this item. +Consider reformulating the item to make it easier to remember.\n" prompt))) + (setq ch (read-char prompt)) (case ch (?q nil) (?e 'edit) @@ -258,6 +281,18 @@ the current topic." (org-show-subtree))) +(defun org-drill-present-two-sided-card () + (let ((drill-sections (org-drill-hide-all-subheadings-except nil))) + (when drill-sections + (save-excursion + (goto-char (nth (random (min 2 (length drill-sections))) drill-sections)) + (org-show-subtree))) + (prog1 + (org-drill-presentation-prompt) + (org-show-subtree)))) + + + (defun org-drill-present-multi-sided-card () (let ((drill-sections (org-drill-hide-all-subheadings-except nil))) (when drill-sections @@ -323,6 +358,9 @@ the current topic." Review will occur regardless of whether the topic is due for review or whether it meets the definition of a 'review topic' used by `org-drill'. +Returns a quality rating from 0 to 5, or nil if the user quit, or the symbol +EDIT if the user chose to exit the drill and edit the current item. + See `org-drill' for more details." (interactive) (unless (org-at-heading-p) @@ -332,7 +370,7 @@ See `org-drill' for more details." (save-restriction (org-narrow-to-subtree) (org-show-subtree) - (org-cycle-hide-drawers 'overview) + (org-cycle-hide-drawers 'all) (let ((presentation-fn (cdr (assoc card-type org-drill-card-type-alist)))) (cond @@ -356,6 +394,81 @@ See `org-drill' for more details." +(defun org-drill-entries (entries) + "Returns nil, t, or a list of markers representing entries that were +'failed' and need to be presented again before the session ends." + (let ((again-entries nil) + (*org-drill-done-entry-count* 0) + (*org-drill-pending-entry-count* (length entries))) + (if (and org-drill-maximum-items-per-session + (> (length entries) + org-drill-maximum-items-per-session)) + (setq entries (subseq entries 0 + org-drill-maximum-items-per-session))) + (block org-drill-entries + (dolist (m entries) + (save-restriction + (switch-to-buffer (marker-buffer m)) + (goto-char (marker-position m)) + (setq result (org-drill-entry)) + (cond + ((null result) + (message "Quit") + (return-from org-drill-entries nil)) + ((eql result 'edit) + (setq end-pos (point-marker)) + (return-from org-drill-entries nil)) + (t + (cond + ((< result 3) + (push m again-entries)) + (t + (decf *org-drill-pending-entry-count*) + (incf *org-drill-done-entry-count*))) + (when (and org-drill-maximum-duration + (> (- (float-time (current-time)) *org-drill-start-time*) + (* org-drill-maximum-duration 60))) + (message "This drill session has reached its maximum duration.") + (return-from org-drill-entries nil)))))) + (or again-entries + t)))) + + +(defun org-drill-final-report () + (read-char +(format + "%d items reviewed, %d items awaiting review +Session duration %s + +Recall of reviewed items: + Excellent (5): %3d%% + Good (4): %3d%% + Hard (3): %3d%% + Near miss (2): %3d%% + Failure (1): %3d%% + Total failure (0): %3d%% + +Session finished. Press a key to continue..." + *org-drill-done-entry-count* + *org-drill-pending-entry-count* + (format-seconds "%h:%.2m:%.2s" + (- (float-time (current-time)) *org-drill-start-time*)) + (round (* 100 (count 5 *org-drill-session-qualities*)) + (length *org-drill-session-qualities*)) + (round (* 100 (count 4 *org-drill-session-qualities*)) + (length *org-drill-session-qualities*)) + (round (* 100 (count 3 *org-drill-session-qualities*)) + (length *org-drill-session-qualities*)) + (round (* 100 (count 2 *org-drill-session-qualities*)) + (length *org-drill-session-qualities*)) + (round (* 100 (count 1 *org-drill-session-qualities*)) + (length *org-drill-session-qualities*)) + (round (* 100 (count 0 *org-drill-session-qualities*)) + (length *org-drill-session-qualities*)) + ))) + + + (defun org-drill (&optional scope) "Begin an interactive 'drill session'. The user is asked to review a series of topics (headers). Each topic is initially @@ -398,49 +511,64 @@ agenda-with-archives (interactive) (let ((entries nil) + (failed-entries nil) + (new-entries nil) + (old-entries nil) (result nil) (results nil) (end-pos nil)) (block org-drill + (setq *org-drill-session-qualities* nil) + (setq *org-drill-start-time* (float-time (current-time))) (save-excursion (org-map-entries - (lambda () (if (org-drill-entry-due-p) - (push (point-marker) entries))) + (lambda () (when (org-drill-entry-due-p) + (cond + ((org-drill-entry-new-p) + (push (point-marker) new-entries)) + ((member (org-drill-entry-last-quality) '(0 1 2)) + (push (point-marker) failed-entries)) + (t + (push (point-marker) old-entries))))) "" scope) + ;; Failed first, then random mix of old + new + (setq entries (append (shuffle-list failed-entries) + (shuffle-list (append old-entries + new-entries)))) (cond ((null entries) (message "I did not find any pending drill items.")) (t - (let ((start-time (float-time (current-time)))) - (dolist (m (if (and org-drill-maximum-items-per-session - (> (length entries) - org-drill-maximum-items-per-session)) - (subseq (shuffle-list entries) 0 - org-drill-maximum-items-per-session) - (shuffle-list entries))) - (save-restriction - (switch-to-buffer (marker-buffer m)) - (goto-char (marker-position m)) - (setq result (org-drill-entry)) - (cond - ((null result) - (message "Quit") - (return-from org-drill nil)) - ((eql result 'edit) - (setq end-pos (point-marker)) - (return-from org-drill nil)) - ((and org-drill-maximum-duration - (> (- (float-time (current-time)) start-time) - (* org-drill-maximum-duration 60))) - (message "This drill session has reached its maximum duration.") - (return-from org-drill nil))))) + (let ((again t)) + (while again + (when (listp again) + (setq entries (shuffle-list again))) + (setq again (org-drill-entries entries)) + (cond + ((null again) + (return-from org-drill nil)) + ((eql t again) + (setq again nil)))) (message "Drill session finished!") ))))) - (when end-pos + (cond + (end-pos (switch-to-buffer (marker-buffer end-pos)) (goto-char (marker-position end-pos)) - (message "Edit topic.")))) + (message "Edit topic.")) + (t + (org-drill-final-report))))) + + +(add-hook 'org-mode-hook + (lambda () + (if org-drill-use-visible-cloze-face-p + (font-lock-add-keywords + 'org-mode + `((,org-drill-cloze-regexp + (0 'org-drill-visible-cloze-face nil))) + t)))) (provide 'org-drill) diff --git a/spanish.org b/spanish.org index 82dc981..cb187b8 100644 --- a/spanish.org +++ b/spanish.org @@ -2,12 +2,14 @@ #+STARTUP: showall # examples of card definitions for use with org-drill. +# Cards, AKA topics, have the 'drill' tag. Note that the higher-level headings +# in the file do NOT have this tag. * Spanish questions ** Greetings -# Simple cards. When each card is presented, any subheadings are collapsed, but +# Simple cards. When each card is presented, all subheadings are collapsed, but # the text under the topic's main heading remains visible. *** Greeting 1 :drill: @@ -19,6 +21,10 @@ What is your name? (formal) ¿Cómo se llama usted? +**** Notes + +llamar = to be named + *** Greeting 2 :drill: Translate into Spanish: @@ -28,17 +34,46 @@ What is your name? (informal) ¿Cómo te llamas? -** Nouns +**** Notes + +llamar = to be named + + +** Grammar rules + +# More simple cards -- here the question and answer are produced purely using +# cloze deletion of test in [square brackets], without the need to hide any +# subtopics (though they WILL still be hidden if present). + +# 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. + +*** Grammar Rule :drill: + +To make the plural of an adjective ending in [a stressed vowel or a consonant +other than -z], add /-es/. + +*** Grammar Rule :drill: + +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. -# Examples of 'multisided' cards. The user will randomly be presented with ONE -# of the subheadings -- in this case either the Spanish word, or the English -# word. +# 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 +# examples below by changing their type to multisided and adding a third +# subheading which contains an inline image. -# (we could include a third subheading which just contains an inline picture.) *** Noun :drill: :PROPERTIES: - :DRILL_CARD_TYPE: multisided + :DRILL_CARD_TYPE: twosided :END: Translate this word. @@ -51,10 +86,15 @@ el gato the cat +**** Example sentence + +*El gato* se sentó en la estera. +*The cat* sat on the mat. + *** Noun :drill: :PROPERTIES: - :DRILL_CARD_TYPE: multisided + :DRILL_CARD_TYPE: twosided :END: Translate this word. @@ -67,22 +107,32 @@ el perro the dog +**** Example sentence -** Grammar rules +Cuidado con *el perro*. +Beware of *the dog*. -# More simple cards -- here the question and answer are produced purely using -# cloze deletion of test in [square brackets], without the need to hide any -# subtopics. -*** Grammar Rule :drill: +*** Adjective :drill: + :PROPERTIES: + :DRILL_CARD_TYPE: twosided + :END: -To make the plural of an adjective ending in [a stressed vowel or a consonant -other than -z], add /-es/. +Translate this word. -*** Grammar Rule :drill: +**** Spanish + +caliente + +**** English + +hot + +**** Example sentence + +El agua está muy caliente. +The water is very hot. -To form an adverb from an adjective, add [-mente] to the [feminine] (gender) -form of the adjective. ** Verbs |
