2026-01-28T15:01:51
This commit is contained in:
127
typing-speed.el
Executable file
127
typing-speed.el
Executable file
@@ -0,0 +1,127 @@
|
||||
;;; 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
|
||||
;; conditions:
|
||||
|
||||
;; 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 <candera@wangdera.com>
|
||||
|
||||
;; 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
|
||||
;; (turn-on-typing-speed-mode)
|
||||
|
||||
(define-minor-mode typing-speed-mode
|
||||
"Displays your typing speed in the status bar."
|
||||
:lighter typing-speed-mode-text
|
||||
:group 'typing-speed
|
||||
(if typing-speed-mode
|
||||
(progn
|
||||
(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)))
|
||||
(progn
|
||||
(remove-hook 'post-command-hook 'typing-speed-post-command-hook)
|
||||
(cancel-timer typing-speed-update-timer))))
|
||||
|
||||
(defcustom typing-speed-window 5
|
||||
"The window (in seconds) over which typing speed should be evaluated."
|
||||
:group 'typing-speed)
|
||||
|
||||
(defcustom typing-speed-mode-text-format " [%s/%s WPM]"
|
||||
"A format string that controls how the typing speed is displayed in the mode line.
|
||||
Must contain at least one %s delimeter. Typing speed will be inserted at the first
|
||||
delimiter, and peak typing speed at the second."
|
||||
:group 'typing-speed)
|
||||
|
||||
(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."
|
||||
:group 'typing-speed)
|
||||
|
||||
(defvar typing-speed-mode-text (format typing-speed-mode-text-format 0 0))
|
||||
(defvar typing-speed-event-queue '())
|
||||
(defvar typing-speed-update-timer nil)
|
||||
(defvar typing-speed-peak-speed 0)
|
||||
(defvar typing-speed-previous-mode-text "")
|
||||
|
||||
(make-variable-buffer-local 'typing-speed-peak-speed)
|
||||
(make-variable-buffer-local 'typing-speed-previous-mode-text)
|
||||
(make-variable-buffer-local 'typing-speed-mode-text)
|
||||
(make-variable-buffer-local 'typing-speed-event-queue)
|
||||
|
||||
(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
|
||||
typing speed."
|
||||
(cond ((eq this-command 'self-insert-command)
|
||||
(let ((current-time (float-time)))
|
||||
(push current-time typing-speed-event-queue)
|
||||
(typing-speed-update)))
|
||||
((member this-command '(delete-backward-char backward-delete-char-untabify))
|
||||
(progn
|
||||
(pop typing-speed-event-queue)
|
||||
(typing-speed-update)))))
|
||||
|
||||
(defun typing-speed-update ()
|
||||
"Calculate and display the typing speed."
|
||||
(let ((current-time (float-time)))
|
||||
(setq typing-speed-event-queue
|
||||
(typing-speed-remove-old-events
|
||||
(- current-time typing-speed-window)
|
||||
typing-speed-event-queue))
|
||||
(typing-speed-message-update)))
|
||||
|
||||
(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-peak-speed (max words-per-min typing-speed-peak-speed))
|
||||
(setq typing-speed-mode-text
|
||||
(if (minibufferp (current-buffer))
|
||||
""
|
||||
(format typing-speed-mode-text-format (floor words-per-min) (floor typing-speed-peak-speed))))
|
||||
;; Attempt to prevent unnecessary flicker in the menu bar. Doesn't seem to help, though.
|
||||
(if (not (string-equal typing-speed-mode-text typing-speed-previous-mode-text))
|
||||
(progn
|
||||
(setq typing-speed-previous-mode-text typing-speed-mode-text)
|
||||
(force-mode-line-update)))))
|
||||
|
||||
|
||||
(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)))
|
||||
nil
|
||||
(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)
|
||||
(typing-speed-mode)))
|
||||
|
||||
(defun turn-off-typing-speed ()
|
||||
"Turns off typing-speed-mode"
|
||||
(if typing-speed-mode
|
||||
(typing-speed-mode)))
|
||||
Reference in New Issue
Block a user