Org Mode tables and fill-in quizzes – Latin verb conjugation drills in Emacs

I was looking for a Latin verb conjugation drill similar to these ones for and nouns and pronouns. I liked the instant feedback and the ability to quickly get hints. I couldn’t find an online drill I liked, though, so I made my own with Emacs and Org. (Because… why not?)

I wrote some code that would take a table like this:

present – 1st sing. – ago / agere agO
present – 2nd sing. – ago / agere agis
present – 3rd sing. – ago / agere agit
present – 1st plu. – ago / agere agimus
present – 2nd plu. – ago / agere agitis
present – 3rd plu. – ago / agere agunt
imperfect – 1st sing. – ago / agere agEbam
imperfect – 2nd sing. – ago / agere agEbAs
imperfect – 3rd sing. – ago / agere agEbat
imperfect – 1st plu. – ago / agere agEbAmus
imperfect – 2nd plu. – ago / agere agEbAtis
imperfect – 3rd plu. – ago / agere agEbant
future – 1st sing. – ago / agere agam
future – 2nd sing. – ago / agere agEs
future – 3rd sing. – ago / agere agEt
future – 1st plu. – ago / agere agEmus
future – 2nd plu. – ago / agere agEtis
future – 3rd plu. – ago / agere agent

I can call my/make-fill-in-quiz to get a quiz buffer that looks like this. If I get stuck, ? shows me a hint in the echo area.


To make it easier, I’ve left case-fold-search set to nil so that I don’t have to match the case (uppercase vowels = macrons), but I can set case-fold-search to t if I want to make sure I’ve got the macrons in the right places.

Here’s the code to display the quiz buffer.

     (require 'widget)
     (defun my/check-widget-value (widget &rest ignore)
       "Provide visual feedback for WIDGET."
        ((string= (widget-value widget) "?")
         ;; Asking for hint
         (message "%s" (widget-get widget :correct))
         (widget-value-set widget ""))
        ;; Use string-match to obey case-fold-search 
          (concat "^"
                  (regexp-quote (widget-get widget :correct))
          (widget-value widget))
         (message "Correct")
         (goto-char (widget-field-start widget))
         (goto-char (line-end-position))
         (insert "✓")
         (widget-forward 1)

   (defun my/make-fill-in-quiz (&optional quiz-table)
     "Create an fill-in quiz for the Org table at point.
The Org table's first column should have the questions and the second column 
should have the answers."
     (interactive (list (org-babel-read-table)))
     (with-current-buffer (get-buffer-create "*Quiz*")
       (let ((inhibit-read-only t))
       (mapc (lambda (row)
               (widget-insert (car row))
               (widget-insert "\t")
               (widget-create 'editable-field
                              :size 15
                              :correct (cadr row)
                              :notify 'my/check-widget-value)
               (widget-insert "\n"))    
       (widget-create 'push-button
                      :table quiz-table
                      :notify (lambda (widget &rest ignore)
                                (my/make-fill-in-quiz (widget-get widget :table))) 
       (use-local-map widget-keymap)
       (goto-char (point-min))
       (widget-forward 1)
       (switch-to-buffer (current-buffer))))

Incidentally, I generated the table above from a larger table of Latin verb conjugations in the appendix of Wheelock’s Latin, specified like this:

#+NAME: present-indicative-active
| laudO    | moneO   | agO    | audiO   | capiO   |
| laudAs   | monEs   | agis   | audIs   | capis   |
| laudat   | monet   | agit   | audit   | capit   |
| laudAmus | monEmus | agimus | audImus | capimus |
| laudAtis | monEtis | agitis | audItis | capitis |
| laudant  | monent  | agunt  | audiunt | capiunt |

#+NAME: imperfect-indicative-active
| laudAbam   | monEbam   | agEbam   | audiEbam   | capiEbam   |
| laudAbas   | monEbas   | agEbAs   | audiEbAs   | capiEbas   |
| laudAbat   | monEbat   | agEbat   | audiEbat   | capiEbat   |
| laudAbAmus | monEbAmus | agEbAmus | audiEbAmus | capiEbAmus |
| laudAbAtis | monEbAtis | agEbAtis | audiEbAtis | capiEbAtis |
| laudAbant  | monEbant  | agEbant  | audiEbant  | capiEbant  |

#+NAME: future-indicative-active
| laudAbO    | monEbO    | agam   | audiam     | capiam     |
| laudAbis   | monEbis   | agEs   | audiEs     | capiEs     |
| laudAbit   | monEbit   | agEt   | audiet     | capiet     |
| laudAbimus | monEbimus | agEmus | audiEmus   | capiEmus   |
| laudAbitis | monEbitis | agEtis | audiEtis   | capiEtis   |
| laudAbunt  | monEbunt  | agent  | audient    | capient    |

with the code:

#+begin_src emacs-lisp :var present=present-indicative-active :var imperfect=imperfect-indicative-active :var future=future-indicative-active
  (defun my/label-latin-with-verbs (table verbs persons tense)
    (apply 'append
           (-zip-with (lambda (row person) 
                        (-zip-with (lambda (word verb)
                                     (list word (format "%s - %s - %s" tense person verb)))
                                   row verbs))
                      table (-cycle persons))))
  (apply 'append 
         (mapcar (lambda (tense)
                    (symbol-value tense)
                    '("laudo / laudare" "moneo / monEre" "ago / agere" "audiO / audIre" "capiO / capere")
                    '("1st sing." "2nd sing." "3rd sing." "1st plu." "2nd plu." "3rd plu.")
                    (symbol-name tense)))
                 '(present imperfect future)))


This uses dash.el for the -zip-with and -cycle functions. There’s probably a much better way to process the lists, but I’m still getting the hang of thinking properly functionally… =)

Anyway, I’m sure it will be handy for a number of other quiz-like things. org-drill and org-drill-table will probably come in handy for flashcards, too!

2015-11-23 Emacs News

Links from, Hacker News,, Youtube, the Emacs commit log, the changes to the Emacs NEWS file, and emacs-devel

Past Emacs News round-ups

Weekly review: Week ending November 20, 2015

This week was a good week for learning more about coding. The Toronto Public Library hackathon turned out to be an excellent excuse to dig into geographic visualizations and user scripts, and I picked up a few search tips from the mentors there. My tiny hack for displaying branch search results on a map of neighbourhood libraries won the best idea prize at the hackathon, yay! I spent some time after the hackathon cleaning up my code and turning it into something I can use without having a server running. I’m starting to really like this practice of having lots of small tests, too – hooray for Jasmine! =) See my notes for more details.

Lots of Emacs-related stuff. Another edition of Emacs News, another Emacs Hangout, and lots of editing of the EmacsWiki. It’s a good community, and it’s nice to be able to help out.

Ups and downs, energy-wise, but W- thoughtfully stepped in with some mid-week cooking. He’s so awesome. I’ll probably take it easy for the next few weeks instead of tilting the balance towards consulting. Still, there’s plenty to do and plenty to learn. =)

2015-11-23a Week ending 2015-11-20 -- index card #journal #weekly output

Blog posts


Focus areas and time review

  • Business (34.9h – 20%)
    • Earn (12.0h – 34% of Business)
      • Earn: E1: 1-2 days of consulting
      • Rewrite to use pg backend
      • Earn: E1: 1-2 days of consulting
    • Build (18.0h – 51% of Business)
      • Drawing (2.8h)
      • Paperwork (0.0h)
      • Exploring neighbourhood libraries, and other notes from the Toronto Public Library Hackathon
      • Convert to client-side code
    • Connect (5.0h – 14% of Business)
  • Relationships (3.5h – 2%)
    • Meet with M
    • G.t.
  • Discretionary – Productive (11.9h – 7%)
    • Emacs (9.6h – 5% of all)
      • Do another Emacs News review
      • Announce Emacs Hangout
      • Host Emacs Hangout
      • Queue Emacs News updates
      • Fix refiling from agenda
      • Clock into existing or new task
      • Write about setup for e-mail
      • Figure out what’s going on with my org mode HTML export and targets
        • Update CUSTOM_ID in my config
      • Write starter guide for Emacs community
      • Write GetHelp page
      • Check out yaoddmuse – johnw
      • Tell Gnus to never show HTML mail
      • Do another Emacs News review
    • Catalogue filing cabinet
    • Set up rsync backup
    • Memorize pronouns
    • Re-memorize declensions
    • Sewing (0.0h)
    • Writing (2.2h)
  • Discretionary – Play (10.0h – 5%)
  • Personal routines (31.3h – 18%)
  • Unpaid work (11.2h – 6%)
  • Sleep (64.0h – 38% – average of 9.1 per day)

Mail with Gnus on Windows

Update 2015-11-26: fixed link to my config. Thanks, Thomas!

I use Gmail for my mail because it:

  • synchronizes with my phone, which is handy for notifications and quick replies
  • filters most of the spam for me
  • works with a few interesting extensions such as Boomerang for Gmail

However, I like the way the Gnus mail/news client in Emacs gives me a much more keyboard-friendly way to manage lots of mail, and I can even write code to partially automate some of my common operations.

I used to have my config in in ~/.gnus, but people might find it handy, so I’ve added it to my public Emacs configuration.

I like using Gmane to read mailing lists, and I use IMAP to read my Gmail.

(setq gnus-select-method '(nnnil ""))
(setq gnus-secondary-select-methods
      '((nntp "")
        (nnimap ""
                (nnimap-address "")
                (nnimap-server-port 993)
                (nnimap-stream ssl)
                (nnimap-authenticator login))))

I have two-factor authentication enabled for Gmail, so I set up an app-specific password for Gnus. I have an ~/.authinfo file set up with something like:

machine login [email protected] password mysecretapppassword
machine login [email protected] password mysecretapppassword port 993
machine login [email protected] password mysecretapppassword port 587

(I should probably get around to using GPG to automatically encrypt and decrypt this file.)

Sending e-mail on Windows was a bit of a pain. Fortunately, I eventually found something that works. I’ve configured emailrelay to accept the mail and forward it to Gmail. The server starts with this batch file:

start "emailrelay" "C:\Program Files (x86)\emailrelay\emailrelay.exe" --as-proxy --client-auth "C:/sacha/.emailrelay" --client-tls --log --pid-file "C:\Program Files (x86)\emailrelay\" --spool-dir C:\sacha\tmp\emailrelay

Sending queued mail works with this batch file:

"c:\Program Files (x86)\emailrelay\emailrelay.exe" --as-client --client-auth c:\sacha\.emailrelay --client-tls --spool-dir c:\sacha\tmp\emailrelay

I should probably get around to using --as-proxy properly, since it still seems to hold mail until I explicitly send it.

Some more config. Not sure how much of this is needed.

(setq message-send-mail-function 'smtpmail-send-it
      smtpmail-starttls-credentials '(("localhost" 25 "[email protected]" nil))
      smtpmail-auth-credentials '(("localhost" 25 "[email protected]" nil))
      smtpmail-default-smtp-server "localhost"
      smtpmail-smtp-server "localhost"
      smtpmail-smtp-service 25
      smtpmail-local-domain "")
(setq send-mail-function 'smtpmail-send-it)
(setq smtpmail-smtp-server "")
(setq smtpmail-smtp-service 25)
(setq user-mail-address "[email protected]")

Hide HTML mail. I need to fiddle with this some more, since Gnus still tries to display them. Sometimes my Gnus crashes when it tries to display HTML mail.

(setq mm-discouraged-alternatives
      '("text/html" "text/richtext")
      (-difference mm-automatic-display '("text/html" "text/enriched" "text/richtext")))

Hide quoted text.

(setq gnus-treat-hide-citation t)

Get smarter about filtering depending on what I reed or mark. I use ! (tick) for marking threads as something that interests me.

(setq gnus-use-adaptive-scoring t)
(setq gnus-default-adaptive-score-alist
       (gnus-ticked-mark (subject 10))
       (gnus-killed-mark (subject -5))
       (gnus-catchup-mark (subject -1))))

2015-11-18 Emacs Hangout

Coding, e-mail, LaTeX, and more. Enjoy!

Event page:


  • 0:02 Podcasts
  • 0:03 sweetgreen – ordering salad
  • 0:14 Windows
  • 0:16 exwm – emacs window manager
  • 0:18 Android development
  • 0:21 Org Mode
  • 0:25 mail, search, notmuch, mairix, filtering, Gmail tabs
  • 0:37 TRAMP, rsync, firestarter, mosh
  • 0:43 stumpwm, conkeror
  • 0:47 concurrency, guile
  • 0:51 dash
  • 0:52 packages
  • 0:53 edit with Emacs (Chrome extension), Cocoa text system on Mac OS X
  • 0:57 railwaycat, spaceline (modeline from spacemacs)
  • 1:04 preview latex, knitr, sweave, Org tables in LaTeX
  • 1:09 spacemacs, vim
  • 1:16 multiple cursors, keyboard macros
  • 1:18 eshell, shells
  • 1:19 volatile-highlights, undo tree
  • 1:21 beacon-mode
  • 1:24 helm-show-kill-ring
  • 1:25 experimenting with versions of code, git-timemachine, undo-tree timestamps and diffs

Text chat:

me 9:30 PM notmuch, mairix
Will Monroe 9:31 PM thanks!
Puneeth Chaganti 9:33 PM Hi everyone.
me 9:34 PM nnmail-split-methods
Puneeth Chaganti 9:36 PM I use imapfilter for my non-gmail account.
Diego Berrocal 9:36 PM what about the gmail one?
Will Monroe 9:36 PM these are excellent suggestions for a new gnus user Puneeth, thank you for org2blog!
Puneeth Chaganti 9:37 PM I don’t yet use gmail with mu4e. Just not sure how long downloading all my mail would take.
Diego Berrocal 9:38 PM ^ better ssh
Will Monroe 9:39 PM Puneeth, I’ve used mu4e with offlineimap to download lots of gmail. It did take a lot of time for ~4GB to download.
Puneeth Chaganti 9:40 PM Yeah, I’m also subscribed to a lot of lists that are filterd out using email filters, but I’m afraid getting new mail also would be really slow. I have a better internet connection these days. May be I should try.
Diego Berrocal 9:41 PM doesn’t gnus freeze your emacs sometimes?
me 9:41 PM I’ve been using for many mailing lists. The web interface has been a bit wonky, but the NNTP through Gnus seems okay.
Diego Berrocal 9:41 PM it did on me last time I used it (years ago) Link to Window Manager:
Puneeth Chaganti 9:44 PM
Will Monroe 9:46 PM Bye everyone! It was nice talking with you.
Daniel Gopar 9:48 PM Diego do you have an example of using firestarter with rsync? Do you have your init.el uploaded in Github or somwhere?
Diego Berrocal 9:49 PM unfortunately it’s not in my config anymore I’ll try to make a blog post
Daniel Gopar 9:50 PM sweet \o/ Let me know if you end up creating a post
Diego Berrocal 9:50 PM yeah \o/
Puneeth Chaganti 9:52 PM Yes, I found it useful too. Thanks for doing those posts, Sacha
me 9:53 PM
Diego Berrocal 9:53 PM not more scrolling through MELPA twitter now edit-with-emacs ^
Bryan Maass 9:54 PM edit-with-emacs
Howard Melman 9:56 PM
Bryan Maass 9:56 PM
me 9:58 PM Reddit discussion of spaceline
me 9:59 PM
Bryan Garza 10:03 PM
me 10:07 PM (org) Tables in arbitrary syntax From Joseph:
Bryan Garza 10:19 PM
Diego Berrocal 10:25 PM git-timemachine
me 10:27 PM (setq undo-tree-visualizer-timestamps t)<br> (setq undo-tree-visualizer-diff t)
Daniel Gopar 10:28 PM Diego can you put a link to your site?
Diego Berrocal 10:30 PM ^

For more information about Emacs Hangouts, see

2015-11-16 Emacs News

Links from, Hacker News,, Youtube, the Emacs commit log, and the changes to the Emacs NEWS file.

Past Emacs News round-ups