Source Reading Log: Hack Emacs speed-type

I practice touch typing with speed-type in Emacs, mostly for fun, although the original motivation was We Are Typists First, Programmers Second. In the past I simply used its default setup and had no problems, but lately I’ve been reading 1984 by George Orwell and wondering if I could practice typing with it. However, speed-type‘s README doesn’t show how to achieve this, hence I read its source code and did a little hack.

Here’s the solution if you’re not interested in the hacking process.

Install speed-type with use-package

I choose to experiment with use-package this time (you can follow the instructions from https://github.com/parkouss/speed-type), because:

  • I normally manage Emacs extensions using git-submodule (it forces me to examine every package introduced so I can gain a better understanding), but at least for now I don’t want to add speed-type to my core setup (https://github.com/RenWenshan/wenshan-emacs) and therefore using git-submodule is an overkill.
  • Also, I’d like to lazy-load speed-type as it’s obviously not an essential package.

Emacs package manager

Following melpa get started I add melpa to package-archives:

;;; package manager
(require 'package)
(add-to-list 'package-archives
             '("melpa-stable" . "http://stable.melpa.org/packages/") t)
(package-initialize)

Then press M-x package-refresh-contents to update packages list.

Then enable use-package:

(eval-when-compile
  (require 'use-package))

speed-type

Finally require speed-type via use-package, which will automatically gets the package (and its dependencies if there’s any) and marks it for lazy loading on Emacs start up:

;;; typing practice
(use-package speed-type
  :ensure t)

Now press M-x speed-type-text and you’re ready to go.

Hack 1: choose practice texts – 1984

Log

C-h f speed-type-text and find its source (with irrelevant code replaced by dot dot dot):

(defun speed-type-text ()
  "Setup a new text sample to practice touch or speed typing."
  (interactive)
  (let ((book-num (nth (random (length speed-type-gb-book-list))
                       speed-type-gb-book-list))
        ...)
    (with-temp-buffer
      (insert-file-contents (speed-type--gb-retrieve book-num))
      ...)))

It randomly picks a book-num from speed-type-gb-book-list then creates a temporary buffer and inserts the content of (speed-type--gb-retrieve book-num).

So we know speed-type-gb-book-list is the variable that decides what content can be picked, and speed-type--gb-retrieve is the function that decides how the content is retrieved.

speed-type-gb-book-list is simply is list of numbers: (1342 11 1952 ...).

Let’s get to speed-type--gb-retrieve:

(defun speed-type--gb-retrieve (book-num)
  "Return buffer with book number BOOK-NUM in it."
  (speed-type--retrieve book-num  (speed-type--gb-url book-num)))

Then speed-type--retrieve:

(defun speed-type--retrieve (filename url)
  "Return buffer FILENAME content in it or download from URL if file doesn't exist."
  (let ((fn (expand-file-name (format "%s.txt" filename) speed-type-gb-dir))
        (url-request-method "GET"))
    (if (file-readable-p fn)
        fn
      (make-directory speed-type-gb-dir 'parents)
      ...
      fn)))

It tries to read the content from speed-type-gb-dir first (cached), if not found then retrieves it from the Internet → which means we can simply put our texts in speed-type-gb-dir, whose default value is ~/.emacs.d/speed-type/.

So create a text file 1984.txt in ~/.emacs.d/speed-type/ and save the content of 1984 (you can get it from here) to it.

Then set speed-type-gb-book-list to only have 1984 so we can test it:

(setq speed-type-gb-book-list '(1984))
(setq speed-type-max-chars 999999999999999)

Note: speed-type-max-chars is set to a big number to avoid removing sentences from large paragraphs (see the definition of function speed-type--pick-text-to-type).

That’s it, you can press M-x speed-type-text to practice with George Orwell’s writing now.

Solution

Add your text content to a new file in ~/.emacs.d/speed-type/ and name it with a number, say 1024.txt, then in your ~/.emacs append 1024 to speed-type-gb-book-list:

(setq speed-type-max-chars 999999999999999)
(setq speed-type-gb-book-list
      (append speed-type-gb-book-list
              ;; replace the list below with your file names,
              ;; if you have 1984.txt and 515.txt then the list should be '(1984 515)
              '(1024)
              ))

Hack 2: how about hanzi?

During Hack 1, I was curious about whether speed-type could handle hanzi.

Let’s try.

Simply create a text file 111.txt in ~/.emacs.d/speed-type/ with content:

秋水时至,百川灌河,泾流之大,两涘渚崖之间,不辩牛马。

Then set speed-type-gb-book-list to 111 (see Hack 1 for explanation):

(setq speed-type-gb-book-list '(111))

Press M-x speed-type and it works like a charm.