;;; follow.el --- synchronize windows showing the same buffer
;; Copyright (C) 1995, 1996, 1997, 1999, 2001, 2002, 2003, 2004,
-;; 2005, 2006, 2007 Free Software Foundation, Inc.
+;; 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
;; Author: Anders Lindgren <andersl@andersl.com>
;; Maintainer: FSF (Anders' email bounces, Sep 2005)
;; Should someone come up with a better solution, please let me
;; know.
+(require 'easymenu)
+
(eval-when-compile
(if (or (featurep 'bytecomp)
(featurep 'byte-compile))
;; the look and feel of Follow mode.)
(define-key mainmap [remap end-of-buffer] 'follow-end-of-buffer)
- ;;
- ;; The menu.
- ;;
-
- (if (not (featurep 'xemacs))
-
- ;;
- ;; Emacs
- ;;
- (let ((menumap (funcall (symbol-function 'make-sparse-keymap)
- "Follow"))
- (count 0)
- id)
- (mapcar
- (function
- (lambda (item)
- (setq id
- (or (cdr item)
- (progn
- (setq count (+ count 1))
- (intern (format "separator-%d" count)))))
- (define-key menumap (vector id) item)
- (or (eq id 'follow-mode)
- (put id 'menu-enable 'follow-mode))))
- ;; In reverse order:
- '(("Toggle Follow mode" . follow-mode)
- ("--")
- ("Recenter" . follow-recenter)
- ("--")
- ("Previous Window" . follow-previous-window)
- ("Next Windows" . follow-next-window)
- ("Last Window" . follow-last-window)
- ("First Window" . follow-first-window)
- ("--")
- ("Switch To Buffer (all windows)"
- . follow-switch-to-buffer-all)
- ("Switch To Buffer" . follow-switch-to-buffer)
- ("--")
- ("Delete Other Windows and Split"
- . follow-delete-other-windows-and-split)
- ("--")
- ("Scroll Down" . follow-scroll-down)
- ("Scroll Up" . follow-scroll-up)))
-
- ;; If there is a `tools' menu, we use it. However, we can't add a
- ;; minor-mode specific item to it (it's broken), so we make the
- ;; contents ghosted when not in use, and add ourselves to the
- ;; global map. If no `tools' menu is present, just make a
- ;; top-level menu visible when the mode is activated.
-
- (let ((tools-map (lookup-key (current-global-map) [menu-bar tools]))
- (last nil))
- (if (sequencep tools-map)
- (progn
- ;; Find the last entry in the menu and store it in `last'.
- (mapcar (function
- (lambda (x)
- (setq last (or (cdr-safe
- (cdr-safe
- (cdr-safe x)))
- last))))
- tools-map)
- (if last
- (progn
- (funcall (symbol-function 'define-key-after)
- tools-map [separator-follow] '("--") last)
- (funcall (symbol-function 'define-key-after)
- tools-map [follow] (cons "Follow" menumap)
- 'separator-follow))
- ;; Didn't find the last item, adding to the top of
- ;; tools. (This will probably never happen...)
- (define-key (current-global-map) [menu-bar tools follow]
- (cons "Follow" menumap))))
- ;; No tools menu, add "Follow" to the menubar.
- (define-key mainmap [menu-bar follow]
- (cons "Follow" menumap)))))
-
- ;;
- ;; XEmacs.
- ;;
-
- ;; place the menu in the `Tools' menu.
- (let ((menu '("Follow"
- :filter follow-menu-filter
- ["Scroll Up" follow-scroll-up t]
- ["Scroll Down" follow-scroll-down t]
- ["Delete Other Windows and Split"
- follow-delete-other-windows-and-split t]
- ["Switch To Buffer" follow-switch-to-buffer t]
- ["Switch To Buffer (all windows)"
- follow-switch-to-buffer-all t]
- ["First Window" follow-first-window t]
- ["Last Window" follow-last-window t]
- ["Next Windows" follow-next-window t]
- ["Previous Window" follow-previous-window t]
- ["Recenter" follow-recenter t]
- ["Deactivate" follow-mode t])))
-
- ;; Why not just `(set-buffer-menubar current-menubar)'? The
- ;; question is a very good question. The reason is that under
- ;; Emacs, neither `set-buffer-menubar' nor
- ;; `current-menubar' is defined, hence the byte-compiler will
- ;; warn.
- (funcall (symbol-function 'set-buffer-menubar)
- (symbol-value 'current-menubar))
- (funcall (symbol-function 'add-submenu) '("Tools") menu))
-
- ;; When the mode is not activated, only one item is visible:
- ;; "Activate".
- (defun follow-menu-filter (menu)
- (if follow-mode
- menu
- '(["Activate " follow-mode t]))))
-
mainmap)
"Minor mode keymap for Follow mode.")
+;; When the mode is not activated, only one item is visible to activate
+;; the mode.
+(defun follow-menu-filter (menu)
+ (if (bound-and-true-p follow-mode)
+ menu
+ '(["Follow mode" follow-mode
+ :style toggle :selected follow-mode])))
+
+;; If there is a `tools' menu, we use it. However, we can't add a
+;; minor-mode specific item to it (it's broken), so we make the
+;; contents ghosted when not in use, and add ourselves to the
+;; global map.
+(easy-menu-add-item nil '("Tools")
+ '("Follow"
+ ;; The Emacs code used to just grey out operations when follow-mode was
+ ;; not enabled, whereas the XEmacs code used to remove it altogether.
+ ;; Not sure which is preferable, but clearly the preference should not
+ ;; depend on the flavor.
+ :filter follow-menu-filter
+ ["Scroll Up" follow-scroll-up follow-mode]
+ ["Scroll Down" follow-scroll-down follow-mode]
+ "--"
+ ["Delete Other Windows and Split" follow-delete-other-windows-and-split follow-mode]
+ "--"
+ ["Switch To Buffer" follow-switch-to-buffer follow-mode]
+ ["Switch To Buffer (all windows)" follow-switch-to-buffer-all follow-mode]
+ "--"
+ ["First Window" follow-first-window follow-mode]
+ ["Last Window" follow-last-window follow-mode]
+ ["Next Window" follow-next-window follow-mode]
+ ["Previous Window" follow-previous-window follow-mode]
+ "--"
+ ["Recenter" follow-recenter follow-mode]
+ "--"
+ ["Follow mode" follow-mode :style toggle :selected follow-mode]))
+
;;}}}
(defcustom follow-mode-line-text " Follow"
;;;###autoload
(defun turn-on-follow-mode ()
"Turn on Follow mode. Please see the function `follow-mode'."
- (interactive)
(follow-mode 1))
;;;###autoload
(defun turn-off-follow-mode ()
"Turn off Follow mode. Please see the function `follow-mode'."
- (interactive)
(follow-mode -1))
(put 'follow-mode 'permanent-local t)
"Return all windows displaying the same buffer as the TESTWIN.
The list contains only windows displayed in the same frame as TESTWIN.
If TESTWIN is nil the selected window is used."
- (or (and testwin (window-live-p testwin))
+ (or (window-live-p testwin)
(setq testwin (selected-window)))
(let* ((top (frame-first-window (window-frame testwin)))
(win top)
(let ((done nil)
win-start
res)
- ;; Always calculate what happend when no line is displayed in the first
+ ;; Always calculate what happens when no line is displayed in the first
;; window. (The `previous' res is needed below!)
(goto-char guess)
(vertical-motion 0 (car windows))
(setq win-start-end (follow-windows-start-end windows))
(follow-invalidate-cache)
;; When the point ends up in another window. This
- ;; happends when dest is in the beginning of the
+ ;; happens when dest is in the beginning of the
;; file and the selected window is not the first.
- ;; It can also, in rare situations happend when
+ ;; It can also, in rare situations happen when
;; long lines are used and there is a big
;; difference between the width of the windows.
;; (When scrolling one line in a wide window which
;; If the region is visible, make it look good when spanning
;; multiple windows.
(if (or (and (boundp 'mark-active) (symbol-value 'mark-active))
+ ;; The following isn't used in Emacs,
+ ;; since `mark-active' is bound.
(and (fboundp 'region-active-p)
(funcall (symbol-function 'region-active-p))))
(follow-maximize-region
report this using the `report-emacs-bug' function."
(interactive)
(follow-tidy-process-filter-alist)
- (let ((list (process-list)))
- (while list
- (if (eq (follow-call-process-filter (car list)) 'follow-generic-filter)
- (progn
- (follow-call-set-process-filter
- (car list)
- (cdr-safe (assq (car list) follow-process-filter-alist)))
- (setq follow-process-filter-alist
- (delq (assq (car list) follow-process-filter-alist)
- follow-process-filter-alist))))
- (setq list (cdr list))))
+ (dolist (process (process-list))
+ (when (eq (follow-call-process-filter process) 'follow-generic-filter)
+ (follow-call-set-process-filter
+ process
+ (cdr-safe (assq process follow-process-filter-alist)))
+ (setq follow-process-filter-alist
+ (delq (assq process follow-process-filter-alist)
+ follow-process-filter-alist))))
(setq follow-intercept-processes nil))
;;}}}
;; If we're in follow mode, do our stuff. Select a new window and
;; redisplay. (Actually, it is redundant to check `buf', but I
;; feel it's more correct.)
- (if (and buf win (window-live-p win))
+ (if (and buf (window-live-p win))
(progn
(set-buffer buf)
(if (and (boundp 'follow-mode) follow-mode)
(setq windows (follow-all-followers win))
(if (memq orig-window windows)
(progn
- ;; Make sure we're redrawing around the
- ;; selected window.
- ;;
- ;; We must be really careful not to do this
- ;; when we are (indirectly) called by
- ;; `post-command-hook'.
+ ;; Make sure we're redrawing around the
+ ;; selected window.
+ ;;
+ ;; We must be really careful not to do this
+ ;; when we are (indirectly) called by
+ ;; `post-command-hook'.
(select-window orig-window)
(follow-post-command-hook)
(setq orig-window (selected-window)))
;;{{{ The end
(defun follow-unload-function ()
+ "Unload Follow mode library."
+ (easy-menu-remove-item nil '("Tools") "Follow")
(follow-stop-intercept-process-output)
(dolist (group '((before
;; XEmacs
(intern (concat "follow-" (symbol-name fun))))
(ad-update fun))
(error nil))))))
+ ;; continue standard processing
nil)
-(defvar follow-unload-function 'follow-unload-function)
-
;;
;; We're done!
;;