diff options
| -rw-r--r-- | lisp/type-break.el | 353 |
1 files changed, 278 insertions, 75 deletions
diff --git a/lisp/type-break.el b/lisp/type-break.el index 690f0842a39..26fec87a702 100644 --- a/lisp/type-break.el +++ b/lisp/type-break.el | |||
| @@ -5,9 +5,9 @@ | |||
| 5 | ;; Author: Noah Friedman <friedman@prep.ai.mit.edu> | 5 | ;; Author: Noah Friedman <friedman@prep.ai.mit.edu> |
| 6 | ;; Maintainer: friedman@prep.ai.mit.edu | 6 | ;; Maintainer: friedman@prep.ai.mit.edu |
| 7 | ;; Keywords: extensions, timers | 7 | ;; Keywords: extensions, timers |
| 8 | ;; Status: known to work in GNU Emacs 19.25 or later. | 8 | ;; Status: Works in GNU Emacs 19.25 or later |
| 9 | ;; Created: 1994-07-13 | 9 | ;; Created: 1994-07-13 |
| 10 | ;; $Id$ | 10 | ;; $Id: type-break.el,v 1.10 1994/10/06 19:12:46 friedman Exp friedman $ |
| 11 | 11 | ||
| 12 | ;; This file is part of GNU Emacs. | 12 | ;; This file is part of GNU Emacs. |
| 13 | 13 | ||
| @@ -22,24 +22,37 @@ | |||
| 22 | ;; GNU General Public License for more details. | 22 | ;; GNU General Public License for more details. |
| 23 | 23 | ||
| 24 | ;; You should have received a copy of the GNU General Public License | 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 | 25 | ;; along with GNU Emacs; see the file COPYING. If not, write to the |
| 26 | ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | 26 | ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
| 27 | ;; Boston, MA 02111-1307, USA. | ||
| 27 | 28 | ||
| 28 | ;;; Commentary: | 29 | ;;; Commentary: |
| 29 | 30 | ||
| 30 | ;;; The docstring for the function `type-break-mode' summarizes most of the | 31 | ;; The docstring for the function `type-break-mode' summarizes most of the |
| 31 | ;;; details of the interface. | 32 | ;; details of the interface. |
| 32 | 33 | ||
| 33 | ;;; This package relies on the assumption that you live entirely in emacs, | 34 | ;; 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 | ;; 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 | ;; 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 | ;; 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 | ;; least, you will want to turn off the keystroke thresholds and rest |
| 38 | ;;; interval tracking. | 39 | ;; interval tracking. |
| 39 | 40 | ||
| 40 | ;;; This package was inspired by Roland McGrath's hanoi-break.el. | 41 | ;; This program has no hope of working in Emacs 18, and it doesn't |
| 41 | ;;; Thanks to both Roland McGrath <roland@gnu.ai.mit.edu> and Mark Ashton | 42 | ;; presently work in Lucid Emacs/XEmacs because the timer.el package is |
| 42 | ;;; <mpashton@gnu.ai.mit.edu> for feedback and ideas. | 43 | ;; entirely different. |
| 44 | |||
| 45 | ;; This program can truly cons up a storm because of all the calls to | ||
| 46 | ;; `current-time' (which always returns 3 fresh conses). I'm dismayed by | ||
| 47 | ;; this, but I think the health of my hands is far more important than a | ||
| 48 | ;; few pages of virtual memory. | ||
| 49 | |||
| 50 | ;; This package was inspired by Roland McGrath's hanoi-break.el. | ||
| 51 | ;; Several people contributed feedback and ideas, including | ||
| 52 | ;; Roland McGrath <roland@gnu.ai.mit.edu> | ||
| 53 | ;; Kleanthes Koniaris <kgk@martigny.ai.mit.edu> | ||
| 54 | ;; Mark Ashton <mpashton@gnu.ai.mit.edu> | ||
| 55 | ;; Matt Wilding <wilding@cli.com> | ||
| 43 | 56 | ||
| 44 | ;;; Code: | 57 | ;;; Code: |
| 45 | 58 | ||
| @@ -53,6 +66,11 @@ | |||
| 53 | "*Non-`nil' means typing break mode is enabled. | 66 | "*Non-`nil' means typing break mode is enabled. |
| 54 | See the docstring for the `type-break-mode' command for more information.") | 67 | See the docstring for the `type-break-mode' command for more information.") |
| 55 | 68 | ||
| 69 | (defvar type-break-warning-message-mode t | ||
| 70 | "*Non-`nil' means warn about imminent typing breaks in echo area. | ||
| 71 | See the docstring for the `type-break-warning-message-mode' command for | ||
| 72 | more information.") | ||
| 73 | |||
| 56 | ;;;###autoload | 74 | ;;;###autoload |
| 57 | (defvar type-break-interval (* 60 60) | 75 | (defvar type-break-interval (* 60 60) |
| 58 | "*Number of seconds between scheduled typing breaks.") | 76 | "*Number of seconds between scheduled typing breaks.") |
| @@ -99,7 +117,35 @@ scheduled break. If this second value is nil, then no pre-emptive breaks | |||
| 99 | will occur; only scheduled ones will. | 117 | will occur; only scheduled ones will. |
| 100 | 118 | ||
| 101 | Keys with bucky bits (shift, control, meta, etc) are counted as only one | 119 | Keys with bucky bits (shift, control, meta, etc) are counted as only one |
| 102 | keystroke even though they really require multiple keys to generate them.") | 120 | keystroke even though they really require multiple keys to generate them. |
| 121 | |||
| 122 | The command `type-break-guesstimate-keystroke-threshold' can be used to | ||
| 123 | guess a reasonably good pair of values for this variable.") | ||
| 124 | |||
| 125 | (defvar type-break-query-function 'yes-or-no-p | ||
| 126 | "Function to use for making query for a typing break. | ||
| 127 | It should take a string as an argument, the prompt. | ||
| 128 | Usually this should be set to `yes-or-no-p' or `y-or-n-p'. | ||
| 129 | |||
| 130 | Some people prefer a less intrusive way of being reminded to take a typing | ||
| 131 | break. One possibility is simply to beep a couple of times. To accomplish | ||
| 132 | this, one could do: | ||
| 133 | |||
| 134 | (defun my-type-break-query (&optional ignored-args) | ||
| 135 | (beep t) | ||
| 136 | (message \"You should take a typing break now. Do `M-x type-break'.\") | ||
| 137 | (sit-for 1) | ||
| 138 | (beep t) | ||
| 139 | ;; return nil so query caller knows to reset reminder, as if user | ||
| 140 | ;; said \"no\" in response to yes-or-no-p. | ||
| 141 | nil) | ||
| 142 | |||
| 143 | (setq type-break-query-function 'my-type-break-query)") | ||
| 144 | |||
| 145 | (defvar type-break-query-interval 60 | ||
| 146 | "*Number of seconds between queries to take a break, if put off. | ||
| 147 | The user will continue to be prompted at this interval until he or she | ||
| 148 | finally submits to taking a typing break.") | ||
| 103 | 149 | ||
| 104 | (defvar type-break-time-warning-intervals '(300 120 60 30) | 150 | (defvar type-break-time-warning-intervals '(300 120 60 30) |
| 105 | "*List of time intervals for warnings about upcoming typing break. | 151 | "*List of time intervals for warnings about upcoming typing break. |
| @@ -113,20 +159,40 @@ keystroke threshold, print a warning in the echo area. | |||
| 113 | If either this variable or the upper threshold is set, then no warnings | 159 | If either this variable or the upper threshold is set, then no warnings |
| 114 | Will occur.") | 160 | Will occur.") |
| 115 | 161 | ||
| 116 | (defvar type-break-query-interval 60 | ||
| 117 | "*Number of seconds between queries to take a break, if put off. | ||
| 118 | The user will continue to be prompted at this interval until he or she | ||
| 119 | finally submits to taking a typing break.") | ||
| 120 | |||
| 121 | (defvar type-break-warning-repeat 40 | 162 | (defvar type-break-warning-repeat 40 |
| 122 | "*Number of keystrokes for which warnings should be repeated. | 163 | "*Number of keystrokes for which warnings should be repeated. |
| 123 | That is, for each of this many keystrokes the warning is redisplayed | 164 | That is, for each of this many keystrokes the warning is redisplayed |
| 124 | in the echo area to make sure it's really seen.") | 165 | in the echo area to make sure it's really seen.") |
| 125 | 166 | ||
| 126 | (defvar type-break-query-function 'yes-or-no-p | 167 | (defvar type-break-warning-countdown-string nil |
| 127 | "Function to use for making query for a typing break. | 168 | "If non-nil, this is a countdown for the next typing break. |
| 128 | It should take a string as an argument, the prompt. | 169 | |
| 129 | Usually this should be set to `yes-or-no-p' or `y-or-n-p'.") | 170 | This variable, in conjunction with `type-break-warning-countdown-string-type' |
| 171 | (which indicates whether this value is a number of keystrokes or seconds) | ||
| 172 | can be installed by the user somewhere in mode-line-format to notify of | ||
| 173 | imminent typing breaks there. | ||
| 174 | |||
| 175 | For example, you could do | ||
| 176 | |||
| 177 | (defvar type-break-mode-line-string | ||
| 178 | '(type-break-warning-countdown-string | ||
| 179 | (\" ***Break in \" | ||
| 180 | type-break-warning-countdown-string | ||
| 181 | \" \" | ||
| 182 | type-break-warning-countdown-string-type | ||
| 183 | \"***\"))) | ||
| 184 | |||
| 185 | (setq global-mode-string | ||
| 186 | (append global-mode-string '(type-break-mode-line-string))) | ||
| 187 | |||
| 188 | If you do this, you may also wish to disable the warning messages in the | ||
| 189 | minibuffer. To do this, either set the variable | ||
| 190 | `type-break-warning-message-mode' to `nil' or call the function of the same | ||
| 191 | name with a negative argument.") | ||
| 192 | |||
| 193 | (defvar type-break-warning-countdown-string-type nil | ||
| 194 | "Indicates the unit type of `type-break-warning-countdown-string'. | ||
| 195 | It will be either \"seconds\" or \"keystrokes\".") | ||
| 130 | 196 | ||
| 131 | (defvar type-break-demo-functions | 197 | (defvar type-break-demo-functions |
| 132 | '(type-break-demo-boring type-break-demo-life type-break-demo-hanoi) | 198 | '(type-break-demo-boring type-break-demo-life type-break-demo-hanoi) |
| @@ -138,7 +204,13 @@ Any function in this list should start a demo which ceases as soon as a | |||
| 138 | key is pressed.") | 204 | key is pressed.") |
| 139 | 205 | ||
| 140 | (defvar type-break-post-command-hook nil | 206 | (defvar type-break-post-command-hook nil |
| 141 | "Hook run indirectly by post-command-hook for typing break functions.") | 207 | "Hook run indirectly by post-command-hook for typing break functions. |
| 208 | This is not really intended to be set by the user, but it's probably | ||
| 209 | harmless to do so. Mainly it is used by various parts of the typing break | ||
| 210 | program to delay actions until after the user has completed some command. | ||
| 211 | It exists because `post-command-hook' itself is inaccessible while its | ||
| 212 | functions are being run, and some type-break--related functions want to | ||
| 213 | remove themselves after running.") | ||
| 142 | 214 | ||
| 143 | ;; These are internal variables. Do not set them yourself. | 215 | ;; These are internal variables. Do not set them yourself. |
| 144 | 216 | ||
| @@ -151,7 +223,45 @@ key is pressed.") | |||
| 151 | (defvar type-break-current-keystroke-warning-interval nil) | 223 | (defvar type-break-current-keystroke-warning-interval nil) |
| 152 | (defvar type-break-time-warning-count 0) | 224 | (defvar type-break-time-warning-count 0) |
| 153 | (defvar type-break-keystroke-warning-count 0) | 225 | (defvar type-break-keystroke-warning-count 0) |
| 226 | |||
| 227 | ;; This should return t if warnings were enabled, nil otherwise. | ||
| 228 | (defsubst type-break-check-keystroke-warning () | ||
| 229 | ;; This is safe because the caller should have checked that the cdr was | ||
| 230 | ;; non-nil already. | ||
| 231 | (let ((left (- (cdr type-break-keystroke-threshold) | ||
| 232 | type-break-keystroke-count))) | ||
| 233 | (cond | ||
| 234 | ((null (car type-break-current-keystroke-warning-interval)) | ||
| 235 | nil) | ||
| 236 | ((> left (car type-break-current-keystroke-warning-interval)) | ||
| 237 | nil) | ||
| 238 | (t | ||
| 239 | (while (and (car type-break-current-keystroke-warning-interval) | ||
| 240 | (< left (car type-break-current-keystroke-warning-interval))) | ||
| 241 | (setq type-break-current-keystroke-warning-interval | ||
| 242 | (cdr type-break-current-keystroke-warning-interval))) | ||
| 243 | (setq type-break-keystroke-warning-count type-break-warning-repeat) | ||
| 244 | (add-hook 'type-break-post-command-hook 'type-break-keystroke-warning) | ||
| 245 | (setq type-break-warning-countdown-string (number-to-string left)) | ||
| 246 | (setq type-break-warning-countdown-string-type "keystrokes") | ||
| 247 | t)))) | ||
| 248 | |||
| 249 | ;; Compute the difference, in seconds, between a and b, two structures | ||
| 250 | ;; similar to those returned by `current-time'. | ||
| 251 | ;; Use addition rather than logand since that is more robust; the low 16 | ||
| 252 | ;; bits of the seconds might have been incremented, making it more than 16 | ||
| 253 | ;; bits wide. | ||
| 254 | (defsubst type-break-time-difference (a b) | ||
| 255 | (+ (lsh (- (car b) (car a)) 16) | ||
| 256 | (- (car (cdr b)) (car (cdr a))))) | ||
| 154 | 257 | ||
| 258 | (defsubst type-break-format-time (secs) | ||
| 259 | (let ((mins (/ secs 60))) | ||
| 260 | (cond | ||
| 261 | ((= mins 1) (format "%d minute" mins)) | ||
| 262 | ((> mins 0) (format "%d minutes" mins)) | ||
| 263 | ((= secs 1) (format "%d second" secs)) | ||
| 264 | (t (format "%d seconds" secs))))) | ||
| 155 | 265 | ||
| 156 | ;;;###autoload | 266 | ;;;###autoload |
| 157 | (defun type-break-mode (&optional prefix) | 267 | (defun type-break-mode (&optional prefix) |
| @@ -192,9 +302,25 @@ or not to continue. | |||
| 192 | 302 | ||
| 193 | The variable `type-break-keystroke-threshold' is used to determine the | 303 | The variable `type-break-keystroke-threshold' is used to determine the |
| 194 | thresholds at which typing breaks should be considered. You can use | 304 | thresholds at which typing breaks should be considered. You can use |
| 195 | the command `type-break-guestimate-keystroke-threshold' to try to | 305 | the command `type-break-guesstimate-keystroke-threshold' to try to |
| 196 | approximate good values for this. | 306 | approximate good values for this. |
| 197 | 307 | ||
| 308 | There are several variables that affect how or when warning messages about | ||
| 309 | imminent typing breaks are displayed. They include: | ||
| 310 | |||
| 311 | type-break-warning-message-mode | ||
| 312 | type-break-time-warning-intervals | ||
| 313 | type-break-keystroke-warning-intervals | ||
| 314 | type-break-warning-repeat | ||
| 315 | type-break-warning-countdown-string | ||
| 316 | type-break-warning-countdown-string-type | ||
| 317 | |||
| 318 | There are several variables that affect how and when queries to begin a | ||
| 319 | typing break occur. They include: | ||
| 320 | |||
| 321 | type-break-query-function | ||
| 322 | type-break-query-interval | ||
| 323 | |||
| 198 | Finally, the command `type-break-statistics' prints interesting things." | 324 | Finally, the command `type-break-statistics' prints interesting things." |
| 199 | (interactive "P") | 325 | (interactive "P") |
| 200 | ;; make sure it's there. | 326 | ;; make sure it's there. |
| @@ -217,6 +343,24 @@ Finally, the command `type-break-statistics' prints interesting things." | |||
| 217 | (message "type-break-mode is disabled")))) | 343 | (message "type-break-mode is disabled")))) |
| 218 | type-break-mode) | 344 | type-break-mode) |
| 219 | 345 | ||
| 346 | (defun type-break-warning-message-mode (&optional prefix) | ||
| 347 | "Enable or disable warnings in the echo area about imminent typing breaks. | ||
| 348 | |||
| 349 | A negative prefix argument disables this mode. | ||
| 350 | No argument or any non-negative argument enables it. | ||
| 351 | |||
| 352 | The user may also enable or disable this mode simply by setting the | ||
| 353 | variable of the same name." | ||
| 354 | (interactive "P") | ||
| 355 | (setq type-break-warning-message-mode (>= (prefix-numeric-value prefix) 0)) | ||
| 356 | (cond | ||
| 357 | ((not (interactive-p))) | ||
| 358 | (type-break-warning-message-mode | ||
| 359 | (message "type-break-warning-message-mode is enabled")) | ||
| 360 | (t | ||
| 361 | (message "type-break-warning-message-mode is disabled"))) | ||
| 362 | type-break-warning-message-mode) | ||
| 363 | |||
| 220 | ;;;###autoload | 364 | ;;;###autoload |
| 221 | (defun type-break () | 365 | (defun type-break () |
| 222 | "Take a typing break. | 366 | "Take a typing break. |
| @@ -255,10 +399,11 @@ as per the function `type-break-schedule'." | |||
| 255 | (cond | 399 | (cond |
| 256 | ((>= break-secs type-break-good-rest-interval) | 400 | ((>= break-secs type-break-good-rest-interval) |
| 257 | (setq continue nil)) | 401 | (setq continue nil)) |
| 258 | ;; Don't be pedantic; if user's rest was only a minute short, | 402 | ;; 60 seconds may be too much leeway if the break is only 3 |
| 259 | ;; why bother? | 403 | ;; minutes to begin with. You can just say "no" to the query |
| 260 | ((> 60 (abs (- break-secs type-break-good-rest-interval))) | 404 | ;; below if you're in that much of a hurry. |
| 261 | (setq continue nil)) | 405 | ;((> 60 (abs (- break-secs type-break-good-rest-interval))) |
| 406 | ; (setq continue nil)) | ||
| 262 | ((funcall | 407 | ((funcall |
| 263 | type-break-query-function | 408 | type-break-query-function |
| 264 | (format "You really ought to rest %s more. Continue break? " | 409 | (format "You really ought to rest %s more. Continue break? " |
| @@ -278,9 +423,11 @@ If time is not specified, default to `type-break-interval'." | |||
| 278 | (interactive (list (and current-prefix-arg | 423 | (interactive (list (and current-prefix-arg |
| 279 | (prefix-numeric-value current-prefix-arg)))) | 424 | (prefix-numeric-value current-prefix-arg)))) |
| 280 | (or time (setq time type-break-interval)) | 425 | (or time (setq time type-break-interval)) |
| 426 | (let ((type-break-mode t)) | ||
| 427 | (type-break-mode 1)) | ||
| 281 | (type-break-cancel-schedule) | 428 | (type-break-cancel-schedule) |
| 282 | (type-break-time-warning-schedule time 'reset) | 429 | (type-break-time-warning-schedule time 'reset) |
| 283 | (run-at-time time nil 'type-break-alarm) | 430 | (run-at-time (max 1 time) nil 'type-break-alarm) |
| 284 | (setq type-break-time-next-break | 431 | (setq type-break-time-next-break |
| 285 | (type-break-time-sum (current-time) time))) | 432 | (type-break-time-sum (current-time) time))) |
| 286 | 433 | ||
| @@ -292,7 +439,7 @@ If time is not specified, default to `type-break-interval'." | |||
| 292 | (setq type-break-time-next-break nil)) | 439 | (setq type-break-time-next-break nil)) |
| 293 | 440 | ||
| 294 | (defun type-break-time-warning-schedule (&optional time resetp) | 441 | (defun type-break-time-warning-schedule (&optional time resetp) |
| 295 | (let (type-break-current-time-warning-interval) | 442 | (let ((type-break-current-time-warning-interval nil)) |
| 296 | (type-break-cancel-time-warning-schedule)) | 443 | (type-break-cancel-time-warning-schedule)) |
| 297 | (cond | 444 | (cond |
| 298 | (type-break-time-warning-intervals | 445 | (type-break-time-warning-intervals |
| @@ -315,21 +462,33 @@ If time is not specified, default to `type-break-interval'." | |||
| 315 | (setq type-break-current-time-warning-interval | 462 | (setq type-break-current-time-warning-interval |
| 316 | (cdr type-break-current-time-warning-interval)) | 463 | (cdr type-break-current-time-warning-interval)) |
| 317 | 464 | ||
| 318 | (let (type-break-current-time-warning-interval) | 465 | ;(let (type-break-current-time-warning-interval) |
| 319 | (type-break-cancel-time-warning-schedule)) | 466 | ; (type-break-cancel-time-warning-schedule)) |
| 320 | (run-at-time time nil 'type-break-time-warning-alarm)))))) | 467 | (run-at-time (max 1 time) nil 'type-break-time-warning-alarm) |
| 468 | |||
| 469 | (cond | ||
| 470 | (resetp | ||
| 471 | (setq type-break-warning-countdown-string nil)) | ||
| 472 | (t | ||
| 473 | (setq type-break-warning-countdown-string (number-to-string time)) | ||
| 474 | (setq type-break-warning-countdown-string-type "seconds")))))))) | ||
| 321 | 475 | ||
| 322 | (defun type-break-cancel-time-warning-schedule () | 476 | (defun type-break-cancel-time-warning-schedule () |
| 323 | (let ((timer-dont-exit t)) | 477 | (let ((timer-dont-exit t)) |
| 324 | (cancel-function-timers 'type-break-time-warning-alarm)) | 478 | (cancel-function-timers 'type-break-time-warning-alarm)) |
| 325 | (remove-hook 'type-break-post-command-hook 'type-break-time-warning) | 479 | (remove-hook 'type-break-post-command-hook 'type-break-time-warning) |
| 326 | (setq type-break-current-time-warning-interval | 480 | (setq type-break-current-time-warning-interval |
| 327 | type-break-time-warning-intervals)) | 481 | type-break-time-warning-intervals) |
| 482 | (setq type-break-warning-countdown-string nil)) | ||
| 328 | 483 | ||
| 329 | (defun type-break-alarm () | 484 | (defun type-break-alarm () |
| 485 | (let ((type-break-mode t)) | ||
| 486 | (type-break-mode 1)) | ||
| 330 | (setq type-break-alarm-p t)) | 487 | (setq type-break-alarm-p t)) |
| 331 | 488 | ||
| 332 | (defun type-break-time-warning-alarm () | 489 | (defun type-break-time-warning-alarm () |
| 490 | (let ((type-break-mode t)) | ||
| 491 | (type-break-mode 1)) | ||
| 333 | (type-break-time-warning-schedule) | 492 | (type-break-time-warning-schedule) |
| 334 | (setq type-break-time-warning-count type-break-warning-repeat) | 493 | (setq type-break-time-warning-count type-break-warning-repeat) |
| 335 | (add-hook 'type-break-post-command-hook 'type-break-time-warning 'append)) | 494 | (add-hook 'type-break-post-command-hook 'type-break-time-warning 'append)) |
| @@ -358,12 +517,16 @@ keystroke threshold has been exceeded." | |||
| 358 | (setq type-break-time-last-command (current-time)))) | 517 | (setq type-break-time-last-command (current-time)))) |
| 359 | 518 | ||
| 360 | (and type-break-keystroke-threshold | 519 | (and type-break-keystroke-threshold |
| 361 | (setq type-break-keystroke-count | 520 | (let ((keys (this-command-keys))) |
| 362 | (+ type-break-keystroke-count (length (this-command-keys))))) | 521 | (cond |
| 522 | ;; Ignore mouse motion | ||
| 523 | ((and (vectorp keys) | ||
| 524 | (consp (aref keys 0)) | ||
| 525 | (memq (car (aref keys 0)) '(mouse-movement)))) | ||
| 526 | (t | ||
| 527 | (setq type-break-keystroke-count | ||
| 528 | (+ type-break-keystroke-count (length keys))))))) | ||
| 363 | 529 | ||
| 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 | 530 | (cond |
| 368 | (type-break-alarm-p | 531 | (type-break-alarm-p |
| 369 | (cond | 532 | (cond |
| @@ -374,7 +537,7 @@ keystroke threshold has been exceeded." | |||
| 374 | (type-break-schedule)) | 537 | (type-break-schedule)) |
| 375 | (t | 538 | (t |
| 376 | ;; If keystroke count is within min-threshold of | 539 | ;; If keystroke count is within min-threshold of |
| 377 | ;; max-threshold, lower it to reduce the liklihood of an | 540 | ;; max-threshold, lower it to reduce the likelihood of an |
| 378 | ;; immediate subsequent query. | 541 | ;; immediate subsequent query. |
| 379 | (and max-threshold | 542 | (and max-threshold |
| 380 | min-threshold | 543 | min-threshold |
| @@ -397,6 +560,8 @@ keystroke threshold has been exceeded." | |||
| 397 | 560 | ||
| 398 | ;; This should return t if warnings were enabled, nil otherwise. | 561 | ;; This should return t if warnings were enabled, nil otherwise. |
| 399 | (defsubst type-break-check-keystroke-warning () | 562 | (defsubst type-break-check-keystroke-warning () |
| 563 | ;; This is safe because the caller should have checked that the cdr was | ||
| 564 | ;; non-nil already. | ||
| 400 | (let ((left (- (cdr type-break-keystroke-threshold) | 565 | (let ((left (- (cdr type-break-keystroke-threshold) |
| 401 | type-break-keystroke-count))) | 566 | type-break-keystroke-count))) |
| 402 | (cond | 567 | (cond |
| @@ -411,44 +576,69 @@ keystroke threshold has been exceeded." | |||
| 411 | (cdr type-break-current-keystroke-warning-interval))) | 576 | (cdr type-break-current-keystroke-warning-interval))) |
| 412 | (setq type-break-keystroke-warning-count type-break-warning-repeat) | 577 | (setq type-break-keystroke-warning-count type-break-warning-repeat) |
| 413 | (add-hook 'type-break-post-command-hook 'type-break-keystroke-warning) | 578 | (add-hook 'type-break-post-command-hook 'type-break-keystroke-warning) |
| 579 | (setq type-break-warning-countdown-string (number-to-string left)) | ||
| 580 | (setq type-break-warning-countdown-string-type "keystrokes") | ||
| 414 | t)))) | 581 | t)))) |
| 415 | 582 | ||
| 583 | ;; Arrange for a break query to be made, when the user stops typing furiously. | ||
| 416 | (defun type-break-query () | 584 | (defun type-break-query () |
| 417 | (condition-case () | 585 | (add-hook 'type-break-post-command-hook 'type-break-do-query)) |
| 418 | (cond | 586 | |
| 419 | ((let ((type-break-mode nil)) | 587 | ;; Ask to take a break, but only after the user stops typing continuously |
| 420 | (funcall type-break-query-function "Take a break from typing now? ")) | 588 | ;; for at least a second. Renaming the minibuffer because you did M-x |
| 421 | (type-break)) | 589 | ;; rename-buffer just as type-break popped the question is... annoying. |
| 422 | (t | 590 | (defun type-break-do-query () |
| 423 | (type-break-schedule type-break-query-interval))) | 591 | (cond |
| 424 | (quit | 592 | ((sit-for 1) |
| 425 | (type-break-schedule type-break-query-interval)))) | 593 | (condition-case () |
| 594 | (cond | ||
| 595 | ((let ((type-break-mode nil) | ||
| 596 | ;; yes-or-no-p sets this-command to exit-minibuffer, | ||
| 597 | ;; which hoses undo or yank-pop (if you happened to be | ||
| 598 | ;; yanking just when the query occurred). | ||
| 599 | (this-command this-command)) | ||
| 600 | (funcall type-break-query-function | ||
| 601 | "Take a break from typing now? ")) | ||
| 602 | (type-break)) | ||
| 603 | (t | ||
| 604 | (type-break-schedule type-break-query-interval))) | ||
| 605 | (quit | ||
| 606 | (type-break-schedule type-break-query-interval))) | ||
| 607 | (remove-hook 'type-break-post-command-hook 'type-break-do-query)))) | ||
| 426 | 608 | ||
| 427 | (defun type-break-time-warning () | 609 | (defun type-break-time-warning () |
| 428 | (cond | 610 | (cond |
| 429 | ((and (car type-break-keystroke-threshold) | 611 | ((and (car type-break-keystroke-threshold) |
| 430 | (< type-break-keystroke-count (car type-break-keystroke-threshold)))) | 612 | (< type-break-keystroke-count (car type-break-keystroke-threshold)))) |
| 431 | ((> type-break-time-warning-count 0) | 613 | ((> type-break-time-warning-count 0) |
| 432 | (cond | 614 | (let ((timeleft (type-break-time-difference (current-time) |
| 433 | ((eq (selected-window) (minibuffer-window))) | 615 | type-break-time-next-break))) |
| 434 | (t | 616 | (setq type-break-warning-countdown-string (number-to-string timeleft)) |
| 435 | ;; Pause for a moment so previous messages can be seen. | 617 | (cond |
| 436 | (sit-for 2) | 618 | ((eq (selected-window) (minibuffer-window))) |
| 437 | (message "Warning: typing break due in %s." | 619 | ;; Do nothing if the command was just a prefix arg, since that will |
| 438 | (type-break-format-time | 620 | ;; immediately be followed by some other interactive command. |
| 439 | (type-break-time-difference (current-time) | 621 | ((memq this-command '(digit-argument universal-argument))) |
| 440 | type-break-time-next-break))) | 622 | (type-break-warning-message-mode |
| 441 | (setq type-break-time-warning-count | 623 | ;; Pause for a moment so any previous message can be seen. |
| 442 | (1- type-break-time-warning-count))))) | 624 | (sit-for 2) |
| 625 | (message "Warning: typing break due in %s." | ||
| 626 | (type-break-format-time timeleft)) | ||
| 627 | (setq type-break-time-warning-count | ||
| 628 | (1- type-break-time-warning-count)))))) | ||
| 443 | (t | 629 | (t |
| 444 | (remove-hook 'type-break-post-command-hook 'type-break-time-warning)))) | 630 | (remove-hook 'type-break-post-command-hook 'type-break-time-warning) |
| 631 | (setq type-break-warning-countdown-string nil)))) | ||
| 445 | 632 | ||
| 446 | (defun type-break-keystroke-warning () | 633 | (defun type-break-keystroke-warning () |
| 447 | (cond | 634 | (cond |
| 448 | ((> type-break-keystroke-warning-count 0) | 635 | ((> type-break-keystroke-warning-count 0) |
| 636 | (setq type-break-warning-countdown-string | ||
| 637 | (number-to-string (- (cdr type-break-keystroke-threshold) | ||
| 638 | type-break-keystroke-count))) | ||
| 449 | (cond | 639 | (cond |
| 450 | ((eq (selected-window) (minibuffer-window))) | 640 | ((eq (selected-window) (minibuffer-window))) |
| 451 | (t | 641 | (type-break-warning-message-mode |
| 452 | (sit-for 2) | 642 | (sit-for 2) |
| 453 | (message "Warning: typing break due in %s keystrokes." | 643 | (message "Warning: typing break due in %s keystrokes." |
| 454 | (- (cdr type-break-keystroke-threshold) | 644 | (- (cdr type-break-keystroke-threshold) |
| @@ -457,7 +647,8 @@ keystroke threshold has been exceeded." | |||
| 457 | (1- type-break-keystroke-warning-count))))) | 647 | (1- type-break-keystroke-warning-count))))) |
| 458 | (t | 648 | (t |
| 459 | (remove-hook 'type-break-post-command-hook | 649 | (remove-hook 'type-break-post-command-hook |
| 460 | 'type-break-keystroke-warning)))) | 650 | 'type-break-keystroke-warning) |
| 651 | (setq type-break-warning-countdown-string nil)))) | ||
| 461 | 652 | ||
| 462 | 653 | ||
| 463 | ;;;###autoload | 654 | ;;;###autoload |
| @@ -468,11 +659,16 @@ scheduled, the keystroke thresholds and the current keystroke count, etc." | |||
| 468 | (interactive) | 659 | (interactive) |
| 469 | (with-output-to-temp-buffer "*Typing Break Statistics*" | 660 | (with-output-to-temp-buffer "*Typing Break Statistics*" |
| 470 | (princ (format "Typing break statistics\n-----------------------\n | 661 | (princ (format "Typing break statistics\n-----------------------\n |
| 471 | Last typing break : %s | 662 | Typing break mode is currently %s. |
| 663 | Warnings of imminent typing breaks in echo area is %s. | ||
| 664 | |||
| 665 | Last typing break ended : %s | ||
| 472 | Next scheduled typing break : %s\n | 666 | Next scheduled typing break : %s\n |
| 473 | Minimum keystroke threshold : %s | 667 | Minimum keystroke threshold : %s |
| 474 | Maximum keystroke threshold : %s | 668 | Maximum keystroke threshold : %s |
| 475 | Current keystroke count : %s" | 669 | Current keystroke count : %s" |
| 670 | (if type-break-mode "enabled" "disabled") | ||
| 671 | (if type-break-warning-message-mode "enabled" "disabled") | ||
| 476 | (if type-break-time-last-break | 672 | (if type-break-time-last-break |
| 477 | (current-time-string type-break-time-last-break) | 673 | (current-time-string type-break-time-last-break) |
| 478 | "never") | 674 | "never") |
| @@ -489,21 +685,28 @@ Current keystroke count : %s" | |||
| 489 | type-break-keystroke-count)))) | 685 | type-break-keystroke-count)))) |
| 490 | 686 | ||
| 491 | ;;;###autoload | 687 | ;;;###autoload |
| 492 | (defun type-break-guestimate-keystroke-threshold (wpm &optional wordlen frac) | 688 | (defun type-break-guesstimate-keystroke-threshold (wpm &optional wordlen frac) |
| 493 | "Guess values for the minimum/maximum keystroke threshold for typing breaks. | 689 | "Guess values for the minimum/maximum keystroke threshold for typing breaks. |
| 690 | |||
| 494 | If called interactively, the user is prompted for their guess as to how | 691 | If called interactively, the user is prompted for their guess as to how |
| 495 | many words per minute they usually type. From that, the command sets the | 692 | many words per minute they usually type. This value should not be your |
| 496 | values in `type-break-keystroke-threshold' based on a fairly simple | 693 | maximum WPM, but your average. Of course, this is harder to gauge since it |
| 497 | algorithm involving assumptions about the average length of words (5). | 694 | can vary considerably depending on what you are doing. For example, one |
| 498 | For the minimum threshold, it uses about a quarter of the computed maximum | 695 | tends actually to type less when debugging a program, as opposed to writing |
| 499 | threshold. | 696 | documentation. (Perhaps a separate program should be written to estimate |
| 697 | average typing speed.) | ||
| 698 | |||
| 699 | From that, this command sets the values in `type-break-keystroke-threshold' | ||
| 700 | based on a fairly simple algorithm involving assumptions about the average | ||
| 701 | length of words (5). For the minimum threshold, it uses about a fifth of | ||
| 702 | the computed maximum threshold. | ||
| 500 | 703 | ||
| 501 | When called from lisp programs, the optional args WORDLEN and FRAC can be | 704 | When called from lisp programs, the optional args WORDLEN and FRAC can be |
| 502 | used to override the default assumption about average word length and the | 705 | used to override the default assumption about average word length and the |
| 503 | fraction of the maximum threshold to which to set the minimum threshold. | 706 | fraction of the maximum threshold to which to set the minimum threshold. |
| 504 | FRAC should be the inverse of the fractional value; for example, a value of | 707 | FRAC should be the inverse of the fractional value; for example, a value of |
| 505 | 2 would mean to use one half, a value of 4 would mean to use one quarter, etc." | 708 | 2 would mean to use one half, a value of 4 would mean to use one quarter, etc." |
| 506 | (interactive "NHow many words per minute do you type? ") | 709 | (interactive "NOn average, how many words per minute do you type? ") |
| 507 | (let* ((upper (* wpm (or wordlen 5) (/ type-break-interval 60))) | 710 | (let* ((upper (* wpm (or wordlen 5) (/ type-break-interval 60))) |
| 508 | (lower (/ upper (or frac 5)))) | 711 | (lower (/ upper (or frac 5)))) |
| 509 | (or type-break-keystroke-threshold | 712 | (or type-break-keystroke-threshold |
| @@ -617,7 +820,7 @@ FRAC should be the inverse of the fractional value; for example, a value of | |||
| 617 | (read-char) | 820 | (read-char) |
| 618 | (kill-buffer "*Life*")) | 821 | (kill-buffer "*Life*")) |
| 619 | (life-extinct | 822 | (life-extinct |
| 620 | (message (get 'life-extinct 'error-message)) | 823 | (message "%s" (get 'life-extinct 'error-message)) |
| 621 | (sit-for 3) | 824 | (sit-for 3) |
| 622 | ;; restart demo | 825 | ;; restart demo |
| 623 | (setq continue t)) | 826 | (setq continue t)) |