Whitespace fixes.
[bpt/emacs.git] / lisp / type-break.el
CommitLineData
be8d412c 1;;; type-break.el --- encourage rests from typing at appropriate intervals
458401b6 2
99c0333b
NF
3;; Copyright (C) 1994 Free Software Foundation, Inc.
4
5;; Author: Noah Friedman <friedman@prep.ai.mit.edu>
6;; Maintainer: friedman@prep.ai.mit.edu
7;; Keywords: extensions, timers
8;; Status: known to work in GNU Emacs 19.25 or later.
9;; Created: 1994-07-13
10;; $Id$
11
12;; This file is part of GNU Emacs.
13
14;; GNU Emacs is free software; you can redistribute it and/or modify
15;; it under the terms of the GNU General Public License as published by
16;; the Free Software Foundation; either version 2, or (at your option)
17;; any later version.
18
19;; GNU Emacs is distributed in the hope that it will be useful,
20;; but WITHOUT ANY WARRANTY; without even the implied warranty of
21;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22;; GNU General Public License for more details.
23
24;; You should have received a copy of the GNU General Public License
25;; along with GNU Emacs; see the file COPYING. If not, write to
26;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
458401b6
NF
27
28;;; Commentary:
be8d412c
NF
29
30;;; The docstring for the function `type-break-mode' summarizes most of the
31;;; details of the interface.
32
33;;; This package relies on the assumption that you live entirely in emacs,
34;;; as the author does. If that's not the case for you (e.g. you often
35;;; suspend emacs or work in other windows) then this won't help very much;
36;;; it will depend on just how often you switch back to emacs. At the very
37;;; least, you will want to turn off the keystroke thresholds and rest
38;;; interval tracking.
39
be8d412c 40;;; This package was inspired by Roland McGrath's hanoi-break.el.
e7b20417
NF
41;;; Thanks to both Roland McGrath <roland@gnu.ai.mit.edu> and Mark Ashton
42;;; <mpashton@gnu.ai.mit.edu> for feedback and ideas.
be8d412c 43
458401b6
NF
44;;; Code:
45
46\f
622aca7c
RM
47(require 'timer)
48
be8d412c
NF
49;; Make this nil initially so that the call to type-break-mode at the end
50;; will cause scheduling and so forth to happen.
622aca7c 51;;;###autoload
be8d412c 52(defvar type-break-mode nil
4cf64c15
NF
53 "*Non-`nil' means typing break mode is enabled.
54See the docstring for the `type-break-mode' command for more information.")
55
56;;;###autoload
57(defvar type-break-interval (* 60 60)
58 "*Number of seconds between scheduled typing breaks.")
458401b6 59
be8d412c
NF
60;;;###autoload
61(defvar type-break-good-rest-interval (/ type-break-interval 6)
62 "*Number of seconds of idle time considered to be an adequate typing rest.
63
64When this variable is non-`nil', emacs checks the idle time between
cc669dd8 65keystrokes. If this idle time is long enough to be considered a \"good\"
be8d412c
NF
66rest from typing, then the next typing break is simply rescheduled for later.
67
cc669dd8
NF
68If a break is interrupted before this much time elapses, the user will be
69asked whether or not really to interrupt the break.")
be8d412c 70
458401b6 71;;;###autoload
4cf64c15 72(defvar type-break-keystroke-threshold
cc669dd8 73 ;; Assuming typing speed is 35wpm (on the average, do you really
f486195c
NF
74 ;; type more than that in a minute? I spend a lot of time reading mail
75 ;; and simply studying code in buffers) and average word length is
4cf64c15
NF
76 ;; about 5 letters, default upper threshold to the average number of
77 ;; keystrokes one is likely to type in a break interval. That way if the
78 ;; user goes through a furious burst of typing activity, cause a typing
79 ;; break to be required sooner than originally scheduled.
f486195c 80 ;; Conversely, the minimum threshold should be about a fifth of this.
cc669dd8 81 (let* ((wpm 35)
4cf64c15
NF
82 (avg-word-length 5)
83 (upper (* wpm avg-word-length (/ type-break-interval 60)))
f486195c 84 (lower (/ upper 5)))
4cf64c15
NF
85 (cons lower upper))
86 "*Upper and lower bound on number of keystrokes for considering typing break.
be8d412c 87This structure is a pair of numbers.
4cf64c15 88
be8d412c
NF
89The first number is the minimum number of keystrokes that must have been
90entered since the last typing break before considering another one, even if
91the scheduled time has elapsed; the break is simply rescheduled until later
92if the minimum threshold hasn't been reached. If this first value is nil,
93then there is no minimum threshold; as soon as the scheduled time has
94elapsed, the user will always be queried.
4cf64c15
NF
95
96The second number is the maximum number of keystrokes that can be entered
97before a typing break is requested immediately, pre-empting the originally
be8d412c
NF
98scheduled break. If this second value is nil, then no pre-emptive breaks
99will occur; only scheduled ones will.
4cf64c15
NF
100
101Keys with bucky bits (shift, control, meta, etc) are counted as only one
102keystroke even though they really require multiple keys to generate them.")
be8d412c 103
e7b20417
NF
104(defvar type-break-time-warning-intervals '(300 120 60 30)
105 "*List of time intervals for warnings about upcoming typing break.
106At each of the intervals (specified in seconds) away from a scheduled
107typing break, print a warning in the echo area.")
108
109(defvar type-break-keystroke-warning-intervals '(300 200 100 50)
110 "*List of keystroke measurements for warnings about upcoming typing break.
111At each of the intervals (specified in keystrokes) away from the upper
112keystroke threshold, print a warning in the echo area.
113If either this variable or the upper threshold is set, then no warnings
114Will occur.")
115
116(defvar type-break-query-interval 60
117 "*Number of seconds between queries to take a break, if put off.
118The user will continue to be prompted at this interval until he or she
119finally submits to taking a typing break.")
120
121(defvar type-break-warning-repeat 40
122 "*Number of keystrokes for which warnings should be repeated.
123That is, for each of this many keystrokes the warning is redisplayed
124in the echo area to make sure it's really seen.")
125
4cf64c15 126(defvar type-break-query-function 'yes-or-no-p
e7b20417 127 "Function to use for making query for a typing break.
4cf64c15
NF
128It should take a string as an argument, the prompt.
129Usually this should be set to `yes-or-no-p' or `y-or-n-p'.")
130
cc669dd8 131(defvar type-break-demo-functions
e7b20417 132 '(type-break-demo-boring type-break-demo-life type-break-demo-hanoi)
cc669dd8 133 "*List of functions to consider running as demos during typing breaks.
458401b6
NF
134When a typing break begins, one of these functions is selected randomly
135to have emacs do something interesting.
622aca7c 136
cc669dd8 137Any function in this list should start a demo which ceases as soon as a
458401b6 138key is pressed.")
622aca7c 139
e7b20417
NF
140(defvar type-break-post-command-hook nil
141 "Hook run indirectly by post-command-hook for typing break functions.")
142
4cf64c15 143;; These are internal variables. Do not set them yourself.
622aca7c 144
defa7346 145(defvar type-break-alarm-p nil)
be8d412c 146(defvar type-break-keystroke-count 0)
be8d412c
NF
147(defvar type-break-time-last-break nil)
148(defvar type-break-time-next-break nil)
149(defvar type-break-time-last-command (current-time))
e7b20417
NF
150(defvar type-break-current-time-warning-interval nil)
151(defvar type-break-current-keystroke-warning-interval nil)
152(defvar type-break-time-warning-count 0)
153(defvar type-break-keystroke-warning-count 0)
cc669dd8
NF
154
155\f
4cf64c15
NF
156;;;###autoload
157(defun type-break-mode (&optional prefix)
158 "Enable or disable typing-break mode.
159This is a minor mode, but it is global to all buffers by default.
160
161When this mode is enabled, the user is encouraged to take typing breaks at
162appropriate intervals; either after a specified amount of time or when the
163user has exceeded a keystroke threshold. When the time arrives, the user
164is asked to take a break. If the user refuses at that time, emacs will ask
165again in a short period of time. The idea is to give the user enough time
166to find a good breaking point in his or her work, but be sufficiently
167annoying to discourage putting typing breaks off indefinitely.
168
4cf64c15 169A negative prefix argument disables this mode.
cc669dd8 170No argument or any non-negative argument enables it.
4cf64c15
NF
171
172The user may enable or disable this mode by setting the variable of the
173same name, though setting it in that way doesn't reschedule a break or
174reset the keystroke counter.
175
be8d412c
NF
176If the mode was previously disabled and is enabled as a consequence of
177calling this function, it schedules a break with `type-break-schedule' to
178make sure one occurs (the user can call that command to reschedule the
179break at any time). It also initializes the keystroke counter.
4cf64c15
NF
180
181The variable `type-break-interval' specifies the number of seconds to
182schedule between regular typing breaks. This variable doesn't directly
183affect the time schedule; it simply provides a default for the
184`type-break-schedule' command.
185
cc669dd8
NF
186If set, the variable `type-break-good-rest-interval' specifies the minimum
187amount of time which is considered a reasonable typing break. Whenever
188that time has elapsed, typing breaks are automatically rescheduled for
189later even if emacs didn't prompt you to take one first. Also, if a break
190is ended before this much time has elapsed, the user will be asked whether
191or not to continue.
be8d412c
NF
192
193The variable `type-break-keystroke-threshold' is used to determine the
194thresholds at which typing breaks should be considered. You can use
195the command `type-break-guestimate-keystroke-threshold' to try to
196approximate good values for this.
4cf64c15 197
be8d412c 198Finally, the command `type-break-statistics' prints interesting things."
4cf64c15
NF
199 (interactive "P")
200 ;; make sure it's there.
e7b20417
NF
201 (add-hook 'post-command-hook 'type-break-run-tb-post-command-hook 'append)
202 (add-hook 'type-break-post-command-hook 'type-break-check)
4cf64c15 203
be8d412c 204 (let ((already-enabled type-break-mode))
cc669dd8 205 (setq type-break-mode (>= (prefix-numeric-value prefix) 0))
be8d412c
NF
206
207 (cond
208 ((and already-enabled type-break-mode)
209 (and (interactive-p)
cc669dd8 210 (message "type-break-mode is enabled")))
be8d412c 211 (type-break-mode
e7b20417 212 (type-break-keystroke-reset)
be8d412c
NF
213 (type-break-schedule)
214 (and (interactive-p)
215 (message "type-break-mode is enabled and reset")))
216 ((interactive-p)
217 (message "type-break-mode is disabled"))))
4cf64c15
NF
218 type-break-mode)
219
622aca7c 220;;;###autoload
458401b6
NF
221(defun type-break ()
222 "Take a typing break.
223
4cf64c15 224During the break, a demo selected from the functions listed in
cc669dd8 225`type-break-demo-functions' is run.
458401b6 226
4cf64c15 227After the typing break is finished, the next break is scheduled
cc669dd8 228as per the function `type-break-schedule'."
622aca7c 229 (interactive)
e7b20417 230 (type-break-cancel-schedule)
cc669dd8
NF
231 (let ((continue t)
232 (start-time (current-time)))
233 (setq type-break-time-last-break start-time)
234 (while continue
235 (save-window-excursion
236 ;; Eat the screen.
237 (and (eq (selected-window) (minibuffer-window))
238 (other-window 1))
239 (delete-other-windows)
240 (scroll-right (window-width))
241 (message "Press any key to resume from typing break.")
242
243 (random t)
244 (let* ((len (length type-break-demo-functions))
245 (idx (random len))
246 (fn (nth idx type-break-demo-functions)))
247 (condition-case ()
248 (funcall fn)
249 (error nil))))
be8d412c 250
cc669dd8
NF
251 (cond
252 (type-break-good-rest-interval
253 (let ((break-secs (type-break-time-difference
254 start-time (current-time))))
255 (cond
256 ((>= break-secs type-break-good-rest-interval)
257 (setq continue nil))
e7b20417
NF
258 ;; Don't be pedantic; if user's rest was only a minute short,
259 ;; why bother?
260 ((> 60 (abs (- break-secs type-break-good-rest-interval)))
cc669dd8 261 (setq continue nil))
e7b20417 262 ((funcall
cc669dd8
NF
263 type-break-query-function
264 (format "You really ought to rest %s more. Continue break? "
265 (type-break-format-time (- type-break-good-rest-interval
266 break-secs)))))
267 (t
268 (setq continue nil)))))
269 (t (setq continue nil)))))
4cf64c15 270
e7b20417 271 (type-break-keystroke-reset)
be8d412c 272 (type-break-schedule))
622aca7c 273
458401b6 274\f
458401b6 275(defun type-break-schedule (&optional time)
defa7346
NF
276 "Schedule a typing break for TIME seconds from now.
277If time is not specified, default to `type-break-interval'."
278 (interactive (list (and current-prefix-arg
279 (prefix-numeric-value current-prefix-arg))))
458401b6 280 (or time (setq time type-break-interval))
4cf64c15 281 (type-break-cancel-schedule)
e7b20417 282 (type-break-time-warning-schedule time 'reset)
be8d412c 283 (run-at-time time nil 'type-break-alarm)
defa7346
NF
284 (setq type-break-time-next-break
285 (type-break-time-sum (current-time) time)))
622aca7c 286
4cf64c15 287(defun type-break-cancel-schedule ()
e7b20417 288 (type-break-cancel-time-warning-schedule)
458401b6 289 (let ((timer-dont-exit t))
4cf64c15 290 (cancel-function-timers 'type-break-alarm))
be8d412c
NF
291 (setq type-break-alarm-p nil)
292 (setq type-break-time-next-break nil))
458401b6 293
e7b20417
NF
294(defun type-break-time-warning-schedule (&optional time resetp)
295 (let (type-break-current-time-warning-interval)
296 (type-break-cancel-time-warning-schedule))
297 (cond
298 (type-break-time-warning-intervals
299 (and resetp
300 (setq type-break-current-time-warning-interval
301 type-break-time-warning-intervals))
302
303 (or time
304 (setq time (type-break-time-difference (current-time)
305 type-break-time-next-break)))
306
307 (while (and type-break-current-time-warning-interval
308 (> (car type-break-current-time-warning-interval) time))
309 (setq type-break-current-time-warning-interval
310 (cdr type-break-current-time-warning-interval)))
311
312 (cond
313 (type-break-current-time-warning-interval
314 (setq time (- time (car type-break-current-time-warning-interval)))
315 (setq type-break-current-time-warning-interval
316 (cdr type-break-current-time-warning-interval))
317
318 (let (type-break-current-time-warning-interval)
319 (type-break-cancel-time-warning-schedule))
320 (run-at-time time nil 'type-break-time-warning-alarm))))))
321
322(defun type-break-cancel-time-warning-schedule ()
323 (let ((timer-dont-exit t))
324 (cancel-function-timers 'type-break-time-warning-alarm))
325 (remove-hook 'type-break-post-command-hook 'type-break-time-warning)
326 (setq type-break-current-time-warning-interval
327 type-break-time-warning-intervals))
328
4cf64c15 329(defun type-break-alarm ()
4cf64c15 330 (setq type-break-alarm-p t))
458401b6 331
e7b20417
NF
332(defun type-break-time-warning-alarm ()
333 (type-break-time-warning-schedule)
334 (setq type-break-time-warning-count type-break-warning-repeat)
335 (add-hook 'type-break-post-command-hook 'type-break-time-warning 'append))
336
337\f
338(defun type-break-run-tb-post-command-hook ()
339 (and type-break-mode
340 (run-hooks 'type-break-post-command-hook)))
341
458401b6 342(defun type-break-check ()
4cf64c15
NF
343 "Ask to take a typing break if appropriate.
344This may be the case either because the scheduled time has come \(and the
345minimum keystroke threshold has been reached\) or because the maximum
346keystroke threshold has been exceeded."
e7b20417
NF
347 (let* ((min-threshold (car type-break-keystroke-threshold))
348 (max-threshold (cdr type-break-keystroke-threshold)))
349 (and type-break-good-rest-interval
350 (progn
351 (and (> (type-break-time-difference
352 type-break-time-last-command (current-time))
353 type-break-good-rest-interval)
354 (progn
355 (type-break-keystroke-reset)
356 (setq type-break-time-last-break (current-time))
357 (type-break-schedule)))
358 (setq type-break-time-last-command (current-time))))
359
360 (and type-break-keystroke-threshold
361 (setq type-break-keystroke-count
362 (+ type-break-keystroke-count (length (this-command-keys)))))
363
364 ;; This has been optimized for speed; calls to input-pending-p and
365 ;; checking for the minibuffer window are only done if it would
366 ;; matter for the sake of querying user.
367 (cond
368 (type-break-alarm-p
369 (cond
370 ((input-pending-p))
371 ((eq (selected-window) (minibuffer-window)))
372 ((and min-threshold
373 (< type-break-keystroke-count min-threshold))
374 (type-break-schedule))
375 (t
376 ;; If keystroke count is within min-threshold of
377 ;; max-threshold, lower it to reduce the liklihood of an
378 ;; immediate subsequent query.
379 (and max-threshold
380 min-threshold
381 (< (- max-threshold type-break-keystroke-count) min-threshold)
382 (progn
383 (type-break-keystroke-reset)
384 (setq type-break-keystroke-count min-threshold)))
385 (type-break-query))))
386 ((and type-break-keystroke-warning-intervals
387 max-threshold
388 (= type-break-keystroke-warning-count 0)
389 (type-break-check-keystroke-warning)))
390 ((and max-threshold
391 (> type-break-keystroke-count max-threshold)
392 (not (input-pending-p))
393 (not (eq (selected-window) (minibuffer-window))))
394 (type-break-keystroke-reset)
395 (setq type-break-keystroke-count (or min-threshold 0))
396 (type-break-query)))))
397
398;; This should return t if warnings were enabled, nil otherwise.
399(defsubst type-break-check-keystroke-warning ()
400 (let ((left (- (cdr type-break-keystroke-threshold)
401 type-break-keystroke-count)))
402 (cond
403 ((null (car type-break-current-keystroke-warning-interval))
404 nil)
405 ((> left (car type-break-current-keystroke-warning-interval))
406 nil)
407 (t
408 (while (and (car type-break-current-keystroke-warning-interval)
409 (< left (car type-break-current-keystroke-warning-interval)))
410 (setq type-break-current-keystroke-warning-interval
411 (cdr type-break-current-keystroke-warning-interval)))
412 (setq type-break-keystroke-warning-count type-break-warning-repeat)
413 (add-hook 'type-break-post-command-hook 'type-break-keystroke-warning)
414 t))))
4cf64c15
NF
415
416(defun type-break-query ()
417 (condition-case ()
418 (cond
e7b20417
NF
419 ((let ((type-break-mode nil))
420 (funcall type-break-query-function "Take a break from typing now? "))
4cf64c15
NF
421 (type-break))
422 (t
423 (type-break-schedule type-break-query-interval)))
424 (quit
425 (type-break-schedule type-break-query-interval))))
458401b6 426
e7b20417
NF
427(defun type-break-time-warning ()
428 (cond
429 ((and (car type-break-keystroke-threshold)
430 (< type-break-keystroke-count (car type-break-keystroke-threshold))))
431 ((> type-break-time-warning-count 0)
432 (cond
433 ((eq (selected-window) (minibuffer-window)))
434 (t
435 ;; Pause for a moment so previous messages can be seen.
436 (sit-for 2)
437 (message "Warning: typing break due in %s."
438 (type-break-format-time
439 (type-break-time-difference (current-time)
440 type-break-time-next-break)))
441 (setq type-break-time-warning-count
442 (1- type-break-time-warning-count)))))
443 (t
444 (remove-hook 'type-break-post-command-hook 'type-break-time-warning))))
445
446(defun type-break-keystroke-warning ()
447 (cond
448 ((> type-break-keystroke-warning-count 0)
449 (cond
450 ((eq (selected-window) (minibuffer-window)))
451 (t
452 (sit-for 2)
453 (message "Warning: typing break due in %s keystrokes."
454 (- (cdr type-break-keystroke-threshold)
455 type-break-keystroke-count))
456 (setq type-break-keystroke-warning-count
457 (1- type-break-keystroke-warning-count)))))
458 (t
459 (remove-hook 'type-break-post-command-hook
460 'type-break-keystroke-warning))))
458401b6
NF
461
462\f
be8d412c
NF
463;;;###autoload
464(defun type-break-statistics ()
465 "Print statistics about typing breaks in a temporary buffer.
466This includes the last time a typing break was taken, when the next one is
467scheduled, the keystroke thresholds and the current keystroke count, etc."
468 (interactive)
469 (with-output-to-temp-buffer "*Typing Break Statistics*"
470 (princ (format "Typing break statistics\n-----------------------\n
471Last typing break : %s
472Next scheduled typing break : %s\n
473Minimum keystroke threshold : %s
474Maximum keystroke threshold : %s
475Current keystroke count : %s"
476 (if type-break-time-last-break
477 (current-time-string type-break-time-last-break)
478 "never")
479 (if (and type-break-mode type-break-time-next-break)
6b62b567 480 (format "%s\t(%s from now)"
be8d412c 481 (current-time-string type-break-time-next-break)
e7b20417 482 (type-break-format-time
cc669dd8 483 (type-break-time-difference
e7b20417 484 (current-time)
cc669dd8 485 type-break-time-next-break)))
be8d412c
NF
486 "none scheduled")
487 (or (car type-break-keystroke-threshold) "none")
488 (or (cdr type-break-keystroke-threshold) "none")
489 type-break-keystroke-count))))
490
491;;;###autoload
492(defun type-break-guestimate-keystroke-threshold (wpm &optional wordlen frac)
493 "Guess values for the minimum/maximum keystroke threshold for typing breaks.
494If called interactively, the user is prompted for their guess as to how
495many words per minute they usually type. From that, the command sets the
496values in `type-break-keystroke-threshold' based on a fairly simple
497algorithm involving assumptions about the average length of words (5).
498For the minimum threshold, it uses about a quarter of the computed maximum
499threshold.
500
501When called from lisp programs, the optional args WORDLEN and FRAC can be
502used to override the default assumption about average word length and the
503fraction of the maximum threshold to which to set the minimum threshold.
504FRAC should be the inverse of the fractional value; for example, a value of
5052 would mean to use one half, a value of 4 would mean to use one quarter, etc."
defa7346 506 (interactive "NHow many words per minute do you type? ")
be8d412c 507 (let* ((upper (* wpm (or wordlen 5) (/ type-break-interval 60)))
f486195c 508 (lower (/ upper (or frac 5))))
be8d412c
NF
509 (or type-break-keystroke-threshold
510 (setq type-break-keystroke-threshold (cons nil nil)))
511 (setcar type-break-keystroke-threshold lower)
512 (setcdr type-break-keystroke-threshold upper)
513 (if (interactive-p)
514 (message "min threshold: %d\tmax threshold: %d" lower upper)
515 type-break-keystroke-threshold)))
516
517\f
e7b20417
NF
518;;; misc functions
519
520;; Compute the difference, in seconds, between a and b, two structures
521;; similar to those returned by `current-time'.
defa7346
NF
522;; Use addition rather than logand since that is more robust; the low 16
523;; bits of the seconds might have been incremented, making it more than 16
524;; bits wide.
e7b20417
NF
525(defsubst type-break-time-difference (a b)
526 (+ (lsh (- (car b) (car a)) 16)
527 (- (car (cdr b)) (car (cdr a)))))
528
defa7346
NF
529;; Return (in a new list the same in structure to that returned by
530;; `current-time') the sum of the arguments. Each argument may be a time
531;; list or a single integer, a number of seconds.
532;; This function keeps the high and low 16 bits of the seconds properly
533;; balanced so that the lower value never exceeds 16 bits. Otherwise, when
534;; the result is passed to `current-time-string' it will toss some of the
535;; "low" bits and return the wrong value.
536(defun type-break-time-sum (&rest tmlist)
537 (let ((high 0)
538 (low 0)
539 (micro 0)
540 tem)
541 (while tmlist
542 (setq tem (car tmlist))
543 (setq tmlist (cdr tmlist))
544 (cond
545 ((numberp tem)
546 (setq low (+ low tem)))
547 (t
548 (setq high (+ high (or (car tem) 0)))
549 (setq low (+ low (or (car (cdr tem)) 0)))
550 (setq micro (+ micro (or (car (cdr (cdr tem))) 0))))))
551
552 (and (>= micro 1000000)
553 (progn
554 (setq tem (/ micro 1000000))
555 (setq low (+ low tem))
556 (setq micro (- micro (* tem 1000000)))))
557
558 (setq tem (lsh low -16))
559 (and (> tem 0)
560 (progn
561 (setq low (logand low 65535))
562 (setq high (+ high tem))))
563
564 (list high low micro)))
565
e7b20417
NF
566(defsubst type-break-format-time (secs)
567 (let ((mins (/ secs 60)))
568 (cond
569 ((= mins 1) (format "%d minute" mins))
570 ((> mins 0) (format "%d minutes" mins))
571 ((= secs 1) (format "%d second" secs))
572 (t (format "%d seconds" secs)))))
573
574(defun type-break-keystroke-reset ()
575 (setq type-break-keystroke-count 0)
576 (setq type-break-keystroke-warning-count 0)
577 (setq type-break-current-keystroke-warning-interval
578 type-break-keystroke-warning-intervals)
579 (remove-hook 'type-break-post-command-hook 'type-break-keystroke-warning))
580
581\f
582;;; Demo wrappers
583
584;; This is a wrapper around hanoi that calls it with an arg large enough to
585;; make the largest discs possible that will fit in the window.
586;; Also, clean up the *Hanoi* buffer after we're done.
587(defun type-break-demo-hanoi ()
588 "Take a hanoiing typing break."
589 (and (get-buffer "*Hanoi*")
590 (kill-buffer "*Hanoi*"))
591 (condition-case ()
592 (progn
593 (hanoi (/ (window-width) 8))
594 ;; Wait for user to come back.
595 (read-char)
596 (kill-buffer "*Hanoi*"))
597 (quit
598 ;; eat char
599 (read-char)
600 (and (get-buffer "*Hanoi*")
601 (kill-buffer "*Hanoi*")))))
602
603;; This is a wrapper around life that calls it with a `sleep' arg to make
604;; it run a little more leisurely.
605;; Also, clean up the *Life* buffer after we're done.
606(defun type-break-demo-life ()
607 "Take a typing break and get a life."
608 (let ((continue t))
609 (while continue
610 (setq continue nil)
611 (and (get-buffer "*Life*")
612 (kill-buffer "*Life*"))
613 (condition-case ()
614 (progn
615 (life 3)
616 ;; wait for user to return
617 (read-char)
618 (kill-buffer "*Life*"))
619 (life-extinct
620 (message (get 'life-extinct 'error-message))
621 (sit-for 3)
622 ;; restart demo
623 (setq continue t))
624 (quit
625 (and (get-buffer "*Life*")
626 (kill-buffer "*Life*")))))))
627
defa7346 628;; Boring demo, but doesn't use many cycles
e7b20417
NF
629(defun type-break-demo-boring ()
630 "Boring typing break demo."
defa7346 631 (let ((rmsg "Press any key to resume from typing break")
e7b20417 632 (buffer-name "*Typing Break Buffer*")
defa7346
NF
633 line col pos
634 elapsed timeleft tmsg)
e7b20417
NF
635 (condition-case ()
636 (progn
637 (switch-to-buffer (get-buffer-create buffer-name))
638 (buffer-disable-undo (current-buffer))
639 (erase-buffer)
defa7346
NF
640 (setq line (1+ (/ (window-height) 2)))
641 (setq col (/ (- (window-width) (length rmsg)) 2))
e7b20417
NF
642 (insert (make-string line ?\C-j)
643 (make-string col ?\ )
defa7346
NF
644 rmsg)
645 (forward-line -1)
646 (beginning-of-line)
647 (setq pos (point))
648 (while (not (input-pending-p))
649 (delete-region pos (progn
650 (goto-char pos)
651 (end-of-line)
652 (point)))
653 (setq elapsed (type-break-time-difference
654 type-break-time-last-break
655 (current-time)))
656 (cond
657 (type-break-good-rest-interval
658 (setq timeleft (- type-break-good-rest-interval elapsed))
659 (if (> timeleft 0)
660 (setq tmsg (format "You should rest for %s more"
661 (type-break-format-time timeleft)))
662 (setq tmsg (format "Typing break has lasted %s"
663 (type-break-format-time elapsed)))))
664 (t
665 (setq tmsg (format "Typing break has lasted %s"
666 (type-break-format-time elapsed)))))
667 (setq col (/ (- (window-width) (length tmsg)) 2))
668 (insert (make-string col ?\ ) tmsg)
669 (goto-char (point-min))
670 (sit-for 60))
e7b20417
NF
671 (read-char)
672 (kill-buffer buffer-name))
673 (quit
674 (and (get-buffer buffer-name)
675 (kill-buffer buffer-name))))))
676
677\f
458401b6
NF
678(provide 'type-break)
679
defa7346
NF
680;; Do not do this at load time because it makes it impossible to load this
681;; file into temacs and then dump it.
682;(type-break-mode t)
622aca7c 683
e7b20417
NF
684;; local variables:
685;; vc-make-backup-files: t
686;; end:
687
458401b6 688;;; type-break.el ends here