Limit number of GnuTLS handshakes per connection.
[bpt/emacs.git] / lisp / type-break.el
CommitLineData
be8d412c 1;;; type-break.el --- encourage rests from typing at appropriate intervals
458401b6 2
acaf905b 3;; Copyright (C) 1994-1995, 1997, 2000-2012 Free Software Foundation, Inc.
99c0333b 4
f6cafb3e
NF
5;; Author: Noah Friedman
6;; Maintainer: Noah Friedman <friedman@splode.com>
99c0333b 7;; Keywords: extensions, timers
99c0333b 8;; Created: 1994-07-13
846f6dd9 9
99c0333b
NF
10;; This file is part of GNU Emacs.
11
eb3fa2cf 12;; GNU Emacs is free software: you can redistribute it and/or modify
99c0333b 13;; it under the terms of the GNU General Public License as published by
eb3fa2cf
GM
14;; the Free Software Foundation, either version 3 of the License, or
15;; (at your option) any later version.
99c0333b
NF
16
17;; GNU Emacs is distributed in the hope that it will be useful,
18;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20;; GNU General Public License for more details.
21
22;; You should have received a copy of the GNU General Public License
eb3fa2cf 23;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
458401b6
NF
24
25;;; Commentary:
be8d412c 26
b4dc9e6a
NF
27;; The docstring for the function `type-break-mode' summarizes most of the
28;; details of the interface.
be8d412c 29
27cd478d 30;; This package relies on the assumption that you live entirely in Emacs,
b4dc9e6a 31;; as the author does. If that's not the case for you (e.g. you often
27cd478d
EZ
32;; suspend Emacs or work in other windows) then this won't help very much;
33;; it will depend on just how often you switch back to Emacs. At the very
b4dc9e6a
NF
34;; least, you will want to turn off the keystroke thresholds and rest
35;; interval tracking.
be8d412c 36
846f6dd9
NF
37;; If you prefer not to be queried about taking breaks, but instead just
38;; want to be reminded, do the following:
39;;
40;; (setq type-break-query-mode nil)
41;;
42;; Or call the command `type-break-query-mode' with a negative prefix
43;; argument.
44
45;; If you find echo area messages annoying and would prefer to see messages
46;; in the mode line instead, do M-x type-break-mode-line-message-mode
47;; or set the variable of the same name to `t'.
b4dc9e6a
NF
48
49;; This program can truly cons up a storm because of all the calls to
7b9430b4 50;; `current-time' (which always returns fresh conses). I'm dismayed by
b4dc9e6a
NF
51;; this, but I think the health of my hands is far more important than a
52;; few pages of virtual memory.
53
846f6dd9
NF
54;; This program has no hope of working in Emacs 18.
55
b4dc9e6a
NF
56;; This package was inspired by Roland McGrath's hanoi-break.el.
57;; Several people contributed feedback and ideas, including
5762abec 58;; Roland McGrath <roland@gnu.org>
ad953485 59;; Kleanthes Koniaris <kgk@koniaris.com>
5762abec 60;; Mark Ashton <mpashton@gnu.org>
b4dc9e6a 61;; Matt Wilding <wilding@cli.com>
846f6dd9 62;; Robert S. Boyer <boyer@cs.utexas.edu>
be8d412c 63
458401b6
NF
64;;; Code:
65
66\f
104221a0
SE
67(defgroup type-break nil
68 "Encourage the user to take a rest from typing at suitable intervals."
69 :prefix "type-break"
70 :group 'keyboard)
71
622aca7c 72;;;###autoload
104221a0 73(defcustom type-break-mode nil
511a0719 74 "Toggle typing break mode.
104221a0 75See the docstring for the `type-break-mode' command for more information.
4de26885
DL
76Setting this variable directly does not take effect;
77use either \\[customize] or the function `type-break-mode'."
06b60517 78 :set (lambda (_symbol value)
104221a0 79 (type-break-mode (if value 1 -1)))
e18b0c51 80 :initialize 'custom-initialize-default
104221a0
SE
81 :type 'boolean
82 :group 'type-break
e18b0c51 83 :require 'type-break)
4cf64c15
NF
84
85;;;###autoload
104221a0 86(defcustom type-break-interval (* 60 60)
9201cc28 87 "Number of seconds between scheduled typing breaks."
104221a0
SE
88 :type 'integer
89 :group 'type-break)
458401b6 90
be8d412c 91;;;###autoload
104221a0 92(defcustom type-break-good-rest-interval (/ type-break-interval 6)
9201cc28 93 "Number of seconds of idle time considered to be an adequate typing rest.
be8d412c 94
27cd478d 95When this variable is non-nil, Emacs checks the idle time between
cc669dd8 96keystrokes. If this idle time is long enough to be considered a \"good\"
be8d412c
NF
97rest from typing, then the next typing break is simply rescheduled for later.
98
cc669dd8 99If a break is interrupted before this much time elapses, the user will be
104221a0
SE
100asked whether or not really to interrupt the break."
101 :type 'integer
102 :group 'type-break)
be8d412c 103
27cd478d
EZ
104;;;###autoload
105(defcustom type-break-good-break-interval nil
9201cc28 106 "Number of seconds considered to be an adequate explicit typing rest.
27cd478d
EZ
107
108When this variable is non-nil, its value is considered to be a \"good\"
109length (in seconds) for a break initiated by the command `type-break',
110overriding `type-break-good-rest-interval'. This provides querying of
111break interruptions when `type-break-good-rest-interval' is nil."
112 :type 'integer
113 :group 'type-break)
114
458401b6 115;;;###autoload
104221a0 116(defcustom type-break-keystroke-threshold
cc669dd8 117 ;; Assuming typing speed is 35wpm (on the average, do you really
f486195c
NF
118 ;; type more than that in a minute? I spend a lot of time reading mail
119 ;; and simply studying code in buffers) and average word length is
4cf64c15
NF
120 ;; about 5 letters, default upper threshold to the average number of
121 ;; keystrokes one is likely to type in a break interval. That way if the
122 ;; user goes through a furious burst of typing activity, cause a typing
123 ;; break to be required sooner than originally scheduled.
f486195c 124 ;; Conversely, the minimum threshold should be about a fifth of this.
cc669dd8 125 (let* ((wpm 35)
4cf64c15
NF
126 (avg-word-length 5)
127 (upper (* wpm avg-word-length (/ type-break-interval 60)))
f486195c 128 (lower (/ upper 5)))
4cf64c15 129 (cons lower upper))
9201cc28 130 "Upper and lower bound on number of keystrokes for considering typing break.
104221a0 131This structure is a pair of numbers (MIN . MAX).
4cf64c15 132
be8d412c
NF
133The first number is the minimum number of keystrokes that must have been
134entered since the last typing break before considering another one, even if
135the scheduled time has elapsed; the break is simply rescheduled until later
136if the minimum threshold hasn't been reached. If this first value is nil,
137then there is no minimum threshold; as soon as the scheduled time has
138elapsed, the user will always be queried.
4cf64c15
NF
139
140The second number is the maximum number of keystrokes that can be entered
141before a typing break is requested immediately, pre-empting the originally
be8d412c
NF
142scheduled break. If this second value is nil, then no pre-emptive breaks
143will occur; only scheduled ones will.
4cf64c15
NF
144
145Keys with bucky bits (shift, control, meta, etc) are counted as only one
b4dc9e6a
NF
146keystroke even though they really require multiple keys to generate them.
147
148The command `type-break-guesstimate-keystroke-threshold' can be used to
104221a0
SE
149guess a reasonably good pair of values for this variable."
150 :type 'sexp
151 :group 'type-break)
b4dc9e6a 152
ad953485 153(defcustom type-break-query-function 'yes-or-no-p
9201cc28 154 "Function to use for making query for a typing break.
b4dc9e6a
NF
155It should take a string as an argument, the prompt.
156Usually this should be set to `yes-or-no-p' or `y-or-n-p'.
157
ee6258ff 158To avoid being queried at all, set `type-break-query-mode' to nil."
ad953485
NF
159 :type '(radio function
160 (function-item yes-or-no-p)
161 (function-item y-or-n-p))
162 :group 'type-break)
b4dc9e6a 163
104221a0 164(defcustom type-break-query-interval 60
9201cc28 165 "Number of seconds between queries to take a break, if put off.
b4dc9e6a 166The user will continue to be prompted at this interval until he or she
104221a0
SE
167finally submits to taking a typing break."
168 :type 'integer
169 :group 'type-break)
be8d412c 170
104221a0 171(defcustom type-break-time-warning-intervals '(300 120 60 30)
9201cc28 172 "List of time intervals for warnings about upcoming typing break.
e7b20417 173At each of the intervals (specified in seconds) away from a scheduled
104221a0
SE
174typing break, print a warning in the echo area."
175 :type '(repeat integer)
176 :group 'type-break)
e7b20417 177
104221a0 178(defcustom type-break-keystroke-warning-intervals '(300 200 100 50)
9201cc28 179 "List of keystroke measurements for warnings about upcoming typing break.
e7b20417
NF
180At each of the intervals (specified in keystrokes) away from the upper
181keystroke threshold, print a warning in the echo area.
182If either this variable or the upper threshold is set, then no warnings
104221a0
SE
183will occur."
184 :type '(repeat integer)
185 :group 'type-break)
186
104221a0 187(defcustom type-break-warning-repeat 40
9201cc28 188 "Number of keystrokes for which warnings should be repeated.
e7b20417 189That is, for each of this many keystrokes the warning is redisplayed
104221a0
SE
190in the echo area to make sure it's really seen."
191 :type 'integer
192 :group 'type-break)
e7b20417 193
ad953485 194(defcustom type-break-time-stamp-format "[%H:%M] "
9201cc28 195 "Timestamp format used to prefix messages.
ad953485
NF
196Format specifiers are as used by `format-time-string'."
197 :type 'string
198 :group 'type-break)
199
104221a0 200(defcustom type-break-demo-functions
e7b20417 201 '(type-break-demo-boring type-break-demo-life type-break-demo-hanoi)
9201cc28 202 "List of functions to consider running as demos during typing breaks.
458401b6 203When a typing break begins, one of these functions is selected randomly
27cd478d 204to have Emacs do something interesting.
622aca7c 205
cc669dd8 206Any function in this list should start a demo which ceases as soon as a
104221a0
SE
207key is pressed."
208 :type '(repeat function)
209 :group 'type-break)
622aca7c 210
27cd478d 211(defcustom type-break-demo-boring-stats nil
9201cc28 212 "Show word per minute and keystroke figures in the Boring demo."
27cd478d
EZ
213 :type 'boolean
214 :group 'type-break)
215
216(defcustom type-break-terse-messages nil
9201cc28 217 "Use slightly terser messages."
27cd478d
EZ
218 :type 'boolean
219 :group 'type-break)
220
221(defcustom type-break-file-name (convert-standard-filename "~/.type-break")
9201cc28 222 "Name of file used to save state across sessions.
a7ed85f0 223If this is nil, no data will be saved across sessions."
27cd478d
EZ
224 :type 'file
225 :group 'type-break)
226
846f6dd9 227(defvar type-break-post-command-hook '(type-break-check)
27cd478d 228 "Hook run indirectly by `post-command-hook' for typing break functions.
b4dc9e6a
NF
229This is not really intended to be set by the user, but it's probably
230harmless to do so. Mainly it is used by various parts of the typing break
231program to delay actions until after the user has completed some command.
232It exists because `post-command-hook' itself is inaccessible while its
233functions are being run, and some type-break--related functions want to
234remove themselves after running.")
e7b20417 235
846f6dd9
NF
236\f
237;; Mode line frobs
238
846f6dd9
NF
239(defvar type-break-mode-line-format
240 '(type-break-mode-line-message-mode
241 (""
242 type-break-mode-line-break-message
243 type-break-mode-line-warning))
244 "*Format of messages in the mode line concerning typing breaks.")
245
246(defvar type-break-mode-line-break-message
247 '(type-break-mode-line-break-message-p
248 type-break-mode-line-break-string))
249
250(defvar type-break-mode-line-break-message-p nil)
ad953485 251(defvar type-break-mode-line-break-string " *** TAKE A TYPING BREAK NOW ***")
846f6dd9
NF
252
253(defvar type-break-mode-line-warning
254 '(type-break-mode-line-break-message-p
255 ("")
256 (type-break-warning-countdown-string
ad953485
NF
257 (" *** "
258 "Break in "
846f6dd9
NF
259 type-break-warning-countdown-string
260 " "
261 type-break-warning-countdown-string-type
262 "***"))))
263
264(defvar type-break-warning-countdown-string nil
265 "If non-nil, this is a countdown for the next typing break.
266
267This variable, in conjunction with `type-break-warning-countdown-string-type'
b688ed44 268\(which indicates whether this value is a number of keystrokes or seconds)
27cd478d 269is installed in `mode-line-format' to notify of imminent typing breaks.")
846f6dd9
NF
270
271(defvar type-break-warning-countdown-string-type nil
272 "Indicates the unit type of `type-break-warning-countdown-string'.
273It will be either \"seconds\" or \"keystrokes\".")
274
275\f
4cf64c15 276;; These are internal variables. Do not set them yourself.
622aca7c 277
defa7346 278(defvar type-break-alarm-p nil)
be8d412c 279(defvar type-break-keystroke-count 0)
be8d412c
NF
280(defvar type-break-time-last-break nil)
281(defvar type-break-time-next-break nil)
282(defvar type-break-time-last-command (current-time))
e7b20417
NF
283(defvar type-break-current-time-warning-interval nil)
284(defvar type-break-current-keystroke-warning-interval nil)
285(defvar type-break-time-warning-count 0)
286(defvar type-break-keystroke-warning-count 0)
27cd478d
EZ
287(defvar type-break-interval-start nil)
288
cc669dd8 289\f
4cf64c15
NF
290;;;###autoload
291(defun type-break-mode (&optional prefix)
292 "Enable or disable typing-break mode.
293This is a minor mode, but it is global to all buffers by default.
294
295When this mode is enabled, the user is encouraged to take typing breaks at
296appropriate intervals; either after a specified amount of time or when the
297user has exceeded a keystroke threshold. When the time arrives, the user
27cd478d 298is asked to take a break. If the user refuses at that time, Emacs will ask
4cf64c15
NF
299again in a short period of time. The idea is to give the user enough time
300to find a good breaking point in his or her work, but be sufficiently
301annoying to discourage putting typing breaks off indefinitely.
302
4cf64c15 303A negative prefix argument disables this mode.
cc669dd8 304No argument or any non-negative argument enables it.
4cf64c15
NF
305
306The user may enable or disable this mode by setting the variable of the
307same name, though setting it in that way doesn't reschedule a break or
308reset the keystroke counter.
309
be8d412c
NF
310If the mode was previously disabled and is enabled as a consequence of
311calling this function, it schedules a break with `type-break-schedule' to
312make sure one occurs (the user can call that command to reschedule the
313break at any time). It also initializes the keystroke counter.
4cf64c15
NF
314
315The variable `type-break-interval' specifies the number of seconds to
316schedule between regular typing breaks. This variable doesn't directly
317affect the time schedule; it simply provides a default for the
318`type-break-schedule' command.
319
cc669dd8
NF
320If set, the variable `type-break-good-rest-interval' specifies the minimum
321amount of time which is considered a reasonable typing break. Whenever
322that time has elapsed, typing breaks are automatically rescheduled for
27cd478d 323later even if Emacs didn't prompt you to take one first. Also, if a break
cc669dd8 324is ended before this much time has elapsed, the user will be asked whether
27cd478d
EZ
325or not to continue. A nil value for this variable prevents automatic
326break rescheduling, making `type-break-interval' an upper bound on the time
327between breaks. In this case breaks will be prompted for as usual before
328the upper bound if the keystroke threshold is reached.
329
330If `type-break-good-rest-interval' is nil and
331`type-break-good-break-interval' is set, then confirmation is required to
332interrupt a break before `type-break-good-break-interval' seconds
333have passed. This provides for an upper bound on the time between breaks
334together with confirmation of interruptions to these breaks.
be8d412c
NF
335
336The variable `type-break-keystroke-threshold' is used to determine the
337thresholds at which typing breaks should be considered. You can use
b4dc9e6a 338the command `type-break-guesstimate-keystroke-threshold' to try to
be8d412c 339approximate good values for this.
4cf64c15 340
b4dc9e6a
NF
341There are several variables that affect how or when warning messages about
342imminent typing breaks are displayed. They include:
343
2157be68
RS
344 `type-break-mode-line-message-mode'
345 `type-break-time-warning-intervals'
346 `type-break-keystroke-warning-intervals'
347 `type-break-warning-repeat'
348 `type-break-warning-countdown-string'
349 `type-break-warning-countdown-string-type'
b4dc9e6a 350
846f6dd9
NF
351There are several variables that affect if, how, and when queries to begin
352a typing break occur. They include:
b4dc9e6a 353
2157be68
RS
354 `type-break-query-mode'
355 `type-break-query-function'
356 `type-break-query-interval'
b4dc9e6a 357
27cd478d
EZ
358The command `type-break-statistics' prints interesting things.
359
360Finally, a file (named `type-break-file-name') is used to store information
361across Emacs sessions. This provides recovery of the break status between
362sessions and after a crash. Manual changes to the file may result in
363problems."
4cf64c15 364 (interactive "P")
846f6dd9 365 (type-break-check-post-command-hook)
4cf64c15 366
be8d412c 367 (let ((already-enabled type-break-mode))
cc669dd8 368 (setq type-break-mode (>= (prefix-numeric-value prefix) 0))
be8d412c
NF
369
370 (cond
371 ((and already-enabled type-break-mode)
32226619 372 (and (called-interactively-p 'interactive)
2157be68 373 (message "Type Break mode is already enabled")))
be8d412c 374 (type-break-mode
cc7fe910
EZ
375 (when type-break-file-name
376 (with-current-buffer (find-file-noselect type-break-file-name 'nowarn)
377 (setq buffer-save-without-query t)))
1b8d0755 378
846f6dd9
NF
379 (or global-mode-string
380 (setq global-mode-string '("")))
7cd3279a
RS
381 (or (assq 'type-break-mode-line-message-mode
382 minor-mode-alist)
383 (setq minor-mode-alist
384 (cons type-break-mode-line-format
385 minor-mode-alist)))
e7b20417 386 (type-break-keystroke-reset)
846f6dd9 387 (type-break-mode-line-countdown-or-break nil)
27cd478d 388
a7ed85f0
EZ
389 (setq type-break-time-last-break
390 (or (type-break-get-previous-time)
391 (current-time)))
27cd478d
EZ
392
393 ;; schedule according to break time from session file
394 (type-break-schedule
395 (let (diff)
396 (if (and type-break-time-last-break
397 (< (setq diff (type-break-time-difference
398 type-break-time-last-break
399 (current-time)))
400 type-break-interval))
401 ;; use the file's value
402 (progn
403 (setq type-break-keystroke-count
404 (type-break-get-previous-count))
405 ;; file the time, in case it was read from the auto-save file
406 (type-break-file-time type-break-interval-start)
407 (setq type-break-interval-start type-break-time-last-break)
408 (- type-break-interval diff))
409 ;; schedule from now
410 (setq type-break-interval-start (current-time))
411 (type-break-file-time type-break-interval-start)
412 type-break-interval))
413 type-break-interval-start
414 type-break-interval)
415
32226619 416 (and (called-interactively-p 'interactive)
27cd478d 417 (message "Type Break mode is enabled and set")))
846f6dd9
NF
418 (t
419 (type-break-keystroke-reset)
420 (type-break-mode-line-countdown-or-break nil)
421 (type-break-cancel-schedule)
27cd478d 422 (do-auto-save)
a7ed85f0
EZ
423 (when type-break-file-name
424 (with-current-buffer (find-file-noselect type-break-file-name
425 'nowarn)
426 (set-buffer-modified-p nil)
427 (unlock-buffer)
428 (kill-this-buffer)))
32226619 429 (and (called-interactively-p 'interactive)
2157be68 430 (message "Type Break mode is disabled")))))
4cf64c15
NF
431 type-break-mode)
432
56eb0904 433(define-minor-mode type-break-mode-line-message-mode
06e21633
CY
434 "Toggle warnings about typing breaks in the mode line.
435With a prefix argument ARG, enable these warnings if ARG is
436positive, and disable them otherwise. If called from Lisp,
437enable them if ARG is omitted or nil.
846f6dd9 438
06e21633
CY
439The user may also enable or disable this mode simply by setting
440the variable of the same name.
846f6dd9
NF
441
442Variables controlling the display of messages in the mode line include:
443
2157be68
RS
444 `mode-line-format'
445 `global-mode-string'
446 `type-break-mode-line-break-message'
447 `type-break-mode-line-warning'"
56eb0904
SM
448 :global t)
449
450(define-minor-mode type-break-query-mode
06e21633
CY
451 "Toggle typing break queries.
452With a prefix argument ARG, enable these queries if ARG is
453positive, and disable them otherwise. If called from Lisp,
454enable them if ARG is omitted or nil.
b4dc9e6a 455
06e21633
CY
456The user may also enable or disable this mode simply by setting
457the variable of the same name."
56eb0904 458 :global t)
b4dc9e6a 459
846f6dd9 460\f
27cd478d
EZ
461;;; session file functions
462
463(defvar type-break-auto-save-file-name
464 (let ((buffer-file-name type-break-file-name))
465 (make-auto-save-file-name))
466 "Auto-save name of `type-break-file-name'.")
467
468(defun type-break-file-time (&optional time)
469 "File break time in `type-break-file-name', unless the file is locked."
a7ed85f0
EZ
470 (if (and type-break-file-name
471 (not (stringp (file-locked-p type-break-file-name))))
27cd478d
EZ
472 (with-current-buffer (find-file-noselect type-break-file-name
473 'nowarn)
474 (let ((inhibit-read-only t))
475 (erase-buffer)
476 (insert (format "%s\n\n" (or time type-break-interval-start)))
477 ;; file saving is left to auto-save
478 ))))
479
480(defun type-break-file-keystroke-count ()
481 "File keystroke count in `type-break-file-name', unless the file is locked."
a7ed85f0
EZ
482 (if (and type-break-file-name
483 (not (stringp (file-locked-p type-break-file-name))))
cf8a2dae
RS
484 ;; Prevent deactivation of the mark in some other buffer.
485 (let (deactivate-mark)
486 (with-current-buffer (find-file-noselect type-break-file-name
487 'nowarn)
488 (save-excursion
489 (let ((inhibit-read-only t))
490 (goto-char (point-min))
491 (forward-line)
5ed619e0 492 (delete-region (point) (line-end-position))
cf8a2dae
RS
493 (insert (format "%s" type-break-keystroke-count))
494 ;; file saving is left to auto-save
495 ))))))
27cd478d
EZ
496
497(defun timep (time)
498 "If TIME is in the format returned by `current-time' then
499return TIME, else return nil."
7b9430b4 500 (condition-case nil
3abb79e5 501 (and (float-time time) time)
7b9430b4 502 (error nil)))
27cd478d
EZ
503
504(defun type-break-choose-file ()
505 "Return file to read from."
506 (cond
a7ed85f0
EZ
507 ((not type-break-file-name)
508 nil)
27cd478d
EZ
509 ((and (file-exists-p type-break-auto-save-file-name)
510 (file-readable-p type-break-auto-save-file-name))
511 type-break-auto-save-file-name)
512 ((and (file-exists-p type-break-file-name)
513 (file-readable-p type-break-file-name))
514 type-break-file-name)
515 (t nil)))
516
517(defun type-break-get-previous-time ()
518 "Get previous break time from `type-break-file-name'.
519Returns nil if the file is missing or if the time breaks with the
520`current-time' format."
521 (let ((file (type-break-choose-file)))
522 (if file
523 (timep ;; returns expected format, else nil
524 (with-current-buffer (find-file-noselect file 'nowarn)
dad757bc
RS
525 (condition-case nil
526 (save-excursion
527 (goto-char (point-min))
528 (read (current-buffer)))
529 (end-of-file
530 (error "End of file in `%s'" file))))))))
27cd478d
EZ
531
532(defun type-break-get-previous-count ()
533 "Get previous keystroke count from `type-break-file-name'.
534Return 0 if the file is missing or if the form read is not an
535integer."
536 (let ((file (type-break-choose-file)))
537 (if (and file
538 (integerp
539 (setq file
540 (with-current-buffer
541 (find-file-noselect file 'nowarn)
7ab2e82f
RS
542 (condition-case nil
543 (save-excursion
544 (goto-char (point-min))
545 (forward-line 1)
546 (read (current-buffer)))
547 (end-of-file
548 (error "End of file in `%s'" file)))))))
27cd478d
EZ
549 file
550 0)))
551
552\f
622aca7c 553;;;###autoload
458401b6
NF
554(defun type-break ()
555 "Take a typing break.
556
4cf64c15 557During the break, a demo selected from the functions listed in
cc669dd8 558`type-break-demo-functions' is run.
458401b6 559
4cf64c15 560After the typing break is finished, the next break is scheduled
cc669dd8 561as per the function `type-break-schedule'."
622aca7c 562 (interactive)
ad953485 563 (do-auto-save)
e7b20417 564 (type-break-cancel-schedule)
27cd478d
EZ
565 ;; remove any query scheduled during interactive invocation
566 (remove-hook 'type-break-post-command-hook 'type-break-do-query)
cc669dd8
NF
567 (let ((continue t)
568 (start-time (current-time)))
569 (setq type-break-time-last-break start-time)
570 (while continue
571 (save-window-excursion
572 ;; Eat the screen.
573 (and (eq (selected-window) (minibuffer-window))
574 (other-window 1))
575 (delete-other-windows)
576 (scroll-right (window-width))
27cd478d
EZ
577 (unless type-break-terse-messages
578 (message "Press any key to resume from typing break."))
cc669dd8
NF
579
580 (random t)
581 (let* ((len (length type-break-demo-functions))
582 (idx (random len))
583 (fn (nth idx type-break-demo-functions)))
584 (condition-case ()
585 (funcall fn)
586 (error nil))))
be8d412c 587
27cd478d
EZ
588 (let ((good-interval (or type-break-good-rest-interval
589 type-break-good-break-interval)))
590 (cond
591 (good-interval
592 (let ((break-secs (type-break-time-difference
593 start-time (current-time))))
594 (cond
595 ((>= break-secs good-interval)
596 (setq continue nil))
597 ;; 60 seconds may be too much leeway if the break is only 3
598 ;; minutes to begin with. You can just say "no" to the query
599 ;; below if you're in that much of a hurry.
600 ;;((> 60 (abs (- break-secs good-interval)))
601 ;; (setq continue nil))
602 ((funcall
603 type-break-query-function
604 (format
605 (if type-break-terse-messages
606 "%s%s remaining. Continue break? "
607 "%sYou really ought to rest %s more. Continue break? ")
608 (type-break-time-stamp)
609 (type-break-format-time (- good-interval
610 break-secs)))))
611 (t
612 (setq continue nil)))))
613 (t (setq continue nil))))))
4cf64c15 614
e7b20417 615 (type-break-keystroke-reset)
27cd478d 616 (type-break-file-time)
846f6dd9 617 (type-break-mode-line-countdown-or-break nil)
be8d412c 618 (type-break-schedule))
622aca7c 619
458401b6 620\f
27cd478d 621(defun type-break-schedule (&optional time start interval)
defa7346 622 "Schedule a typing break for TIME seconds from now.
27cd478d
EZ
623If time is not specified it defaults to `type-break-interval'.
624START and INTERVAL are used when recovering a break.
625START is the start of the break (defaults to now).
626INTERVAL is the full length of an interval (defaults to TIME)."
defa7346
NF
627 (interactive (list (and current-prefix-arg
628 (prefix-numeric-value current-prefix-arg))))
458401b6 629 (or time (setq time type-break-interval))
846f6dd9 630 (type-break-check-post-command-hook)
4cf64c15 631 (type-break-cancel-schedule)
e7b20417 632 (type-break-time-warning-schedule time 'reset)
846f6dd9 633 (type-break-run-at-time (max 1 time) nil 'type-break-alarm)
defa7346 634 (setq type-break-time-next-break
27cd478d
EZ
635 (type-break-time-sum (or start (current-time))
636 (or interval time))))
622aca7c 637
4cf64c15 638(defun type-break-cancel-schedule ()
e7b20417 639 (type-break-cancel-time-warning-schedule)
846f6dd9 640 (type-break-cancel-function-timers 'type-break-alarm)
be8d412c
NF
641 (setq type-break-alarm-p nil)
642 (setq type-break-time-next-break nil))
458401b6 643
e7b20417 644(defun type-break-time-warning-schedule (&optional time resetp)
b4dc9e6a 645 (let ((type-break-current-time-warning-interval nil))
e7b20417 646 (type-break-cancel-time-warning-schedule))
846f6dd9 647 (add-hook 'type-break-post-command-hook 'type-break-time-warning 'append)
e7b20417
NF
648 (cond
649 (type-break-time-warning-intervals
650 (and resetp
651 (setq type-break-current-time-warning-interval
652 type-break-time-warning-intervals))
653
654 (or time
655 (setq time (type-break-time-difference (current-time)
656 type-break-time-next-break)))
657
658 (while (and type-break-current-time-warning-interval
659 (> (car type-break-current-time-warning-interval) time))
660 (setq type-break-current-time-warning-interval
661 (cdr type-break-current-time-warning-interval)))
662
663 (cond
664 (type-break-current-time-warning-interval
665 (setq time (- time (car type-break-current-time-warning-interval)))
666 (setq type-break-current-time-warning-interval
667 (cdr type-break-current-time-warning-interval))
668
b4dc9e6a
NF
669 ;(let (type-break-current-time-warning-interval)
670 ; (type-break-cancel-time-warning-schedule))
846f6dd9 671 (type-break-run-at-time (max 1 time) nil 'type-break-time-warning-alarm)
b4dc9e6a
NF
672
673 (cond
674 (resetp
675 (setq type-break-warning-countdown-string nil))
676 (t
677 (setq type-break-warning-countdown-string (number-to-string time))
678 (setq type-break-warning-countdown-string-type "seconds"))))))))
e7b20417
NF
679
680(defun type-break-cancel-time-warning-schedule ()
846f6dd9 681 (type-break-cancel-function-timers 'type-break-time-warning-alarm)
e7b20417
NF
682 (remove-hook 'type-break-post-command-hook 'type-break-time-warning)
683 (setq type-break-current-time-warning-interval
b4dc9e6a 684 type-break-time-warning-intervals)
27cd478d 685 (setq type-break-time-warning-count 0) ; avoid warnings after break
b4dc9e6a 686 (setq type-break-warning-countdown-string nil))
e7b20417 687
4cf64c15 688(defun type-break-alarm ()
846f6dd9
NF
689 (type-break-check-post-command-hook)
690 (setq type-break-alarm-p t)
691 (type-break-mode-line-countdown-or-break 'break))
458401b6 692
e7b20417 693(defun type-break-time-warning-alarm ()
846f6dd9 694 (type-break-check-post-command-hook)
e7b20417
NF
695 (type-break-time-warning-schedule)
696 (setq type-break-time-warning-count type-break-warning-repeat)
846f6dd9
NF
697 (type-break-time-warning)
698 (type-break-mode-line-countdown-or-break 'countdown))
e7b20417
NF
699
700\f
701(defun type-break-run-tb-post-command-hook ()
702 (and type-break-mode
703 (run-hooks 'type-break-post-command-hook)))
704
458401b6 705(defun type-break-check ()
4cf64c15
NF
706 "Ask to take a typing break if appropriate.
707This may be the case either because the scheduled time has come \(and the
708minimum keystroke threshold has been reached\) or because the maximum
709keystroke threshold has been exceeded."
27cd478d 710 (type-break-file-keystroke-count)
e7b20417
NF
711 (let* ((min-threshold (car type-break-keystroke-threshold))
712 (max-threshold (cdr type-break-keystroke-threshold)))
713 (and type-break-good-rest-interval
714 (progn
715 (and (> (type-break-time-difference
716 type-break-time-last-command (current-time))
717 type-break-good-rest-interval)
718 (progn
719 (type-break-keystroke-reset)
846f6dd9 720 (type-break-mode-line-countdown-or-break nil)
e7b20417
NF
721 (setq type-break-time-last-break (current-time))
722 (type-break-schedule)))
723 (setq type-break-time-last-command (current-time))))
724
725 (and type-break-keystroke-threshold
b4dc9e6a
NF
726 (let ((keys (this-command-keys)))
727 (cond
728 ;; Ignore mouse motion
729 ((and (vectorp keys)
730 (consp (aref keys 0))
731 (memq (car (aref keys 0)) '(mouse-movement))))
732 (t
733 (setq type-break-keystroke-count
734 (+ type-break-keystroke-count (length keys)))))))
e7b20417 735
e7b20417
NF
736 (cond
737 (type-break-alarm-p
738 (cond
739 ((input-pending-p))
740 ((eq (selected-window) (minibuffer-window)))
741 ((and min-threshold
742 (< type-break-keystroke-count min-threshold))
743 (type-break-schedule))
744 (t
745 ;; If keystroke count is within min-threshold of
b4dc9e6a 746 ;; max-threshold, lower it to reduce the likelihood of an
e7b20417
NF
747 ;; immediate subsequent query.
748 (and max-threshold
749 min-threshold
750 (< (- max-threshold type-break-keystroke-count) min-threshold)
751 (progn
752 (type-break-keystroke-reset)
753 (setq type-break-keystroke-count min-threshold)))
754 (type-break-query))))
755 ((and type-break-keystroke-warning-intervals
756 max-threshold
757 (= type-break-keystroke-warning-count 0)
758 (type-break-check-keystroke-warning)))
759 ((and max-threshold
760 (> type-break-keystroke-count max-threshold)
761 (not (input-pending-p))
762 (not (eq (selected-window) (minibuffer-window))))
763 (type-break-keystroke-reset)
764 (setq type-break-keystroke-count (or min-threshold 0))
765 (type-break-query)))))
766
767;; This should return t if warnings were enabled, nil otherwise.
846f6dd9 768(defun type-break-check-keystroke-warning ()
b4dc9e6a
NF
769 ;; This is safe because the caller should have checked that the cdr was
770 ;; non-nil already.
e7b20417
NF
771 (let ((left (- (cdr type-break-keystroke-threshold)
772 type-break-keystroke-count)))
773 (cond
774 ((null (car type-break-current-keystroke-warning-interval))
775 nil)
776 ((> left (car type-break-current-keystroke-warning-interval))
777 nil)
778 (t
779 (while (and (car type-break-current-keystroke-warning-interval)
780 (< left (car type-break-current-keystroke-warning-interval)))
781 (setq type-break-current-keystroke-warning-interval
782 (cdr type-break-current-keystroke-warning-interval)))
783 (setq type-break-keystroke-warning-count type-break-warning-repeat)
784 (add-hook 'type-break-post-command-hook 'type-break-keystroke-warning)
b4dc9e6a
NF
785 (setq type-break-warning-countdown-string (number-to-string left))
786 (setq type-break-warning-countdown-string-type "keystrokes")
846f6dd9 787 (type-break-mode-line-countdown-or-break 'countdown)
e7b20417 788 t))))
4cf64c15 789
b4dc9e6a 790;; Arrange for a break query to be made, when the user stops typing furiously.
4cf64c15 791(defun type-break-query ()
b4dc9e6a
NF
792 (add-hook 'type-break-post-command-hook 'type-break-do-query))
793
b4dc9e6a
NF
794(defun type-break-do-query ()
795 (cond
846f6dd9
NF
796 ((not type-break-query-mode)
797 (type-break-noninteractive-query)
798 (type-break-schedule type-break-query-interval)
799 (remove-hook 'type-break-post-command-hook 'type-break-do-query))
800 ((sit-for 2)
b4dc9e6a
NF
801 (condition-case ()
802 (cond
803 ((let ((type-break-mode nil)
804 ;; yes-or-no-p sets this-command to exit-minibuffer,
805 ;; which hoses undo or yank-pop (if you happened to be
806 ;; yanking just when the query occurred).
807 (this-command this-command))
ad953485
NF
808 ;; Cancel schedule to prevent possibility of a second query
809 ;; from taking place before this one has even returned.
810 ;; The condition-case wrapper will reschedule on quit.
811 (type-break-cancel-schedule)
27cd478d
EZ
812 ;; Also prevent a second query when the break is interrupted.
813 (remove-hook 'type-break-post-command-hook 'type-break-do-query)
b4dc9e6a 814 (funcall type-break-query-function
ad953485
NF
815 (format "%s%s"
816 (type-break-time-stamp)
27cd478d
EZ
817 (if type-break-terse-messages
818 "Break now? "
819 "Take a break from typing now? "))))
b4dc9e6a
NF
820 (type-break))
821 (t
822 (type-break-schedule type-break-query-interval)))
823 (quit
27cd478d 824 (type-break-schedule type-break-query-interval))))))
458401b6 825
06b60517 826(defun type-break-noninteractive-query (&optional _ignored-args)
846f6dd9
NF
827 "Null query function which doesn't interrupt user and assumes `no'.
828It prints a reminder in the echo area to take a break, but doesn't enforce
829this or ask the user to start one right now."
830 (cond
831 (type-break-mode-line-message-mode)
832 (t
833 (beep t)
ad953485
NF
834 (message "%sYou should take a typing break now. Do `M-x type-break'."
835 (type-break-time-stamp))
846f6dd9
NF
836 (sit-for 1)
837 (beep t)
838 ;; return nil so query caller knows to reset reminder, as if user
839 ;; said "no" in response to yes-or-no-p.
840 nil)))
841
e7b20417
NF
842(defun type-break-time-warning ()
843 (cond
844 ((and (car type-break-keystroke-threshold)
845 (< type-break-keystroke-count (car type-break-keystroke-threshold))))
846 ((> type-break-time-warning-count 0)
b4dc9e6a
NF
847 (let ((timeleft (type-break-time-difference (current-time)
848 type-break-time-next-break)))
849 (setq type-break-warning-countdown-string (number-to-string timeleft))
850 (cond
851 ((eq (selected-window) (minibuffer-window)))
852 ;; Do nothing if the command was just a prefix arg, since that will
853 ;; immediately be followed by some other interactive command.
846f6dd9
NF
854 ;; Otherwise, it is particularly annoying for the sit-for below to
855 ;; delay redisplay when one types sequences like `C-u -1 C-l'.
b4dc9e6a 856 ((memq this-command '(digit-argument universal-argument)))
846f6dd9 857 ((not type-break-mode-line-message-mode)
b4dc9e6a
NF
858 ;; Pause for a moment so any previous message can be seen.
859 (sit-for 2)
ad953485
NF
860 (message "%sWarning: typing break due in %s."
861 (type-break-time-stamp)
b4dc9e6a
NF
862 (type-break-format-time timeleft))
863 (setq type-break-time-warning-count
864 (1- type-break-time-warning-count))))))
e7b20417 865 (t
b4dc9e6a
NF
866 (remove-hook 'type-break-post-command-hook 'type-break-time-warning)
867 (setq type-break-warning-countdown-string nil))))
e7b20417
NF
868
869(defun type-break-keystroke-warning ()
870 (cond
871 ((> type-break-keystroke-warning-count 0)
b4dc9e6a
NF
872 (setq type-break-warning-countdown-string
873 (number-to-string (- (cdr type-break-keystroke-threshold)
874 type-break-keystroke-count)))
e7b20417
NF
875 (cond
876 ((eq (selected-window) (minibuffer-window)))
846f6dd9
NF
877 ;; Do nothing if the command was just a prefix arg, since that will
878 ;; immediately be followed by some other interactive command.
879 ;; Otherwise, it is particularly annoying for the sit-for below to
880 ;; delay redisplay when one types sequences like `C-u -1 C-l'.
881 ((memq this-command '(digit-argument universal-argument)))
882 ((not type-break-mode-line-message-mode)
e7b20417 883 (sit-for 2)
ad953485
NF
884 (message "%sWarning: typing break due in %s keystrokes."
885 (type-break-time-stamp)
e7b20417
NF
886 (- (cdr type-break-keystroke-threshold)
887 type-break-keystroke-count))
888 (setq type-break-keystroke-warning-count
889 (1- type-break-keystroke-warning-count)))))
890 (t
891 (remove-hook 'type-break-post-command-hook
b4dc9e6a
NF
892 'type-break-keystroke-warning)
893 (setq type-break-warning-countdown-string nil))))
458401b6 894
846f6dd9
NF
895(defun type-break-mode-line-countdown-or-break (&optional type)
896 (cond
897 ((not type-break-mode-line-message-mode))
898 ((eq type 'countdown)
899 ;(setq type-break-mode-line-break-message-p nil)
900 (add-hook 'type-break-post-command-hook
901 'type-break-force-mode-line-update 'append))
902 ((eq type 'break)
903 ;; Alternate
904 (setq type-break-mode-line-break-message-p
905 (not type-break-mode-line-break-message-p))
906 (remove-hook 'type-break-post-command-hook
907 'type-break-force-mode-line-update))
908 (t
909 (setq type-break-mode-line-break-message-p nil)
910 (setq type-break-warning-countdown-string nil)
911 (remove-hook 'type-break-post-command-hook
912 'type-break-force-mode-line-update)))
913 (type-break-force-mode-line-update))
914
458401b6 915\f
be8d412c
NF
916;;;###autoload
917(defun type-break-statistics ()
918 "Print statistics about typing breaks in a temporary buffer.
919This includes the last time a typing break was taken, when the next one is
920scheduled, the keystroke thresholds and the current keystroke count, etc."
921 (interactive)
922 (with-output-to-temp-buffer "*Typing Break Statistics*"
923 (princ (format "Typing break statistics\n-----------------------\n
b4dc9e6a 924Typing break mode is currently %s.
846f6dd9
NF
925Interactive query for breaks is %s.
926Warnings of imminent typing breaks in mode line is %s.
b4dc9e6a
NF
927
928Last typing break ended : %s
be8d412c
NF
929Next scheduled typing break : %s\n
930Minimum keystroke threshold : %s
931Maximum keystroke threshold : %s
932Current keystroke count : %s"
b4dc9e6a 933 (if type-break-mode "enabled" "disabled")
846f6dd9
NF
934 (if type-break-query-mode "enabled" "disabled")
935 (if type-break-mode-line-message-mode "enabled" "disabled")
be8d412c
NF
936 (if type-break-time-last-break
937 (current-time-string type-break-time-last-break)
938 "never")
939 (if (and type-break-mode type-break-time-next-break)
6b62b567 940 (format "%s\t(%s from now)"
be8d412c 941 (current-time-string type-break-time-next-break)
e7b20417 942 (type-break-format-time
cc669dd8 943 (type-break-time-difference
e7b20417 944 (current-time)
cc669dd8 945 type-break-time-next-break)))
be8d412c
NF
946 "none scheduled")
947 (or (car type-break-keystroke-threshold) "none")
948 (or (cdr type-break-keystroke-threshold) "none")
949 type-break-keystroke-count))))
950
951;;;###autoload
b4dc9e6a 952(defun type-break-guesstimate-keystroke-threshold (wpm &optional wordlen frac)
be8d412c 953 "Guess values for the minimum/maximum keystroke threshold for typing breaks.
b4dc9e6a 954
be8d412c 955If called interactively, the user is prompted for their guess as to how
b4dc9e6a
NF
956many words per minute they usually type. This value should not be your
957maximum WPM, but your average. Of course, this is harder to gauge since it
958can vary considerably depending on what you are doing. For example, one
846f6dd9 959tends to type less when debugging a program as opposed to writing
b4dc9e6a
NF
960documentation. (Perhaps a separate program should be written to estimate
961average typing speed.)
962
963From that, this command sets the values in `type-break-keystroke-threshold'
964based on a fairly simple algorithm involving assumptions about the average
965length of words (5). For the minimum threshold, it uses about a fifth of
966the computed maximum threshold.
be8d412c 967
27cd478d 968When called from Lisp programs, the optional args WORDLEN and FRAC can be
be8d412c
NF
969used to override the default assumption about average word length and the
970fraction of the maximum threshold to which to set the minimum threshold.
971FRAC should be the inverse of the fractional value; for example, a value of
9722 would mean to use one half, a value of 4 would mean to use one quarter, etc."
b4dc9e6a 973 (interactive "NOn average, how many words per minute do you type? ")
be8d412c 974 (let* ((upper (* wpm (or wordlen 5) (/ type-break-interval 60)))
f486195c 975 (lower (/ upper (or frac 5))))
be8d412c
NF
976 (or type-break-keystroke-threshold
977 (setq type-break-keystroke-threshold (cons nil nil)))
978 (setcar type-break-keystroke-threshold lower)
979 (setcdr type-break-keystroke-threshold upper)
32226619 980 (if (called-interactively-p 'interactive)
5d610140
RS
981 (message "min threshold: %d\tmax threshold: %d" lower upper))
982 type-break-keystroke-threshold))
be8d412c
NF
983
984\f
e7b20417
NF
985;;; misc functions
986
987;; Compute the difference, in seconds, between a and b, two structures
988;; similar to those returned by `current-time'.
846f6dd9 989(defun type-break-time-difference (a b)
7b9430b4 990 (round (float-time (time-subtract b a))))
e7b20417 991
defa7346
NF
992;; Return (in a new list the same in structure to that returned by
993;; `current-time') the sum of the arguments. Each argument may be a time
994;; list or a single integer, a number of seconds.
995;; This function keeps the high and low 16 bits of the seconds properly
996;; balanced so that the lower value never exceeds 16 bits. Otherwise, when
997;; the result is passed to `current-time-string' it will toss some of the
846f6dd9 998;; "low" bits and format the time incorrectly.
defa7346 999(defun type-break-time-sum (&rest tmlist)
2f81380d 1000 (let ((sum '(0 0 0)))
3de63bf8 1001 (dolist (tem tmlist sum)
2f81380d
PE
1002 (setq sum (time-add sum (if (integerp tem)
1003 (list (floor tem 65536) (mod tem 65536))
3de63bf8 1004 tem))))))
defa7346 1005
ad953485
NF
1006(defun type-break-time-stamp (&optional when)
1007 (if (fboundp 'format-time-string)
1008 (format-time-string type-break-time-stamp-format when)
1009 ;; Emacs 19.28 and prior do not have format-time-string.
1010 ;; In that case, result is not customizable. Upgrade today!
1011 (format "[%s] " (substring (current-time-string when) 11 16))))
1012
846f6dd9 1013(defun type-break-format-time (secs)
e7b20417
NF
1014 (let ((mins (/ secs 60)))
1015 (cond
1016 ((= mins 1) (format "%d minute" mins))
1017 ((> mins 0) (format "%d minutes" mins))
1018 ((= secs 1) (format "%d second" secs))
1019 (t (format "%d seconds" secs)))))
1020
1021(defun type-break-keystroke-reset ()
27cd478d 1022 (setq type-break-interval-start (current-time)) ; not a keystroke
e7b20417
NF
1023 (setq type-break-keystroke-count 0)
1024 (setq type-break-keystroke-warning-count 0)
1025 (setq type-break-current-keystroke-warning-interval
1026 type-break-keystroke-warning-intervals)
1027 (remove-hook 'type-break-post-command-hook 'type-break-keystroke-warning))
1028
846f6dd9
NF
1029(defun type-break-force-mode-line-update (&optional all)
1030 "Force the mode-line of the current buffer to be redisplayed.
1031With optional non-nil ALL, force redisplay of all mode-lines."
7fdbcd83 1032 (and all (with-current-buffer (other-buffer)))
846f6dd9
NF
1033 (set-buffer-modified-p (buffer-modified-p)))
1034
27cd478d 1035;; If an exception occurs in Emacs while running the post command hook, the
846f6dd9
NF
1036;; value of that hook is clobbered. This is because the value of the
1037;; variable is temporarily set to nil while it's running to prevent
1038;; recursive application, but it also means an exception aborts the routine
1039;; of restoring it. This function is called from the timers to restore it,
1040;; just in case.
1041(defun type-break-check-post-command-hook ()
1042 (add-hook 'post-command-hook 'type-break-run-tb-post-command-hook 'append))
1043
1044\f
1045;;; Timer wrapper functions
7fdbcd83
SM
1046;;
1047;; These shield type-break from variations in the interval timer packages
1048;; for different versions of Emacs.
846f6dd9
NF
1049
1050(defun type-break-run-at-time (time repeat function)
2c8155f7 1051 (condition-case nil (or (require 'timer) (require 'itimer)) (error nil))
5d610140 1052 (run-at-time time repeat function))
846f6dd9 1053
2c8155f7 1054(defvar timer-dont-exit)
846f6dd9 1055(defun type-break-cancel-function-timers (function)
5d610140
RS
1056 (let ((timer-dont-exit t))
1057 (cancel-function-timers function)))
846f6dd9 1058
e7b20417
NF
1059\f
1060;;; Demo wrappers
1061
a5b5e31e
CY
1062(defun type-break-catch-up-event ()
1063 ;; If the last input event is a down-event, read and discard the
1064 ;; corresponding up-event too, to avoid triggering another prompt.
1065 (and (eventp last-input-event)
1066 (memq 'down (event-modifiers last-input-event))
1067 (read-event)))
1068
e7b20417
NF
1069;; This is a wrapper around hanoi that calls it with an arg large enough to
1070;; make the largest discs possible that will fit in the window.
1071;; Also, clean up the *Hanoi* buffer after we're done.
1072(defun type-break-demo-hanoi ()
1073 "Take a hanoiing typing break."
1074 (and (get-buffer "*Hanoi*")
1075 (kill-buffer "*Hanoi*"))
1076 (condition-case ()
1077 (progn
1078 (hanoi (/ (window-width) 8))
1079 ;; Wait for user to come back.
1dfdb0c0 1080 (read-event)
a5b5e31e 1081 (type-break-catch-up-event)
e7b20417
NF
1082 (kill-buffer "*Hanoi*"))
1083 (quit
1dfdb0c0 1084 (read-event)
a5b5e31e 1085 (type-break-catch-up-event)
e7b20417
NF
1086 (and (get-buffer "*Hanoi*")
1087 (kill-buffer "*Hanoi*")))))
1088
1089;; This is a wrapper around life that calls it with a `sleep' arg to make
1090;; it run a little more leisurely.
1091;; Also, clean up the *Life* buffer after we're done.
1092(defun type-break-demo-life ()
1093 "Take a typing break and get a life."
1094 (let ((continue t))
1095 (while continue
1096 (setq continue nil)
1097 (and (get-buffer "*Life*")
1098 (kill-buffer "*Life*"))
1099 (condition-case ()
1100 (progn
1101 (life 3)
1102 ;; wait for user to return
1dfdb0c0 1103 (read-event)
a5b5e31e 1104 (type-break-catch-up-event)
e7b20417
NF
1105 (kill-buffer "*Life*"))
1106 (life-extinct
b4dc9e6a 1107 (message "%s" (get 'life-extinct 'error-message))
e7b20417
NF
1108 ;; restart demo
1109 (setq continue t))
1110 (quit
a5b5e31e 1111 (type-break-catch-up-event)
e7b20417
NF
1112 (and (get-buffer "*Life*")
1113 (kill-buffer "*Life*")))))))
1114
defa7346 1115;; Boring demo, but doesn't use many cycles
e7b20417
NF
1116(defun type-break-demo-boring ()
1117 "Boring typing break demo."
27cd478d
EZ
1118 (let ((rmsg (if type-break-terse-messages
1119 ""
1120 "Press any key to resume from typing break"))
e7b20417 1121 (buffer-name "*Typing Break Buffer*")
27cd478d 1122 lines elapsed timeleft tmsg)
e7b20417
NF
1123 (condition-case ()
1124 (progn
1125 (switch-to-buffer (get-buffer-create buffer-name))
1126 (buffer-disable-undo (current-buffer))
27cd478d
EZ
1127 (setq lines (/ (window-body-height) 2))
1128 (unless type-break-terse-messages (setq lines (1- lines)))
1129 (if type-break-demo-boring-stats
1130 (setq lines (- lines 2)))
1131 (setq lines (make-string lines ?\C-j))
defa7346 1132 (while (not (input-pending-p))
27cd478d 1133 (erase-buffer)
defa7346
NF
1134 (setq elapsed (type-break-time-difference
1135 type-break-time-last-break
1136 (current-time)))
27cd478d
EZ
1137 (let ((good-interval (or type-break-good-rest-interval
1138 type-break-good-break-interval)))
1139 (cond
1140 (good-interval
1141 (setq timeleft (- good-interval elapsed))
1142 (if (> timeleft 0)
1143 (setq tmsg
1144 (format (if type-break-terse-messages
1145 "Break remaining: %s"
1146 "You should rest for %s more")
1147 (type-break-format-time timeleft)))
1148 (setq tmsg
1149 (format (if type-break-terse-messages
1150 "Break complete (%s elapsed in total)"
1151 "Typing break has lasted %s")
1152 (type-break-format-time elapsed)))))
1153 (t
1154 (setq tmsg
1155 (format (if type-break-terse-messages
1156 "Break has lasted %s"
1157 "Typing break has lasted %s")
1158 (type-break-format-time elapsed))))))
1159 (insert lines
1160 (make-string (/ (- (window-width) (length tmsg)) 2) ?\ )
1161 tmsg)
1162 (if (> (length rmsg) 0)
1163 (insert "\n"
1164 (make-string (/ (- (window-width) (length rmsg)) 2)
1165 ?\ )
1166 rmsg))
1167 (if type-break-demo-boring-stats
1168 (let*
1169 ((message
1170 (format
1171 (if type-break-terse-messages
1172 "Since last break: %s keystrokes\n"
1173 "Since your last break you've typed %s keystrokes\n")
1174 type-break-keystroke-count))
1175 (column-spaces
1176 (make-string (/ (- (window-width) (length message)) 2)
1177 ?\ ))
1178 (wpm (/ (/ (float type-break-keystroke-count) 5)
1179 (/ (type-break-time-difference
1180 type-break-interval-start
1181 type-break-time-last-break)
1182 60.0))))
1183 (insert "\n\n" column-spaces message)
1184 (if type-break-terse-messages
1185 (insert (format " %s%.2f wpm"
1186 column-spaces
1187 wpm))
1188 (setq message
1189 (format "at an average of %.2f words per minute"
1190 wpm))
1191 (insert
1192 (make-string (/ (- (window-width) (length message)) 2)
1193 ?\ )
1194 message))))
defa7346
NF
1195 (goto-char (point-min))
1196 (sit-for 60))
a5b5e31e
CY
1197 (read-event)
1198 (type-break-catch-up-event)
e7b20417
NF
1199 (kill-buffer buffer-name))
1200 (quit
1201 (and (get-buffer buffer-name)
1202 (kill-buffer buffer-name))))))
1203
1204\f
458401b6
NF
1205(provide 'type-break)
1206
104221a0
SE
1207(if type-break-mode
1208 (type-break-mode 1))
ad953485 1209
458401b6 1210;;; type-break.el ends here