# HG changeset patch # User Noah Friedman # Date 774187827 0 # Node ID 5ecef3b02f2d738399fca2a8f91526161023f835 # Parent 26dbb6234efd93065468ea0ba3b59b4003deb65f Real initial revision. (rewrite from hanoi-break.) diff -r 26dbb6234efd -r 5ecef3b02f2d lisp/type-break.el --- a/lisp/type-break.el Thu Jul 14 05:00:21 1994 +0000 +++ b/lisp/type-break.el Thu Jul 14 12:10:27 1994 +0000 @@ -1,65 +1,209 @@ +;;; type-break.el --- take breaks from typing + +;;; Copyright (C) 1994 Roland McGrath +;;; Copyright (C) 1994 Noah S. Friedman + +;;; Author: Noah Friedman +;;; Roland McGrath +;;; Maintainer: friedman@prep.ai.mit.edu +;;; Keywords: extensions, timer, RSI, CTS, tendinitis, suffering, pain +;;; Created: 1994-07-13 + +;;; $Id$ + +;;; This program is free software; you can redistribute it and/or modify +;;; it under the terms of the GNU General Public License as published by +;;; the Free Software Foundation; either version 2, or (at your option) +;;; any later version. +;;; +;;; This program is distributed in the hope that it will be useful, +;;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;; GNU General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with this program; if not, you can either send email to this +;;; program's maintainer or write to: The Free Software Foundation, +;;; Inc.; 675 Massachusetts Avenue; Cambridge, MA 02139, USA. + +;;; Commentary: + +;;; Based on Roland McGrath's hanoi-break.el (unreleased). +;;; The idea for keystroke recording was suggested by +;;; Mark Ashton + +;;; Code: + + (require 'timer) ;;;###autoload -(defvar hanoi-break-interval (* 60 30) - "*Number of seconds between Hanoi breaks.") - -(add-hook 'post-command-hook 'hanoi-break-check t) - -(defvar hanoi-break-p nil - "Non-nil if we need a Hanoi break real soon now.") - -(defun hanoi-break-check () - "Take a Hanoi break if the time has come." - (and (not (input-pending-p)) - (prog1 hanoi-break-p - (setq hanoi-break-p nil)) - (hanoi-break))) +(defvar type-break-interval (* 60 30) + "*Number of seconds between typing breaks.") ;;;###autoload -(defun hanoi-break () - "Take a Hanoi break, son." +(defvar type-break-delay-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 +finally submits to taking a typing break.") + +;; Assuming average typing speed is 45wpm, default this to the average +;; number of keystrokes one is likely to type in a break interval. +;; That way if the user goes through a furious burst of typing activity, +;; cause a typing break to be required sooner than originally scheduled. +;;;###autoload +(defvar type-break-keystroke-interval (* 45 (/ type-break-interval 60)) + "*Number of keystrokes to record before querying for a typing break. +If not a number, don't keep track of keystrokes. + +Actually, this is not the number of keystrokes per se, but the number of +interactive commands (including self-inserting characters typed). +Compound key bindings like C-x C-f count as a single command even though +that consists of multiple keystrokes.") + +;;;###autoload +(defvar type-break-demo-function-vector + [type-break-life type-break-hanoi] + "*Vector consisting of functions to run as demos during typing breaks. +When a typing break begins, one of these functions is selected randomly +to have emacs do something interesting. + +Any function in this vector should start a demo which ceases as soon as a +key is pressed.") + +;; The original motivation for this variable was that in emacs 19.25 (or +;; perhaps just in unreleased versions of emacs 19.26), the function +;; keyboard.c:safe_run_hooks wasn't reentrant, so that running yes-or-no-p +;; from a post-command-hook caused the inferior command loop to wipe out +;; the original value of the hook. That was fixed, but it occured to me +;; that some people might prefer y-or-n-p. +;;;###autoload +(defvar type-break-query-function 'yes-or-no-p + "*Function to use for making query for a typing break. +Usually this will be `yes-or-no-p' or `y-or-n-p'.") + +;; The rest 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 if we need a typing break soon. +(defvar type-break-p nil) + + +;;;###autoload +(defun type-break () + "Take a typing break. + +If `type-break-delay-interval' seconds have passed since the last typing +break, or `type-break-keystroke-interval' keystrokes have been recorded +since the last typing break, ask the user to take a break now. + +The user can refuse by answering \"no\", in which case another query will +be made in `type-break-delay-interval' seconds. + +During the typing break, a demo selected from the functions listed in +`type-break-demo-function-vector' is run." (interactive) + (setq type-break-p nil) + (setq type-break-keystroke-count 0) + (cancel-type-break) (save-window-excursion - (eval (condition-case error - (if (not (yes-or-no-p "Take a break now? ")) - '(hanoi-break-schedule 60) ; Bug him again in one minute. - ;; Eat the screen. - (if (eq (selected-window) (minibuffer-window)) - (other-window 1)) - (delete-other-windows) - (scroll-right (window-width)) - ;; Send him on his way. - (message "Take a break, son.") - (if (get-buffer "*Hanoi*") - (kill-buffer "*Hanoi*")) - (condition-case () - (progn - (hanoi (/ (window-width) 8)) - ;; Wait for him to come back. - (read-char) - (kill-buffer "*Hanoi*")) - (quit nil)) - '(hanoi-break-schedule)) ; Schedule next break. - (quit '(hanoi-break-schedule 60)) ; Bug him again in one minute. - ;;(error t) - )))) + (condition-case () + (cond + ((funcall type-break-query-function "Take a break from typing now? ") + ;; Eat the screen. + (and (eq (selected-window) (minibuffer-window)) + (other-window 1)) + (delete-other-windows) + (scroll-right (window-width)) + (message "Take a break from typing.") + (type-break-select) + (type-break-schedule)) + (t + (type-break-schedule type-break-delay-interval))) + (quit + (type-break-schedule type-break-delay-interval))))) +(defun type-break-select () + (random t) + (let* ((len (length type-break-demo-function-vector)) + (idx (random len)) + (fn (aref type-break-demo-function-vector idx))) + (condition-case () + (funcall fn) + (error nil)))) + + ;;;###autoload -(defun hanoi-break-schedule (&optional time) - "Schedule a break for ARG seconds from now (default: hanoi-break-interval)." +(defun type-break-schedule (&optional time) + "Schedule a typing break TIME seconds from now. +If time is not specified, default to type-break-interval." (interactive (list (and current-prefix-arg (prefix-numeric-value current-prefix-arg)))) - (or time (setq time hanoi-break-interval)) - (run-at-time time nil 'hanoi-break-soon)) + (or time (setq time type-break-interval)) + ;; Remove any old scheduled break + (cancel-type-break) + (run-at-time time nil 'type-break-soon)) + +(defun cancel-type-break () + "Cancel scheduled typing breaks." + (interactive) + (let ((timer-dont-exit t)) + (cancel-function-timers 'type-break-soon))) -(defun hanoi-break-soon () - "Take a Hanoi break very soon." - (setq hanoi-break-p t)) +(defun type-break-soon () + "Take a typing break very soon." + (setq type-break-p t)) + +(defun type-break-check () + "Take a typing break if the time has come." + (setq type-break-keystroke-count (1+ type-break-keystroke-count)) + (cond + ((input-pending-p)) + ((or type-break-p + (and (natnump type-break-keystroke-interval) + (> type-break-keystroke-count type-break-keystroke-interval))) + (type-break)))) -(defun cancel-hanoi-break () - "Cancel scheduled Hanoi breaks." - (interactive) - (cancel-function-timers 'hanoi-break-soon)) + +;; This is a wrapper around hanoi that calls it with an arg large enough to +;; make the largest discs possible that will fit in the window. +;; Also, clean up the *Hanoi* buffer after we're done. +(defun type-break-hanoi () + "Take a hanoiing typing break." + (and (get-buffer "*Hanoi*") + (kill-buffer "*Hanoi*")) + (condition-case () + (progn + (hanoi (/ (window-width) 8)) + ;; Wait for user to come back. + (read-char) + (kill-buffer "*Hanoi*")) + (quit + (and (get-buffer "*Hanoi*") + (kill-buffer "*Hanoi*"))))) -(provide 'hanoi-break) +;; This is a wrapper around life that calls it with a `sleep' arg to make +;; it run a little more leisurely. +;; Also, clean up the *Life* buffer after we're done. +(defun type-break-life () + "Take a typing break and get a life." + (and (get-buffer "*Life*") + (kill-buffer "*Life*")) + (condition-case () + (progn + (life 3) + ;; Wait for user to come back. + (read-char) + (kill-buffer "*Life*")) + (quit + (and (get-buffer "*Life*") + (kill-buffer "*Life*"))))) + + +(provide 'type-break) + +(add-hook 'post-command-hook 'type-break-check 'append) + +;;; type-break.el ends here