changeset 18249:cb7e72b9a09d

Make view mode more similar to `less'. Changed documentation for most commands. (view-scroll-auto-exit): New variable, replaces view-mode-auto-exit. (view-mode-auto-exit): Variable deleted. (view-mode): Doesn't only toggle `view-mode', it also calls view-mode-enter or view-mode-exit. (view-buffer, view-buffer-other-window): New argument exit-action. (view-file, view-file-other-window, view-buffer-other-window) (view-buffer, view-mode-enter): Changed method used to restore windows when leaving view mode. (view-mode-exit): New function. (view-return-to-alist): New variable. (view-return-here, view-exit-position): Variables deleted. (view-remove-frame-by-deleting, view-exit-all-windows-at-exit): New option variables. (view-page-size, view-half-page-size): New variables. (view-scroll-size): Var deleted; replaced by the previous two. (view-mode-map): Make the bindings inside defvar. Added new commands and new key bindings. Added view-mode-exit to `change-major-mode-hook' to always leave view mode when changing major mode. (view-file-other-frame, view-buffer-other-frame): New commands. (View-leave, View-kill-and-leave, View-exit, View-exit-and-edit) (View-quit, View-quit-all): new commands for leaving view mode. (view-exit): Function deleted. (View-goto-percent, View-scroll-to-buffer-end): New commands. (view-try-extend-at-buffer-end): New option variable. (View-scroll-page-forward, View-scroll-page-backward) (View-scroll-page-forward-set-page-size) (View-scroll-page-backward-set-page-size, View-scroll-line-forward) (View-scroll-line-backward, View-scroll-half-page-forward) (View-scroll-half-page-backward) (View-revert-buffer-scroll-page-forward): New commands. (View-scroll-lines-forward, View-scroll-lines-backward) (View-scroll-lines-forward-set-scroll-size) (View-scroll-one-more-line): Commands deleted. (view-scroll-lines, view-end-message, view-page-size-default) (view-set-half-page-size-default, view-really-at-end) (view-recenter): New functions. (view-scroll-size): Variable deleted. (View-search-regexp-forward, View-search-regexp-backward) (View-search-last-regexp-forward, View-search-last-regexp-backward) (view-search): ! and @ are special at beginning of regexp. (view-search-no-match-lines): New function.
author Richard M. Stallman <rms@gnu.org>
date Sat, 14 Jun 1997 21:06:09 +0000
parents 4518d1520edb
children 4eabe22131dd
files lisp/view.el
diffstat 1 files changed, 725 insertions(+), 312 deletions(-) [+]
line wrap: on
line diff
--- a/lisp/view.el	Sat Jun 14 18:45:38 1997 +0000
+++ b/lisp/view.el	Sat Jun 14 21:06:09 1997 +0000
@@ -1,6 +1,6 @@
 ;;; view.el --- peruse file or buffer without editing.
 
-;; Copyright (C) 1985, 1989, 1994, 1995 Free Software Foundation, Inc.
+;; Copyright (C) 1985, 1989, 1994, 1995, 1997 Free Software Foundation, Inc.
 
 ;; Author: K. Shane Hartman
 ;; Maintainer: FSF
@@ -26,6 +26,21 @@
 
 ;; 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
+;; 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
+;; user to use command name completion.
+
+;;; Suggested key bindings:
+;;
+;; (define-key ctl-x-4-map "v" 'view-file-other-window)  ; ^x4v
+;; (define-key ctl-x-5-map "v" 'view-file-other-frame)  ; ^x5v
+;;
+;; You could also bind view-file, view-buffer, view-buffer-other-window and
+;; view-buffer-other-frame to keys.
 
 ;;; Code:
 
@@ -33,33 +48,71 @@
 (defvar view-highlight-face 'highlight
    "*The overlay face used for highlighting the match found by View mode search.")
 
+;; `view-mode-auto-exit' is replaced by the following global 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
+  "*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.")
+
+;;;###autoload
+(defvar view-try-extend-at-buffer-end nil
+ "*Non-nil means try load more of file when reaching end of buffer.")
+
+;;;###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-auto-exit nil
-  "Non-nil means scrolling past the end of buffer exits View mode.
-Some commands, such as \\[view-file], set this to t locally;
-the only way to override that is to set it to nil using `view-mode-hook'.")
-
-(make-variable-buffer-local 'view-mode-auto-exit)
+(defvar view-mode-hook nil
+  "Normal hook run when starting to view a buffer or file.")
 
 (defvar view-old-buffer-read-only nil)
 (make-variable-buffer-local 'view-old-buffer-read-only)
+
 (defvar view-old-Helper-return-blurb)
 (make-variable-buffer-local 'view-old-Helper-return-blurb)
 
-(defvar view-scroll-size nil)
-(make-variable-buffer-local 'view-scroll-size)
+(defvar view-page-size nil
+  "Default number of lines to scroll by View page commands.
+If nil then the local value of this is initially set to window size.")
+(make-variable-buffer-local 'view-page-size)
+
+(defvar view-half-page-size nil
+  "Default number of lines to scroll by View half page commands.
+If nil then the local value of this is initially set to half window size.")
+(make-variable-buffer-local 'view-half-page-size)
 
 (defvar view-last-regexp nil)
-(make-variable-buffer-local 'view-last-regexp)
+(make-variable-buffer-local 'view-last-regexp) ; Global is better???
 
-(defvar view-exit-action nil)
+(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
+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.
+The \\[view-file] and \\[view-file-other-window] commands may set this to
+`kill-buffer'.")
 (make-variable-buffer-local 'view-exit-action)
-(defvar view-return-here nil)
-(make-variable-buffer-local 'view-return-here)
-(defvar view-exit-position nil)
-(make-variable-buffer-local 'view-exit-position)
 
 (defvar view-overlay nil
   "Overlay used to display where a search operation found its match.
@@ -70,243 +123,427 @@
     (setq minor-mode-alist
 	  (cons '(view-mode " View") minor-mode-alist)))
 
-(defvar view-mode-map nil)
-(if view-mode-map
-    nil
-  (setq view-mode-map (make-keymap))
-  ;; We used to call suppress-keymap here, but that isn't good in a minor mode.
-  ;; Self-inserting characters will beep anyway, since the buffer is read-only,
-  ;; and we should not interfere with letters that serve as useful commands.
-  (define-key view-mode-map "q" 'view-exit)
-  (define-key view-mode-map "<" 'beginning-of-buffer)
-  (define-key view-mode-map ">" 'end-of-buffer)
-  (define-key view-mode-map "\ev" 'View-scroll-lines-backward)
-  (define-key view-mode-map "\C-v" 'View-scroll-lines-forward)
-  (define-key view-mode-map " " 'View-scroll-lines-forward)
-  (define-key view-mode-map "\C-?" 'View-scroll-lines-backward)
-  (define-key view-mode-map "\n" 'View-scroll-one-more-line)
-  (define-key view-mode-map "\r" 'View-scroll-one-more-line)
-  (define-key view-mode-map "z" 'View-scroll-lines-forward-set-scroll-size)
-  (define-key view-mode-map "g" 'View-goto-line)
-  (define-key view-mode-map "=" 'what-line)
-  (define-key view-mode-map "." 'set-mark-command)
-  (define-key view-mode-map "'" 'View-back-to-mark)
-  (define-key view-mode-map "@" 'View-back-to-mark)  
-  (define-key view-mode-map "x" 'exchange-point-and-mark)
-  (define-key view-mode-map "h" 'describe-mode)
-  (define-key view-mode-map "?" 'describe-mode)
-  (define-key view-mode-map "s" 'isearch-forward)
-  (define-key view-mode-map "r" 'isearch-backward)
-  (define-key view-mode-map "/" 'View-search-regexp-forward)
-  (define-key view-mode-map "\\" 'View-search-regexp-backward)
-  ;; This conflicts with the standard binding of isearch-regexp-forward
-  (define-key view-mode-map "\e\C-s" 'View-search-regexp-forward)
-  (define-key view-mode-map "\e\C-r" 'View-search-regexp-backward)  
-  (define-key view-mode-map "n" 'View-search-last-regexp-forward)
-  (define-key view-mode-map "p" 'View-search-last-regexp-backward)
-  )
+;; Define keymap inside defvar to make it easier to load changes.
+(defvar view-mode-map
+  (let ((map (make-sparse-keymap)))
+    (define-key map "C" 'View-kill-and-leave)
+    (define-key map "c" 'View-leave)
+    (define-key map "Q" 'View-quit-all)
+    (define-key map "E" 'View-exit-and-edit)
+;    (define-key map "v" 'View-exit)
+    (define-key map "e" 'View-exit)
+    (define-key map "q" 'View-quit)
+;    (define-key map "N" 'View-search-last-regexp-backward)
+    (define-key map "p" 'View-search-last-regexp-backward)
+    (define-key map "n" 'View-search-last-regexp-forward)
+;    (define-key map "?" 'View-search-regexp-backward) ; Less does this.
+    (define-key map "\\" 'View-search-regexp-backward)
+    (define-key map "/" 'View-search-regexp-forward)
+    (define-key map "r" 'isearch-backward)
+    (define-key map "s" 'isearch-forward)
+    (define-key map "m" 'point-to-register)
+    (define-key map "'" 'register-to-point)
+    (define-key map "x" 'exchange-point-and-mark)
+    (define-key map "@" 'View-back-to-mark)  
+    (define-key map "." 'set-mark-command)
+    (define-key map "%" 'View-goto-percent)
+;    (define-key map "G" 'View-goto-line-last)
+    (define-key map "g" 'View-goto-line)
+    (define-key map "=" 'what-line)
+    (define-key map "F" 'View-revert-buffer-scroll-page-forward)
+;    (define-key map "k" 'View-scroll-line-backward)
+    (define-key map "y" 'View-scroll-line-backward)
+;    (define-key map "j" 'View-scroll-line-forward)
+    (define-key map "\n" 'View-scroll-line-forward)
+    (define-key map "\r" 'View-scroll-line-forward)
+    (define-key map "u" 'View-scroll-half-page-backward)
+    (define-key map "d" 'View-scroll-half-page-forward)
+    (define-key map "z" 'View-scroll-page-forward-set-page-size)
+    (define-key map "w" 'View-scroll-page-backward-set-page-size)
+;    (define-key map "b" 'View-scroll-page-backward)
+    (define-key map "\C-?" 'View-scroll-page-backward)
+;    (define-key map "f" 'View-scroll-page-forward)
+    (define-key map " " 'View-scroll-page-forward)
+    (define-key map "o" 'View-scroll-to-buffer-end)
+    (define-key map ">" 'end-of-buffer)
+    (define-key map "<" 'beginning-of-buffer)
+    (define-key map "-" 'negative-argument)
+    (define-key map "9" 'digit-argument)
+    (define-key map "8" 'digit-argument)
+    (define-key map "7" 'digit-argument)
+    (define-key map "6" 'digit-argument)
+    (define-key map "5" 'digit-argument)
+    (define-key map "4" 'digit-argument)
+    (define-key map "3" 'digit-argument)
+    (define-key map "2" 'digit-argument)
+    (define-key map "1" 'digit-argument)
+    (define-key map "0" 'digit-argument)
+    (define-key map "H" 'describe-mode)
+    (define-key map "?" 'describe-mode)	; Maybe do as less instead?
+    (define-key map "h" 'describe-mode)
+    map))
 
 (or (assq 'view-mode minor-mode-map-alist)
     (setq minor-mode-map-alist
 	  (cons (cons 'view-mode view-mode-map) minor-mode-map-alist)))
 
+;; Always leave view mode before changing major mode.
+;; This is to guarantee that the buffer-read-only variable is restored.
+(add-hook 'change-major-mode-hook 'view-mode-exit)
+
+;;; Commands that enter or exit view mode.
 
 ;;;###autoload
 (defun view-file (file-name)
   "View FILE in View mode, returning to previous buffer when done.
-The usual Emacs commands are not available; instead,
+Emacs commands editing the buffer contents are not available; instead,
 a special set of commands (mostly letters and punctuation)
 are defined for moving around in the buffer.
 Space scrolls forward, Delete scrolls backward.
-For list of all View commands, type ? or h while viewing.
-
-This command runs the normal hook `view-mode-hook'."
-  (interactive "fView file: ")
-  (let ((old-buf (current-buffer))
-	(had-a-buf (get-file-buffer file-name))
-	(buf-to-view (find-file-noselect file-name)))
-    ;; This used to pass t as second argument,
-    ;; but then the buffer did not show up in the Buffers menu.
-    (switch-to-buffer buf-to-view had-a-buf)
-    (view-mode-enter old-buf
-		     (and (not had-a-buf) (not (buffer-modified-p buf-to-view))
-			  'kill-buffer))))
-
-;;;###autoload
-(defun view-file-other-window (file-name)
-  "View FILE in View mode in other window.
-Return to previous buffer when done.
-The usual Emacs commands are not available; instead,
-a special set of commands (mostly letters and punctuation)
-are defined for moving around in the buffer.
-Space scrolls forward, Delete scrolls backward.
-For list of all View commands, type ? or h while viewing.
+For list of all View commands, type H or h while viewing.
 
 This command runs the normal hook `view-mode-hook'."
   (interactive "fView file: ")
-  (let ((old-arrangement (current-window-configuration))
-	(had-a-buf (get-file-buffer file-name))
-	(buf-to-view (find-file-noselect file-name)))
-    (switch-to-buffer-other-window buf-to-view)
-    (view-mode-enter old-arrangement
-		     (and (not had-a-buf) (not (buffer-modified-p buf-to-view))
-			  'kill-buffer))))
+  (let ((had-a-buf (get-file-buffer file-name)))
+    (view-buffer (find-file-noselect file-name)
+		 (and (not had-a-buf) 'kill-buffer))))
+
+;;;###autoload
+(defun view-file-other-window (file-name)
+  "View FILE in View mode in another window.
+Return that window to its previous buffer when done.
+Emacs commands editing the buffer contents are not available; instead,
+a special set of commands (mostly letters and punctuation)
+are defined for moving around in the buffer.
+Space scrolls forward, Delete scrolls backward.
+For list of all View commands, type H or h while viewing.
+
+This command runs the normal hook `view-mode-hook'."
+  (interactive "fIn other window view file: ")
+  (let ((had-a-buf (get-file-buffer file-name)))
+    (view-buffer-other-window (find-file-noselect file-name) nil
+			      (and (not had-a-buf) 'kill-buffer))))
 
 ;;;###autoload
-(defun view-buffer (buffer-name)
+(defun view-file-other-frame (file-name)
+  "View FILE in View mode in another frame.
+Maybe delete other frame and/or return to previous buffer when done.
+Emacs commands editing the buffer contents are not available; instead,
+a special set of commands (mostly letters and punctuation)
+are defined for moving around in the buffer.
+Space scrolls forward, Delete scrolls backward.
+For list of all View commands, type H or h while viewing.
+
+This command runs the normal hook `view-mode-hook'."
+  (interactive "fIn other frame view file: ")
+  (let ((had-a-buf (get-file-buffer file-name)))
+    (view-buffer-other-frame (find-file-noselect file-name) nil
+			     (and (not had-a-buf) 'kill-buffer))))
+
+
+;;;###autoload
+(defun view-buffer (buffer-name &optional exit-action)
   "View BUFFER in View mode, returning to previous buffer when done.
-The usual Emacs commands are not available; instead,
+Emacs commands editing the buffer contents are not available; instead,
 a special set of commands (mostly letters and punctuation)
 are defined for moving around in the buffer.
 Space scrolls forward, Delete scrolls backward.
-For list of all View commands, type ? or h while viewing.
+For list of all View commands, type H or h while viewing.
+
+This command runs the normal hook `view-mode-hook'.
 
-This command runs the normal hook `view-mode-hook'."
+Optional argument EXIT-ACTION is either nil or a function with buffer as
+argument. This function is called when finished viewing buffer.
+Use this argument instead of explicitly setting `view-exit-action'."
+
   (interactive "bView buffer: ")
-  (let ((old-buf (current-buffer)))
-    (switch-to-buffer buffer-name t)
-    (view-mode-enter old-buf nil)))
+  (let ((undo-window (list (window-buffer) (window-start) (window-point))))
+    (switch-to-buffer buffer-name)
+    (view-mode-enter (cons (selected-window) (cons nil undo-window))
+		     exit-action)))
 
 ;;;###autoload
-(defun view-buffer-other-window (buffer-name not-return)
+(defun view-buffer-other-window
+  (buffer-name &optional not-return exit-action)
   "View BUFFER in View mode in another window.
-Return to previous buffer when done, unless NOT-RETURN is non-nil.
-
-The usual Emacs commands are not available in View mode; instead,
+Return to previous buffer when done, unless optional NOT-RETURN is non-nil.
+Emacs commands editing the buffer contents are not available; instead,
 a special set of commands (mostly letters and punctuation)
 are defined for moving around in the buffer.
 Space scrolls forward, Delete scrolls backward.
-For list of all View commands, type ? or h while viewing.
+For list of all View commands, type H or h while viewing.
+
+This command runs the normal hook `view-mode-hook'.
+
+Optional argument EXIT-ACTION is either nil or a function with buffer as
+argument. This function is called when finished viewing buffer.
+Use this argument instead of explicitly setting `view-exit-action'."
+  (interactive "bIn other window view buffer:\nP")
+  (let* ((win				; This window will be selected by
+	  (get-lru-window))		; switch-to-buffer-other-window below.
+	 (return-to
+	  (and (not not-return)
+	       (cons (selected-window)
+		     (if (eq win (selected-window))
+			 t			; Has to make new window.
+		       (list 
+			(window-buffer win)	; Other windows old buffer.
+			(window-start win)
+			(window-point win)))))))
+    (switch-to-buffer-other-window buffer-name)
+    (view-mode-enter (and return-to (cons (selected-window) return-to))
+		     exit-action)))
 
-This command runs the normal hook `view-mode-hook'."
-  (interactive "bView buffer:\nP")
-  (let ((return-to (and not-return (current-window-configuration))))
-    (switch-to-buffer-other-window buffer-name)
-    (view-mode-enter return-to)))
+;;;###autoload
+(defun view-buffer-other-frame
+  (buffer-name &optional not-return exit-action)
+  "View BUFFER in View mode in another frame.
+Return to previous buffer when done, unless optional NOT-RETURN is non-nil.
+Emacs commands editing the buffer contents are not available; instead,
+a special set of commands (mostly letters and punctuation)
+are defined for moving around in the buffer.
+Space scrolls forward, Delete scrolls backward.
+For list of all View commands, type H or h while viewing.
+
+This command runs the normal hook `view-mode-hook'.
+
+Optional argument EXIT-ACTION is either nil or a function with buffer as
+argument. This function is called when finished viewing buffer.
+Use this argument instead of explicitly setting `view-exit-action'."
+  (interactive "bView buffer in other frame: \nP")
+  (let ((return-to
+	 (and (not not-return) (cons (selected-window) t)))) ; Old window.
+    (switch-to-buffer-other-frame buffer-name)
+    (view-mode-enter (and return-to (cons (selected-window) return-to))
+		     exit-action)))
 
 ;;;###autoload
 (defun view-mode (&optional arg)
-  "Toggle View mode.
-With a prefix argument, turn View mode on if the argument is >= zero
-and off if it is not.
+  ;; In the following documentation string we have to use some explicit key
+  ;; bindings instead of using the \\[] construction. The reason for this
+  ;; is that most commands have more than one key binding.
+  "Toggle View mode, a minor mode for viewing text but not editing it.
+With arg, turn View mode on iff arg is positive.
 
-If you use this function to turn on View mode, then subsequently
-\"exiting\" View mode does nothing except turn View mode off.  The
-other way to turn View mode on is by calling `view-mode-enter';
-that is what Lisp programs usually use.
-
-Letters do not insert themselves.  Instead these commands are provided.
-Most commands take prefix arguments.  Commands dealing with lines
-default to \"scroll size\" lines (initially size of window).
-Search commands default to a repeat count of one.
+Emacs commands that do not change the buffer contents are available as usual.
+Kill commands insert text in kill buffers but do not delete. Other commands
+\(among them most letters and punctuation) beep and tell that the buffer is
+read-only.
+\\<view-mode-map>
+The following additional commands are provided.  Most commands take prefix
+arguments.  Page commands default to \"page size\" lines which is almost a whole
+window full, or number of lines set by \\[View-scroll-page-forward-set-page-size] or \\[View-scroll-page-backward-set-page-size].  Half page commands default to
+and set \"half page size\" lines which initially is half a window full.  Search
+commands default to a repeat count of one.
 
-M-< or <	move to beginning of buffer.
-M-> or >	move to end of buffer.
-C-v or Space	scroll forward lines.
-M-v or DEL	scroll backward lines.
-CR or LF	scroll forward one line (backward with prefix argument).
-z		like Space except set number of lines for further
-		   scrolling commands to scroll by.
-C-u and Digits	provide prefix arguments.  `-' denotes negative argument.
-=		prints the current line number.
-g		goes to line given by prefix argument.
-/ or M-C-s	searches forward for regular expression
-\\ or M-C-r	searches backward for regular expression.
-n		searches forward for last regular expression.
-p		searches backward for last regular expression.
-C-@ or .	set the mark.
-x		exchanges point and mark.
-C-s or s	do forward incremental search.
-C-r or r	do reverse incremental search.
-@ or '		return to mark and pops mark ring.
-		  Mark ring is pushed at start of every
-		  successful search and when jump to line to occurs.
-		  The mark is set on jump to buffer start or end.
-? or h		provide help message (list of commands).
-\\[help-command]		provides help (list of commands or description of a command).
-C-n		moves down lines vertically.
-C-p		moves upward lines vertically.
-C-l		recenters the screen.
-q		exit view-mode and return to previous buffer."
+H, h, ?	 This message.
+Digits	provide prefix arguments.
+\\[negative-argument]	negative prefix argument.
+\\[beginning-of-buffer]	move to the beginning of buffer.
+>	move to the end of buffer.
+\\[View-scroll-to-buffer-end]	scroll so that buffer end is at last line of window.
+SPC	scroll forward prefix (default \"page size\") lines.
+DEL	scroll backward prefix (default \"page size\") lines.
+\\[View-scroll-page-forward-set-page-size]	like  \\[View-scroll-page-forward]  except prefix sets \"page size\".
+\\[View-scroll-page-backward-set-page-size]	like  \\[View-scroll-page-backward]  except prefix sets \"page size\".
+\\[View-scroll-half-page-forward]	scroll forward (and if prefix set) \"half page size\" lines.
+\\[View-scroll-half-page-backward]	scroll backward (and if prefix set) \"half page size\" lines.
+RET, LFD  scroll forward prefix (default one) line(s).
+y	scroll backward prefix (default one) line(s).
+\\[View-revert-buffer-scroll-page-forward]	revert-buffer if necessary and scroll forward.
+	  Use this to view a changing file.
+\\[what-line]	prints the current line number.
+\\[View-goto-percent]	goes prefix argument (default 100) percent into buffer.
+\\[View-goto-line]	goes to line given by prefix argument (default first line).
+.	set the mark.
+x	exchanges point and mark.
+\\[View-back-to-mark]	return to mark and pops mark ring.
+	  Mark ring is pushed at start of every successful search and when
+	  jump to line occurs. The mark is set on jump to buffer start or end.
+\\[point-to-register]	save current position in character register.
+'	go to position saved in character register.
+s	do forward incremental search.
+r	do reverse incremental search.
+\\[View-search-regexp-forward]	searches forward for regular expression, starting after current page.
+	  ! and @ have a special meaning at the beginning of the regexp.
+	  ! means search for a line with no match for regexp. @ means start
+	  search at beginning (end for backward search) of buffer.
+\\	searches backward for regular expression, starting before current page.
+\\[View-search-last-regexp-forward]	searches forward for last regular expression.
+p	searches backward for last regular expression.
+\\[View-quit]	quit View mode, trying to restore window and buffer to previous state.
+	  \\[View-quit] is the normal way to leave view mode.
+\\[View-exit]	exit View mode but stay in current buffer. Use this if you started
+	  viewing a buffer (file) and find out you want to edit it.
+\\[View-exit-and-edit]	exit View mode and make the current buffer editable.
+\\[View-quit-all]	quit View mode, trying to restore windows and buffer to previous state.
+\\[View-leave]	quit View mode and maybe switch buffers, but don't kill this buffer.
+\\[View-kill-and-leave]	quit View mode, kill current buffer and go back to other buffer.
+
+The effect of \\[View-leave] , \\[View-quit] and \\[View-kill-and-leave] depends on how view-mode was entered. If it was
+entered by view-file, view-file-other-window or view-file-other-frame (\\[view-file],
+\\[view-file-other-window], \\[view-file-other-frame] or the dired mode v command), then \\[View-quit] will try to kill the
+current buffer. If view-mode was entered from another buffer as is done by
+View-buffer, View-buffer-other-window, View-buffer-other frame, View-file,
+View-file-other-window or View-file-other-frame then \\[view-leave] , \\[view-quit] and \\[view-kill-and-leave] will return
+to that buffer.
+
+Entry to view-mode runs the normal hook `view-mode-hook'."
   (interactive "P")
-  (setq view-mode
-	(if (null arg)
-	    (not view-mode)
-	  (> (prefix-numeric-value arg) 0)))
-  (force-mode-line-update))
+  (cond
+   ((and arg
+	 (if (> (prefix-numeric-value arg) 0) view-mode (not view-mode)))
+    ())					; Do nothing if already OK.
+   (view-mode (view-mode-exit))
+   (t (view-mode-enter))))
 
-(defun view-mode-enter (&optional prev-buffer action)
-  "Enter View mode, a Minor mode for viewing text but not editing it.
-See the function `view-mode' for more details.
+;;;###autoload
+(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.
+Save EXIT-ACTION in buffer local variable view-exit-action.
+RETURN-TO is either nil, meaning do nothing when exiting view mode, or
+\(<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:
+1) nil       Do nothing.
+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>.
+EXIT-ACTION is either nil or a function with buffer as argument. This function
+is called by view-mode-exit.
 
-This function runs the normal hook `view-mode-hook'.
+See the function `view-mode' for details of view mode.
 
-\\{view-mode-map}"
-;  Not interactive because dangerous things happen
-;  if you call it without passing a buffer as argument
-;  and they are not easy to fix.
-;  (interactive)
-  (setq view-old-buffer-read-only buffer-read-only)
-  (setq view-old-Helper-return-blurb
-	(and (boundp 'Helper-return-blurb) Helper-return-blurb))
-
-  ;; Enable view-exit to make use of the data we just saved
-  ;; and to perform the exit action.
-  (setq view-mode-auto-exit t)
-
-  (setq buffer-read-only t)
-  (setq view-mode t)
-  (setq Helper-return-blurb
-	(format "continue viewing %s"
-		(if (buffer-file-name)
-		    (file-name-nondirectory (buffer-file-name))
-		    (buffer-name))))
-
-  (setq view-exit-action action)
-  (setq view-return-here prev-buffer)
-  (setq view-exit-position (point-marker))
-
-  (beginning-of-line)
-  (setq goal-column nil)
+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.
+    (setq view-mode t
+	  view-page-size (view-page-size-default view-page-size)
+	  view-half-page-size (or view-half-page-size (/ (view-window-size) 2))
+	  view-old-buffer-read-only buffer-read-only
+	  buffer-read-only t
+	  view-old-Helper-return-blurb (and (boundp 'Helper-return-blurb)
+					    Helper-return-blurb)
+	  Helper-return-blurb
+	  (format "continue viewing %s"
+		  (if (buffer-file-name)
+		      (file-name-nondirectory (buffer-file-name))
+		    (buffer-name)))
+	  view-exit-action exit-action)
+    (run-hooks 'view-mode-hook)
+    (force-mode-line-update)
+    (message "%s"
+	     (substitute-command-keys "\
+Type \\[help-command] for help, \\[describe-mode] for commands, \\[View-quit] to quit."))))
 
-  (run-hooks 'view-mode-hook)
-  (message "%s"
-     (substitute-command-keys
-      "Type \\[help-command] for help, \\[describe-mode] for commands, \\[view-exit] to quit.")))
-
-(defun view-exit ()
-  "Exit from view-mode.
-If you viewed an existing buffer, that buffer returns to its previous mode.
-If you viewed a file that was not present in Emacs, its buffer is killed."
-  (interactive)
-  (setq view-mode nil)
-  (and view-overlay (delete-overlay view-overlay))
-  (force-mode-line-update)
-  (cond (view-mode-auto-exit
-	 (setq buffer-read-only view-old-buffer-read-only)
-	 (setq view-mode-auto-exit nil)
+(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-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:
+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>.
+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>."
+  (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.
+	(and view-overlay (delete-overlay view-overlay))
+	(setq view-mode nil
+	      view-exit-action nil
+	      view-return-to-alist nil
+	      Helper-return-blurb view-old-Helper-return-blurb
+	      buffer-read-only view-old-buffer-read-only)
+	(while alist			; Restore windows with info.
+	  (if (and (window-live-p (setq window (car (car alist))))
+		   (eq buffer (window-buffer window)))
+	      (let ((frame (window-frame window))
+		    (old-buf-info (cdr (cdr (car alist)))))
+		(if all-win (select-window window))
+		(cond
+		 ((and (consp old-buf-info) ; Case 3.
+		       (buffer-live-p (car old-buf-info)))
+		  (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)))))
+		 ((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.
+	  (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))
+	(force-mode-line-update))))
 
-	 (goto-char view-exit-position)
-	 (set-marker view-exit-position nil)
+(defun View-exit ()
+  "Exit View mode but stay in current buffer."
+  (interactive)
+  (view-mode-exit))
+
+(defun View-exit-and-edit ()
+  "Exit View mode and make the current buffer editable."
+  (interactive)
+  (view-mode-exit)
+  (setq buffer-read-only nil))
+
+(defun View-leave ()
+  "Quit View mode and maybe switch buffers, but don't kill this buffer."
+  (interactive)
+  (view-mode-exit view-return-to-alist))
 
-	 ;; Now do something to the buffer that we were viewing
-	 ;; (such as kill it).
-	 (let ((viewed-buffer (current-buffer))
-	       (action view-exit-action))
-	   (cond
-	    ((bufferp view-return-here)
-	     (switch-to-buffer view-return-here))
-	    ((window-configuration-p view-return-here)
-	     (set-window-configuration view-return-here)))
-	   (if action (funcall action viewed-buffer))))))
+(defun View-quit ()
+  "Quit View mode, trying to restore window and buffer to previous state.
+Maybe kill current buffer. Try to restore selected window to previous state
+and go to previous buffer or window."
+  (interactive)
+  (view-mode-exit view-return-to-alist view-exit-action))
 
-(defun view-window-size () (1- (window-height)))
+(defun View-quit-all ()
+  "Quit View mode, trying to restore all windows and buffer to previous state.
+Maybe kill current buffer. Try to restore all windows viewing buffer to
+previous state and go to previous buffer or window."
+  (interactive)
+  (view-mode-exit view-return-to-alist view-exit-action t))
 
-(defun view-scroll-size ()
-  (min (view-window-size) (or view-scroll-size (view-window-size))))
+(defun View-kill-and-leave ()
+  "Quit View mode, kill current buffer and return to previous buffer."
+  (interactive)
+  (view-mode-exit view-return-to-alist (or view-exit-action 'kill-buffer) t))
+
 
-(defvar view-mode-hook nil
-  "Normal hook run when starting to view a buffer or file.")
+;;; Some help routines.
+
+(defun view-window-size ()
+  ;; Window height excluding mode line.
+  (1- (window-height)))
 
 ;(defun view-last-command (&optional who what)
 ;  (setq view-last-command-entry this-command)
@@ -321,117 +558,203 @@
 ;      (funcall view-last-command view-last-command-argument))
 ;  (setq this-command view-last-command-entry))
 
-(defun View-goto-line (line)
-  "Move to line LINE in View mode.
-Display is centered at LINE.  Sets mark at starting position and pushes
-mark ring."
+(defun view-recenter ()
+  ;; Center point in window.
+  (recenter (/ (view-window-size) 2)))
+
+(defun view-page-size-default (lines)
+  ;; Get page size.
+  (let ((default (- (view-window-size) next-screen-context-lines)))
+    (if (or (null lines) (zerop (setq lines (prefix-numeric-value lines))))
+	default
+      (min (abs lines) default))))
+
+(defun view-set-half-page-size-default (lines)
+  ;; Get and maybe set half page size.
+  (if (not lines) view-half-page-size
+    (setq view-half-page-size
+	  (if (zerop (setq lines (prefix-numeric-value lines)))
+	      (/ (view-window-size) 2)
+	    (view-page-size-default lines)))))
+
+
+;;; Commands for moving around in the buffer.
+
+(defun View-goto-percent (&optional percent)
+  "Move to end (or prefix PERCENT) of buffer in View mode.
+Display is centered at point.
+Sets mark at starting position and pushes mark ring."
+  (interactive "P")
+  (push-mark)
+  (goto-char
+   (if percent
+       (+ (point-min)
+	  (floor (* (- (point-max) (point-min)) 0.01
+		    (max 0 (min 100 (prefix-numeric-value percent))))))
+     (point-max)))
+  (view-recenter))
+
+;(defun View-goto-line-last (&optional line)
+;"Move to last (or prefix LINE) line in View mode.
+;Display is centered at LINE.
+;Sets mark at starting position and pushes mark ring."
+;  (interactive "P")
+;  (push-mark)
+;  (if line (goto-line (prefix-numeric-value line))
+;    (goto-char (point-max))
+;    (beginning-of-line))
+;  (view-recenter))
+  
+(defun View-goto-line (&optional line)
+  "Move to first (or prefix LINE) line in View mode.
+Display is centered at LINE.
+Sets mark at starting position and pushes mark ring."
   (interactive "p")
   (push-mark)
   (goto-line line)
-  (recenter (/ (view-window-size) 2)))
+  (view-recenter))
+
+(defun View-scroll-to-buffer-end ()
+  "Scroll backward or forward so that buffer end is at last line of window."
+  (interactive)
+  (let ((p (if (pos-visible-in-window-p (point-max)) (point))))
+    (goto-char (point-max))
+    (recenter -1)
+    (and p (goto-char p))))
 
-(defun View-scroll-lines-forward (&optional lines)
-  "Scroll forward in View mode, or exit if end of text is visible.
-No arg means whole window full, or number of lines set by \\[View-scroll-lines-forward-set-scroll-size].
-Arg is number of lines to scroll."
-  (interactive "P")
-  (setq lines
-	(if lines (prefix-numeric-value lines)
-	  (view-scroll-size)))
-  (if (and (pos-visible-in-window-p (point-max))
-	   ;; Allow scrolling backward at the end of the buffer.
-	   (> lines 0)
-	   view-mode-auto-exit)
-      (view-exit)
-    ;; (view-last-command 'View-scroll-lines-forward lines)
-    (if (>= lines (view-window-size))
-	(scroll-up nil)
-      (if (>= (- lines) (view-window-size))
-	  (scroll-down nil)
-	(scroll-up lines)))
-    (cond ((pos-visible-in-window-p (point-max))
-	   (goto-char (point-max))
-	   (message "%s"
-		    (substitute-command-keys
-		     "End.  Type \\[view-exit] to quit viewing."))))
-    (move-to-window-line -1)
-    (beginning-of-line)))
+(defun view-scroll-lines (lines backward default maxdefault)
+  ;; This function does the job for all the scrolling commands.
+  ;; Scroll forward LINES lines. If BACKWARD is true scroll backwards.
+  ;; If LINES is negative scroll in the other direction. If LINES is 0 or nil,
+  ;; scroll DEFAULT lines. If MAXDEFAULT is true then scroll no more than a
+  ;; 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))))
+  (setq default (view-page-size-default nil)) ; Max scrolled at a time.
+  (if maxdefault (setq lines (min lines default)))
+  (cond
+   (backward (scroll-down lines))
+   ((view-really-at-end)
+    (if view-scroll-auto-exit (View-quit)
+      (ding)
+      (view-end-message)))
+   (t (while (> lines default)
+	(scroll-up default)
+	(setq lines (- lines default))
+	(if (view-really-at-end) (setq lines 0)))
+      (scroll-up lines)
+      (if (view-really-at-end) (view-end-message))
+      (move-to-window-line -1)
+      (beginning-of-line))))
 
-(defun View-scroll-lines-forward-set-scroll-size (&optional lines)
-  "Scroll forward LINES lines in View mode, setting the \"scroll size\".
-This is the number of lines which \\[View-scroll-lines-forward] and \\[View-scroll-lines-backward] scroll by default.
-The absolute value of LINES is used, so this command can be used to scroll
-backwards (but \"scroll size\" is always positive).  If LINES is greater than
-window height or omitted, then window height is assumed.  If LINES is less
-than window height then scrolling context is provided from previous screen."
-  (interactive "P")
-  (if (not lines)
-      (setq view-scroll-size (view-window-size))
-    (setq lines (prefix-numeric-value lines))
-    (setq view-scroll-size
-	  (min (if (> lines 0) lines (- lines)) (view-window-size))))
-  (View-scroll-lines-forward lines))
+(defun view-really-at-end ()
+  ;; Return true if buffer end visible. Maybe revert buffer and test.
+  (and (pos-visible-in-window-p (point-max))
+       (let ((buf (current-buffer))
+	     (bufname (buffer-name))
+	     (file (buffer-file-name)))
+	 (or (not view-try-extend-at-buffer-end)
+	     (not 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)))))))
 
-(defun View-scroll-one-more-line (&optional arg)
-  "Scroll one more line up in View mode.
-With ARG scroll one line down."
-  (interactive "P")
-  (View-scroll-lines-forward (if (not arg) 1 -1)))
+(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]"))))
 
-(defun View-scroll-lines-backward (&optional lines)
-  "Scroll backward in View mode.
-No arg means whole window full, or number of lines set by \\[View-scroll-lines-forward-set-scroll-size].
-Arg is number of lines to scroll."
+(defun View-scroll-page-forward (&optional lines)
+  "Scroll \"page size\" or prefix LINES lines forward in View mode.
+This will exit if end of text is visible and view-scroll-auto-exit is non-nil.
+\"page size\" is whole window full, or number of lines set by
+\\[View-scroll-page-forward-set-page-size] or
+\\[View-scroll-page-backward-set-page-size].
+If LINES is more than a window-full, only the last window-full is shown."
   (interactive "P")
-  (View-scroll-lines-forward (if lines
-				 (- (prefix-numeric-value lines))
-			       (- (view-scroll-size)))))
+  (view-scroll-lines lines nil view-page-size nil))
+
+(defun View-scroll-page-backward (&optional lines) 
+  "Scroll \"page size\" or prefix LINES lines backward in View mode.
+See further View-scroll-page-forward."
+  (interactive "P")
+  (view-scroll-lines lines t view-page-size nil))
   
-(defun View-search-regexp-forward (n regexp)
-  "Search forward for Nth occurrence of REGEXP.
-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.
+(defun View-scroll-page-forward-set-page-size (&optional lines)
+  "Scroll forward prefix 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.
+See further View-scroll-page-forward."
+  (interactive "P")
+  (view-scroll-lines lines nil
+		     (setq view-page-size (view-page-size-default lines))
+		     nil))
 
-The variable `view-highlight-face' controls the face that is used
-for highlighting the match that is found."
-  (interactive "p\nsSearch forward (regexp): ")
-;;;(view-last-command 'View-search-last-regexp-forward n)
-  (view-search n (if (equal regexp "") view-last-regexp regexp)))
-
-(defun View-search-regexp-backward (n regexp)
-  "Search backward from window start for Nth instance of REGEXP.
-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.
+(defun View-scroll-page-backward-set-page-size (&optional lines)
+  "Scroll backward prefix LINES lines in View mode, setting the \"page size\".
+See further View-scroll-page-forward-set-page-size."
+  (interactive "P")
+  (view-scroll-lines lines t
+		     (setq view-page-size (view-page-size-default lines))
+		     nil))
 
-The variable `view-highlight-face' controls the face that is used
-for highlighting the match that is found."
-  (interactive "p\nsSearch backward (regexp): ")
-  (View-search-regexp-forward (- n)
-			      (if (equal regexp "") view-last-regexp regexp)))
+(defun View-scroll-line-forward (&optional lines)
+  "Scroll forward one line (or prefix LINES lines) in View mode.
+See further View-scroll-page-forward, but note that scrolling is limited
+to minimum of LINES and one window-full."
+  (interactive "P")
+  (view-scroll-lines lines nil 1 t))
 
-(defun View-search-last-regexp-forward (n)
-  "Search forward from window end for Nth instance of last regexp.
-Displays line found at center of window.  Sets mark at starting position
-and pushes mark ring.
+(defun View-scroll-line-backward (&optional lines)
+  "Scroll backward one line (or prefix LINES lines) in View mode.
+See further View-scroll-line-forward."
+  (interactive "P")
+  (view-scroll-lines lines t 1 t))
 
-The variable `view-highlight-face' controls the face that is used
-for highlighting the match that is found."
-  (interactive "p")
-  (if view-last-regexp
-      (View-search-regexp-forward n view-last-regexp)
-    (error "No previous View-mode search")))
+(defun View-scroll-half-page-forward (&optional lines)
+  "Scroll forward \"half page size\" (or prefix LINES) lines in View mode.
+If LINES is not omitted, the \"half page size\" is set to the minimum of
+window height and the absolute value of LINES.
+LINES=0 resets \"half page size\" to half window height."
+  (interactive "P")
+  (view-scroll-lines lines nil (view-set-half-page-size-default lines) t))
+
+(defun View-scroll-half-page-backward (&optional lines)
+  "Scroll backward \"half page size\" (or prefix LINES) lines in View mode.
+See further View-scroll-half-page-forward."
+  (interactive "P")
+  (view-scroll-lines lines t (view-set-half-page-size-default lines) t))
 
-(defun View-search-last-regexp-backward (n)
-  "Search backward from window start for Nth instance of last regexp.
-Displays line found at center of window.  Sets mark at starting position and
-pushes mark ring.
-
-The variable `view-highlight-face' controls the face that is used
-for highlighting the match that is found."
-  (interactive "p")
-  (if view-last-regexp
-      (View-search-regexp-backward n view-last-regexp)
-    (error "No previous View-mode search")))
+(defun View-revert-buffer-scroll-page-forward (&optional lines)  "\
+Scroll \"page size\" or prefix LINES lines forward reverting buffer if needed.
+If buffer has not been changed and the corresponding file is newer, first
+revert the buffer, then scroll.
+This command is useful if you are viewing a changing file.
+\"page size\" is whole window full, or number of lines set by
+\\[View-scroll-page-forward-set-page-size] or
+\\[View-scroll-page-backward-set-page-size].
+If LINES is more than a window-full, only the last window-full is shown."
+  (interactive "P")
+  (let ((view-mode-auto-exit nil)
+	(view-try-extend-at-buffer-end t))
+    (view-scroll-lines lines nil view-page-size nil)))
 
 (defun View-back-to-mark (&optional ignore)
   "Return to last mark set in View mode, else beginning of file.
@@ -440,14 +763,82 @@
   (interactive)
   (goto-char (or (mark t) (point-min)))
   (pop-mark)
-  (recenter (/ (view-window-size) 2)))
+  (view-recenter))
 	     
+(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.
+
+The variable `view-highlight-face' controls the face that is used
+for highlighting the match that is found."
+  (interactive "p\nsSearch forward (regexp): ") 
+  (view-search n regexp))
+
+(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.
+
+The variable `view-highlight-face' controls the face that is used
+for highlighting the match that is found."
+  (interactive "p\nsSearch backward (regexp): ")
+  (view-search (- n) regexp))
+
+(defun View-search-last-regexp-forward (n) "\
+Search forward for first (or prefix Nth) instance of last regexp in View mode.
+Displays line found at center of window.  Sets mark at starting position and
+pushes mark ring.
+
+The variable `view-highlight-face' controls the face that is used
+for highlighting the match that is found."
+  (interactive "p")
+  (view-search n nil))
+
+(defun View-search-last-regexp-backward (n) "\
+Search backward for first (or prefix Nth) instance of last regexp in View mode.
+Displays line found at center of window.  Sets mark at starting position and
+pushes mark ring.
+
+The variable `view-highlight-face' controls the face that is used
+for highlighting the match that is found."
+  (interactive "p")
+  (view-search (- n) nil))
+
 (defun view-search (times regexp)
-  (setq view-last-regexp regexp)
-  (let (where)
+  ;; This function does the job for all the view-search commands.
+  (let (where no end ln)
+    (cond
+     ((and regexp (> (length regexp) 0)
+	   (or (not (memq (string-to-char regexp) '(?! ?@)))
+	       (progn
+		 (if (member (substring regexp 0 2) '("!@" "@!"))
+		     (setq end t no t ln 2)
+		   (setq no (not (setq end (eq ?@ (string-to-char regexp))))
+			 ln 1))
+		 (> (length (setq regexp (substring regexp ln))) 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)))
+     (view-last-regexp (setq regexp view-last-regexp)
+		       (if no (setq view-last-regexp (list regexp))))
+     (t (error "No previous View-mode search")))
     (save-excursion
-      (move-to-window-line (if (< times 0) 0 -1))
-      (if (re-search-forward regexp nil t times)
+      (if end (goto-char (if (< times 0) (point-max) (point-min)))
+	(move-to-window-line (if (< times 0) 0 -1)))
+      (if (if no (view-search-no-match-lines times regexp)
+	    (re-search-forward regexp nil t times))
 	  (setq where (point))))
     (if where
 	(progn
@@ -459,11 +850,33 @@
 		  (make-overlay (match-beginning 0) (match-end 0))))
 	  (overlay-put view-overlay 'face view-highlight-face)
 	  (beginning-of-line)
-	  (recenter (/ (view-window-size) 2)))
-      (message "Can't find occurrence %d of %s" times regexp)
+	  (view-recenter))
+      (message "Can't find occurrence %d of %s%s"
+	       times (if no "no " "") regexp)
       (sit-for 4))))
 
-
+(defun view-search-no-match-lines (times regexp)
+  ;; Search for the TIMESt occurrence of line with no match for REGEXP.
+  (let ((back (and (< times 0) (setq times (- times)) -1))
+	n)
+    (while (> times 0)
+      (save-excursion (beginning-of-line (if back (- times) (1+ times)))
+		      (setq n (point)))
+      (setq times
+	    (cond
+	     ((< (count-lines (point) n) times) -1) ; Not enough lines.
+	     ((or (null (re-search-forward regexp nil t back))
+		  (if back (and (< (match-end 0) n)
+				(> (count-lines (match-end 0) n) 1))
+		    (and (< n (match-beginning 0))
+			 (> (count-lines n (match-beginning 0)) 1))))
+	      0)			; No match within lines.
+	     (back (count-lines (max n (match-beginning 0)) (match-end 0)))
+	     (t (count-lines (match-beginning 0) (min n (match-end 0))))))
+      (goto-char n))
+    (and (zerop times) (looking-at "^.*$"))))
+
+
 (provide 'view)
 
 ;;; view.el ends here