Mercurial > emacs
changeset 8276:73b85998c868
type-break-mode: Make variable `nil' by default.
type-break-mode (function): If setting to t and mode was already enabled,
don't reschedule breaks or reset keystroke counter.
type-break-good-rest-interval: New variable.
type-break-time-difference: New inline function (defsubst).
tyype-break-time-last-break, type-break-time-next-break,
type-break-time-last-command: New variables.
type-break-check: Reset timers and counters if user has been idle more than
type-break-good-rest-interval seconds (assuming it's set).
Never set keystroke counter to be less than the min threshold.
type-break: Admonish user if s/he rested less than
type-break-good-rest-interval seconds (assuming it's set).
type-break-demo-hanoi: Eat a char when quitting.
type-break-statistics, type-break-guestimate-keystroke-threshold: New
commands.
author | Noah Friedman <friedman@splode.com> |
---|---|
date | Mon, 18 Jul 1994 15:21:50 +0000 |
parents | 4fdf77f4e45c |
children | 824fb42f33ab |
files | lisp/type-break.el |
diffstat | 1 files changed, 214 insertions(+), 62 deletions(-) [+] |
line wrap: on
line diff
--- a/lisp/type-break.el Mon Jul 18 07:37:18 1994 +0000 +++ b/lisp/type-break.el Mon Jul 18 15:21:50 1994 +0000 @@ -1,18 +1,16 @@ -;;; type-break.el --- take breaks from typing at appropriate intervals +;;; type-break.el --- encourage rests from typing at appropriate intervals -;;; Copyright (C) 1994 Roland McGrath ;;; Copyright (C) 1994 Noah S. Friedman ;;; Author: Noah Friedman <friedman@prep.ai.mit.edu> -;;; Roland McGrath <roland@prep.ai.mit.edu> ;;; Maintainer: friedman@prep.ai.mit.edu ;;; Keywords: extensions, timers -;;; Status: works in GNU Emacs 19 +;;; Status: known to work in GNU Emacs 19.25 or later. ;;; Created: 1994-07-13 ;;; LCD Archive Entry: ;;; type-break|Noah Friedman|friedman@prep.ai.mit.edu| -;;; take breaks from typing at appropriate intervals| +;;; encourage rests from typing at appropriate intervals| ;;; $Date$|$Revision$|| ;;; $Id$ @@ -33,13 +31,32 @@ ;;; Inc.; 675 Massachusetts Avenue; Cambridge, MA 02139, USA. ;;; Commentary: + +;;; The docstring for the function `type-break-mode' summarizes most of the +;;; details of the interface. + +;;; This package relies on the assumption that you live entirely in emacs, +;;; as the author does. If that's not the case for you (e.g. you often +;;; suspend emacs or work in other windows) then this won't help very much; +;;; it will depend on just how often you switch back to emacs. At the very +;;; least, you will want to turn off the keystroke thresholds and rest +;;; interval tracking. + +;;; Setting type-break-good-rest-interval makes emacs cons like a maniac +;;; because of repeated calls to `current-time'. There's not really any +;;; good way to avoid this without disabling the variable. + +;;; This package was inspired by Roland McGrath's hanoi-break.el. + ;;; Code: (require 'timer) +;; Make this nil initially so that the call to type-break-mode at the end +;; will cause scheduling and so forth to happen. ;;;###autoload -(defvar type-break-mode t +(defvar type-break-mode nil "*Non-`nil' means typing break mode is enabled. See the docstring for the `type-break-mode' command for more information.") @@ -48,6 +65,17 @@ "*Number of seconds between scheduled typing breaks.") ;;;###autoload +(defvar type-break-good-rest-interval (/ type-break-interval 6) + "*Number of seconds of idle time considered to be an adequate typing rest. + +When this variable is non-`nil', emacs checks the idle time between +keystrokes. If this idle time is long enough to be considered a "good" +rest from typing, then the next typing break is simply rescheduled for later. + +The user will also be admonished if a forced break isn't at least as long +as this time, to remind them to rest longer next time.") + +;;;###autoload (defvar type-break-query-interval 60 "*Number of seconds between queries to take a break, if put off. The user will continue to be prompted at this interval until he or she @@ -67,20 +95,23 @@ (lower (/ upper 4))) (cons lower upper)) "*Upper and lower bound on number of keystrokes for considering typing break. +This structure is a pair of numbers. -This structure is a pair of numbers. The first number is the minimum -number of keystrokes that must have been entered since the last typing -break before considering another one, even if the scheduled time has -elapsed; the break is simply rescheduled until later if the minimum -threshold hasn't been reached. +The first number is the minimum number of keystrokes that must have been +entered since the last typing break before considering another one, even if +the scheduled time has elapsed; the break is simply rescheduled until later +if the minimum threshold hasn't been reached. If this first value is nil, +then there is no minimum threshold; as soon as the scheduled time has +elapsed, the user will always be queried. The second number is the maximum number of keystrokes that can be entered before a typing break is requested immediately, pre-empting the originally -scheduled break. +scheduled break. If this second value is nil, then no pre-emptive breaks +will occur; only scheduled ones will. Keys with bucky bits (shift, control, meta, etc) are counted as only one keystroke even though they really require multiple keys to generate them.") - + ;;;###autoload (defvar type-break-query-function 'yes-or-no-p "*Function to use for making query for a typing break. @@ -98,13 +129,25 @@ ;; These are internal variables. Do not set them yourself. -;; Number of commands (roughly # of keystrokes) recorded since last break. -(defvar type-break-keystroke-count 0) - ;; Non-nil when a scheduled typing break is due. (defvar type-break-alarm-p nil) +(defvar type-break-keystroke-count 0) + +(defvar type-break-time-last-break nil) +(defvar type-break-time-next-break nil) +(defvar type-break-time-last-command (current-time)) + +;; Compute the difference, in seconds, between a and b, two structures +;; similar to those returned by `current-time'. +;; Use addition rather than logand since I found it convenient to add +;; seconds to the cdr of some of my stored time values, which may throw off +;; the number of bits in the cdr. +(defsubst type-break-time-difference (a b) + (+ (lsh (- (car b) (car a)) 16) + (- (car (cdr b)) (car (cdr a))))) + ;;;###autoload (defun type-break-mode (&optional prefix) "Enable or disable typing-break mode. @@ -126,10 +169,10 @@ same name, though setting it in that way doesn't reschedule a break or reset the keystroke counter. -When this function enables the mode, it schedules a break with -`type-break-schedule' to make sure one occurs (the user can call that -command to reschedule the break at any time). It also initializes the -keystroke counter. +If the mode was previously disabled and is enabled as a consequence of +calling this function, it schedules a break with `type-break-schedule' to +make sure one occurs (the user can call that command to reschedule the +break at any time). It also initializes the keystroke counter. The variable `type-break-interval' specifies the number of seconds to schedule between regular typing breaks. This variable doesn't directly @@ -140,35 +183,47 @@ schedule between repeated queries for breaks when the user answers \"no\" to the previous query. -The variable `type-break-keystroke-theshold' is used to determine the -thresholds at which typing breaks should be considered. +The variable `type-break-good-rest-interval' specifies the minimum amount +of time which is considered a reasonable typing break. Whenever that time +has elapsed, typing breaks are automatically rescheduled for later even if +emacs didn't prompt you to take one first. You can disable this behavior. + +The variable `type-break-keystroke-threshold' is used to determine the +thresholds at which typing breaks should be considered. You can use +the command `type-break-guestimate-keystroke-threshold' to try to +approximate good values for this. The variable `type-break-query-function' should contain a function (or the symbolic name of a function) to be used to query the user for typing -breaks." +breaks. + +Finally, the command `type-break-statistics' prints interesting things." (interactive "P") ;; make sure it's there. (add-hook 'post-command-hook 'type-break-check 'append) - (cond - ((null prefix) - (setq type-break-mode (not type-break-mode))) - ((numberp (prefix-numeric-value prefix)) - (setq type-break-mode (>= (prefix-numeric-value prefix) 0))) - (prefix - (setq type-break-mode t)) - (t - (setq type-break-mode nil))) + (let ((already-enabled type-break-mode)) + (cond + ((null prefix) + (setq type-break-mode (not type-break-mode))) + ((numberp (prefix-numeric-value prefix)) + (setq type-break-mode (>= (prefix-numeric-value prefix) 0))) + (prefix + (setq type-break-mode t)) + (t + (setq type-break-mode nil))) - (cond - (type-break-mode - (setq type-break-keystroke-count 0) - (type-break-schedule) - (and (interactive-p) - (message "type-break-mode is enabled and reset"))) - ((interactive-p) - (message "type-break-mode is disabled"))) - + (cond + ((and already-enabled type-break-mode) + (and (interactive-p) + (message "type-break-mode was already enabled"))) + (type-break-mode + (setq type-break-keystroke-count 0) + (type-break-schedule) + (and (interactive-p) + (message "type-break-mode is enabled and reset"))) + ((interactive-p) + (message "type-break-mode is disabled")))) type-break-mode) ;;;###autoload @@ -182,13 +237,14 @@ as per the function `type-break-schedule', and the keystroke counter is reset." (interactive) + (setq type-break-time-last-break (current-time)) (save-window-excursion ;; Eat the screen. (and (eq (selected-window) (minibuffer-window)) (other-window 1)) (delete-other-windows) (scroll-right (window-width)) - (message "Press any key to finish typing break.") + (message "Press any key to resume from typing break.") (random t) (let* ((len (length type-break-demo-function-vector)) @@ -196,10 +252,16 @@ (fn (aref type-break-demo-function-vector idx))) (condition-case () (funcall fn) - (error nil))) + (error nil)))) - (setq type-break-keystroke-count 0) - (type-break-schedule))) + (and type-break-good-rest-interval + (< (type-break-time-difference type-break-time-last-command + (current-time)) + type-break-good-rest-interval) + (message "That typing break wasn't really long enough. Rest more next time.")) + + (setq type-break-keystroke-count 0) + (type-break-schedule)) ;;;###autoload @@ -211,7 +273,11 @@ (or time (setq time type-break-interval)) ;; Remove any old scheduled break (type-break-cancel-schedule) - (run-at-time time nil 'type-break-alarm)) + (run-at-time time nil 'type-break-alarm) + + (setq type-break-time-next-break (current-time)) + (setcar (cdr type-break-time-next-break) + (+ time (car (cdr type-break-time-next-break))))) (defun type-break-cancel-schedule () "Cancel scheduled typing breaks. @@ -221,7 +287,8 @@ (interactive) (let ((timer-dont-exit t)) (cancel-function-timers 'type-break-alarm)) - (setq type-break-alarm-p nil)) + (setq type-break-alarm-p nil) + (setq type-break-time-next-break nil)) (defun type-break-alarm () "This function is run when a scheduled typing break is due." @@ -234,27 +301,56 @@ keystroke threshold has been exceeded." (cond (type-break-mode - (let* ((pair (and (consp type-break-keystroke-threshold) - type-break-keystroke-threshold)) - (min-threshold (car pair)) - (max-threshold (cdr pair))) - (and pair - (stringp (this-command-keys)) + (let* ((threshold-pair (and (consp type-break-keystroke-threshold) + type-break-keystroke-threshold)) + (min-threshold (car threshold-pair)) + (max-threshold (cdr threshold-pair))) + + ;; Reset schedule and keystroke count if user has been idle longer + ;; than a normal resting period. + (cond + (type-break-good-rest-interval + (and (> (type-break-time-difference type-break-time-last-command + (current-time)) + type-break-good-rest-interval) + (progn + (setq type-break-keystroke-count 0) + (type-break-schedule))) + (setq type-break-time-last-command (current-time)))) + + (and threshold-pair (setq type-break-keystroke-count (+ type-break-keystroke-count (length (this-command-keys))))) + (cond ((input-pending-p)) - ((and (numberp max-threshold) - (> type-break-keystroke-count max-threshold)) - (setq type-break-keystroke-count 0) - (type-break-query)) (type-break-alarm-p (cond - ((and (numberp min-threshold) + ((and min-threshold (< type-break-keystroke-count min-threshold))) (t - (setq type-break-keystroke-count 0) - (type-break-query))))))))) + ;; If the keystroke count is within min-threshold characters of + ;; the maximum threshold, set the count to min-threshold. That + ;; way, if the count was really close the threshold and the user + ;; doesn't choose to take a break now, s/he won't be pestered + ;; almost immediately after saying "no"; that's what the query + ;; interval delay is for. + ;; On the other hand, don't set it too small (make it at least + ;; min-threshold); that way we can be sure the user will be asked + ;; again to take a break after the query interval has elapsed. + ;; If the user chooses to take a break now, the break function + ;; will reset the keystroke count anyway. + (and max-threshold + min-threshold + (> (- max-threshold type-break-keystroke-count) min-threshold) + (setq type-break-keystroke-count min-threshold)) + (type-break-query)))) + ((and max-threshold + (> type-break-keystroke-count max-threshold)) + ;; Set it to the min threshold if possible, to be sure the user + ;; will be pestered again in at least a minute. + (setq type-break-keystroke-count (or min-threshold 0)) + (type-break-query))))))) (defun type-break-query () (condition-case () @@ -280,7 +376,9 @@ ;; Wait for user to come back. (read-char) (kill-buffer "*Hanoi*")) - (quit + (quit + ;; eat char + (read-char) (and (get-buffer "*Hanoi*") (kill-buffer "*Hanoi*"))))) @@ -297,11 +395,65 @@ ;; Wait for user to come back. (read-char) (kill-buffer "*Life*")) - (quit + (quit (and (get-buffer "*Life*") (kill-buffer "*Life*"))))) +;;;###autoload +(defun type-break-statistics () + "Print statistics about typing breaks in a temporary buffer. +This includes the last time a typing break was taken, when the next one is +scheduled, the keystroke thresholds and the current keystroke count, etc." + (interactive) + (with-output-to-temp-buffer "*Typing Break Statistics*" + (princ (format "Typing break statistics\n-----------------------\n +Last typing break : %s +Next scheduled typing break : %s\n +Minimum keystroke threshold : %s +Maximum keystroke threshold : %s +Current keystroke count : %s" + (if type-break-time-last-break + (current-time-string type-break-time-last-break) + "never") + (if (and type-break-mode type-break-time-next-break) + (format "%s\t(%d minutes from now)" + (current-time-string type-break-time-next-break) + (/ (type-break-time-difference + (current-time) type-break-time-next-break) + 60)) + "none scheduled") + (or (car type-break-keystroke-threshold) "none") + (or (cdr type-break-keystroke-threshold) "none") + type-break-keystroke-count)))) + +;;;###autoload +(defun type-break-guestimate-keystroke-threshold (wpm &optional wordlen frac) + "Guess values for the minimum/maximum keystroke threshold for typing breaks. +If called interactively, the user is prompted for their guess as to how +many words per minute they usually type. From that, the command sets the +values in `type-break-keystroke-threshold' based on a fairly simple +algorithm involving assumptions about the average length of words (5). +For the minimum threshold, it uses about a quarter of the computed maximum +threshold. + +When called from lisp programs, the optional args WORDLEN and FRAC can be +used to override the default assumption about average word length and the +fraction of the maximum threshold to which to set the minimum threshold. +FRAC should be the inverse of the fractional value; for example, a value of +2 would mean to use one half, a value of 4 would mean to use one quarter, etc." + (interactive "nHow many words per minute do you type? ") + (let* ((upper (* wpm (or wordlen 5) (/ type-break-interval 60))) + (lower (/ upper (or frac 4)))) + (or type-break-keystroke-threshold + (setq type-break-keystroke-threshold (cons nil nil))) + (setcar type-break-keystroke-threshold lower) + (setcdr type-break-keystroke-threshold upper) + (if (interactive-p) + (message "min threshold: %d\tmax threshold: %d" lower upper) + type-break-keystroke-threshold))) + + (provide 'type-break) (type-break-mode t)