diff options
| author | Stefan Monnier | 2006-04-26 05:50:51 +0000 |
|---|---|---|
| committer | Stefan Monnier | 2006-04-26 05:50:51 +0000 |
| commit | 08a1dbe66260be7c7e95ec9752243167ac168cfb (patch) | |
| tree | d271cd0826a2c9ba473e4bb9dfcc1321f2d0da34 | |
| parent | 7e5d77dc2ca1d4064cba18955ab2c50766f62fa8 (diff) | |
| download | emacs-08a1dbe66260be7c7e95ec9752243167ac168cfb.tar.gz emacs-08a1dbe66260be7c7e95ec9752243167ac168cfb.zip | |
Use (featurep 'xemacs) everywhere.
(follow-mode): Use define-minor-mode.
(follow-mode-map): Move initialization into the declaration.
Use command remapping.
(follow-emacs-version-xemacs-p): Remove.
(follow-submit-feedback): Remove.
| -rw-r--r-- | lisp/ChangeLog | 7 | ||||
| -rw-r--r-- | lisp/follow.el | 525 |
2 files changed, 229 insertions, 303 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 76881128585..b4c19727934 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -1,5 +1,12 @@ | |||
| 1 | 2006-04-26 Stefan Monnier <monnier@iro.umontreal.ca> | 1 | 2006-04-26 Stefan Monnier <monnier@iro.umontreal.ca> |
| 2 | 2 | ||
| 3 | * follow.el: Use (featurep 'xemacs) everywhere. | ||
| 4 | (follow-mode): Use define-minor-mode. | ||
| 5 | (follow-mode-map): Move initialization into the declaration. | ||
| 6 | Use command remapping. | ||
| 7 | (follow-emacs-version-xemacs-p): Remove. | ||
| 8 | (follow-submit-feedback): Remove. | ||
| 9 | |||
| 3 | * allout.el (allout-layout, allout-passphrase-verifier-string) | 10 | * allout.el (allout-layout, allout-passphrase-verifier-string) |
| 4 | (allout-passphrase-hint-string): Tighten up a bit the safety predicate. | 11 | (allout-passphrase-hint-string): Tighten up a bit the safety predicate. |
| 5 | 12 | ||
diff --git a/lisp/follow.el b/lisp/follow.el index 1958c407664..27c37132f0a 100644 --- a/lisp/follow.el +++ b/lisp/follow.el | |||
| @@ -7,7 +7,6 @@ | |||
| 7 | ;; Maintainer: FSF (Anders' email bounces, Sep 2005) | 7 | ;; Maintainer: FSF (Anders' email bounces, Sep 2005) |
| 8 | ;; Created: 1995-05-25 | 8 | ;; Created: 1995-05-25 |
| 9 | ;; Keywords: display, window, minor-mode, convenience | 9 | ;; Keywords: display, window, minor-mode, convenience |
| 10 | ;; Last Changed: 1999-11-17 | ||
| 11 | 10 | ||
| 12 | ;; This file is part of GNU Emacs. | 11 | ;; This file is part of GNU Emacs. |
| 13 | 12 | ||
| @@ -46,14 +45,14 @@ | |||
| 46 | ;; movement commands. | 45 | ;; movement commands. |
| 47 | ;; | 46 | ;; |
| 48 | ;; Follow mode comes to its prime when a large screen and two | 47 | ;; Follow mode comes to its prime when a large screen and two |
| 49 | ;; side-by-side window are used. The user can, with the help of Follow | 48 | ;; side-by-side window are used. The user can, with the help of Follow |
| 50 | ;; mode, use two full-height windows as though they would have been | 49 | ;; mode, use two full-height windows as though they would have been |
| 51 | ;; one. Imagine yourself editing a large function, or section of text, | 50 | ;; one. Imagine yourself editing a large function, or section of text, |
| 52 | ;; and being able to use 144 lines instead of the normal 72... (your | 51 | ;; and being able to use 144 lines instead of the normal 72... (your |
| 53 | ;; mileage may vary). | 52 | ;; mileage may vary). |
| 54 | 53 | ||
| 55 | ;; To test this package, make sure `follow' is loaded, or will be | 54 | ;; To test this package, make sure `follow' is loaded, or will be |
| 56 | ;; autoloaded when activated (see below). Then do the following: | 55 | ;; autoloaded when activated (see below). Then do the following: |
| 57 | ;; | 56 | ;; |
| 58 | ;; * Find your favorite file (preferably a long one). | 57 | ;; * Find your favorite file (preferably a long one). |
| 59 | ;; | 58 | ;; |
| @@ -77,13 +76,13 @@ | |||
| 77 | ;; +----------+----------+ | 76 | ;; +----------+----------+ |
| 78 | ;; | 77 | ;; |
| 79 | ;; As you can see, the right-hand window starts at line 73, the line | 78 | ;; As you can see, the right-hand window starts at line 73, the line |
| 80 | ;; immediately below the end of the left-hand window. As long as | 79 | ;; immediately below the end of the left-hand window. As long as |
| 81 | ;; `follow-mode' is active, the two windows will follow eachother! | 80 | ;; `follow-mode' is active, the two windows will follow eachother! |
| 82 | ;; | 81 | ;; |
| 83 | ;; * Play around and enjoy! Scroll one window and watch the other. | 82 | ;; * Play around and enjoy! Scroll one window and watch the other. |
| 84 | ;; Jump to the beginning or end. Press `Cursor down' at the last | 83 | ;; Jump to the beginning or end. Press `Cursor down' at the last |
| 85 | ;; line of the left-hand window. Enter new lines into the | 84 | ;; line of the left-hand window. Enter new lines into the |
| 86 | ;; text. Enter long lines spanning several lines, or several | 85 | ;; text. Enter long lines spanning several lines, or several |
| 87 | ;; windows. | 86 | ;; windows. |
| 88 | ;; | 87 | ;; |
| 89 | ;; * Should you find `Follow' mode annoying, just type | 88 | ;; * Should you find `Follow' mode annoying, just type |
| @@ -146,7 +145,7 @@ | |||
| 146 | ;; Usage: | 145 | ;; Usage: |
| 147 | ;; | 146 | ;; |
| 148 | ;; To activate issue the command "M-x follow-mode" | 147 | ;; To activate issue the command "M-x follow-mode" |
| 149 | ;; and press return. To deactivate, do it again. | 148 | ;; and press return. To deactivate, do it again. |
| 150 | ;; | 149 | ;; |
| 151 | ;; The following is a list of commands useful when follow-mode is active. | 150 | ;; The following is a list of commands useful when follow-mode is active. |
| 152 | ;; | 151 | ;; |
| @@ -197,7 +196,7 @@ | |||
| 197 | ;; in the same frame. (My apoligies to you who can't use frames.) | 196 | ;; in the same frame. (My apoligies to you who can't use frames.) |
| 198 | ;; | 197 | ;; |
| 199 | ;; 2) Bind `follow-mode' to key so you can turn it off whenever | 198 | ;; 2) Bind `follow-mode' to key so you can turn it off whenever |
| 200 | ;; you want to view two locations. Of course, `follow' mode can | 199 | ;; you want to view two locations. Of course, `follow' mode can |
| 201 | ;; be reactivated by hitting the same key again. | 200 | ;; be reactivated by hitting the same key again. |
| 202 | ;; | 201 | ;; |
| 203 | ;; Example from my ~/.emacs: | 202 | ;; Example from my ~/.emacs: |
| @@ -208,7 +207,7 @@ | |||
| 208 | ;; | 207 | ;; |
| 209 | ;; In an ideal world, follow mode would have been implemented in the | 208 | ;; In an ideal world, follow mode would have been implemented in the |
| 210 | ;; kernel of the display routines, making sure that the windows (using | 209 | ;; kernel of the display routines, making sure that the windows (using |
| 211 | ;; follow mode) ALWAYS are aligned. On planet earth, however, we must | 210 | ;; follow mode) ALWAYS are aligned. On planet earth, however, we must |
| 212 | ;; accept a solution where we ALMOST ALWAYS can make sure that the | 211 | ;; accept a solution where we ALMOST ALWAYS can make sure that the |
| 213 | ;; windows are aligned. | 212 | ;; windows are aligned. |
| 214 | ;; | 213 | ;; |
| @@ -222,7 +221,7 @@ | |||
| 222 | ;; | 221 | ;; |
| 223 | ;; Note that only the selected window is checked, for the reason of | 222 | ;; Note that only the selected window is checked, for the reason of |
| 224 | ;; efficiency and code complexity. (I.e. it is possible to make a | 223 | ;; efficiency and code complexity. (I.e. it is possible to make a |
| 225 | ;; non-selected windows unaligned. It will, however, pop right back | 224 | ;; non-selected windows unaligned. It will, however, pop right back |
| 226 | ;; when it is selected.) | 225 | ;; when it is selected.) |
| 227 | 226 | ||
| 228 | ;;}}} | 227 | ;;}}} |
| @@ -259,7 +258,7 @@ | |||
| 259 | (eval-when-compile | 258 | (eval-when-compile |
| 260 | (if (or (featurep 'bytecomp) | 259 | (if (or (featurep 'bytecomp) |
| 261 | (featurep 'byte-compile)) | 260 | (featurep 'byte-compile)) |
| 262 | (cond ((string-match "XEmacs" emacs-version) | 261 | (cond ((featurep 'xemacs) |
| 263 | ;; Make XEmacs shut up! I'm using standard Emacs | 262 | ;; Make XEmacs shut up! I'm using standard Emacs |
| 264 | ;; functions, they are NOT obsolete! | 263 | ;; functions, they are NOT obsolete! |
| 265 | (if (eq (get 'force-mode-line-update 'byte-compile) | 264 | (if (eq (get 'force-mode-line-update 'byte-compile) |
| @@ -278,176 +277,44 @@ | |||
| 278 | :group 'windows | 277 | :group 'windows |
| 279 | :group 'convenience) | 278 | :group 'convenience) |
| 280 | 279 | ||
| 281 | (defvar follow-mode nil | ||
| 282 | "Variable indicating if Follow mode is active.") | ||
| 283 | |||
| 284 | (defcustom follow-mode-hook nil | 280 | (defcustom follow-mode-hook nil |
| 285 | "*Hooks to run when follow-mode is turned on." | 281 | "Hooks to run when follow-mode is turned on." |
| 286 | :type 'hook | 282 | :type 'hook |
| 287 | :group 'follow) | 283 | :group 'follow) |
| 288 | 284 | ||
| 289 | (defcustom follow-mode-off-hook nil | 285 | (defcustom follow-mode-off-hook nil |
| 290 | "*Hooks to run when follow-mode is turned off." | 286 | "Hooks to run when follow-mode is turned off." |
| 291 | :type 'hook | 287 | :type 'hook |
| 292 | :group 'follow) | 288 | :group 'follow) |
| 293 | 289 | ||
| 294 | (defvar follow-mode-map nil | ||
| 295 | "*Minor mode keymap for Follow mode.") | ||
| 296 | 290 | ||
| 297 | (defcustom follow-mode-line-text " Follow" | 291 | ;;{{{ Keymap/Menu |
| 298 | "*Text shown in the mode line when Follow mode is active. | ||
| 299 | Defaults to \" Follow\". Examples of other values | ||
| 300 | are \" Fw\", or simply \"\"." | ||
| 301 | :type 'string | ||
| 302 | :group 'follow) | ||
| 303 | 292 | ||
| 304 | (defcustom follow-auto nil | 293 | ;; Define keys for the follow-mode minor mode map and replace some |
| 305 | "*Non-nil activates Follow mode whenever a file is loaded." | 294 | ;; functions in the global map. All `follow' mode special functions |
| 306 | :type 'boolean | 295 | ;; can be found on (the somewhat cumbersome) "C-c . <key>" |
| 307 | :group 'follow) | 296 | ;; (Control-C dot <key>). (As of Emacs 19.29 the keys |
| 297 | ;; C-c <punctuation character> are reserved for minor modes.) | ||
| 298 | ;; | ||
| 299 | ;; To change the prefix, redefine `follow-mode-prefix' before | ||
| 300 | ;; `follow' is loaded, or see the section on `follow-mode-hook' | ||
| 301 | ;; above for an example of how to bind the keys the way you like. | ||
| 302 | ;; | ||
| 303 | ;; Please note that the keymap is defined the first time this file is | ||
| 304 | ;; loaded. Also note that the only legal way to manipulate the | ||
| 305 | ;; keymap is to use `define-key'. Don't change it using `setq' or | ||
| 306 | ;; similar! | ||
| 308 | 307 | ||
| 309 | (defcustom follow-mode-prefix "\C-c." | 308 | (defcustom follow-mode-prefix "\C-c." |
| 310 | "*Prefix key to use for follow commands in Follow mode. | 309 | "Prefix key to use for follow commands in Follow mode. |
| 311 | The value of this variable is checked as part of loading Follow mode. | 310 | The value of this variable is checked as part of loading Follow mode. |
| 312 | After that, changing the prefix key requires manipulating keymaps." | 311 | After that, changing the prefix key requires manipulating keymaps." |
| 313 | :type 'string | 312 | :type 'string |
| 314 | :group 'follow) | 313 | :group 'follow) |
| 315 | 314 | ||
| 316 | (defcustom follow-intercept-processes | 315 | (defvar follow-mode-map |
| 317 | (fboundp 'start-process) | 316 | (let ((mainmap (make-sparse-keymap)) |
| 318 | "*When non-nil, Follow Mode will monitor process output." | 317 | (map (make-sparse-keymap))) |
| 319 | :type 'boolean | ||
| 320 | :group 'follow) | ||
| 321 | |||
| 322 | (defvar follow-emacs-version-xemacs-p | ||
| 323 | (string-match "XEmacs" emacs-version) | ||
| 324 | "Non-nil when running under XEmacs.") | ||
| 325 | |||
| 326 | (defvar follow-avoid-tail-recenter-p | ||
| 327 | (not follow-emacs-version-xemacs-p) | ||
| 328 | "*When non-nil, patch emacs so that tail windows won't be recentered. | ||
| 329 | |||
| 330 | A \"tail window\" is a window that displays only the end of | ||
| 331 | the buffer. Normally it is practical for the user that empty | ||
| 332 | windows are recentered automatically. However, when using | ||
| 333 | Follow Mode it breaks the display when the end is displayed | ||
| 334 | in a window \"above\" the last window. This is for | ||
| 335 | example the case when displaying a short page in info. | ||
| 336 | |||
| 337 | Must be set before Follow Mode is loaded. | ||
| 338 | |||
| 339 | Please note that it is not possible to fully prevent Emacs from | ||
| 340 | recentering empty windows. Please report if you find a repeatable | ||
| 341 | situation in which Emacs recenters empty windows. | ||
| 342 | |||
| 343 | XEmacs, as of 19.12, does not recenter windows, good!") | ||
| 344 | |||
| 345 | (defvar follow-cache-command-list | ||
| 346 | '(next-line previous-line forward-char backward-char) | ||
| 347 | "List of commands that don't require recalculation. | ||
| 348 | |||
| 349 | In order to be able to use the cache, a command should not change the | ||
| 350 | contents of the buffer, nor should it change selected window or current | ||
| 351 | buffer. | ||
| 352 | |||
| 353 | The commands in this list are checked at load time. | ||
| 354 | |||
| 355 | To mark other commands as suitable for caching, set the symbol | ||
| 356 | property `follow-mode-use-cache' to non-nil.") | ||
| 357 | |||
| 358 | (defvar follow-debug nil | ||
| 359 | "*Non-nil when debugging Follow mode.") | ||
| 360 | |||
| 361 | |||
| 362 | ;; Internal variables: | ||
| 363 | |||
| 364 | (defvar follow-internal-force-redisplay nil | ||
| 365 | "True when Follow mode should redisplay the windows.") | ||
| 366 | |||
| 367 | (defvar follow-process-filter-alist '() | ||
| 368 | "The original filters for processes intercepted by Follow mode.") | ||
| 369 | |||
| 370 | (defvar follow-active-menu nil | ||
| 371 | "The menu visible when Follow mode is active.") | ||
| 372 | |||
| 373 | (defvar follow-deactive-menu nil | ||
| 374 | "The menu visible when Follow mode is deactivated.") | ||
| 375 | |||
| 376 | (defvar follow-inside-post-command-hook nil | ||
| 377 | "Non-nil when inside Follow modes `post-command-hook'. | ||
| 378 | Used by `follow-window-size-change'.") | ||
| 379 | |||
| 380 | (defvar follow-windows-start-end-cache nil | ||
| 381 | "Cache used by `follow-window-start-end'.") | ||
| 382 | |||
| 383 | ;;}}} | ||
| 384 | ;;{{{ Bug report | ||
| 385 | |||
| 386 | (eval-when-compile (require 'reporter)) | ||
| 387 | |||
| 388 | (defun follow-submit-feedback () | ||
| 389 | "Submit feedback on Follow mode to the author: andersl@andersl.com" | ||
| 390 | (interactive) | ||
| 391 | (require 'reporter) | ||
| 392 | (and (y-or-n-p "Do you really want to submit a report on Follow mode? ") | ||
| 393 | (reporter-submit-bug-report | ||
| 394 | "Anders Lindgren <andersl@andersl.com>" | ||
| 395 | "follow.el" | ||
| 396 | '(post-command-hook | ||
| 397 | pre-command-hook | ||
| 398 | window-size-change-functions | ||
| 399 | window-scroll-functions | ||
| 400 | follow-mode-hook | ||
| 401 | follow-mode-off-hook | ||
| 402 | follow-auto | ||
| 403 | follow-intercept-processes | ||
| 404 | follow-avoid-tail-recenter-p | ||
| 405 | follow-process-filter-alist) | ||
| 406 | nil | ||
| 407 | nil | ||
| 408 | (concat | ||
| 409 | "Hi Anders!\n\n" | ||
| 410 | "(I have read the section on how to report bugs in the " | ||
| 411 | "Emacs manual.)\n\n" | ||
| 412 | "Even though I know you are busy, I thought you might " | ||
| 413 | "want to know...\n\n")))) | ||
| 414 | |||
| 415 | ;;}}} | ||
| 416 | ;;{{{ Debug messages | ||
| 417 | |||
| 418 | ;; This inline function must be as small as possible! | ||
| 419 | ;; Maybe we should define a macro that expands to nil if | ||
| 420 | ;; the variable is not set. | ||
| 421 | |||
| 422 | (defsubst follow-debug-message (&rest args) | ||
| 423 | "Like message, but only active when `follow-debug' is non-nil." | ||
| 424 | (if (and (boundp 'follow-debug) follow-debug) | ||
| 425 | (apply 'message args))) | ||
| 426 | |||
| 427 | ;;}}} | ||
| 428 | |||
| 429 | ;;{{{ Keymap/Menu | ||
| 430 | |||
| 431 | ;;; Define keys for the follow-mode minor mode map and replace some | ||
| 432 | ;;; functions in the global map. All `follow' mode special functions | ||
| 433 | ;;; can be found on (the somewhat cumbersome) "C-c . <key>" | ||
| 434 | ;;; (Control-C dot <key>). (As of Emacs 19.29 the keys | ||
| 435 | ;;; C-c <punctuation character> are reserved for minor modes.) | ||
| 436 | ;;; | ||
| 437 | ;;; To change the prefix, redefine `follow-mode-prefix' before | ||
| 438 | ;;; `follow' is loaded, or see the section on `follow-mode-hook' | ||
| 439 | ;;; above for an example of how to bind the keys the way you like. | ||
| 440 | ;;; | ||
| 441 | ;;; Please note that the keymap is defined the first time this file is | ||
| 442 | ;;; loaded. Also note that the only legal way to manipulate the | ||
| 443 | ;;; keymap is to use `define-key'. Don't change it using `setq' or | ||
| 444 | ;;; similar! | ||
| 445 | |||
| 446 | |||
| 447 | (if follow-mode-map | ||
| 448 | nil | ||
| 449 | (setq follow-mode-map (make-sparse-keymap)) | ||
| 450 | (let ((map (make-sparse-keymap))) | ||
| 451 | (define-key map "\C-v" 'follow-scroll-up) | 318 | (define-key map "\C-v" 'follow-scroll-up) |
| 452 | (define-key map "\M-v" 'follow-scroll-down) | 319 | (define-key map "\M-v" 'follow-scroll-down) |
| 453 | (define-key map "v" 'follow-scroll-down) | 320 | (define-key map "v" 'follow-scroll-down) |
| @@ -460,38 +327,26 @@ Used by `follow-window-size-change'.") | |||
| 460 | (define-key map "n" 'follow-next-window) | 327 | (define-key map "n" 'follow-next-window) |
| 461 | (define-key map "p" 'follow-previous-window) | 328 | (define-key map "p" 'follow-previous-window) |
| 462 | 329 | ||
| 463 | (define-key follow-mode-map follow-mode-prefix map) | 330 | (define-key mainmap follow-mode-prefix map) |
| 464 | 331 | ||
| 465 | ;; Replace the standard `end-of-buffer', when in Follow Mode. (I | 332 | ;; Replace the standard `end-of-buffer', when in Follow Mode. (I |
| 466 | ;; don't see the point in trying to replace every function that | 333 | ;; don't see the point in trying to replace every function that |
| 467 | ;; could be enhanced in Follow mode. End-of-buffer is a special | 334 | ;; could be enhanced in Follow mode. End-of-buffer is a special |
| 468 | ;; case since it is very simple to define and it greatly enhances | 335 | ;; case since it is very simple to define and it greatly enhances |
| 469 | ;; the look and feel of Follow mode.) | 336 | ;; the look and feel of Follow mode.) |
| 470 | ;; | 337 | (define-key mainmap [remap end-of-buffer] 'follow-end-of-buffer) |
| 471 | ;; (The function `substitute-key-definition' does not work | ||
| 472 | ;; in all versions of Emacs.) | ||
| 473 | (mapcar | ||
| 474 | (function | ||
| 475 | (lambda (pair) | ||
| 476 | (let ((old (car pair)) | ||
| 477 | (new (cdr pair))) | ||
| 478 | (mapcar (function (lambda (key) | ||
| 479 | (define-key follow-mode-map key new))) | ||
| 480 | (where-is-internal old global-map))))) | ||
| 481 | '((end-of-buffer . follow-end-of-buffer) | ||
| 482 | (fkey-end-of-buffer . follow-end-of-buffer))) | ||
| 483 | 338 | ||
| 484 | ;;; | 339 | ;; |
| 485 | ;;; The menu. | 340 | ;; The menu. |
| 486 | ;;; | 341 | ;; |
| 487 | 342 | ||
| 488 | (if (not follow-emacs-version-xemacs-p) | 343 | (if (not (featurep 'xemacs)) |
| 489 | 344 | ||
| 490 | ;; | 345 | ;; |
| 491 | ;; Emacs | 346 | ;; Emacs |
| 492 | ;; | 347 | ;; |
| 493 | (let ((menumap (funcall (symbol-function 'make-sparse-keymap) | 348 | (let ((menumap (funcall (symbol-function 'make-sparse-keymap) |
| 494 | "Follow")) | 349 | "Follow")) |
| 495 | (count 0) | 350 | (count 0) |
| 496 | id) | 351 | id) |
| 497 | (mapcar | 352 | (mapcar |
| @@ -516,16 +371,16 @@ Used by `follow-window-size-change'.") | |||
| 516 | ("First Window" . follow-first-window) | 371 | ("First Window" . follow-first-window) |
| 517 | ("--") | 372 | ("--") |
| 518 | ("Switch To Buffer (all windows)" | 373 | ("Switch To Buffer (all windows)" |
| 519 | . follow-switch-to-buffer-all) | 374 | . follow-switch-to-buffer-all) |
| 520 | ("Switch To Buffer" . follow-switch-to-buffer) | 375 | ("Switch To Buffer" . follow-switch-to-buffer) |
| 521 | ("--") | 376 | ("--") |
| 522 | ("Delete Other Windows and Split" | 377 | ("Delete Other Windows and Split" |
| 523 | . follow-delete-other-windows-and-split) | 378 | . follow-delete-other-windows-and-split) |
| 524 | ("--") | 379 | ("--") |
| 525 | ("Scroll Down" . follow-scroll-down) | 380 | ("Scroll Down" . follow-scroll-down) |
| 526 | ("Scroll Up" . follow-scroll-up))) | 381 | ("Scroll Up" . follow-scroll-up))) |
| 527 | 382 | ||
| 528 | ;; If there is a `tools' meny, we use it. However, we can't add a | 383 | ;; If there is a `tools' menu, we use it. However, we can't add a |
| 529 | ;; minor-mode specific item to it (it's broken), so we make the | 384 | ;; minor-mode specific item to it (it's broken), so we make the |
| 530 | ;; contents ghosted when not in use, and add ourselves to the | 385 | ;; contents ghosted when not in use, and add ourselves to the |
| 531 | ;; global map. If no `tools' menu is present, just make a | 386 | ;; global map. If no `tools' menu is present, just make a |
| @@ -546,7 +401,7 @@ Used by `follow-window-size-change'.") | |||
| 546 | (if last | 401 | (if last |
| 547 | (progn | 402 | (progn |
| 548 | (funcall (symbol-function 'define-key-after) | 403 | (funcall (symbol-function 'define-key-after) |
| 549 | tools-map [separator-follow] '("--") last) | 404 | tools-map [separator-follow] '("--") last) |
| 550 | (funcall (symbol-function 'define-key-after) | 405 | (funcall (symbol-function 'define-key-after) |
| 551 | tools-map [follow] (cons "Follow" menumap) | 406 | tools-map [follow] (cons "Follow" menumap) |
| 552 | 'separator-follow)) | 407 | 'separator-follow)) |
| @@ -555,7 +410,7 @@ Used by `follow-window-size-change'.") | |||
| 555 | (define-key (current-global-map) [menu-bar tools follow] | 410 | (define-key (current-global-map) [menu-bar tools follow] |
| 556 | (cons "Follow" menumap)))) | 411 | (cons "Follow" menumap)))) |
| 557 | ;; No tools menu, add "Follow" to the menubar. | 412 | ;; No tools menu, add "Follow" to the menubar. |
| 558 | (define-key follow-mode-map [menu-bar follow] | 413 | (define-key mainmap [menu-bar follow] |
| 559 | (cons "Follow" menumap))))) | 414 | (cons "Follow" menumap))))) |
| 560 | 415 | ||
| 561 | ;; | 416 | ;; |
| @@ -593,21 +448,103 @@ Used by `follow-window-size-change'.") | |||
| 593 | (defun follow-menu-filter (menu) | 448 | (defun follow-menu-filter (menu) |
| 594 | (if follow-mode | 449 | (if follow-mode |
| 595 | menu | 450 | menu |
| 596 | '(["Activate " follow-mode t])))))) | 451 | '(["Activate " follow-mode t])))) |
| 452 | |||
| 453 | mainmap) | ||
| 454 | "Minor mode keymap for Follow mode.") | ||
| 597 | 455 | ||
| 456 | ;;}}} | ||
| 598 | 457 | ||
| 599 | ;;; Register the follow mode keymap. | 458 | (defcustom follow-mode-line-text " Follow" |
| 600 | (or (assq 'follow-mode minor-mode-map-alist) | 459 | "Text shown in the mode line when Follow mode is active. |
| 601 | (setq minor-mode-map-alist | 460 | Defaults to \" Follow\". Examples of other values |
| 602 | (cons (cons 'follow-mode follow-mode-map) minor-mode-map-alist))) | 461 | are \" Fw\", or simply \"\"." |
| 462 | :type 'string | ||
| 463 | :group 'follow) | ||
| 464 | |||
| 465 | (defcustom follow-auto nil | ||
| 466 | "Non-nil activates Follow mode whenever a file is loaded." | ||
| 467 | :type 'boolean | ||
| 468 | :group 'follow) | ||
| 469 | |||
| 470 | (defcustom follow-intercept-processes (fboundp 'start-process) | ||
| 471 | "When non-nil, Follow Mode will monitor process output." | ||
| 472 | :type 'boolean | ||
| 473 | :group 'follow) | ||
| 474 | |||
| 475 | (defvar follow-avoid-tail-recenter-p (not (featurep 'xemacs)) | ||
| 476 | "*When non-nil, patch emacs so that tail windows won't be recentered. | ||
| 477 | |||
| 478 | A \"tail window\" is a window that displays only the end of | ||
| 479 | the buffer. Normally it is practical for the user that empty | ||
| 480 | windows are recentered automatically. However, when using | ||
| 481 | Follow Mode it breaks the display when the end is displayed | ||
| 482 | in a window \"above\" the last window. This is for | ||
| 483 | example the case when displaying a short page in info. | ||
| 484 | |||
| 485 | Must be set before Follow Mode is loaded. | ||
| 486 | |||
| 487 | Please note that it is not possible to fully prevent Emacs from | ||
| 488 | recentering empty windows. Please report if you find a repeatable | ||
| 489 | situation in which Emacs recenters empty windows. | ||
| 490 | |||
| 491 | XEmacs, as of 19.12, does not recenter windows, good!") | ||
| 492 | |||
| 493 | (defvar follow-cache-command-list | ||
| 494 | '(next-line previous-line forward-char backward-char) | ||
| 495 | "List of commands that don't require recalculation. | ||
| 496 | |||
| 497 | In order to be able to use the cache, a command should not change the | ||
| 498 | contents of the buffer, nor should it change selected window or current | ||
| 499 | buffer. | ||
| 500 | |||
| 501 | The commands in this list are checked at load time. | ||
| 502 | |||
| 503 | To mark other commands as suitable for caching, set the symbol | ||
| 504 | property `follow-mode-use-cache' to non-nil.") | ||
| 505 | |||
| 506 | (defvar follow-debug nil | ||
| 507 | "*Non-nil when debugging Follow mode.") | ||
| 508 | |||
| 509 | |||
| 510 | ;; Internal variables: | ||
| 511 | |||
| 512 | (defvar follow-internal-force-redisplay nil | ||
| 513 | "True when Follow mode should redisplay the windows.") | ||
| 514 | |||
| 515 | (defvar follow-process-filter-alist '() | ||
| 516 | "The original filters for processes intercepted by Follow mode.") | ||
| 517 | |||
| 518 | (defvar follow-active-menu nil | ||
| 519 | "The menu visible when Follow mode is active.") | ||
| 520 | |||
| 521 | (defvar follow-deactive-menu nil | ||
| 522 | "The menu visible when Follow mode is deactivated.") | ||
| 523 | |||
| 524 | (defvar follow-inside-post-command-hook nil | ||
| 525 | "Non-nil when inside Follow modes `post-command-hook'. | ||
| 526 | Used by `follow-window-size-change'.") | ||
| 527 | |||
| 528 | (defvar follow-windows-start-end-cache nil | ||
| 529 | "Cache used by `follow-window-start-end'.") | ||
| 530 | |||
| 531 | ;;}}} | ||
| 532 | ;;{{{ Debug messages | ||
| 533 | |||
| 534 | ;; This inline function must be as small as possible! | ||
| 535 | ;; Maybe we should define a macro that expands to nil if | ||
| 536 | ;; the variable is not set. | ||
| 537 | |||
| 538 | (defsubst follow-debug-message (&rest args) | ||
| 539 | "Like message, but only active when `follow-debug' is non-nil." | ||
| 540 | (if (and (boundp 'follow-debug) follow-debug) | ||
| 541 | (apply 'message args))) | ||
| 603 | 542 | ||
| 604 | ;;}}} | 543 | ;;}}} |
| 605 | ;;{{{ Cache | 544 | ;;{{{ Cache |
| 606 | 545 | ||
| 607 | (let ((cmds follow-cache-command-list)) | 546 | (dolist (cmd follow-cache-command-list) |
| 608 | (while cmds | 547 | (put cmd 'follow-mode-use-cache t)) |
| 609 | (put (car cmds) 'follow-mode-use-cache t) | ||
| 610 | (setq cmds (cdr cmds)))) | ||
| 611 | 548 | ||
| 612 | ;;}}} | 549 | ;;}}} |
| 613 | 550 | ||
| @@ -615,20 +552,20 @@ Used by `follow-window-size-change'.") | |||
| 615 | 552 | ||
| 616 | ;;;###autoload | 553 | ;;;###autoload |
| 617 | (defun turn-on-follow-mode () | 554 | (defun turn-on-follow-mode () |
| 618 | "Turn on Follow mode. Please see the function `follow-mode'." | 555 | "Turn on Follow mode. Please see the function `follow-mode'." |
| 619 | (interactive) | 556 | (interactive) |
| 620 | (follow-mode 1)) | 557 | (follow-mode 1)) |
| 621 | 558 | ||
| 622 | 559 | ||
| 623 | ;;;###autoload | 560 | ;;;###autoload |
| 624 | (defun turn-off-follow-mode () | 561 | (defun turn-off-follow-mode () |
| 625 | "Turn off Follow mode. Please see the function `follow-mode'." | 562 | "Turn off Follow mode. Please see the function `follow-mode'." |
| 626 | (interactive) | 563 | (interactive) |
| 627 | (follow-mode -1)) | 564 | (follow-mode -1)) |
| 628 | 565 | ||
| 629 | 566 | (put 'follow-mode 'permanent-local t) | |
| 630 | ;;;###autoload | 567 | ;;;###autoload |
| 631 | (defun follow-mode (arg) | 568 | (define-minor-mode follow-mode |
| 632 | "Minor mode that combines windows into one tall virtual window. | 569 | "Minor mode that combines windows into one tall virtual window. |
| 633 | 570 | ||
| 634 | The feeling of a \"virtual window\" has been accomplished by the use | 571 | The feeling of a \"virtual window\" has been accomplished by the use |
| @@ -665,39 +602,21 @@ is called. When turned off, `follow-mode-off-hook' is called. | |||
| 665 | 602 | ||
| 666 | Keys specific to Follow mode: | 603 | Keys specific to Follow mode: |
| 667 | \\{follow-mode-map}" | 604 | \\{follow-mode-map}" |
| 668 | (interactive "P") | 605 | :keymap follow-mode-map |
| 669 | (make-local-variable 'follow-mode) | 606 | (if (and follow-mode follow-intercept-processes) |
| 670 | (put 'follow-mode 'permanent-local t) | 607 | (follow-intercept-process-output)) |
| 671 | (let ((follow-mode-orig follow-mode)) | 608 | (cond (follow-mode ; On |
| 672 | (setq follow-mode | 609 | ;; XEmacs: If this is non-nil, the window will scroll before |
| 673 | (if (null arg) | 610 | ;; the point will have a chance to get into the next window. |
| 674 | (not follow-mode) | 611 | (if (boundp 'scroll-on-clipped-lines) |
| 675 | (> (prefix-numeric-value arg) 0))) | 612 | (setq scroll-on-clipped-lines nil)) |
| 676 | (if (and follow-mode follow-intercept-processes) | 613 | (force-mode-line-update) |
| 677 | (follow-intercept-process-output)) | 614 | (add-hook 'post-command-hook 'follow-post-command-hook t) |
| 678 | (cond ((and follow-mode (not follow-mode-orig)) ; On | 615 | (run-hooks 'follow-mode-hook)) |
| 679 | ;; XEmacs: If this is non-nil, the window will scroll before | 616 | |
| 680 | ;; the point will have a chance to get into the next window. | 617 | ((not follow-mode) ; Off |
| 681 | (if (boundp 'scroll-on-clipped-lines) | 618 | (force-mode-line-update) |
| 682 | (set 'scroll-on-clipped-lines nil)) | 619 | (run-hooks 'follow-mode-off-hook)))) |
| 683 | (force-mode-line-update) | ||
| 684 | (add-hook 'post-command-hook 'follow-post-command-hook t) | ||
| 685 | (run-hooks 'follow-mode-hook)) | ||
| 686 | |||
| 687 | ((and (not follow-mode) follow-mode-orig) ; Off | ||
| 688 | (force-mode-line-update) | ||
| 689 | (run-hooks 'follow-mode-off-hook))))) | ||
| 690 | |||
| 691 | |||
| 692 | ;; Register follow-mode as a minor mode. | ||
| 693 | |||
| 694 | (if (fboundp 'add-minor-mode) | ||
| 695 | ;; XEmacs | ||
| 696 | (funcall (symbol-function 'add-minor-mode) | ||
| 697 | 'follow-mode 'follow-mode-line-text) | ||
| 698 | (or (assq 'follow-mode minor-mode-alist) | ||
| 699 | (setq minor-mode-alist | ||
| 700 | (cons '(follow-mode follow-mode-line-text) minor-mode-alist)))) | ||
| 701 | 620 | ||
| 702 | ;;}}} | 621 | ;;}}} |
| 703 | ;;{{{ Find file hook | 622 | ;;{{{ Find file hook |
| @@ -1033,7 +952,7 @@ window, normally is the end plus one. | |||
| 1033 | If WIN is nil, the selected window is used. | 952 | If WIN is nil, the selected window is used. |
| 1034 | 953 | ||
| 1035 | Returns (end-pos end-of-buffer-p)" | 954 | Returns (end-pos end-of-buffer-p)" |
| 1036 | (if follow-emacs-version-xemacs-p | 955 | (if (featurep 'xemacs) |
| 1037 | ;; XEmacs can calculate the end of the window by using | 956 | ;; XEmacs can calculate the end of the window by using |
| 1038 | ;; the 'guarantee options. GOOD! | 957 | ;; the 'guarantee options. GOOD! |
| 1039 | (let ((end (window-end win t))) | 958 | (let ((end (window-end win t))) |
| @@ -1511,7 +1430,7 @@ non-first windows in Follow Mode." | |||
| 1511 | ;;}}} | 1430 | ;;}}} |
| 1512 | ;;{{{ Post Command Hook | 1431 | ;;{{{ Post Command Hook |
| 1513 | 1432 | ||
| 1514 | ;;; The magic little box. This function is called after every command. | 1433 | ;; The magic little box. This function is called after every command. |
| 1515 | 1434 | ||
| 1516 | ;; This is not as complicated as it seems. It is simply a list of common | 1435 | ;; This is not as complicated as it seems. It is simply a list of common |
| 1517 | ;; display situations and the actions to take, plus commands for redrawing | 1436 | ;; display situations and the actions to take, plus commands for redrawing |
| @@ -1735,17 +1654,17 @@ non-first windows in Follow Mode." | |||
| 1735 | 1654 | ||
| 1736 | ;;;; Scroll-bar support code. | 1655 | ;;;; Scroll-bar support code. |
| 1737 | 1656 | ||
| 1738 | ;;; Why is it needed? Well, if the selected window is in follow mode, | 1657 | ;; Why is it needed? Well, if the selected window is in follow mode, |
| 1739 | ;;; all its follower stick to it blindly. If one of them is scrolled, | 1658 | ;; all its follower stick to it blindly. If one of them is scrolled, |
| 1740 | ;;; it immediately returns to the original position when the mouse is | 1659 | ;; it immediately returns to the original position when the mouse is |
| 1741 | ;;; released. If the selected window is not a follower of the dragged | 1660 | ;; released. If the selected window is not a follower of the dragged |
| 1742 | ;;; window the windows will be unaligned. | 1661 | ;; window the windows will be unaligned. |
| 1743 | 1662 | ||
| 1744 | ;;; The advices doesn't get compiled. Aestetically, this might be a | 1663 | ;; The advices doesn't get compiled. Aestetically, this might be a |
| 1745 | ;;; problem but in practical life it isn't. | 1664 | ;; problem but in practical life it isn't. |
| 1746 | 1665 | ||
| 1747 | ;;; Discussion: Now when the other windows in the chain follow the | 1666 | ;; Discussion: Now when the other windows in the chain follow the |
| 1748 | ;;; dragged, should we really select it? | 1667 | ;; dragged, should we really select it? |
| 1749 | 1668 | ||
| 1750 | (cond ((fboundp 'scroll-bar-drag) | 1669 | (cond ((fboundp 'scroll-bar-drag) |
| 1751 | ;;; | 1670 | ;;; |
| @@ -1851,29 +1770,29 @@ WINDOW can be an object or a window." | |||
| 1851 | ;;}}} | 1770 | ;;}}} |
| 1852 | ;;{{{ Process output | 1771 | ;;{{{ Process output |
| 1853 | 1772 | ||
| 1854 | ;;; The following sections installs a spy that listens to process | 1773 | ;; The following sections installs a spy that listens to process |
| 1855 | ;;; output and tries to reposition the windows whose buffers are in | 1774 | ;; output and tries to reposition the windows whose buffers are in |
| 1856 | ;;; Follow mode. We play safe as much as possible... | 1775 | ;; Follow mode. We play safe as much as possible... |
| 1857 | ;;; | 1776 | ;; |
| 1858 | ;;; When follow-mode is activated all active processes are | 1777 | ;; When follow-mode is activated all active processes are |
| 1859 | ;;; intercepted. All new processes that change their filter function | 1778 | ;; intercepted. All new processes that change their filter function |
| 1860 | ;;; using `set-process-filter' are also intercepted. The reason is | 1779 | ;; using `set-process-filter' are also intercepted. The reason is |
| 1861 | ;;; that a process can cause a redisplay recentering "tail" windows. | 1780 | ;; that a process can cause a redisplay recentering "tail" windows. |
| 1862 | ;;; Note that it doesn't hurt to spy on more processes than needed. | 1781 | ;; Note that it doesn't hurt to spy on more processes than needed. |
| 1863 | ;;; | 1782 | ;; |
| 1864 | ;;; Technically, we set the process filter to `follow-generic-filter'. | 1783 | ;; Technically, we set the process filter to `follow-generic-filter'. |
| 1865 | ;;; The original filter is stored in `follow-process-filter-alist'. | 1784 | ;; The original filter is stored in `follow-process-filter-alist'. |
| 1866 | ;;; Our generic filter calls the original filter, or inserts the | 1785 | ;; Our generic filter calls the original filter, or inserts the |
| 1867 | ;;; output into the buffer, if the buffer originally didn't have an | 1786 | ;; output into the buffer, if the buffer originally didn't have an |
| 1868 | ;;; output filter. It also makes sure that the windows connected to | 1787 | ;; output filter. It also makes sure that the windows connected to |
| 1869 | ;;; the buffer are aligned. | 1788 | ;; the buffer are aligned. |
| 1870 | ;;; | 1789 | ;; |
| 1871 | ;;; Discussion: How do we find processes that don't call | 1790 | ;; Discussion: How do we find processes that don't call |
| 1872 | ;;; `set-process-filter'? (How often are processes created in a | 1791 | ;; `set-process-filter'? (How often are processes created in a |
| 1873 | ;;; buffer after Follow mode are activated?) | 1792 | ;; buffer after Follow mode are activated?) |
| 1874 | ;;; | 1793 | ;; |
| 1875 | ;;; Discussion: Should we also advice `process-filter' to make our | 1794 | ;; Discussion: Should we also advice `process-filter' to make our |
| 1876 | ;;; filter invisible to others? | 1795 | ;; filter invisible to others? |
| 1877 | 1796 | ||
| 1878 | ;;{{{ Advice for `set-process-filter' | 1797 | ;;{{{ Advice for `set-process-filter' |
| 1879 | 1798 | ||
| @@ -1980,7 +1899,7 @@ connected to processes. | |||
| 1980 | 1899 | ||
| 1981 | The only reason to call this function is if the Follow mode spy filter | 1900 | The only reason to call this function is if the Follow mode spy filter |
| 1982 | would interfere with some other package. If this happens, please | 1901 | would interfere with some other package. If this happens, please |
| 1983 | report this using the `follow-submit-feedback' function." | 1902 | report this using the `report-emacs-bug' function." |
| 1984 | (interactive) | 1903 | (interactive) |
| 1985 | (follow-tidy-process-filter-alist) | 1904 | (follow-tidy-process-filter-alist) |
| 1986 | (let ((list (process-list))) | 1905 | (let ((list (process-list))) |
| @@ -1999,12 +1918,12 @@ report this using the `follow-submit-feedback' function." | |||
| 1999 | ;;}}} | 1918 | ;;}}} |
| 2000 | ;;{{{ The filter | 1919 | ;;{{{ The filter |
| 2001 | 1920 | ||
| 2002 | ;;; The following section is a naive method to make buffers with | 1921 | ;; The following section is a naive method to make buffers with |
| 2003 | ;;; process output to work with Follow mode. Whenever the start of the | 1922 | ;; process output to work with Follow mode. Whenever the start of the |
| 2004 | ;;; window displaying the buffer is moved, we moves it back to its | 1923 | ;; window displaying the buffer is moved, we moves it back to its |
| 2005 | ;;; original position and try to select a new window. (If we fail, | 1924 | ;; original position and try to select a new window. (If we fail, |
| 2006 | ;;; the normal redisplay functions of Emacs will scroll it right | 1925 | ;; the normal redisplay functions of Emacs will scroll it right |
| 2007 | ;;; back!) | 1926 | ;; back!) |
| 2008 | 1927 | ||
| 2009 | (defun follow-generic-filter (proc output) | 1928 | (defun follow-generic-filter (proc output) |
| 2010 | "Process output filter for process connected to buffers in Follow mode." | 1929 | "Process output filter for process connected to buffers in Follow mode." |
| @@ -2219,7 +2138,7 @@ report this using the `follow-submit-feedback' function." | |||
| 2219 | ;; unless we are in `slow-search-mode', i.e. only a few lines | 2138 | ;; unless we are in `slow-search-mode', i.e. only a few lines |
| 2220 | ;; of text is visible. | 2139 | ;; of text is visible. |
| 2221 | 2140 | ||
| 2222 | (if follow-emacs-version-xemacs-p | 2141 | (if (featurep 'xemacs) |
| 2223 | (defadvice isearch-done (before follow-isearch-done activate) | 2142 | (defadvice isearch-done (before follow-isearch-done activate) |
| 2224 | (if (and (boundp 'follow-mode) | 2143 | (if (and (boundp 'follow-mode) |
| 2225 | follow-mode | 2144 | follow-mode |
| @@ -2235,28 +2154,28 @@ report this using the `follow-submit-feedback' function." | |||
| 2235 | ;;}}} | 2154 | ;;}}} |
| 2236 | ;;{{{ Tail window handling | 2155 | ;;{{{ Tail window handling |
| 2237 | 2156 | ||
| 2238 | ;;; In Emacs (not XEmacs) windows showing nothing are sometimes | 2157 | ;; In Emacs (not XEmacs) windows showing nothing are sometimes |
| 2239 | ;;; recentered. When in Follow Mode, this is not desireable for | 2158 | ;; recentered. When in Follow Mode, this is not desireable for |
| 2240 | ;;; non-first windows in the window chain. This section tries to | 2159 | ;; non-first windows in the window chain. This section tries to |
| 2241 | ;;; make the windows stay where they should be. | 2160 | ;; make the windows stay where they should be. |
| 2242 | ;;; | 2161 | ;; |
| 2243 | ;;; If the display is updated, all windows starting at (point-max) are | 2162 | ;; If the display is updated, all windows starting at (point-max) are |
| 2244 | ;;; going to be recentered at the next redisplay, unless we do a | 2163 | ;; going to be recentered at the next redisplay, unless we do a |
| 2245 | ;;; read-and-write cycle to update the `force' flag inside the windows. | 2164 | ;; read-and-write cycle to update the `force' flag inside the windows. |
| 2246 | ;;; | 2165 | ;; |
| 2247 | ;;; In 19.30, a new varible `window-scroll-functions' is called every | 2166 | ;; In 19.30, a new varible `window-scroll-functions' is called every |
| 2248 | ;;; time a window is recentered. It is not perfect for our situation, | 2167 | ;; time a window is recentered. It is not perfect for our situation, |
| 2249 | ;;; since when it is called for a tail window, it is to late. However, | 2168 | ;; since when it is called for a tail window, it is to late. However, |
| 2250 | ;;; if it is called for another window, we can try to update our | 2169 | ;; if it is called for another window, we can try to update our |
| 2251 | ;;; windows. | 2170 | ;; windows. |
| 2252 | ;;; | 2171 | ;; |
| 2253 | ;;; By patching `sit-for' we can make sure that to catch all explicit | 2172 | ;; By patching `sit-for' we can make sure that to catch all explicit |
| 2254 | ;;; updates initiated by lisp programs. Internal calls, on the other | 2173 | ;; updates initiated by lisp programs. Internal calls, on the other |
| 2255 | ;;; hand, are not handled. | 2174 | ;; hand, are not handled. |
| 2256 | ;;; | 2175 | ;; |
| 2257 | ;;; Please note that the function `follow-avoid-tail-recenter' is also | 2176 | ;; Please note that the function `follow-avoid-tail-recenter' is also |
| 2258 | ;;; called from other places, e.g. `post-command-hook' and | 2177 | ;; called from other places, e.g. `post-command-hook' and |
| 2259 | ;;; `post-command-idle-hook'. | 2178 | ;; `post-command-idle-hook'. |
| 2260 | 2179 | ||
| 2261 | ;; If this function is called it is too late for this window, but | 2180 | ;; If this function is called it is too late for this window, but |
| 2262 | ;; we might save other windows from being recentered. | 2181 | ;; we might save other windows from being recentered. |
| @@ -2328,9 +2247,9 @@ This prevents `mouse-drag-region' from messing things up." | |||
| 2328 | 2247 | ||
| 2329 | ;;{{{ The end | 2248 | ;;{{{ The end |
| 2330 | 2249 | ||
| 2331 | ;;; | 2250 | ;; |
| 2332 | ;;; We're done! | 2251 | ;; We're done! |
| 2333 | ;;; | 2252 | ;; |
| 2334 | 2253 | ||
| 2335 | (provide 'follow) | 2254 | (provide 'follow) |
| 2336 | 2255 | ||