;; This package provides the `view' minor mode documented in the Emacs
;; user's manual.
;; View mode entry and exit is done through the functions view-mode-enter
-;; and view-mode-exit. Use these functions to enter or exit view-mode from
+;; and view-mode-exit. Use these functions to enter or exit view-mode from
;; emacs lisp programs.
-;; We use both view- and View- as prefix for symbols. View- is used as
-;; prefix for commands that have a key binding. view- is used for commands
-;; without key binding. The purpose of this is to make it easier for a
+;; We use both view- and View- as prefix for symbols. View- is used as
+;; prefix for commands that have a key binding. view- is used for commands
+;; without key binding. The purpose of this is to make it easier for a
;; user to use command name completion.
;;; Suggested key bindings:
;;; Code:
-;;;###autoload
-(defvar view-highlight-face 'highlight
- "*The face used for highlighting the match found by View mode search.")
+(defgroup view nil
+ "Peruse file or buffer without editing."
+ :link '(function-link view-mode)
+ :link '(custom-manual "(emacs)Misc File Ops")
+ :group 'wp
+ :group 'editing)
+
+(defcustom view-read-only nil
+ "*Non-nil means buffers visiting files read-only, do it in view mode."
+ :type 'boolean
+ :group 'view)
+
+(defcustom view-highlight-face 'highlight
+ "*The face used for highlighting the match found by View mode search."
+ :type 'face
+ :group 'view)
-;; `view-mode-auto-exit' is replaced by the following global variable which
+;; `view-mode-auto-exit' is replaced by the following option variable which
;; only says if scrolling past buffer end should leave view mode or not, it
;; doesn't say if leaving view mode should restore windows or not. The latter
;; is now controlled by the presence of a value in `view-return-to-alist'.
-;;;###autoload
-(defvar view-scroll-auto-exit nil
+(defcustom view-scroll-auto-exit nil
"*Non-nil means scrolling past the end of buffer exits View mode.
nil means attempting to scroll past the end of the buffer,
-only rings the bell and gives a message on how to leave.")
+only rings the bell and gives a message on how to leave."
+ :type 'boolean
+ :group 'view)
+
+(defcustom view-try-extend-at-buffer-end nil
+ "*Non-nil means try load more of file when reaching end of buffer.
+This variable is mainly intended to be temporarily set to non-nil by
+the F command in view-mode, but you can set it to t if you want the action
+for all scroll commands in view mode."
+ :type 'boolean
+ :group 'view)
+
+(defcustom view-remove-frame-by-deleting nil
+ "*Determine how View mode removes a frame no longer needed.
+If nil, make an icon of the frame. If non-nil, delete the frame."
+ :type 'boolean
+ :group 'view)
+
+(defcustom view-exits-all-viewing-windows nil
+ "*Non-nil means restore all windows used to view buffer.
+Commands that restore windows when finished viewing a buffer, apply to all
+windows that display the buffer and have restore information in
+`view-return-to-alist'.
+If `view-exits-all-viewing-windows' is nil, only the selected window is
+considered for restoring."
+ :type 'boolean
+ :group 'view)
;;;###autoload
-(defvar view-try-extend-at-buffer-end nil
- "*Non-nil means try load more of file when reaching end of buffer.")
-
+(defvar view-mode nil
+ "Non-nil if View mode is enabled.
+Don't change this variable directly, you must change it by one of the
+functions that enable or disable view mode.")
;;;###autoload
-(defvar view-remove-frame-by-deleting nil
- "*Determine how to remove a not needed frame.
-If nil, make an icon of the frame. If non-nil, delete the frame.")
-
-;;;###autoload
-(defvar view-exit-all-windows-at-exit nil
- "*Non-nil means restore all windows displaying buffer.
-Commands that restore windows apply to all windows displaying buffer.
-Buffer is removed from all windows displaying it, by using information in
-`view-return-to-alist' if that is available, otherwise by using
-`replace-buffer-in-windows'.")
-
-(defvar view-mode nil "Non-nil if View mode is enabled.")
(make-variable-buffer-local 'view-mode)
-(defvar view-mode-hook nil
- "Normal hook run when starting to view a buffer or file.")
+(defcustom view-mode-hook nil
+ "Normal hook run when starting to view a buffer or file."
+ :type 'hook
+ :group 'view)
(defvar view-old-buffer-read-only nil)
(make-variable-buffer-local 'view-old-buffer-read-only)
(make-variable-buffer-local 'view-last-regexp) ; Global is better???
(defvar view-return-to-alist nil
- "What to do with selected window and where to go when leaving View mode.
-Added to by view-mode-enter when entering View mode.
-See RETURN-TO-ALIST argument of function `view-mode-exit' for format of
+ "What to do with used windows and where to go when finished viewing buffer.
+This is local in each buffer being viewed.
+It is added to by `view-mode-enter' when starting to view a buffer and
+subtracted from by `view-mode-exit' when finished viewing the buffer.
+
+See RETURN-TO-ALIST argument of function `view-mode-exit' for the format of
`view-return-to-alist'.")
(make-variable-buffer-local 'view-return-to-alist)
(defvar view-exit-action nil
- "\\<view-mode-map>
-nil or a function with one argument (a buffer) called at exit of view mode.
+ "nil or a function with one argument (a buffer) called when finished viewing.
+This is local in each buffer being viewed.
The \\[view-file] and \\[view-file-other-window] commands may set this to
`kill-buffer'.")
(make-variable-buffer-local 'view-exit-action)
+(defvar view-no-disable-on-exit nil
+ "If non-nil, View mode \"exit\" commands don't actually disable View mode.
+Instead, these commands just switch buffers or windows.
+This is set in certain buffers by specialized features such as help commands
+that use View mode automatically.")
+
(defvar view-overlay nil
"Overlay used to display where a search operation found its match.
This is local in each buffer, once it is used.")
(cons '(view-mode " View") minor-mode-alist)))
;; Define keymap inside defvar to make it easier to load changes.
+;; Some redundant "less"-like key bindings below have been commented out.
(defvar view-mode-map
(let ((map (make-sparse-keymap)))
(define-key map "C" 'View-kill-and-leave)
Entry to view-mode runs the normal hook `view-mode-hook'."
(interactive "P")
- (cond
- ((and arg
- (if (> (prefix-numeric-value arg) 0) view-mode (not view-mode)))
- ()) ; Do nothing if already OK.
- (view-mode (view-mode-disable))
- (t (view-mode-enable))))
+ (unless (and arg ; Do nothing if already OK.
+ (if (> (prefix-numeric-value arg) 0) view-mode (not view-mode)))
+ (if view-mode (view-mode-disable)
+ (view-mode-enable))))
(defun view-mode-enable ()
"Turn on View mode."
(defun view-mode-enter (&optional return-to exit-action) "\
Enter View mode and set up exit from view mode depending on optional arguments.
If RETURN-TO is non-nil it is added as an element to the buffer local alist
-view-return-to-alist.
+`view-return-to-alist'.
Save EXIT-ACTION in buffer local variable `view-exit-action'.
It should be either nil or a function that takes a buffer as argument.
-This function will called by `view-mode-exit'.
+This function will be called by `view-mode-exit'.
RETURN-TO is either nil, meaning do nothing when exiting view mode, or
- \(WINDOW OLD-WINDOW . OLD-BUF-INFO).
+it has the format (WINDOW OLD-WINDOW . OLD-BUF-INFO).
WINDOW is a window used for viewing.
OLD-WINDOW is nil or the window to select after viewing.
OLD-BUF-INFO tells what to do with WINDOW when exiting. It is one of:
2) t Delete WINDOW or, if it is the only window, its frame.
3) (OLD-BUFF START POINT) Display buffer OLD-BUFF with displayed text
starting at START and point at POINT in WINDOW.
+4) quit-window Do quit-window in WINDOW.
-See the function `view-mode' for the commands of View mode.
+For list of all View commands, type H or h while viewing.
This function runs the normal hook `view-mode-hook'."
(if return-to
(let ((entry (assq (car return-to) view-return-to-alist)))
(if entry (setcdr entry (cdr return-to))
(setq view-return-to-alist (cons return-to view-return-to-alist)))))
- (if view-mode ; Do nothing if already in view mode.
- nil
- (setq view-exit-action exit-action)
+ (if exit-action (setq view-exit-action exit-action))
+ (unless view-mode ; Do nothing if already in view mode.
(view-mode-enable)
(force-mode-line-update)
(message "%s"
Type \\[help-command] for help, \\[describe-mode] for commands, \\[View-quit] to quit."))))
(defun view-mode-exit (&optional return-to-alist exit-action all-win)
- "Exit view-mode in various ways, depending on optional arguments.
-RETURN-TO-ALIST, EXIT-ACTION and ALL-WIN determine what to do after
-exit.
+ "Exit View mode in various ways, depending on optional arguments.
+RETURN-TO-ALIST, EXIT-ACTION and ALL-WIN determine what to do after exit.
EXIT-ACTION is nil or a function that is called with current buffer as
argument.
-RETURN-TO-ALIST is an alist that for some of the windows displaying the current
-buffer, associate information on what to do with those windows. If ALL-WIN is
-non-nil, then all windows on RETURN-TO-ALIST are restored to their old state.
-If ALL-WIN is nil, then only the selected window is affected (if it is on
-ALL-WIN). Each element has the format (WINDOW OLD-WINDOW . OLD-BUF-INFO)
-where WINDOW is a window displaying the current buffer and OLD-BUF-INFO is
-information on what to do with WINDOW. OLD-BUF-INFO is one of:
+RETURN-TO-ALIST is an alist that for some of the windows displaying the
+current buffer, associate information on what to do with those windows.
+If ALL-WIN or the variable `view-exits-all-viewing-windows' is non-nil,
+then all windows on RETURN-TO-ALIST are restored to their old state.
+Otherwise only the selected window is affected (if it is on RETURN-TO-ALIST).
+
+Elements of RETURN-TO-ALIST have the format (WINDOW OLD-WINDOW . OLD-BUF-INFO).
+WINDOW is a window displaying the current buffer.
+OLD-WINDOW is nil or a window to select after viewing.
+OLD-BUF-INFO is information on what to do with WINDOW and is one of:
1) nil Do nothing.
2) t Delete WINDOW or, if it is the only window, its frame.
3) (OLD-BUF START POINT) Display buffer OLD-BUF with displayed text
starting at START and point at POINT in WINDOW.
+4) quit-window Do quit-window in WINDOW.
+
If one of the WINDOW in RETURN-TO-ALIST is the selected window and the
corresponding OLD-WINDOW is a live window, then select OLD-WINDOW."
+ (setq all-win
+ (and return-to-alist (or all-win view-exits-all-viewing-windows)))
(if view-mode ; Only do something if in view mode.
(let* ((buffer (current-buffer))
window
(sel-old (assq (selected-window) return-to-alist))
- (old-window (or (and sel-old (car (cdr sel-old)))
- (and all-win (selected-window))))
- (alist (if (setq all-win
- (or all-win view-exit-all-windows-at-exit))
- return-to-alist ; Try to restore all windows.
- (and sel-old (list sel-old))))) ; Only selected window.
- (view-mode-disable)
- (setq view-exit-action nil
- view-return-to-alist nil)
+ (alist (cond
+ (all-win ; Try to restore all windows.
+ (append return-to-alist nil)) ; Copy.
+ (sel-old ; Only selected window.
+ (list sel-old))))
+ (old-window (if sel-old (car (cdr sel-old)))))
+ (if all-win ; Follow chains of old-windows.
+ (let ((c (length alist)) a)
+ (while (and (> c 0) ; Safety if mutually refering windows.
+ (or (not (window-live-p old-window))
+ (eq buffer (window-buffer old-window)))
+ (setq a (assq old-window alist)))
+ (setq c (1- c))
+ (setq old-window (car (cdr a))))
+ (if (or (zerop c) (not (window-live-p old-window)))
+ (setq old-window (selected-window)))))
+ (or view-no-disable-on-exit
+ (view-mode-disable))
(while alist ; Restore windows with info.
(if (and (window-live-p (setq window (car (car alist))))
(eq buffer (window-buffer window)))
(set-window-buffer window (car old-buf-info)) ; old-buf
(set-window-start window (car (cdr old-buf-info)))
(set-window-point window (car (cdr (cdr old-buf-info)))))
+ ((eq old-buf-info 'quit-window)
+ (quit-window)) ; Not case 2, do nothing.
((not (eq old-buf-info t)) nil) ; Not case 2, do nothing.
((not (one-window-p t)) (delete-window))
- ((not (eq frame (next-frame))) ; Not the only frame, so
- (if view-remove-frame-by-deleting (delete-frame frame)
- (iconify-frame frame)))))) ; can safely be removed.
+ ((not (eq frame (next-frame)))
+ ;; Not the only frame, so can safely be removed.
+ (if view-remove-frame-by-deleting
+ (delete-frame frame)
+ (iconify-frame frame))))))
+ ;; Altering view-return-to-alist causes trouble when
+ ;; the user deiconifies the frame, then types q again.
+ ;; If we leave view-return-to-alist unchanged, that
+ ;; iconifies the frame again, as expected.
+;;; (setq view-return-to-alist (delete (car alist) view-return-to-alist))
(setq alist (cdr alist)))
- (if (and return-to-alist view-exit-all-windows-at-exit)
- (replace-buffer-in-windows buffer))
(if (window-live-p old-window) ; still existing window
(select-window old-window))
- (if (and exit-action (not (get-buffer-window buffer)))
- (funcall exit-action buffer))
+ (when exit-action
+ (setq view-exit-action nil)
+ (funcall exit-action buffer))
(force-mode-line-update))))
(defun View-exit ()
(interactive)
(view-mode-exit))
+;;;###autoload
(defun View-exit-and-edit ()
"Exit View mode and make the current buffer editable."
(interactive)
- (view-mode-exit)
- (setq buffer-read-only nil))
+ (let ((view-old-buffer-read-only nil))
+ (view-mode-exit)))
(defun View-leave ()
"Quit View mode and maybe switch buffers, but don't kill this buffer."
;; window full.
(if (or (null lines) (zerop (setq lines (prefix-numeric-value lines))))
(setq lines default))
- (if (< lines 0)
- (progn (setq backward (not backward)) (setq lines (- lines))))
+ (when (< lines 0)
+ (setq backward (not backward)) (setq lines (- lines)))
(setq default (view-page-size-default nil)) ; Max scrolled at a time.
(if maxdefault (setq lines (min lines default)))
(cond
(bufname (buffer-name))
(file (buffer-file-name)))
(or (not view-try-extend-at-buffer-end)
- (not file)
+ (null file)
(verify-visited-file-modtime buf)
(not (file-exists-p file))
- (and (buffer-modified-p buf)
- (setq file (file-name-nondirectory file))
- (not (yes-or-no-p
- (format
- "File %s changed on disk. Discard your edits%s? "
- file
- (if (string= bufname file) ""
- (concat " in " bufname))))))
- (progn (revert-buffer t t t)
- (pos-visible-in-window-p (point-max)))))))
+ (when (buffer-modified-p buf)
+ (setq file (file-name-nondirectory file))
+ (not (yes-or-no-p
+ (format
+ "File %s changed on disk. Discard your edits%s? "
+ file
+ (if (string= bufname file) ""
+ (concat " in " bufname))))))
+ (progn
+ (revert-buffer t t t)
+ (pos-visible-in-window-p (point-max)))))))
(defun view-end-message ()
;; Tell that we are at end of buffer.
(goto-char (point-max))
- (message "End of buffer. Type %s to quit viewing."
- (substitute-command-keys
- (if view-scroll-auto-exit "\\[View-scroll-page-forward]"
- "\\[View-quit]"))))
+ (if view-return-to-alist
+ (message "End of buffer. Type %s to quit viewing."
+ (substitute-command-keys
+ (if view-scroll-auto-exit "\\[View-scroll-page-forward]"
+ "\\[View-quit]")))
+ (message "End of buffer")))
(defun View-scroll-page-forward (&optional lines)
"Scroll \"page size\" or prefix LINES lines forward in View mode.
(defun View-scroll-page-forward-set-page-size (&optional lines)
"Scroll forward LINES lines in View mode, setting the \"page size\".
This is the number of lines which \\[View-scroll-page-forward] and
-\\[View-scroll-page-backward] scroll by default. If LINES is omitted or = 0,
-sets \"page size\" to window height and scrolls forward that much, otherwise
-scrolls forward LINES lines and sets \"page size\" to the minimum of window
-height and the absolute value of LINES.
+\\[View-scroll-page-backward] scroll by default.
+If LINES is omitted or = 0, sets \"page size\" to window height and
+scrolls forward that much, otherwise scrolls forward LINES lines and sets
+\"page size\" to the minimum of window height and the absolute value of LINES.
See also `View-scroll-page-forward'."
(interactive "P")
(view-scroll-lines lines nil
(defun View-search-regexp-forward (n regexp)
"Search forward for first (or prefix Nth) occurrence of REGEXP in View mode.
-Displays line found at center of window. REGEXP is remembered for searching
-with \\[View-search-last-regexp-forward] and \\[View-search-last-regexp-backward]. Sets mark at starting position and pushes mark ring.
-Characters @ or ! or combined as @! or !@ are special if entered at the
-beginning of REGEXP. They modify the search rather than become part of pattern
-searched for. @ means start search at the beginning of buffer. ! means search
-for line that not contains match for pattern. If REGEXP only consist of these
-control characters, then an earlier remembered REGEXP is used.
+
+Displays line found at center of window. Sets mark at starting position and
+pushes mark ring.
+
+Characters @ and ! are special at the beginning of REGEXP. They modify
+the search rather than become part of the pattern searched for.
+@ means search all the buffer i.e. start search at the beginning of buffer.
+! means search for a line that contains no match for the pattern.
+If REGEXP is empty or only consist of these control characters, then
+an earlier remembered REGEXP is used, otherwise REGEXP is remembered
+for use by later search commands.
The variable `view-highlight-face' controls the face that is used
for highlighting the match that is found."
(defun View-search-regexp-backward (n regexp)
"Search backward for first (or prefix Nth) occurrence of REGEXP in View mode.
-Displays line found at center of window. REGEXP is remembered for searching
-with \\[View-search-last-regexp-forward] and \\[View-search-last-regexp-backward]. Sets mark at starting position and pushes mark ring.
-Characters @ or ! or combined as @! or !@ are special if entered at the
-beginning of REGEXP. They modify the search rather than become part of pattern
-searched for. @ means start search at the end of buffer. ! means search
-for line that not contains match for pattern. If REGEXP only consist of these
-control characters, then an earlier remembered REGEXP is used.
+
+Displays line found at center of window. Sets mark at starting position and
+pushes mark ring.
+
+Characters @ and ! are special at the beginning of REGEXP. They modify
+the search rather than become part of the pattern searched for.
+@ means search all the buffer i.e. start search at the end of buffer.
+! means search for a line that contains no match for the pattern.
+If REGEXP is empty or only consist of these control characters, then
+an earlier remembered REGEXP is used, otherwise REGEXP is remembered
+for use by later search commands.
The variable `view-highlight-face' controls the face that is used
for highlighting the match that is found."
(view-search (- n) nil))
(defun view-search (times regexp)
- ;; This function does the job for all the view-search commands.
+ ;; This function does the job for all the View-search- commands.
+ ;; Search for the TIMESt match for REGEXP. If TIMES is negative
+ ;; search backwards. If REGEXP is nil use `view-last-regexp'.
+ ;; Charcters "!" and "@" have a special meaning at the beginning of
+ ;; REGEXP and are removed from REGEXP before the search "!" means
+ ;; search for lines with no match for REGEXP. "@" means search in
+ ;; the whole buffer, don't start searching from the present point.
(let (where no end ln)
(cond
((and regexp (> (length regexp) 0)
(setq view-last-regexp (if no (list regexp) regexp)))
((consp view-last-regexp)
(setq regexp (car view-last-regexp))
- (if (not (setq no (not no))) (setq view-last-regexp regexp)))
+ (unless (setq no (not no)) (setq view-last-regexp regexp)))
(view-last-regexp (setq regexp view-last-regexp)
(if no (setq view-last-regexp (list regexp))))
(t (error "No previous View-mode search")))