Making medieval manuscript transcription less painful with GNU Emacs
Originally posted in 2020
Introduction
I don't usually bother trying to introduce automations into my workflow if all I stand to save is a little time. Even if a certain common activity is taking a too long and automation would help, I usually stop at the question: how many seconds/minutes per day could actually be saved by automating, especially once the time taken to find or build a solution to the problem is factored in? When it comes to comfort, on the other hand, my philosophy is very different. If any frequent action you perform on your computer causes you physical discomfort (or even risk of injury), no amount of time spent tweaking things to find a suitable solution is "too much."
As a medievalist, one of my most common activities - sometimes to the tune of hours a day - involves transcribing digital facsimiles of medieval manuscripts so that I can compare them with one another. I do this because what we usually imagine as a single medieval literary work often survives in several different manuscript copies, each of which would have been produced by one or more scribes undertaking the laborious process of copying out the entire text by hand. As a result, the various surviving copies of any given story typically differ from one another in intriguing ways, whether because scribes intervened to change them on purpose, or simply because messages tend to get confused when people communicate them to one another in a chain (one need only consider the 'game of telephone' to see how this happens). The sense of discovery is exhilarating: with enough patience, one has the chance to find some truly crazy variation in these texts.
The problem is that like any long-term typing activity, transcribing can put a lot of strain on the hands and wrists. The issue is especially noticeable when dealing with a passage like this one, which comes from a manuscript of the Old French Roman de Renart:
The little squiggles that look like accent marks or apostrophes are abbreviations, and it is up to the reader to know how to make the words comprehensible by expanding them into their full forms. Because this is ultimately an act of interpretation (sometimes abbreviations are a little unclear), I like to mark some kind of visual difference in my transcriptions between the "real letters" actually written by the scribe and the extra letters that I believe the scribe intended to express in the form of abbreviations. To do this, I expand the abbreviations within parentheses: for example, if I were to transcribe this passage, the "q" near the middle of the first line would expand to "q(ue)".
This means that my right hand needs to contort to type parentheses constantly, multiple times per line, at a rate of many hundreds of lines per day. This is far from ideal: because the standard US keyboard layout requires chorded input (Shift+9 or Shift+0) to type parentheses, using parentheses all the time can quickly lead to wrist pain and increase the risk of repetitive strain injury (RSI).
Early approaches
It suddenly occurred to me: this seems like a problem that could be solved by writing a custom function for GNU Emacs, the famously extensible/re-programmable text editor in which I do almost all of my work. What if I could partially automate the insertion of the most common abbreviation forms that I find in the manuscripts I read?
My first attempt at writing such a function was dead simple:
In case anyone reading this is unfamiliar with Emacs Lisp (I myself am
only just learning), here's a quick breakdown: the function takes
input from the user (the string selection
), then compares
it as it is being typed against a list of possible options
(choices
). Thanks to ido-completing-read, the whole word
does not need to be typed, only enough to distinguish it from others
in the list (more info
at Xah
Emacs Site). Then, by pressing Enter
, the user can
insert the string into the file at point (i.e. the cursor's current
location the buffer currently being edited in Emacs). Note the use
of let*
, which differs from let
by allowing
a declared variable to reference a preceding variable. This is needed
because selection
references choices
(see
the relevant section of
the Emacs
Lisp Manual).
However, I quickly realized the deal-breaker with this was that I'd still have to be typing parentheses, defeating the whole point. This led to a second stab at the function, this time with more words incorporated as well:
This seemed like good progress: by using a conditional
(cond
) structure to take easy-to-type words and output
them in the appropriate abbreviated form, the function was able to
insert properly formatted abbreviations without the user's hands
needing to leave the home row, and also without requiring the entire
word to be typed. To save an extra keystroke, I added a trailing space
to all of the outputs.
The last step was to bind it to a key sequence (on keys left for the user to bind without causing conflicts, see the wonderfully detailed Emacs manual):
Redesign: writing a minor mode
It worked, but I had the sense more could be done. Even though my right hand no longer needed to stretch to reach parentheses, this new approach still involved an awful lot of typing, and I wasn't sure it was really helping all that much. It would be nice to have a way to call up the words directly by their first letter (in other words, without pressing c and j beforehand). The problem was that I would need to do this without stepping on the toes of any other key bindings in my configuration, which is now quite extensive.
Emacs has a solution: minor
modes,A
tip for anyone else thinking of writing their first minor mode: at
this stage, I ran into a persistent problem in which the mode would
be loaded globally for all buffers every time. Turns out I needed to
read
the manual
more closely: don't forget that nil
! which can
change key bindings only in certain contexts (i.e., when they're
enabled). By following a couple of
greathttps://nullprogram.com/blog/2013/02/06/
guides,https://zerokspot.com/weblog/2019/07/07/defining-a-new-minor-mode-in-emacs/
I began work on my first minor mode,
scribe-mode
:
Now by pressing Ctrl+c
and then b
, I can
insert the text "b(ie)n". Note that I have Ctrl
globally
remapped to Caps Lock
, which makes this a relatively easy
move.
What about other letters like p, though, which might indicate the start of one of several different potential abbreviated forms? For these, I wrote some simple helper functions based on the earlier idea:
In addition to these, I added one extra function for inserting abbreviations in the middle of word. To allow for maximum flexibility, the user's input is not compared against a list of options.
Here's what the minor mode's key map looked like at this stage. Letters that point to only one possibility have their associated words inserted right away, whereas letters that open onto several different possibilities offer a menu of options:
Improving the experience
After trying it out for a few days, though, I began to find that key
bindings like C-j b
weren't really a great solution to
the problem of strain: they simply shifted the stress over to the left
hand, which needed to reach over to Caps Lock
all the
time. What to do?
My Model M
keyboard doesn't have a hyper or a super button, but it has one
advantage: the right Alt key sits all by itself just below the palm of
the right hand when one's fingers rest on the home keys. To
press Alt
(META
or M
in Emacs
lingo) while typing, all one needs to do is lower one's right hand
very slightly. It is therefore an ideal candidate for a button to
press over and over for hours at a time. Since the effects of minor
modes are confined to the buffer(s) in which they're active, there's
no need to be shy about wreaking havoc on the normal Emacs key
bindings by simply using M for everything - provided, of course, that
you don't write over the key binding for a function that you would
want to use while doing whatever work your minor mode is hoping to
help with.
Here's the full code that I wound up settling on for scribe-mode.el
:
The hook at the end tells Emacs to load this minor mode whenever I open an XML file, which is helpful because all of my transcriptions follow a (very) simplified form of the TEI guidelines.
One last step: this line in my Emacs configuration file tells the
program to load scribe-mode.el
(note that this assumes
scribe-mode.el is in
the Load Path):
Here's a look at the process in action (image generated with gif-screencast.el and keycast.el):
Wrapping up
And there you have it: no more pain, and a fun excuse to learn some more Emacs Lisp!
I think this is a great example of why Emacs is so amazing: it puts the user in a direct, active relationship with their working environment. Even though it seems like just another text editor at first, having an immediately useful malleable system at your fingertips every day has a certain cumulative effect. If you use Emacs all the time, it won't be long before you start getting curious about how you might be able to make your life a little easier - or make your wrists hurt a little less! - by molding the program to your exact needs.
Comments welcome by e-mail; see discussions about this post on Reddit and lobste.rs.