Mercurial > emacs
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