(view-remove-frame-by-deleting): Change default value to t.
[bpt/emacs.git] / lisp / view.el
CommitLineData
e8af40ee 1;;; view.el --- peruse file or buffer without editing
d501f516 2
0d30b337 3;; Copyright (C) 1985, 1989, 1994, 1995, 1997, 2000, 2001, 2002,
d7a0267c 4;; 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
eea8d4ef 5
e5167999 6;; Author: K. Shane Hartman
1036798c 7;; Maintainer: Inge Frick <inge@nada.kth.se>
284b3043 8;; Keywords: files
e6211d55
RS
9
10;; This file is part of GNU Emacs.
11
12;; GNU Emacs is free software; you can redistribute it and/or modify
13;; it under the terms of the GNU General Public License as published by
b4aa6026 14;; the Free Software Foundation; either version 3, or (at your option)
e6211d55
RS
15;; any later version.
16
17;; GNU Emacs is distributed in the hope that it will be useful,
18;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20;; GNU General Public License for more details.
21
22;; You should have received a copy of the GNU General Public License
b578f267 23;; along with GNU Emacs; see the file COPYING. If not, write to the
086add15
LK
24;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
25;; Boston, MA 02110-1301, USA.
e6211d55 26
c91c4e6d
ER
27;;; Commentary:
28
bab0c3c1 29;; This package provides the `view' minor mode documented in the Emacs
c91c4e6d 30;; user's manual.
ab7782fc 31;; View mode entry and exit is done through the functions view-mode-enter
66d3a2b5 32;; and view-mode-exit. Use these functions to enter or exit view-mode from
ab7782fc 33;; emacs lisp programs.
66d3a2b5 34;; We use both view- and View- as prefix for symbols. View- is used as
cae55197 35;; prefix for commands that have a key binding. view- is used for commands
66d3a2b5 36;; without key binding. The purpose of this is to make it easier for a
ab7782fc
RS
37;; user to use command name completion.
38
39;;; Suggested key bindings:
40;;
41;; (define-key ctl-x-4-map "v" 'view-file-other-window) ; ^x4v
42;; (define-key ctl-x-5-map "v" 'view-file-other-frame) ; ^x5v
43;;
44;; You could also bind view-file, view-buffer, view-buffer-other-window and
45;; view-buffer-other-frame to keys.
0d63ba8c 46\f
e5167999 47;;; Code:
e6211d55 48
cae55197
KH
49(defgroup view nil
50 "Peruse file or buffer without editing."
51 :link '(function-link view-mode)
52 :link '(custom-manual "(emacs)Misc File Ops")
53 :group 'wp
54 :group 'editing)
55
cae55197
KH
56(defcustom view-highlight-face 'highlight
57 "*The face used for highlighting the match found by View mode search."
58 :type 'face
59 :group 'view)
82380f84 60
66d3a2b5 61;; `view-mode-auto-exit' is replaced by the following option variable which
ab7782fc 62;; only says if scrolling past buffer end should leave view mode or not, it
e51f616f 63;; doesn't say if leaving view mode should restore windows or not. The latter
ab7782fc 64;; is now controlled by the presence of a value in `view-return-to-alist'.
cae55197 65(defcustom view-scroll-auto-exit nil
ab7782fc 66 "*Non-nil means scrolling past the end of buffer exits View mode.
39d9e44f 67A value of nil means attempting to scroll past the end of the buffer,
cae55197
KH
68only rings the bell and gives a message on how to leave."
69 :type 'boolean
70 :group 'view)
ab7782fc 71
cae55197 72(defcustom view-try-extend-at-buffer-end nil
39d9e44f 73 "*Non-nil means try to load more of file when reaching end of buffer.
66d3a2b5
RS
74This variable is mainly intended to be temporarily set to non-nil by
75the F command in view-mode, but you can set it to t if you want the action
cae55197
KH
76for all scroll commands in view mode."
77 :type 'boolean
78 :group 'view)
ab7782fc 79
78ddc123
MR
80;;;###autoload
81(defcustom view-remove-frame-by-deleting t
cae55197
KH
82 "*Determine how View mode removes a frame no longer needed.
83If nil, make an icon of the frame. If non-nil, delete the frame."
84 :type 'boolean
78ddc123
MR
85 :group 'view
86 ;; Changed the default of this to t for Emacs 23. Users consider
87 ;; frame iconification annoying.
88 :version "23.1")
ab7782fc 89
cae55197 90(defcustom view-exits-all-viewing-windows nil
66d3a2b5
RS
91 "*Non-nil means restore all windows used to view buffer.
92Commands that restore windows when finished viewing a buffer, apply to all
93windows that display the buffer and have restore information in
cae55197 94`view-return-to-alist'.
d9855810 95If `view-exits-all-viewing-windows' is nil, only the selected window is
cae55197
KH
96considered for restoring."
97 :type 'boolean
98 :group 'view)
ab7782fc 99
1c0484e2 100(defcustom view-inhibit-help-message nil
39d9e44f 101 "*Non-nil inhibits the help message shown upon entering View mode."
1c0484e2
RF
102 :type 'boolean
103 :group 'view
104 :version "22.1")
105
0093dc5a 106;;;###autoload
cae55197
KH
107(defvar view-mode nil
108 "Non-nil if View mode is enabled.
109Don't change this variable directly, you must change it by one of the
110functions that enable or disable view mode.")
0093dc5a 111;;;###autoload
bab0c3c1
KH
112(make-variable-buffer-local 'view-mode)
113
cae55197
KH
114(defcustom view-mode-hook nil
115 "Normal hook run when starting to view a buffer or file."
116 :type 'hook
117 :group 'view)
0d63ba8c 118\f
c88daaef
RS
119(defvar view-old-buffer-read-only nil)
120(make-variable-buffer-local 'view-old-buffer-read-only)
ab7782fc 121
c88daaef
RS
122(defvar view-old-Helper-return-blurb)
123(make-variable-buffer-local 'view-old-Helper-return-blurb)
124
0d63ba8c
RS
125;; Just to avoid warnings.
126(defvar Helper-return-blurb)
127
ab7782fc
RS
128(defvar view-page-size nil
129 "Default number of lines to scroll by View page commands.
5bf70f47 130If nil that means use the window size.")
ab7782fc 131(make-variable-buffer-local 'view-page-size)
c88daaef 132
ab7782fc
RS
133(defvar view-half-page-size nil
134 "Default number of lines to scroll by View half page commands.
5bf70f47 135If nil that means use half the window size.")
ab7782fc 136(make-variable-buffer-local 'view-half-page-size)
c88daaef 137
ab7782fc
RS
138(defvar view-last-regexp nil)
139(make-variable-buffer-local 'view-last-regexp) ; Global is better???
140
141(defvar view-return-to-alist nil
66d3a2b5
RS
142 "What to do with used windows and where to go when finished viewing buffer.
143This is local in each buffer being viewed.
d9855810
RS
144It is added to by `view-mode-enter' when starting to view a buffer and
145subtracted from by `view-mode-exit' when finished viewing the buffer.
66d3a2b5
RS
146
147See RETURN-TO-ALIST argument of function `view-mode-exit' for the format of
e51f616f 148`view-return-to-alist'.")
ab7782fc 149(make-variable-buffer-local 'view-return-to-alist)
da932079 150(put 'view-return-to-alist 'permanent-local t)
ab7782fc
RS
151
152(defvar view-exit-action nil
78ddc123
MR
153 "If non-nil, a function with one argument (a buffer) called when finished viewing.
154Commands like \\[view-file] and \\[view-file-other-window] may
155set this to bury or kill the viewed buffer.
156Observe that the buffer viewed might not appear in any window at
157the time this function is called.")
c88daaef 158(make-variable-buffer-local 'view-exit-action)
c88daaef 159
1a552841
RS
160(defvar view-no-disable-on-exit nil
161 "If non-nil, View mode \"exit\" commands don't actually disable View mode.
162Instead, these commands just switch buffers or windows.
163This is set in certain buffers by specialized features such as help commands
164that use View mode automatically.")
165
4fe11426 166(defvar view-overlay nil
82380f84
RS
167 "Overlay used to display where a search operation found its match.
168This is local in each buffer, once it is used.")
4fe11426
RS
169(make-variable-buffer-local 'view-overlay)
170
fd78d527
GM
171(unless (assq 'view-mode minor-mode-alist)
172 (setq minor-mode-alist
173 (cons (list 'view-mode
174 (propertize " View"
175 'local-map mode-line-minor-mode-keymap
176 'help-echo "mouse-3: minor mode menu"))
177 minor-mode-alist)))
0d63ba8c 178\f
ab7782fc 179;; Define keymap inside defvar to make it easier to load changes.
cae55197 180;; Some redundant "less"-like key bindings below have been commented out.
ab7782fc
RS
181(defvar view-mode-map
182 (let ((map (make-sparse-keymap)))
183 (define-key map "C" 'View-kill-and-leave)
184 (define-key map "c" 'View-leave)
185 (define-key map "Q" 'View-quit-all)
186 (define-key map "E" 'View-exit-and-edit)
187; (define-key map "v" 'View-exit)
188 (define-key map "e" 'View-exit)
189 (define-key map "q" 'View-quit)
190; (define-key map "N" 'View-search-last-regexp-backward)
191 (define-key map "p" 'View-search-last-regexp-backward)
192 (define-key map "n" 'View-search-last-regexp-forward)
193; (define-key map "?" 'View-search-regexp-backward) ; Less does this.
194 (define-key map "\\" 'View-search-regexp-backward)
195 (define-key map "/" 'View-search-regexp-forward)
196 (define-key map "r" 'isearch-backward)
197 (define-key map "s" 'isearch-forward)
198 (define-key map "m" 'point-to-register)
199 (define-key map "'" 'register-to-point)
200 (define-key map "x" 'exchange-point-and-mark)
d1ed8492 201 (define-key map "@" 'View-back-to-mark)
ab7782fc
RS
202 (define-key map "." 'set-mark-command)
203 (define-key map "%" 'View-goto-percent)
204; (define-key map "G" 'View-goto-line-last)
205 (define-key map "g" 'View-goto-line)
206 (define-key map "=" 'what-line)
207 (define-key map "F" 'View-revert-buffer-scroll-page-forward)
208; (define-key map "k" 'View-scroll-line-backward)
209 (define-key map "y" 'View-scroll-line-backward)
210; (define-key map "j" 'View-scroll-line-forward)
211 (define-key map "\n" 'View-scroll-line-forward)
212 (define-key map "\r" 'View-scroll-line-forward)
213 (define-key map "u" 'View-scroll-half-page-backward)
214 (define-key map "d" 'View-scroll-half-page-forward)
215 (define-key map "z" 'View-scroll-page-forward-set-page-size)
216 (define-key map "w" 'View-scroll-page-backward-set-page-size)
217; (define-key map "b" 'View-scroll-page-backward)
218 (define-key map "\C-?" 'View-scroll-page-backward)
219; (define-key map "f" 'View-scroll-page-forward)
220 (define-key map " " 'View-scroll-page-forward)
221 (define-key map "o" 'View-scroll-to-buffer-end)
222 (define-key map ">" 'end-of-buffer)
223 (define-key map "<" 'beginning-of-buffer)
224 (define-key map "-" 'negative-argument)
225 (define-key map "9" 'digit-argument)
226 (define-key map "8" 'digit-argument)
227 (define-key map "7" 'digit-argument)
228 (define-key map "6" 'digit-argument)
229 (define-key map "5" 'digit-argument)
230 (define-key map "4" 'digit-argument)
231 (define-key map "3" 'digit-argument)
232 (define-key map "2" 'digit-argument)
233 (define-key map "1" 'digit-argument)
234 (define-key map "0" 'digit-argument)
235 (define-key map "H" 'describe-mode)
d1ed8492 236 (define-key map "?" 'describe-mode) ; Maybe do as less instead? See above.
ab7782fc
RS
237 (define-key map "h" 'describe-mode)
238 map))
e6211d55 239
c88daaef
RS
240(or (assq 'view-mode minor-mode-map-alist)
241 (setq minor-mode-map-alist
242 (cons (cons 'view-mode view-mode-map) minor-mode-map-alist)))
0d63ba8c 243\f
ab7782fc 244;;; Commands that enter or exit view mode.
e6211d55 245
7229064d 246;;;###autoload
d1ed8492 247(defun view-file (file)
e6211d55 248 "View FILE in View mode, returning to previous buffer when done.
78ddc123
MR
249Emacs commands editing the buffer contents are not available; instead, a
250special set of commands (mostly letters and punctuation) are defined for
251moving around in the buffer.
e6211d55 252Space scrolls forward, Delete scrolls backward.
78ddc123 253For a list of all View commands, type H or h while viewing.
e6211d55 254
bd0d2c58 255This command runs the normal hook `view-mode-hook'."
e6211d55 256 (interactive "fView file: ")
981b7b0c 257 (unless (file-exists-p file) (error "%s does not exist" file))
90bb2ff4
RS
258 (let ((had-a-buf (get-file-buffer file))
259 (buffer (find-file-noselect file)))
260 (if (eq (with-current-buffer buffer
261 (get major-mode 'mode-class))
262 'special)
263 (progn
264 (switch-to-buffer buffer)
265 (message "Not using View mode because the major mode is special"))
266 (view-buffer buffer (and (not had-a-buf) 'kill-buffer)))))
e6211d55 267
b82fef5c 268;;;###autoload
d1ed8492 269(defun view-file-other-window (file)
ab7782fc 270 "View FILE in View mode in another window.
78ddc123
MR
271Return that window to its previous buffer when done. Emacs commands
272editing the buffer contents are not available; instead, a special set of
273commands (mostly letters and punctuation) are defined for moving around
274in the buffer.
b82fef5c 275Space scrolls forward, Delete scrolls backward.
78ddc123 276For a list of all View commands, type H or h while viewing.
b82fef5c 277
bd0d2c58 278This command runs the normal hook `view-mode-hook'."
ab7782fc 279 (interactive "fIn other window view file: ")
981b7b0c 280 (unless (file-exists-p file) (error "%s does not exist" file))
d1ed8492
GM
281 (let ((had-a-buf (get-file-buffer file)))
282 (view-buffer-other-window (find-file-noselect file) nil
ab7782fc 283 (and (not had-a-buf) 'kill-buffer))))
b82fef5c 284
7229064d 285;;;###autoload
d1ed8492 286(defun view-file-other-frame (file)
ab7782fc
RS
287 "View FILE in View mode in another frame.
288Maybe delete other frame and/or return to previous buffer when done.
78ddc123
MR
289Emacs commands editing the buffer contents are not available; instead, a
290special set of commands (mostly letters and punctuation) are defined for
291moving around in the buffer.
e6211d55 292Space scrolls forward, Delete scrolls backward.
78ddc123 293For a list of all View commands, type H or h while viewing.
e6211d55 294
bd0d2c58 295This command runs the normal hook `view-mode-hook'."
ab7782fc 296 (interactive "fIn other frame view file: ")
981b7b0c 297 (unless (file-exists-p file) (error "%s does not exist" file))
d1ed8492
GM
298 (let ((had-a-buf (get-file-buffer file)))
299 (view-buffer-other-frame (find-file-noselect file) nil
ab7782fc
RS
300 (and (not had-a-buf) 'kill-buffer))))
301
302
303;;;###autoload
d1ed8492 304(defun view-buffer (buffer &optional exit-action)
ab7782fc 305 "View BUFFER in View mode, returning to previous buffer when done.
78ddc123
MR
306Emacs commands editing the buffer contents are not available; instead, a
307special set of commands (mostly letters and punctuation) are defined for
308moving around in the buffer.
ab7782fc 309Space scrolls forward, Delete scrolls backward.
78ddc123 310For a list of all View commands, type H or h while viewing.
ab7782fc
RS
311
312This command runs the normal hook `view-mode-hook'.
313
314Optional argument EXIT-ACTION is either nil or a function with buffer as
78ddc123
MR
315argument. This function is called when finished viewing buffer. Use
316this argument instead of explicitly setting `view-exit-action'."
e6211d55 317 (interactive "bView buffer: ")
ab7782fc 318 (let ((undo-window (list (window-buffer) (window-start) (window-point))))
d1ed8492 319 (switch-to-buffer buffer)
ab7782fc
RS
320 (view-mode-enter (cons (selected-window) (cons nil undo-window))
321 exit-action)))
e6211d55 322
b82fef5c 323;;;###autoload
d1ed8492 324(defun view-buffer-other-window (buffer &optional not-return exit-action)
bab0c3c1 325 "View BUFFER in View mode in another window.
78ddc123
MR
326Return to previous buffer when done, unless optional NOT-RETURN is
327non-nil. Emacs commands editing the buffer contents are not available;
328instead, a special set of commands (mostly letters and punctuation) are
329defined for moving around in the buffer.
ab7782fc 330Space scrolls forward, Delete scrolls backward.
78ddc123 331For a list of all View commands, type H or h while viewing.
ab7782fc
RS
332
333This command runs the normal hook `view-mode-hook'.
334
335Optional argument EXIT-ACTION is either nil or a function with buffer as
78ddc123
MR
336argument. This function is called when finished viewing buffer. Use
337this argument instead of explicitly setting `view-exit-action'."
ab7782fc
RS
338 (interactive "bIn other window view buffer:\nP")
339 (let* ((win ; This window will be selected by
340 (get-lru-window)) ; switch-to-buffer-other-window below.
341 (return-to
342 (and (not not-return)
343 (cons (selected-window)
344 (if (eq win (selected-window))
345 t ; Has to make new window.
d1ed8492 346 (list
ab7782fc
RS
347 (window-buffer win) ; Other windows old buffer.
348 (window-start win)
349 (window-point win)))))))
d1ed8492 350 (switch-to-buffer-other-window buffer)
ab7782fc
RS
351 (view-mode-enter (and return-to (cons (selected-window) return-to))
352 exit-action)))
5c05f569 353
ab7782fc 354;;;###autoload
d1ed8492 355(defun view-buffer-other-frame (buffer &optional not-return exit-action)
ab7782fc 356 "View BUFFER in View mode in another frame.
78ddc123
MR
357Return to previous buffer when done, unless optional NOT-RETURN is
358non-nil. Emacs commands editing the buffer contents are not available;
359instead, a special set of commands (mostly letters and punctuation) are
360defined for moving around in the buffer.
b82fef5c 361Space scrolls forward, Delete scrolls backward.
78ddc123 362For a list of all View commands, type H or h while viewing.
b82fef5c 363
ab7782fc
RS
364This command runs the normal hook `view-mode-hook'.
365
366Optional argument EXIT-ACTION is either nil or a function with buffer as
78ddc123
MR
367argument. This function is called when finished viewing buffer. Use
368this argument instead of explicitly setting `view-exit-action'."
ab7782fc
RS
369 (interactive "bView buffer in other frame: \nP")
370 (let ((return-to
371 (and (not not-return) (cons (selected-window) t)))) ; Old window.
d1ed8492 372 (switch-to-buffer-other-frame buffer)
ab7782fc
RS
373 (view-mode-enter (and return-to (cons (selected-window) return-to))
374 exit-action)))
0d63ba8c 375\f
7229064d 376;;;###autoload
c88daaef 377(defun view-mode (&optional arg)
ab7782fc 378 ;; In the following documentation string we have to use some explicit key
e51f616f 379 ;; bindings instead of using the \\[] construction. The reason for this
ab7782fc
RS
380 ;; is that most commands have more than one key binding.
381 "Toggle View mode, a minor mode for viewing text but not editing it.
4837b516
GM
382With prefix argument ARG, turn View mode on if ARG is positive, otherwise
383turn it off.
ab7782fc
RS
384
385Emacs commands that do not change the buffer contents are available as usual.
e51f616f 386Kill commands insert text in kill buffers but do not delete. Other commands
ab7782fc
RS
387\(among them most letters and punctuation) beep and tell that the buffer is
388read-only.
389\\<view-mode-map>
390The following additional commands are provided. Most commands take prefix
391arguments. Page commands default to \"page size\" lines which is almost a whole
392window 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
393and set \"half page size\" lines which initially is half a window full. Search
394commands default to a repeat count of one.
395
396H, h, ? This message.
397Digits provide prefix arguments.
398\\[negative-argument] negative prefix argument.
399\\[beginning-of-buffer] move to the beginning of buffer.
400> move to the end of buffer.
401\\[View-scroll-to-buffer-end] scroll so that buffer end is at last line of window.
d1ed8492
GM
402SPC scroll forward \"page size\" lines.
403 With prefix scroll forward prefix lines.
404DEL scroll backward \"page size\" lines.
405 With prefix scroll backward prefix lines.
406\\[View-scroll-page-forward-set-page-size] like \\[View-scroll-page-forward] but with prefix sets \"page size\" to prefix.
407\\[View-scroll-page-backward-set-page-size] like \\[View-scroll-page-backward] but with prefix sets \"page size\" to prefix.
408\\[View-scroll-half-page-forward] scroll forward \"half page size\" lines. With prefix, sets
409 \"half page size\" to prefix lines and scrolls forward that much.
410\\[View-scroll-half-page-backward] scroll backward \"half page size\" lines. With prefix, sets
411 \"half page size\" to prefix lines and scrolls backward that much.
412RET, LFD scroll forward one line. With prefix scroll forward prefix line(s).
413y scroll backward one line. With prefix scroll backward prefix line(s).
ab7782fc
RS
414\\[View-revert-buffer-scroll-page-forward] revert-buffer if necessary and scroll forward.
415 Use this to view a changing file.
416\\[what-line] prints the current line number.
417\\[View-goto-percent] goes prefix argument (default 100) percent into buffer.
418\\[View-goto-line] goes to line given by prefix argument (default first line).
419. set the mark.
420x exchanges point and mark.
421\\[View-back-to-mark] return to mark and pops mark ring.
422 Mark ring is pushed at start of every successful search and when
e51f616f 423 jump to line occurs. The mark is set on jump to buffer start or end.
ab7782fc
RS
424\\[point-to-register] save current position in character register.
425' go to position saved in character register.
426s do forward incremental search.
427r do reverse incremental search.
428\\[View-search-regexp-forward] searches forward for regular expression, starting after current page.
429 ! and @ have a special meaning at the beginning of the regexp.
e51f616f 430 ! means search for a line with no match for regexp. @ means start
ab7782fc
RS
431 search at beginning (end for backward search) of buffer.
432\\ searches backward for regular expression, starting before current page.
433\\[View-search-last-regexp-forward] searches forward for last regular expression.
434p searches backward for last regular expression.
4790accb 435\\[View-quit] quit View mode, restoring this window and buffer to previous state.
ab7782fc 436 \\[View-quit] is the normal way to leave view mode.
e51f616f 437\\[View-exit] exit View mode but stay in current buffer. Use this if you started
ab7782fc 438 viewing a buffer (file) and find out you want to edit it.
4790accb
RS
439 This command restores the previous read-only status of the buffer.
440\\[View-exit-and-edit] exit View mode, and make the current buffer editable
441 even if it was not editable before entry to View mode.
442\\[View-quit-all] quit View mode, restoring all windows to previous state.
ab7782fc
RS
443\\[View-leave] quit View mode and maybe switch buffers, but don't kill this buffer.
444\\[View-kill-and-leave] quit View mode, kill current buffer and go back to other buffer.
445
38acf670 446The effect of \\[View-leave], \\[View-quit] and \\[View-kill-and-leave] depends on how view-mode was entered. If it was
2f33468c
EZ
447entered by view-file, view-file-other-window, view-file-other-frame, or
448\\[dired-view-file] \(\\[view-file], \\[view-file-other-window],
449\\[view-file-other-frame], or the Dired mode v command),
450then \\[View-quit] will try to kill the current buffer.
451If view-mode was entered from another buffer, by \\[view-buffer],
452\\[view-buffer-other-window], \\[view-buffer-other frame], \\[view-file],
453\\[view-file-other-window], or \\[view-file-other-frame],
38acf670 454then \\[View-leave], \\[View-quit] and \\[View-kill-and-leave] will return to that buffer.
ab7782fc
RS
455
456Entry to view-mode runs the normal hook `view-mode-hook'."
bc15ba42 457 (interactive "P")
cae55197
KH
458 (unless (and arg ; Do nothing if already OK.
459 (if (> (prefix-numeric-value arg) 0) view-mode (not view-mode)))
460 (if view-mode (view-mode-disable)
461 (view-mode-enable))))
0d63ba8c 462\f
e51f616f
RS
463(defun view-mode-enable ()
464 "Turn on View mode."
8b7037d9
RS
465 ;; Always leave view mode before changing major mode.
466 ;; This is to guarantee that the buffer-read-only variable is restored.
8b7037d9 467 (add-hook 'change-major-mode-hook 'view-mode-disable nil t)
e51f616f 468 (setq view-mode t
5bf70f47
RS
469 view-page-size nil
470 view-half-page-size nil
e51f616f
RS
471 view-old-buffer-read-only buffer-read-only
472 buffer-read-only t
473 view-old-Helper-return-blurb (and (boundp 'Helper-return-blurb)
474 Helper-return-blurb)
475 Helper-return-blurb
476 (format "continue viewing %s"
477 (if (buffer-file-name)
478 (file-name-nondirectory (buffer-file-name))
479 (buffer-name))))
19b7f6c9 480 (force-mode-line-update)
e51f616f
RS
481 (run-hooks 'view-mode-hook))
482
483(defun view-mode-disable ()
484 "Turn off View mode."
8b7037d9 485 (remove-hook 'change-major-mode-hook 'view-mode-disable t)
e51f616f 486 (and view-overlay (delete-overlay view-overlay))
19b7f6c9 487 (force-mode-line-update)
b75c9917
RS
488 ;; Calling toggle-read-only while View mode is enabled
489 ;; sets view-read-only to t as a buffer-local variable
490 ;; after exiting View mode. That arranges that the next toggle-read-only
491 ;; will reenable View mode.
492 ;; Cancelling View mode in any other way should cancel that, too,
493 ;; so that View mode stays off if toggle-read-only is called.
494 (if (local-variable-p 'view-read-only)
495 (kill-local-variable 'view-read-only))
e51f616f 496 (setq view-mode nil
bf551cf7
KH
497 Helper-return-blurb view-old-Helper-return-blurb)
498 (if buffer-read-only
499 (setq buffer-read-only view-old-buffer-read-only)))
ab7782fc
RS
500
501;;;###autoload
78ddc123
MR
502(defun view-return-to-alist-update (buffer &optional item)
503 "Update `view-return-to-alist' of buffer BUFFER.
504Remove from `view-return-to-alist' all entries referencing dead
505windows. Optional argument ITEM non-nil means add ITEM to
506`view-return-to-alist' after purging. For a decsription of items
507that can be added see the RETURN-TO-ALIST argument of the
508function `view-mode-exit'. If `view-return-to-alist' contains an
509entry for the selected window, purge that entry from
510`view-return-to-alist' before adding ITEM."
511 (with-current-buffer buffer
512 (when view-return-to-alist
513 (let* ((list view-return-to-alist)
514 entry entry-window last)
515 (while list
516 (setq entry (car list))
517 (setq entry-window (car entry))
518 (if (and (windowp entry-window)
519 (or (and item (eq entry-window (selected-window)))
520 (not (window-live-p entry-window))))
521 ;; Remove that entry.
522 (if last
523 (setcdr last (cdr list))
524 (setq view-return-to-alist
525 (cdr view-return-to-alist)))
526 ;; Leave entry alone.
527 (setq last entry))
528 (setq list (cdr list)))))
529 ;; Add ITEM.
530 (when item
531 (setq view-return-to-alist
532 (cons item view-return-to-alist)))))
533
534;;;###autoload
535(defun view-mode-enter (&optional return-to exit-action)
536 "Enter View mode and set up exit from view mode depending on optional arguments.
537RETURN-TO non-nil means add RETURN-TO as an element to the buffer
538local alist `view-return-to-alist'. Save EXIT-ACTION in buffer
539local variable `view-exit-action'. It should be either nil or a
540function that takes a buffer as argument. This function will be
541called by `view-mode-exit'.
542
543RETURN-TO is either nil, meaning do nothing when exiting view
544mode, or must have the format (WINDOW OLD-WINDOW . OLD-BUF-INFO).
545WINDOW is the window used for viewing. OLD-WINDOW is nil or the
546window to select after viewing. OLD-BUF-INFO tells what to do
547with WINDOW when exiting. It is one of:
5481) nil Do nothing.
5492) t Delete WINDOW or, if it is the only window and
550 `view-remove-frame-by-deleting' is non-nil, its
551 frame.
e51f616f 5523) (OLD-BUFF START POINT) Display buffer OLD-BUFF with displayed text
78ddc123
MR
553 starting at START and point at POINT in WINDOW.
5544) quit-window Do `quit-window' in WINDOW.
5555) keep-frame Like case 2) but do not delete the frame.
ab7782fc 556
78ddc123 557For a list of all View commands, type H or h while viewing.
ab7782fc
RS
558
559This function runs the normal hook `view-mode-hook'."
78ddc123
MR
560 (when return-to
561 (let ((entry (assq (car return-to) view-return-to-alist)))
562 (if entry
563 (setcdr entry (cdr return-to))
564 (setq view-return-to-alist (cons return-to view-return-to-alist)))))
565 (when exit-action
566 (setq view-exit-action exit-action))
567
568 (unless view-mode
e51f616f 569 (view-mode-enable)
ab7782fc 570 (force-mode-line-update)
1c0484e2
RF
571 (unless view-inhibit-help-message
572 (message "%s"
573 (substitute-command-keys "\
574View mode: type \\[help-command] for help, \\[describe-mode] for commands, \\[View-quit] to quit.")))))
0d63ba8c 575\f
ab7782fc 576(defun view-mode-exit (&optional return-to-alist exit-action all-win)
7f9fcc0f 577 "Exit View mode in various ways, depending on optional arguments.
78ddc123
MR
578RETURN-TO-ALIST, EXIT-ACTION and ALL-WIN determine what to do
579after exit. EXIT-ACTION is nil or a function that is called with
580current buffer as argument.
581
582RETURN-TO-ALIST is an alist that, for some of the windows
583displaying the current buffer, maintains information on what to
584do when exiting those windows. If ALL-WIN is non-nil or the
585variable `view-exits-all-viewing-windows' is non-nil,
586view-mode-exit attempts to restore all windows showing the
587current buffer to their old state. Otherwise, only the selected
588window is affected (provided it is on RETURN-TO-ALIST).
589
590Elements of RETURN-TO-ALIST must have the format
591 (WINDOW OLD-WINDOW . OLD-BUF-INFO) where
592
593WINDOW is a window displaying the current buffer and OLD-WINDOW
594is either nil or a window to select after viewing. OLD-BUF-INFO
595provides information on what to do with WINDOW and may be one of:
5961) nil Do nothing.
5972) t Delete WINDOW and, if it is the only window and
598 `view-remove-frame-by-deleting' is non-nil, its
599 frame.
e51f616f 6003) (OLD-BUF START POINT) Display buffer OLD-BUF with displayed text
78ddc123
MR
601 starting at START and point at POINT in WINDOW.
6024) quit-window Do `quit-window' in WINDOW.
6035) keep-frame Like case 2) but do not delete the frame.
604
605If one of the WINDOW in RETURN-TO-ALIST is the selected window
606and the corresponding OLD-WINDOW is a live window, then select
607OLD-WINDOW."
608 (when view-mode ; Only do something if in view mode.
609 (setq all-win
610 (and return-to-alist
611 (or all-win view-exits-all-viewing-windows)))
612 (let* ((buffer (current-buffer))
613 window notlost
614 (sel-old (assq (selected-window) return-to-alist))
615 (alist (cond
616 (all-win ; Try to restore all windows.
617 (append return-to-alist nil)) ; Copy.
618 (sel-old ; Only selected window.
619 (list sel-old))))
620 (old-window (if sel-old (car (cdr sel-old)))))
621 (if all-win ; Follow chains of old-windows.
622 (let ((c (length alist)) a)
623 (while (and (> c 0) ; Safety if mutually refering windows.
624 (or (not (window-live-p old-window))
625 (eq buffer (window-buffer old-window)))
626 (setq a (assq old-window alist)))
627 (setq c (1- c))
628 (setq old-window (car (cdr a))))
629 (if (or (zerop c) (not (window-live-p old-window)))
630 (setq old-window (selected-window)))))
631 (unless view-no-disable-on-exit
632 (view-mode-disable))
633 (while alist ; Restore windows with info.
634 (setq notlost nil)
635 (when (and (window-live-p (setq window (car (car alist))))
ab7782fc 636 (eq buffer (window-buffer window)))
78ddc123
MR
637 (let ((frame (window-frame window))
638 (old-buf-info (cdr (cdr (car alist)))))
639 (if all-win (select-window window))
640 (cond
641 ((and (consp old-buf-info) ; Case 3.
642 (buffer-live-p (car old-buf-info)))
643 (set-window-buffer window (car old-buf-info)) ; old-buf
644 (set-window-start window (car (cdr old-buf-info)))
645 (set-window-point window (car (cdr (cdr old-buf-info)))))
646 ((eq old-buf-info 'quit-window)
647 (quit-window)) ; Case 4.
648 (old-buf-info ; Case 2 or 5.
649 (cond
650 ((not (one-window-p t)) ; Not only window.
651 (delete-window))
652 ((eq old-buf-info 'keep-frame) ; Case 5.
653 (bury-buffer))
654 ((not (eq frame (next-frame))) ; Case 2 and only window.
655 ;; Not the only frame, so can safely be removed.
656 (if view-remove-frame-by-deleting
657 (delete-frame frame)
658 (setq notlost t) ; Keep the window. See below.
659 (iconify-frame frame))))))))
660 ;; If a frame is removed by iconifying it, the window is not
661 ;; really lost. In this case we keep the entry in
662 ;; `view-return-to-alist' so that if the user deiconifies the
663 ;; frame and then hits q, the frame is iconified again.
664 (unless notlost
665 (with-current-buffer buffer
d1ed8492 666 (setq view-return-to-alist
78ddc123
MR
667 (delete (car alist) view-return-to-alist))))
668 (setq alist (cdr alist)))
669 (when (window-live-p old-window)
670 ;; old-window is still alive => select it.
671 (select-window old-window))
672 (when exit-action
673 ;; Don't do that: If the user wants to quit the *Help* buffer a
674 ;; second time it won't have any effect.
675;;; (setq view-exit-action nil)
676 (funcall exit-action buffer))
677 (force-mode-line-update))))
0d63ba8c 678\f
ab7782fc
RS
679(defun View-exit ()
680 "Exit View mode but stay in current buffer."
e6211d55 681 (interactive)
ab7782fc 682 (view-mode-exit))
e6211d55 683
0093dc5a 684;;;###autoload
ab7782fc
RS
685(defun View-exit-and-edit ()
686 "Exit View mode and make the current buffer editable."
687 (interactive)
72b5cb89
KH
688 (let ((view-old-buffer-read-only nil)
689 (view-no-disable-on-exit nil))
66d3a2b5 690 (view-mode-exit)))
ab7782fc
RS
691
692(defun View-leave ()
693 "Quit View mode and maybe switch buffers, but don't kill this buffer."
694 (interactive)
695 (view-mode-exit view-return-to-alist))
696
697(defun View-quit ()
698 "Quit View mode, trying to restore window and buffer to previous state.
e51f616f 699Maybe kill this buffer. Try to restore selected window to previous state
ab7782fc
RS
700and go to previous buffer or window."
701 (interactive)
702 (view-mode-exit view-return-to-alist view-exit-action))
703
704(defun View-quit-all ()
e51f616f
RS
705 "Quit View mode, trying to restore windows and buffers to previous state.
706Maybe kill current buffer. Try to restore all windows viewing buffer to
ab7782fc
RS
707previous state and go to previous buffer or window."
708 (interactive)
709 (view-mode-exit view-return-to-alist view-exit-action t))
710
711(defun View-kill-and-leave ()
712 "Quit View mode, kill current buffer and return to previous buffer."
713 (interactive)
714 (view-mode-exit view-return-to-alist (or view-exit-action 'kill-buffer) t))
0d63ba8c 715\f
ab7782fc
RS
716
717;;; Some help routines.
718
719(defun view-window-size ()
720 ;; Window height excluding mode line.
721 (1- (window-height)))
bd0d2c58 722
e6211d55
RS
723;(defun view-last-command (&optional who what)
724; (setq view-last-command-entry this-command)
725; (setq view-last-command who)
726; (setq view-last-command-argument what))
727
728;(defun View-repeat-last-command ()
729; "Repeat last command issued in View mode."
730; (interactive)
731; (if (and view-last-command
732; (eq view-last-command-entry last-command))
733; (funcall view-last-command view-last-command-argument))
734; (setq this-command view-last-command-entry))
735
ab7782fc
RS
736(defun view-recenter ()
737 ;; Center point in window.
738 (recenter (/ (view-window-size) 2)))
739
740(defun view-page-size-default (lines)
741 ;; Get page size.
742 (let ((default (- (view-window-size) next-screen-context-lines)))
743 (if (or (null lines) (zerop (setq lines (prefix-numeric-value lines))))
744 default
745 (min (abs lines) default))))
746
747(defun view-set-half-page-size-default (lines)
748 ;; Get and maybe set half page size.
5bf70f47
RS
749 (if (not lines) (or view-half-page-size
750 (/ (view-window-size) 2))
ab7782fc
RS
751 (setq view-half-page-size
752 (if (zerop (setq lines (prefix-numeric-value lines)))
753 (/ (view-window-size) 2)
754 (view-page-size-default lines)))))
755
756
757;;; Commands for moving around in the buffer.
758
759(defun View-goto-percent (&optional percent)
760 "Move to end (or prefix PERCENT) of buffer in View mode.
761Display is centered at point.
e51f616f 762Also set the mark at the position where point was."
ab7782fc
RS
763 (interactive "P")
764 (push-mark)
765 (goto-char
766 (if percent
767 (+ (point-min)
768 (floor (* (- (point-max) (point-min)) 0.01
769 (max 0 (min 100 (prefix-numeric-value percent))))))
770 (point-max)))
771 (view-recenter))
772
773;(defun View-goto-line-last (&optional line)
774;"Move to last (or prefix LINE) line in View mode.
775;Display is centered at LINE.
776;Sets mark at starting position and pushes mark ring."
777; (interactive "P")
778; (push-mark)
779; (if line (goto-line (prefix-numeric-value line))
780; (goto-char (point-max))
781; (beginning-of-line))
782; (view-recenter))
f1180544 783
ab7782fc
RS
784(defun View-goto-line (&optional line)
785 "Move to first (or prefix LINE) line in View mode.
786Display is centered at LINE.
e51f616f 787Also set the mark at the position where point was."
e6211d55
RS
788 (interactive "p")
789 (push-mark)
bab0c3c1 790 (goto-line line)
ab7782fc 791 (view-recenter))
e6211d55 792
0d63ba8c
RS
793(defun View-back-to-mark (&optional ignore)
794 "Return to last mark set in View mode, else beginning of file.
795Display that line at the center of the window.
796This command pops the mark ring, so that successive
797invocations return to earlier marks."
ab7782fc 798 (interactive)
0d63ba8c
RS
799 (goto-char (or (mark t) (point-min)))
800 (pop-mark)
801 (view-recenter))
802\f
ab7782fc
RS
803(defun view-scroll-lines (lines backward default maxdefault)
804 ;; This function does the job for all the scrolling commands.
e51f616f
RS
805 ;; Scroll forward LINES lines. If BACKWARD is true scroll backwards.
806 ;; If LINES is negative scroll in the other direction. If LINES is 0 or nil,
807 ;; scroll DEFAULT lines. If MAXDEFAULT is true then scroll no more than a
ab7782fc
RS
808 ;; window full.
809 (if (or (null lines) (zerop (setq lines (prefix-numeric-value lines))))
810 (setq lines default))
cae55197
KH
811 (when (< lines 0)
812 (setq backward (not backward)) (setq lines (- lines)))
ab7782fc
RS
813 (setq default (view-page-size-default nil)) ; Max scrolled at a time.
814 (if maxdefault (setq lines (min lines default)))
815 (cond
816 (backward (scroll-down lines))
817 ((view-really-at-end)
818 (if view-scroll-auto-exit (View-quit)
819 (ding)
820 (view-end-message)))
821 (t (while (> lines default)
822 (scroll-up default)
823 (setq lines (- lines default))
824 (if (view-really-at-end) (setq lines 0)))
825 (scroll-up lines)
826 (if (view-really-at-end) (view-end-message))
827 (move-to-window-line -1)
828 (beginning-of-line))))
829
830(defun view-really-at-end ()
e51f616f 831 ;; Return true if buffer end visible. Maybe revert buffer and test.
ab7782fc
RS
832 (and (pos-visible-in-window-p (point-max))
833 (let ((buf (current-buffer))
834 (bufname (buffer-name))
835 (file (buffer-file-name)))
69576401
AS
836 (or (not view-try-extend-at-buffer-end)
837 (null file)
838 (verify-visited-file-modtime buf)
839 (not (file-exists-p file))
840 (when (buffer-modified-p buf)
841 (setq file (file-name-nondirectory file))
842 (not (yes-or-no-p
843 (format
844 "File %s changed on disk. Discard your edits%s? "
845 file
846 (if (string= bufname file) ""
847 (concat " in " bufname))))))
848 (progn
849 (revert-buffer t t t)
850 (pos-visible-in-window-p (point-max)))))))
ab7782fc
RS
851
852(defun view-end-message ()
853 ;; Tell that we are at end of buffer.
854 (goto-char (point-max))
19d73313
RS
855 (if view-return-to-alist
856 (message "End of buffer. Type %s to quit viewing."
857 (substitute-command-keys
858 (if view-scroll-auto-exit "\\[View-scroll-page-forward]"
859 "\\[View-quit]")))
860 (message "End of buffer")))
0d63ba8c
RS
861\f
862(defun View-scroll-to-buffer-end ()
863 "Scroll backward or forward so that buffer end is at last line of window."
864 (interactive)
865 (let ((p (if (pos-visible-in-window-p (point-max)) (point))))
866 (goto-char (point-max))
867 (recenter -1)
868 (and p (goto-char p))))
ab7782fc
RS
869
870(defun View-scroll-page-forward (&optional lines)
871 "Scroll \"page size\" or prefix LINES lines forward in View mode.
e51f616f 872Exit if end of text is visible and `view-scroll-auto-exit' is non-nil.
ab7782fc
RS
873\"page size\" is whole window full, or number of lines set by
874\\[View-scroll-page-forward-set-page-size] or
875\\[View-scroll-page-backward-set-page-size].
876If LINES is more than a window-full, only the last window-full is shown."
e6211d55 877 (interactive "P")
5bf70f47 878 (view-scroll-lines lines nil (view-page-size-default view-page-size) nil))
ab7782fc 879
d1ed8492 880(defun View-scroll-page-backward (&optional lines)
ab7782fc 881 "Scroll \"page size\" or prefix LINES lines backward in View mode.
e51f616f 882See also `View-scroll-page-forward'."
e6211d55 883 (interactive "P")
5bf70f47 884 (view-scroll-lines lines t (view-page-size-default view-page-size) nil))
f1180544 885
ab7782fc 886(defun View-scroll-page-forward-set-page-size (&optional lines)
e51f616f 887 "Scroll forward LINES lines in View mode, setting the \"page size\".
ab7782fc 888This is the number of lines which \\[View-scroll-page-forward] and
66d3a2b5
RS
889\\[View-scroll-page-backward] scroll by default.
890If LINES is omitted or = 0, sets \"page size\" to window height and
891scrolls forward that much, otherwise scrolls forward LINES lines and sets
892\"page size\" to the minimum of window height and the absolute value of LINES.
e51f616f 893See also `View-scroll-page-forward'."
e6211d55 894 (interactive "P")
ab7782fc
RS
895 (view-scroll-lines lines nil
896 (setq view-page-size (view-page-size-default lines))
897 nil))
e6211d55 898
ab7782fc
RS
899(defun View-scroll-page-backward-set-page-size (&optional lines)
900 "Scroll backward prefix LINES lines in View mode, setting the \"page size\".
e51f616f 901See also `View-scroll-page-forward-set-page-size'."
e6211d55 902 (interactive "P")
ab7782fc
RS
903 (view-scroll-lines lines t
904 (setq view-page-size (view-page-size-default lines))
905 nil))
906
907(defun View-scroll-line-forward (&optional lines)
908 "Scroll forward one line (or prefix LINES lines) in View mode.
e51f616f 909See also `View-scroll-page-forward,' but note that scrolling is limited
ab7782fc
RS
910to minimum of LINES and one window-full."
911 (interactive "P")
912 (view-scroll-lines lines nil 1 t))
913
914(defun View-scroll-line-backward (&optional lines)
915 "Scroll backward one line (or prefix LINES lines) in View mode.
e51f616f 916See also `View-scroll-line-forward'."
ab7782fc
RS
917 (interactive "P")
918 (view-scroll-lines lines t 1 t))
919
920(defun View-scroll-half-page-forward (&optional lines)
e51f616f 921 "Scroll forward a \"half page\" (or prefix LINES) lines in View mode.
ab7782fc
RS
922If LINES is not omitted, the \"half page size\" is set to the minimum of
923window height and the absolute value of LINES.
924LINES=0 resets \"half page size\" to half window height."
925 (interactive "P")
926 (view-scroll-lines lines nil (view-set-half-page-size-default lines) t))
927
928(defun View-scroll-half-page-backward (&optional lines)
e51f616f
RS
929 "Scroll backward a \"half page\" (or prefix LINES) lines in View mode.
930See also `View-scroll-half-page-forward'."
ab7782fc
RS
931 (interactive "P")
932 (view-scroll-lines lines t (view-set-half-page-size-default lines) t))
933
e51f616f
RS
934(defun View-revert-buffer-scroll-page-forward (&optional lines)
935 "Scroll forward, reverting buffer if needed, in View mode.
ab7782fc
RS
936If buffer has not been changed and the corresponding file is newer, first
937revert the buffer, then scroll.
938This command is useful if you are viewing a changing file.
e51f616f
RS
939
940The prefix argument LINES says how many lines to scroll.
941If you don't specify a prefix argument, it uses the number of lines set by
ab7782fc
RS
942\\[View-scroll-page-forward-set-page-size] or
943\\[View-scroll-page-backward-set-page-size].
944If LINES is more than a window-full, only the last window-full is shown."
945 (interactive "P")
5d9b78b7 946 (let ((view-scroll-auto-exit nil)
ab7782fc 947 (view-try-extend-at-buffer-end t))
a312f214 948 (view-scroll-lines lines nil (view-page-size-default view-page-size) nil)))
0d63ba8c 949\f
5c05f569 950(defun View-search-regexp-forward (n regexp)
ab7782fc 951 "Search forward for first (or prefix Nth) occurrence of REGEXP in View mode.
66d3a2b5
RS
952
953Displays line found at center of window. Sets mark at starting position and
954pushes mark ring.
955
956Characters @ and ! are special at the beginning of REGEXP. They modify
957the search rather than become part of the pattern searched for.
958@ means search all the buffer i.e. start search at the beginning of buffer.
959! means search for a line that contains no match for the pattern.
960If REGEXP is empty or only consist of these control characters, then
961an earlier remembered REGEXP is used, otherwise REGEXP is remembered
962for use by later search commands.
5534818b
RS
963
964The variable `view-highlight-face' controls the face that is used
965for highlighting the match that is found."
d1ed8492 966 (interactive "p\nsSearch forward (regexp): ")
ab7782fc 967 (view-search n regexp))
e6211d55 968
5c05f569 969(defun View-search-regexp-backward (n regexp)
ab7782fc 970 "Search backward for first (or prefix Nth) occurrence of REGEXP in View mode.
66d3a2b5
RS
971
972Displays line found at center of window. Sets mark at starting position and
973pushes mark ring.
974
975Characters @ and ! are special at the beginning of REGEXP. They modify
976the search rather than become part of the pattern searched for.
977@ means search all the buffer i.e. start search at the end of buffer.
978! means search for a line that contains no match for the pattern.
979If REGEXP is empty or only consist of these control characters, then
980an earlier remembered REGEXP is used, otherwise REGEXP is remembered
981for use by later search commands.
5534818b
RS
982
983The variable `view-highlight-face' controls the face that is used
984for highlighting the match that is found."
e6211d55 985 (interactive "p\nsSearch backward (regexp): ")
ab7782fc 986 (view-search (- n) regexp))
e6211d55 987
ab7782fc
RS
988(defun View-search-last-regexp-forward (n) "\
989Search forward for first (or prefix Nth) instance of last regexp in View mode.
990Displays line found at center of window. Sets mark at starting position and
991pushes mark ring.
5534818b
RS
992
993The variable `view-highlight-face' controls the face that is used
994for highlighting the match that is found."
e6211d55 995 (interactive "p")
ab7782fc 996 (view-search n nil))
e6211d55 997
ab7782fc
RS
998(defun View-search-last-regexp-backward (n) "\
999Search backward for first (or prefix Nth) instance of last regexp in View mode.
e6211d55 1000Displays line found at center of window. Sets mark at starting position and
5534818b
RS
1001pushes mark ring.
1002
1003The variable `view-highlight-face' controls the face that is used
1004for highlighting the match that is found."
e6211d55 1005 (interactive "p")
ab7782fc 1006 (view-search (- n) nil))
e6211d55 1007
e6211d55 1008(defun view-search (times regexp)
66d3a2b5 1009 ;; This function does the job for all the View-search- commands.
cae55197
KH
1010 ;; Search for the TIMESt match for REGEXP. If TIMES is negative
1011 ;; search backwards. If REGEXP is nil use `view-last-regexp'.
1012 ;; Charcters "!" and "@" have a special meaning at the beginning of
1013 ;; REGEXP and are removed from REGEXP before the search "!" means
1014 ;; search for lines with no match for REGEXP. "@" means search in
1015 ;; the whole buffer, don't start searching from the present point.
ab7782fc
RS
1016 (let (where no end ln)
1017 (cond
1018 ((and regexp (> (length regexp) 0)
1019 (or (not (memq (string-to-char regexp) '(?! ?@)))
1020 (progn
1021 (if (member (substring regexp 0 2) '("!@" "@!"))
1022 (setq end t no t ln 2)
1023 (setq no (not (setq end (eq ?@ (string-to-char regexp))))
1024 ln 1))
1025 (> (length (setq regexp (substring regexp ln))) 0))))
1026 (setq view-last-regexp (if no (list regexp) regexp)))
1027 ((consp view-last-regexp)
1028 (setq regexp (car view-last-regexp))
cae55197 1029 (unless (setq no (not no)) (setq view-last-regexp regexp)))
ab7782fc
RS
1030 (view-last-regexp (setq regexp view-last-regexp)
1031 (if no (setq view-last-regexp (list regexp))))
1032 (t (error "No previous View-mode search")))
e6211d55 1033 (save-excursion
ab7782fc
RS
1034 (if end (goto-char (if (< times 0) (point-max) (point-min)))
1035 (move-to-window-line (if (< times 0) 0 -1)))
1036 (if (if no (view-search-no-match-lines times regexp)
1037 (re-search-forward regexp nil t times))
e6211d55
RS
1038 (setq where (point))))
1039 (if where
1040 (progn
1041 (push-mark)
1042 (goto-char where)
4fe11426
RS
1043 (if view-overlay
1044 (move-overlay view-overlay (match-beginning 0) (match-end 0))
1045 (setq view-overlay
1046 (make-overlay (match-beginning 0) (match-end 0))))
82380f84 1047 (overlay-put view-overlay 'face view-highlight-face)
e6211d55 1048 (beginning-of-line)
ab7782fc
RS
1049 (view-recenter))
1050 (message "Can't find occurrence %d of %s%s"
1051 times (if no "no " "") regexp)
e6211d55
RS
1052 (sit-for 4))))
1053
5aca5ac3
GM
1054;; This is the dumb approach, looking at each line. The original
1055;; version of this function looked like it might have been trying to
1056;; do something clever, but not succeeding:
1057;; http://lists.gnu.org/archive/html/bug-gnu-emacs/2007-09/msg00073.html
ab7782fc 1058(defun view-search-no-match-lines (times regexp)
5aca5ac3
GM
1059 "Search for the TIMESth occurrence of a line with no match for REGEXP.
1060If such a line is found, return non-nil and set the match-data to that line.
1061If TIMES is negative, search backwards."
138c66b0
GM
1062 (let ((step (if (>= times 0) 1
1063 (setq times (- times))
1064 -1)))
5aca5ac3
GM
1065 ;; Note that we do not check the current line.
1066 (while (and (> times 0)
1067 (zerop (forward-line step)))
138c66b0
GM
1068 ;; (forward-line 1) returns 0 on moving within the last line.
1069 (if (eobp)
1070 (setq times -1)
1071 (or (re-search-forward regexp (line-end-position) t)
1072 (setq times (1- times))))))
1073 (and (zerop times)
1074 (looking-at ".*")))
ab7782fc 1075
49116ac0
JB
1076(provide 'view)
1077
ab5796a9 1078;;; arch-tag: 6d0ace36-1d12-4de3-8de3-1fa3231636d7
d501f516 1079;;; view.el ends here