1;;; page.el --- page motion commands for Emacs
2
3;; Copyright (C) 1985, 2001, 2002, 2003, 2004, 2005,
4;;   2006, 2007 Free Software Foundation, Inc.
5
6;; Maintainer: FSF
7;; Keywords: wp convenience
8
9;; This file is part of GNU Emacs.
10
11;; GNU Emacs is free software; you can redistribute it and/or modify
12;; it under the terms of the GNU General Public License as published by
13;; the Free Software Foundation; either version 2, or (at your option)
14;; any later version.
15
16;; GNU Emacs is distributed in the hope that it will be useful,
17;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19;; GNU General Public License for more details.
20
21;; You should have received a copy of the GNU General Public License
22;; along with GNU Emacs; see the file COPYING.  If not, write to the
23;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
24;; Boston, MA 02110-1301, USA.
25
26;;; Commentary:
27
28;; This code provides the page-oriented movement and selection commands
29;; documented in the Emacs manual.
30
31;;; Code:
32
33(defun forward-page (&optional count)
34  "Move forward to page boundary.  With arg, repeat, or go back if negative.
35A page boundary is any line whose beginning matches the regexp
36`page-delimiter'."
37  (interactive "p")
38  (or count (setq count 1))
39  (while (and (> count 0) (not (eobp)))
40    ;; In case the page-delimiter matches the null string,
41    ;; don't find a match without moving.
42    (if (bolp) (forward-char 1))
43    (if (re-search-forward page-delimiter nil t)
44	nil
45      (goto-char (point-max)))
46    (setq count (1- count)))
47  (while (and (< count 0) (not (bobp)))
48    ;; In case the page-delimiter matches the null string,
49    ;; don't find a match without moving.
50    (and (save-excursion (re-search-backward page-delimiter nil t))
51	 (= (match-end 0) (point))
52	 (goto-char (match-beginning 0)))
53    (forward-char -1)
54    (if (re-search-backward page-delimiter nil t)
55	;; We found one--move to the end of it.
56	(goto-char (match-end 0))
57      ;; We found nothing--go to beg of buffer.
58      (goto-char (point-min)))
59    (setq count (1+ count))))
60
61(defun backward-page (&optional count)
62  "Move backward to page boundary.  With arg, repeat, or go fwd if negative.
63A page boundary is any line whose beginning matches the regexp
64`page-delimiter'."
65  (interactive "p")
66  (or count (setq count 1))
67  (forward-page (- count)))
68
69(defun mark-page (&optional arg)
70  "Put mark at end of page, point at beginning.
71A numeric arg specifies to move forward or backward by that many pages,
72thus marking a page other than the one point was originally in."
73  (interactive "P")
74  (setq arg (if arg (prefix-numeric-value arg) 0))
75  (if (> arg 0)
76      (forward-page arg)
77    (if (< arg 0)
78        (forward-page (1- arg))))
79  (forward-page)
80  (push-mark nil t t)
81  (forward-page -1))
82
83(defun narrow-to-page (&optional arg)
84  "Make text outside current page invisible.
85A numeric arg specifies to move forward or backward by that many pages,
86thus showing a page other than the one point was originally in."
87  (interactive "P")
88  (setq arg (if arg (prefix-numeric-value arg) 0))
89  (save-excursion
90    (widen)
91    (if (> arg 0)
92	(forward-page arg)
93      (if (< arg 0)
94	  (let ((adjust 0)
95		(opoint (point)))
96	    ;; If we are not now at the beginning of a page,
97	    ;; move back one extra time, to get to the start of this page.
98	    (save-excursion
99	      (beginning-of-line)
100	      (or (and (looking-at page-delimiter)
101		       (eq (match-end 0) opoint))
102		  (setq adjust 1)))
103	    (forward-page (- arg adjust)))))
104    ;; Find the end of the page.
105    (set-match-data nil)
106    (forward-page)
107    ;; If we stopped due to end of buffer, stay there.
108    ;; If we stopped after a page delimiter, put end of restriction
109    ;; at the beginning of that line.
110    ;; Before checking the match that was found,
111    ;; verify that forward-page actually set the match data.
112    (if (and (match-beginning 0)
113	     (save-excursion
114	       (goto-char (match-beginning 0)) ; was (beginning-of-line)
115	       (looking-at page-delimiter)))
116	(goto-char (match-beginning 0))) ; was (beginning-of-line)
117    (narrow-to-region (point)
118		      (progn
119			;; Find the top of the page.
120			(forward-page -1)
121			;; If we found beginning of buffer, stay there.
122			;; If extra text follows page delimiter on same line,
123			;; include it.
124			;; Otherwise, show text starting with following line.
125			(if (and (eolp) (not (bobp)))
126			    (forward-line 1))
127			(point)))))
128(put 'narrow-to-page 'disabled t)
129
130(defun count-lines-page ()
131  "Report number of lines on current page, and how many are before or after point."
132  (interactive)
133  (save-excursion
134    (let ((opoint (point)) beg end
135	  total before after)
136      (forward-page)
137      (beginning-of-line)
138      (or (looking-at page-delimiter)
139	  (end-of-line))
140      (setq end (point))
141      (backward-page)
142      (setq beg (point))
143      (setq total (count-lines beg end)
144	    before (count-lines beg opoint)
145	    after (count-lines opoint end))
146      (message "Page has %d lines (%d + %d)" total before after))))
147
148(defun what-page ()
149  "Print page and line number of point."
150  (interactive)
151  (save-restriction
152    (widen)
153    (save-excursion
154      (beginning-of-line)
155      (let ((count 1)
156	    (opoint (point)))
157	(goto-char 1)
158	(while (re-search-forward page-delimiter opoint t)
159	  (setq count (1+ count)))
160	(message "Page %d, line %d"
161		 count
162		 (1+ (count-lines (point) opoint)))))))
163
164;;; Place `provide' at end of file.
165(provide 'page)
166
167;;; arch-tag: e8d7a0bd-8655-4b6e-b852-f2ee25316a1d
168;;; page.el ends here
169