Spaced-repetition system for use with Emacs org-mode.
Org-fc has been tested with org-mode version 9.3.6 and gawk version
5.1.0. You can check your versions with M-x org-version
and gawk -V
.
In the most abstract sense, this package deals with
- Attaching timestamped review information to headlines
- Querying all headings where reviews are due
- Reviewing due positions of headings
As mentioned in step 3, a heading can have multiple positions, e.g. to implement cloze-deletions where multiple items are reviewed independently from each other.
In the reviewing step, display functions can be registered by card type. This allows easy addition of user-defined card types without having to think about storing and updating review data.
Review functions are called with point on the headline of the card that should be reviewed and get passed a single argument, the position to be reviewed.
They are expected to return either 'quit
to end the review or one of
'again
, 'hard
, 'good
, 'ease
, to rate the card.
See also:
- Use of
awk
for quickly finding cards due for review - Support for multiple positions in a card / heading
- All relevant data kept in org files for easy version control
- Review directly on the source org file for easy editing of cards during review
See Design Choices for more information.
There are a few other packages for implementing a SRS based on org-mode.
Below, I've listed a the ones I've found so far that are actively maintained and implement a lot of useful functionality.
Other (open source) flashcard / spaced repetition software:
Thanks to the maintainers and all contributors for their work on these packages!
All user-facing commands (especially during review) should be as fast as possible (<300ms).
Using the awk
indexer, searching 2500 org files (~200k lines in
total) for due flashcards takes around ~500ms on my laptop (Thinkpad
L470, SSD).
Using the lisp indexer based on org-map-entries
, searching a single
6500 line file with 333 flashcards takes ~1000ms, indexing the same
file with awk
takes around ~50ms.
Before using this package, org-fc-directories
should be set to the
directory to search for org files containing flashcards.
The file used to store the review history can be customized with
org-fc-review-history-file
and defaults to
/path/to/config/org-fc-reviews.tsv
.
This package is not (yet) available on MELPA / ELPA, to install it,
clone the repository (e.g. to src/org-fc/
) and follow the setup
instructions.
- The
gawk
extension ofawk
for extracting review data from.org
files find
for finding all org files in theorg-fc-directories
xargs
for processing files in parallel
-
Linux / UNIX
find
andxargs
should be included in most distributions,gawk
can be installed from source or using your package manager of choice.Examples:
pacman -S gawk
(Arch Linux)apt-get install gawk
(Ubuntu, Debian, ...)yum install gawk
(CentOS)
For more information, see gawk manual - Installation.
-
MacOS
On MacOS all dependencies can be installed using macports or homebrew.
find
andxargs
are part of thefindutils
package.port install gawk findutils
brew install gawk findutils
You might have to adjust your
$PATH
to make sure Emacs can find all relevant binaries.export PATH="/opt/local/libexec/gnubin:/opt/local/bin:$PATH"
For more information, refer to the documentation of macports / homebrew.
Setup with use-package
(use-package hydra)
(use-package org-fc
:load-path "~/src/org-fc"
:custom (org-fc-directories '("~/org/"))
:config
(require 'org-fc-hydra))
Or, using straight.el:
(use-package hydra)
(use-package org-fc
:straight
(org-fc
:type git :host github :repo "l3kn/org-fc"
:files (:defaults "awk" "demo.org"))
:custom
(org-fc-directories '("~/org/"))
:config
(require 'org-fc-hydra))
Note that in this case, you don't have to clone the repository.
Setup with straight.el
(straight-use-package 'hydra)
(straight-use-package
'(org-fc
:type git :host github :repo "l3kn/org-fc"
:files (:defaults "awk" "demo.org")
:custom (org-fc-directories '("~/org/"))
:config
(require 'org-fc-hydra)))
Setup with spacemacs
You don't need to manually clone the repository, just put this in your
.spacemacs
:
;; ...
dotspacemacs-additional-packages
'((org-fc
:location (recipe :fetcher github
:repo "l3kn/org-fc"
:files (:defaults "awk" "demo.org"))))
;; ...
(defun dotspacemacs/user-config ()
;; ...
;; Org-fc
(use-package hydra)
(require 'org-fc-hydra)
(setq org-fc-directories '("~/org/"))
;; ...
)
Assuming abo-abo/hydra is already loaded.
(add-to-list 'load-path "~/src/org-fc/")
(setq org-fc-directories '("~/org/"))
A file demonstrating all card types is included. M-x org-fc-demo
starts a review of this file.
This package comes with a few predefined card types. They are documented in Card Types.
demo.org includes examples for each of these types.
A card is an org-mode headline with a :fc:
tag attached to it.
Each card can have multiple positions reviewed independently from
each other, e.g. one for each hole of a cloze card.
Review data (ease, interval in days, box, due date) is stored in a table in a drawer inside the card.
:REVIEW_DATA:
| position | ease | box | interval | due |
|---------- ------ ----- ---------- ------------------------|
| 2 | 2.65 | 6 | 107.13 | 2020-04-07T01:01:00 |
| 1 | 2.65 | 6 | 128.19 | 2020-04-29T06:44:00 |
| 0 | 2.95 | 6 | 131.57 | 2020-04-30T18:03:00 |
:END:
Review results are appended to a csv file to avoid cluttering the org files.
Each card needs at least two properties, an unique :ID:
and a
:FC_TYPE:
. In addition to that, the date a card was created (i.e. the
headline was marked as a flashcard) is stored to allow making statistics
for how many cards were created in the last day / week / month.
:PROPERTIES:
:ID: 4ffe66a7-7b5c-4811-bd3e-02b5c0862f55
:FC_TYPE: normal
:FC_CREATED: 2019-10-11T14:08:32
:END:
Card types (should) implement a org-fc-type-...-init
command that
initializes these properties and sets up the review data drawer
All timestamps created and used by org-flashcards use ISO8601 format with second precision and without a timezone (timezone UTC0).
This prevents flashcard due dates from showing up in the org-agenda and allows filtering for due cards by string-comparing a timestamp with one of the current time.
Cards can be suspended (excluded from review) by adding a suspended
tag, either by hand or using the org-fc-suspend-card
command.
The suspended
tag is inherited, so all cards in a subtree can be
suspended by adding the tag to the parent heading, and all cards in a
file can be suspended by adding # FILETAGS: suspended
at the start.
Cards can be unsuspended using the org-fc-unsuspend-card
command or by
manually removing the suspended
tag.
It might be preferable to suspend multiple cards by adding the
suspended
tag to each one, so they remain suspended when moved to
another headline or file.
In this case, you can use the following commands:
org-fc-suspend-tree
,org-fc-unsuspend-tree
for suspending all cards in a subtreeorg-fc-suspend-buffer
,org-fc-unsuspend-buffer
for suspending all cards in the current buffer
Note that these commands don't affect filetags or tags of parent headlines.
This package uses a modified version of the SM2 spacing algorithm, based on the one used by Anki.
See also:
A review session can be started with M-x org-fc-review
. Due cards are
reviewed in random order.
If a card was rated "again", it will be reviewed again at the end of
the current review session. This can be disabled by setting
org-fc-append-failed-cards
to nil
.
- Open file of card
- Narrow to heading
- Set up card for review
- Activate
org-fc-flip-mode
- Flip the card (user)
- Switch to
org-fc-rate-mode
- Rate the card (user)
- Repeat process with next due card
Key Binding
RET flip card n flip card s suspend card p pause review for editing q quit review
Key Binding
a rate again h rate hard g rate good e rate easy s suspend card p pause review for editing q quit review
The key bindings used by the review modes of org-fc conflict with some of the bindings used by evil mode.
As a workaround, you can add minor mode keymaps for each of the evil-mode states you're using org-fc with.
(evil-define-minor-mode-key '(normal insert emacs) 'org-fc-review-flip-mode
(kbd "RET") 'org-fc-review-flip
(kbd "n") 'org-fc-review-flip
(kbd "s") 'org-fc-review-suspend-card
(kbd "q") 'org-fc-review-quit)
(evil-define-minor-mode-key '(normal insert emacs) 'org-fc-review-rate-mode
(kbd "a") 'org-fc-review-rate-again
(kbd "h") 'org-fc-review-rate-hard
(kbd "g") 'org-fc-review-rate-good
(kbd "e") 'org-fc-review-rate-easy
(kbd "s") 'org-fc-review-suspend-card
(kbd "q") 'org-fc-review-quit)
By default, two contexts are defined:
all
: all cards in org-fc-directories
buffer : all cards in the current buffer
New contexts can be defined by adding them to the alist
org-fc-custom-contexts
.
Contexts have the form (:paths paths :filter filter)
.
:paths
(optional) either a list of paths, a single path or'buffer
for the current buffer. Paths don't have to be included in theorg-fc-directories
. Defaults toorg-fc-directories
.:filter
(optional), a card filter defaulting to a filter that matches all cards.
Filters can be combinations of the following expressions:
(and ex1 ex2 ...)
(or ex1 ex2 ...)
(not ex)
(tag "tag")
(type card-type) or (type "card-type")
All double cards with tag "math":
(add-to-list 'org-fc-custom-contexts
'(double-math-cards . (:filter (and (type double) (tag "math")))))
All cards in that don't have one of the tags "foo" and "bar":
(add-to-list 'org-fc-custom-contexts
'(no-foo-bar-cards . (:filter (not (or (tag "foo") (tag "bar"))))))
All cards in ~/combinatorics/
or ~/number_theory.org
:
(add-to-list 'org-fc-custom-contexts
'(math-cards . (:paths ("~/combinatorics/" "~/number_theory.org"))))
All cards in ~/combinatorics/
with tag "theorem":
(add-to-list 'org-fc-custom-contexts
'(combinatorics-theorems .
(:paths "~/combinatorics/" :filter (tag "theorem"))))
All double cards in the current buffer:
(add-to-list 'org-fc-custom-contexts
'(current-double .
(:paths buffer :filter (type double))))
Because parsing of tags is done in AWK, tag filters don't work for tags
defined in the # FILETAGS:
of a # SETUP_FILE:
.
org-fc-dashboard
shows a buffer with statistics for review performance
and cards / card types.
Only cards with a box >= org-fc-stats-review-min-box
(default: 0) are
included in the review statistics.
Setting this to a higher value (e.g. 2) excludes the first few "learning" reviews of a card.
See also:
org-fc-before-setup-hook
Runs before a card is set up for revieworg-fc-after-setup-hook
Runs after a card is set up for revieworg-fc-after-review-hook
Runs when the review ends / is quit
Org-fc comes with a number of extensions that are not enabled by default.
Can be enabled with (require 'org-fc-audio)
.
Adds audio attachments for cards that are played during review, either before or after a card is set up. (This distinction is relevant for text-input cards).
Commands:
org-fc-audio-set-before
org-fc-audio-set-after
Can be enabled with (require 'org-fc-keymap-hint)
.
Shows a list of available key bindings during the review, to recreate the look & feel of the previous hydra-based implementation.
[RET] flip [q] quit [s] suspend-card
[a] rate-again [h] rate-hard [g] rate-good [e] rate-easy [s] suspend-card [q] quit
file:org-fc-hydra.el defines a hydra for accessing commonly used org-fc commands and for marking headlines as flashcards.
It can be loaded and bound to a hotkey like this:
(require 'org-fc-hydra)
(global-set-key (kbd "C-c f") 'org-fc-hydra/body)
- Internals
- Sharing Decks (todo)
Copyright © Leon Rische and contributors. Distributed under the GNU General Public License, Version 3