I’ve been really into Lisp lately, especially Clojure, which looks really interesting. More on that some other time, though. Anyway, I’m always looking for an excuse to write code in Lisp – any Lisp.
As I was writing some prose in emacs this morning, I got into a real flow. I started to wonder how fast I was typing…and there was my excuse! About an hour later, I had written the code below. It’s an emacs minor mode that displays your typing speed (defined as the number of times self-insert-command has been run in the last five seconds, times twelve) in the mode-line. So you can watch your typing speed go up and down in real time. Note that you can customize a few things about it, like changing the default five-second window.
My emacs-fu (and my Lisp-fu) is not all that it could be, so the code is likely suboptimal in several ways, but it seems to work, and I always hate it when people say, “I’ll post the code once I get a chance to clean it up.” To hell with that: enjoy my code for the garbage it is :).
;;; typing-speed.el --- Minor mode which displays your typing speed
;; Copyright (C) 2008 Wangdera Corporation
;; Permission is hereby granted, free of charge, to any person
;; obtaining a copy of this software and associated documentation
;; files (the "Software"), to deal in the Software without
;; restriction, including without limitation the rights to use,
;; copy, modify, merge, publish, distribute, sublicense, and/or sell
;; copies of the Software, and to permit persons to whom the
;; Software is furnished to do so, subject to the following
;; The above copyright notice and this permission notice shall be
;; included in all copies or substantial portions of the Software.
;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
;; OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
;; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
;; HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
;; WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
;; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
;; OTHER DEALINGS IN THE SOFTWARE.
;; Author: Craig Andera <firstname.lastname@example.org>
;; Commentary: Invoke this minor mode to have your typing speed
;; continuously displayed in the mode line, in the format [75 WPM]
;; To use, just load this file and invoke (typing-speed-mode) or
"Displays your typing speed in the status bar."
(add-hook 'post-command-hook 'typing-speed-post-command-hook)
(setq typing-speed-event-queue '())
(setq typing-speed-update-timer (run-with-timer 0 typing-speed-update-interval 'typing-speed-update)))
(remove-hook 'post-command-hook 'typing-speed-post-command-hook)
(defcustom typing-speed-window 5
"The window (in seconds) over which typing speed should be evaluated."
(defcustom typing-speed-mode-text-format " [%s WPM]"
"A format string that controls how the typing speed is displayed in the mode line.
Must contain exactly one %s delimeter where the typing speed will be inserted."
(defcustom typing-speed-update-interval 1
"How often the typing speed will update in the mode line, in seconds.
It will always also update after every command."
(defvar typing-speed-mode-text (format typing-speed-mode-text-format 0))
(defvar typing-speed-event-queue '())
(defvar typing-speed-update-timer nil)
(defun typing-speed-post-command-hook ()
"When typing-speed-mode is enabled, fires after every command. If the
command is self-insert-command, log it as a keystroke and update the
(if (eq this-command 'self-insert-command)
(let ((current-time (float-time)))
(push current-time typing-speed-event-queue)
(defun typing-speed-update ()
"Calculate and display the typing speed."
(let ((current-time (float-time)))
(- current-time typing-speed-window)
(defun typing-speed-message-update ()
"Updates the status bar with the current typing speed"
(let* ((chars-per-second (/ (length typing-speed-event-queue) (float typing-speed-window)))
(chars-per-min (* chars-per-second 60))
(words-per-min (/ chars-per-min 5)))
(setq typing-speed-mode-text (format " [%s WPM]" (floor words-per-min)))
(defun typing-speed-remove-old-events (threshold queue)
"Removes events older than than the threshold (in seconds) from the specified queue"
(if (or (null queue)
(> threshold (car queue)))
(cons (car queue)
(typing-speed-remove-old-events threshold (cdr queue)))))
(defun turn-on-typing-speed ()
"Turns on typing-speed-mode"
(if (not typing-speed-mode)
(defun turn-off-typing-speed ()
"Turns off typing-speed-mode"