(texinfo-mode): Undo changes mistakenly added with
[bpt/emacs.git] / lisp / textmodes / page-ext.el
CommitLineData
6594deb0 1;;; page-ext.el --- page handling commands
0d2d639a 2
0d2d639a 3;;; Copyright (C) 1990 Free Software Foundation
0d2d639a 4
9750e079
ER
5;; Author: Robert J. Chassell <bob@gnu.ai.mit.edu>
6
3bab998b
ER
7;; This file is part of GNU Emacs.
8
9;; GNU Emacs is free software; you can redistribute it and/or modify
10;; it under the terms of the GNU General Public License as published by
e5167999 11;; the Free Software Foundation; either version 2, or (at your option)
3bab998b
ER
12;; any later version.
13
14;; GNU Emacs is distributed in the hope that it will be useful,
15;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17;; GNU General Public License for more details.
18
19;; You should have received a copy of the GNU General Public License
20;; along with GNU Emacs; see the file COPYING. If not, write to
21;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
22
e5167999
ER
23;;; Commentary:
24
25;;; You may use these commands to handle an address list or other
26;;; small data base.
27
28;;; Change Log:
29
0d2d639a
JB
30;;; Change Log ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
31;;;
32;;; Version 0.043
33;;; 24 May 1990 - When the cursor is at the end of the pages directory
34;;; buffer (which is empty), a `C-c C-c' (pages-directory-goto)
35;;; command now takes you to the end of the buffer.
36;;;
37;;; Version 0.042
38;;; 16 May 1990 - Since people often handle address and other files
39;;; differently, variable `pages-directory-for-addresses-narrowing-p'
40;;; now specifies whether `pages-directory-goto' should narrow
41;;; addresses buffer to entry to which it goes.
42;;; `pages-directory-buffer-narrowing-p' continues to control
43;;; narrowing of pages buffer.
44;;;
45;;; `add-new-page' documentation string now explains
46;;; that the value of the inserted page-delimiter is a `^L'.
47;;;
48;;; `pages-directory-previous-regexp' definition reworded.
49;;;
50;;; Removed unneeded defvar for `pages-directory-buffer'.
51;;;
52;;; Version 0.041
53;;; 14 May 1990 - `pages-last-search' bound to nil initially.
54;;; Remove unnecessary lines from `search-pages' definition.
55;;;
56;;; Version 0.04
57;;; 18 Mar 1990 - `pages-directory' creates a directory for only the
58;;; accessible portion of the buffer; it does not automatically widen
59;;; the buffer.
60;;;
61;;; However, `pages-directory-for-addresses' does widen the addresses'
62;;; buffer before constructing the addresses' directory.
63;;;
64;;; Version 0.032
65;;; 20 Feb 1990 - `pages-directory-for-addresses' no longer copies
66;;; first line of addresses directory to kill-ring
67;;;
68;;; Remove `(kill-all-local-variables)' line from
69;;; `pages-directory-address-mode' so Emacs will not be told to forget
70;;; the name of the file containing the addresses!
71;;;
72;;; Version 0.031
73;;; 15 Feb 1990 - `pages-directory-goto' no longer erroneously selects
74;;; the entry on the following line when the cursor is at the end of
75;;; the line, but selects the entry on which the cursor rests.
76;;;
77;;; `pages-directory-address-mode' now sets local variables and enables
78;;; `describe-mode' to describe Addresses Directory mode.
79;;;
eb8c3be9 80;;; `pages-directory-for-addresses' now sets the buffer-modified flag
0d2d639a
JB
81;;; for the Addresses Directory to nil.
82;;;
83;;; The documentation string for both `pages-directory-mode' and
84;;; `pages-directory-address-mode' now provide a lookup for the
85;;; `pages-directory-goto' keybinding.
86;;;
87;;; Version 0.03
88;;; 10 Feb 1990 - Incorporated a specialized extension of the
89;;; `pages-directory' command called `pages-directory-for-addresses'
90;;; and bound it to ctl-x-ctl-p-map "d" for integration with other
91;;; page functions. This function finds a file, creates a directory
92;;; for it using the `pages-directory' command, and displays the
93;;; directory. It is primarily for lists of addresses and the like.
94;;;
95;;; The difference between this and the `pages-directory' command is
96;;; that the `pages-directory-for-addresses' command presumes a
97;;; default addresses file (although you may optionally specify a file
98;;; name) and it switches you to the directory for the file, but the
99;;; `pages-directory' command creates a directory for the current
100;;; buffer, and pops to the directory in another window.
101;;;
102;;; `pages-directory' now places the cursor over the header line of
103;;; the page in which point was located in the pages buffer.
104;;;
105;;; New `set-page-delimiter' command sets the buffer local value of
106;;; the page-delimiter variable. With prefix arg, resets function to
107;;; original value. (Quicker to use than `edit-options'.)
108;;;
109;;; Version 0.02
110;;; 9 Feb 1990 - `pages-directory' now displays the
111;;; first line that contains a non-blank character that follows the
112;;; `page-delimiter'; this may be the rest of the line that contains
113;;; the `page-delimiter' or a line following. (In most instances, the
114;;; line containing a non-blank character is a line of text.)
115;;; Modification includes changes to `pages-copy-header-and-position'.
116;;;
117;;; Each directory created by `pages-directory' now possesses a name
118;;; derived on the name of the pages buffer. Consequently, you may
119;;; create several different directories, one for each pages buffer.
120;;;
121;;; `sort-pages-in-region' no longers requires the text to start on
122;;; the line immediately following the line containing the
123;;; page-delimiter.
124;;;
125;;; `pages-directory-goto' no longer narrows to the page
126;;; automatically. Instead, if you wish it to narrow to the page, set
127;;; variable pages-directory-buffer-narrowing-p to a non-nil value.
128;;; Default is nil; this is an experiment to see whether it is useful
129;;; to see the surrounding context.
130;;;
131;;; Version 0.011
132;;; 2 Feb 1990 - `add-new-page': removed extraneous space.
133;;;
134;;; Version 0.01
135;;; 28 Jan 1990 - Initial definitions.
136;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
137
e5167999 138;;; Code:
0d2d639a
JB
139\f
140;;;; Summary
141
142; The current page commands are:
143
144; forward-page C-x ]
145; backward-page C-x [
146; narrow-to-page C-x p
147; count-lines-page C-x l
148; mark-page C-x C-p (change this to C-x C-p C-m)
149; sort-pages not bound
150; what-page not bound
151
152; The new page handling commands all use `C-x C-p' as a prefix. This
153; means that the key binding for `mark-page' must be changed.
154; Otherwise, no other changes are made to the current commands or
155; their bindings.
156
157; New page handling commands:
158
159; next-page C-x C-p C-n
160; previous-page C-x C-p C-p
161; search-pages C-x C-p C-s
162; add-new-page C-x C-p C-a
163; sort-pages-buffer C-x C-p s
164; set-page-delimiter C-x C-p C-l
165; pages-directory C-x C-p C-d
166; pages-directory-for-addresses C-x C-p d
167; goto-page C-c C-c
168
169\f
170;;;; Using the page commands
171;
172; The page commands are helpful in several different contexts. For
173; example, programmers often divide source files into sections using the
174; `page-delimiter'; you can use the `pages-directory' command to list
175; the sections.
176
177; You may change the buffer local value of the `page-delimiter' with
178; the `set-page-delimiter' command. This command is bound to `C-x C-p
179; C-l' The command prompts you for a new value for the page-delimiter.
180; Called with a prefix-arg, the command resets the value of the
181; page-delimiter to its original value.
182
183\f
184;;;; Handling an address list or small data base
185
186; You may use the page commands to handle an address list or other
187; small data base. Put each address or entry on its own page. The
188; first line of text in each page is a `header line' and is listed by
189; the `pages-directory' or `pages-directory-for-addresses' command.
190
191; Specifically:
192;
193; 1. Begin each entry with a `page-delimiter' (which is, by default,
194; `^L' at the beginning of the line).
195;
196; 2. The first line of text in each entry is the `heading line'; it
197; will appear in the pages-directory-buffer which is constructed
198; using the `C-x C-p C-d' (pages-directory) command or the `C-x
199; C-p d' (pages-directory-for-addresses) command.
200;
201; The heading line may be on the same line as the page-delimiter
202; or it may follow after. It is the first non-blank line on the
203; page. Conventionally, the heading line is placed on the line
204; immediately following the line containing page-delimiter.
205;
206; 3. Follow the heading line with the body of the entry. The body
207; extends up to the next `page-delimiter'. The body may be of any
208; length. It is conventional to place a blank line after the last
209; line of the body.
210
211; For example, a file might look like this:
212;
213; FSF
214; Free Software Foundation
215; 675 Massachusetts Avenue
216; Cambridge, MA 02139 USA
217; (617) 876-3296
218; gnu@prep.ai.mit.edu
219;
220; \f
221; House Subcommittee on Intellectual Property,
222; U.S. House of Representatives,
223; Washington, DC 20515
224;
225; Congressional committee concerned with permitting or preventing
eb8c3be9 226; monopolistic restrictions on the use of software technology
0d2d639a
JB
227;
228; \f
229; George Lakoff
230; ``Women, Fire, and Dangerous Things:
231; What Categories Reveal about the Mind''
232; 1987, Univ. of Chicago Press
233;
234; About philosophy, Whorfian effects, and linguistics.
235;
236; \f
237; OBI (On line text collection.)
238; Open Book Initiative
239; c/o Software Tool & Die
240; 1330 Beacon St, Brookline, MA 02146 USA
241; (617) 739-0202
242; obi@world.std.com
243
244; In this example, the heading lines are:
245;
246; FSF
247; House Subcommittee on Intellectual Property
248; George Lakoff
249; OBI (On line text collection.)
250
251; The `C-x C-p s' (sort-pages-buffer) command sorts the entries in the
252; buffer alphabetically.
253
254; You may use any of the page commands, including the `next-page',
255; `previous-page', `add-new-page', `mark-page', and `search-pages'
256; commands.
257
258; You may use either the `C-x C-p d' (pages-directory-for-addresses)
259; or the `C-x C-p C-d' (pages-directory) command to construct and
260; dislay a directory of all the heading lines.
261
262; In the directory, you may position the cursor over a heading line
263; and type `C-c C-c' to go to the entry to which it refers in the
264; pages buffer.
265
266; When used in conjunction with the `pages-directory-for-addresses'
267; command, the `C-c C-c' (pages-directory-goto) command narrows to the
268; entry to which it goes. But, when used in conjunction with the
269; `pages-directory' command, the `C-c C-c' (pages-directory-goto)
270; command does not narrow to the entry, but widens the buffer so you
271; can see the context surrounding the entry.
272
273; If you wish, you may create several different directories,
274; one for each different buffer.
275
276;; `pages-directory-for-addresses' in detail
277
278; The `pages-directory-for-addresses' assumes a default addresses
279; file. You do not need to specify the addresses file but merely type
280; `C-x C-p d' from any buffer. The command finds the file, constructs
281; a directory for it, and switches you to the directory. If you call
282; the command with a prefix arg, `C-u C-x C-p d', it prompts you for a
283; file name.
284
285;; `pages-directory' in detail
286
287; Call the `pages-directory' from the buffer for which you want a
288; directory created; it creates a directory for the buffer and pops
289; you to the directory.
290
291; The `pages-directory' command has several options:
292
293; Called with a prefix arg, `C-u C-x C-p C-d', the `pages-directory'
294; prompts you for a regular expression and only lists only those
295; header lines that are part of pages that contain matches to the
296; regexp. In the example above, `C-u C-x C-p C-d 617 RET' would
297; match the telephone area code of the first and fourth entries, so
298; only the header lines of those two entries would appear in the
299; pages-directory-buffer.
300;
301; Called with a numeric argument, the `pages-directory' command
302; lists the number of lines in each page. This is helpful when you
303; are printing hardcopy.
304
305; Called with a negative numeric argument, the `pages-directory'
306; command lists the lengths of pages whose contents match a regexp.
307
308\f
309;;;; Key bindings for page handling functions
310
311(global-unset-key "\C-x\C-p")
312
313(defvar ctl-x-ctl-p-map (make-sparse-keymap)
314 "Keymap for subcommands of C-x C-p, which are for page handling.")
315
316(define-key ctl-x-map "\C-p" 'ctl-x-ctl-p-prefix)
317(fset 'ctl-x-ctl-p-prefix ctl-x-ctl-p-map)
318
319(define-key ctl-x-ctl-p-map "\C-n" 'next-page)
320(define-key ctl-x-ctl-p-map "\C-p" 'previous-page)
321(define-key ctl-x-ctl-p-map "\C-a" 'add-new-page)
322(define-key ctl-x-ctl-p-map "\C-m" 'mark-page)
323(define-key ctl-x-ctl-p-map "\C-s" 'search-pages)
324(define-key ctl-x-ctl-p-map "s" 'sort-pages-buffer)
325(define-key ctl-x-ctl-p-map "\C-l" 'set-page-delimiter)
326(define-key ctl-x-ctl-p-map "\C-d" 'pages-directory)
327(define-key ctl-x-ctl-p-map "d" 'pages-directory-for-addresses)
328
329\f
330;;;; Page movement function definitions
331
332(defun next-page (&optional count)
333 "Move to the next page bounded by the `page-delimiter' variable.
334With arg (prefix if interactive), move that many pages."
335 (interactive "p")
336 (or count (setq count 1))
337 (widen)
338 ;; Cannot use forward-page because of problems at page boundaries.
339 (while (and (> count 0) (not (eobp)))
340 (if (re-search-forward page-delimiter nil t)
341 nil
342 (goto-char (point-max)))
343 (setq count (1- count)))
817d6535
JB
344 ;; If COUNT is negative, we want to go back -COUNT + 1 page boundaries.
345 ;; The first page boundary we reach is the top of the current page,
346 ;; which doesn't count.
347 (while (and (< count 1) (not (bobp)))
0d2d639a
JB
348 (if (re-search-backward page-delimiter nil t)
349 (goto-char (match-beginning 0))
350 (goto-char (point-min)))
351 (setq count (1+ count)))
352 (narrow-to-page)
353 (goto-char (point-min))
354 (recenter 0))
355
356(defun previous-page (&optional count)
357 "Move to the previous page bounded by the `page-delimiter' variable.
358With arg (prefix if interactive), move that many pages."
359 (interactive "p")
360 (or count (setq count 1))
361 (next-page (- count)))
362
363\f
364;;;; Adding and searching pages
365
366(defun add-new-page (header-line)
367 "Insert new page at point; prompt for header line.
368Page begins with a `^L' as the page-delimiter.
369Point is left in the body of page."
370 (interactive "sHeader line: ")
371 (widen)
372 (insert (format "\n\f\n%s\n\n" header-line))
373 ;; don't renarrow; stay unnarrowed to see context
374 (forward-line -1))
375
376(defvar pages-last-search nil
377 "Value of last regexp searched for. Initially, nil.")
378
379(defun search-pages (regexp)
380 "Search for REGEXP, starting from point, and narrow to page it is in."
381 (interactive (list
382 (read-string
383 (format "Search for `%s' (end with RET): "
384 (or pages-last-search "regexp")))))
385 (if (equal regexp "")
386 (setq regexp pages-last-search)
387 (setq pages-last-search regexp))
388 (widen)
389 (re-search-forward regexp)
390 (narrow-to-page))
391
392\f
393;;;; Sorting pages
394
395(autoload 'sort-subr "sort" "Primary function for sorting." t nil)
396
397(defun sort-pages-in-region (reverse beg end)
398 "Sort pages in region alphabetically. Prefix arg means reverse order.
399
400Called from a program, there are three arguments:
401REVERSE (non-nil means reverse order), BEG and END (region to sort)."
402
403;;; This sort function handles ends of pages differently than
404;;; `sort-pages' and works better with lists of addresses and similar
405;;; files.
406
407 (interactive "P\nr")
408 (save-restriction
409 (narrow-to-region beg end)
410 (goto-char (point-min))
411 ;;; `sort-subr' takes three arguments
412 (sort-subr reverse
413
414 ;; NEXTRECFUN is called with point at the end of the
415 ;; previous record. It moves point to the start of the
416 ;; next record.
417 (function (lambda ()
418 (re-search-forward page-delimiter nil t)
419 (skip-chars-forward " \t\n")
420 ))
421
422 ;; ENDRECFUN is is called with point within the record.
423 ;; It should move point to the end of the record.
424 (function (lambda ()
425 (if (re-search-forward
426 page-delimiter
427 nil
428 t)
429 (goto-char (match-beginning 0))
430 (goto-char (point-max))))))))
431
432(defun sort-pages-buffer (&optional reverse)
433 "Sort pages alphabetically in buffer. Prefix arg means reverse order.
434\(Non-nil arg if not interactive.\)"
435
436 (interactive "P")
437 (or reverse (setq reverse nil))
438 (widen)
439 (let ((beginning (point-min))
440 (end (point-max)))
441 (sort-pages-in-region reverse beginning end)))
442
443\f
444;;;; Pages directory ancillary definitions
445
446(defvar pages-directory-buffer-narrowing-p nil
447 "*If non-nil, `pages-directory-goto' narrows pages buffer to entry.")
448
449(defvar pages-directory-previous-regexp nil
450 "Value of previous regexp used by `pages-directory'.
451\(This regular expression may be used to select only those pages that
452contain matches to the regexp.\)")
453
454(defvar pages-buffer nil
455 "The buffer for which the pages-directory function creates the directory.")
456
457(defvar pages-directory-prefix "*Directory for:"
458 "Prefix of name of temporary buffer for pages-directory.")
459
460(defvar pages-pos-list nil
461 "List containing the positions of the pages in the pages-buffer.")
462
463(defvar pages-directory-map nil
464 "Keymap for the pages-directory-buffer.")
465
466(if pages-directory-map
467 ()
468 (setq pages-directory-map (make-sparse-keymap))
469 (define-key pages-directory-map "\C-c\C-c"
470 'pages-directory-goto))
471
472(defun set-page-delimiter (regexp reset-p)
473 "Set buffer local value of page-delimiter to REGEXP.
474Called interactively with a prefix argument, reset `page-delimiter' to
475its original value.
476
477In a program, non-nil second arg causes first arg to be ignored and
478resets the page-delimiter to the original value."
479
480 (interactive
481 (if current-prefix-arg
482 (list original-page-delimiter nil)
483 (list (read-string "Set page-delimiter to regexp: " page-delimiter)
484 nil)))
485 (make-local-variable 'original-page-delimiter)
486 (make-local-variable 'page-delimiter)
487 (setq original-page-delimiter
488 (or original-page-delimiter page-delimiter))
489 (if (not reset-p)
490 (setq page-delimiter regexp)
491 (setq page-delimiter original-page-delimiter))
492 (if (interactive-p)
493 (message "The value of `page-delimiter' is now: %s" page-delimiter)))
494
495\f
496;;;; Pages directory main definitions
497
498(defun pages-directory
499 (pages-list-all-headers-p count-lines-p &optional regexp)
500 "Display a directory of the page headers in a temporary buffer.
501A header is the first non-blank line after the page-delimiter.
502\\[pages-directory-mode]
503You may move point to one of the lines in the temporary buffer,
504then use \\<pages-directory-goto> to go to the same line in the pages buffer.
505
506In interactive use:
507
508 1. With no prefix arg, display all headers.
509
510 2. With prefix arg, display the headers of only those pages that
511 contain matches to a regular expression for which you are
512 prompted.
513
514 3. With numeric prefix arg, for every page, print the number of
515 lines within each page.
516
517 4. With negative numeric prefix arg, for only those pages that
518 match a regular expression, print the number of lines within
519 each page.
520
521When called from a program, non-nil first arg means list all headers;
522non-nil second arg means print numbers of lines in each page; if first
523arg is nil, optional third arg is regular expression.
524
525If the buffer is narrowed, the `pages-directory' command creates a
526directory for only the accessible portion of the buffer."
527
528 (interactive
529 (cond ((not current-prefix-arg)
530 (list t nil nil))
531 ((listp current-prefix-arg)
532 (list nil
533 nil
534 (read-string
535 (format "Select according to `%s' (end with RET): "
536 (or pages-directory-previous-regexp "regexp")))))
537 ((> (prefix-numeric-value current-prefix-arg) 0)
538 (list t t nil))
539 ((< (prefix-numeric-value current-prefix-arg) 0)
540 (list nil
541 t
542 (read-string
543 (format "Select according to `%s' (end with RET): "
544 (or pages-directory-previous-regexp "regexp")))))))
545
546 (if (equal regexp "")
547 (setq regexp pages-directory-previous-regexp)
548 (setq pages-directory-previous-regexp regexp))
549
550 (if (interactive-p)
551 (message "Creating directory for: %s "
552 (buffer-name)))
553
554 (let ((buffer (current-buffer))
555 (pages-directory-buffer
556 (concat pages-directory-prefix " " (buffer-name) " "))
557 (linenum 1)
558 (pages-buffer-original-position (point))
559 (pages-buffer-original-page 0))
560
561 ;; `with-output-to-temp-buffer' binds the value of the variable
562 ;; `standard-output' to the buffer named as its first argument,
563 ;; but does not switch to that buffer.
564 (with-output-to-temp-buffer pages-directory-buffer
565 (save-excursion
566 (set-buffer standard-output)
567 (pages-directory-mode)
568 (insert
569 "==== Pages Directory: use `C-c C-c' to go to page under cursor. ====" ?\n)
570 (setq pages-buffer buffer)
571 (setq pages-pos-list nil))
572
573 (if pages-list-all-headers-p
574
575 ;; 1. If no prefix argument, list all headers
576 (save-excursion
577 (goto-char (point-min))
578
579 ;; (a) Point is at beginning of buffer; but the first
580 ;; page may not begin with a page-delimiter
581 (save-restriction
582 ;; If page delimiter is at beginning of buffer, skip it
583 (if (and (save-excursion
584 (re-search-forward page-delimiter nil t))
585 (= 1 (match-beginning 0)))
586 (goto-char (match-end 0)))
587 (narrow-to-page)
588 (pages-copy-header-and-position count-lines-p))
589
590 ;; (b) Search within pages buffer for next page-delimiter
591 (while (re-search-forward page-delimiter nil t)
592 (pages-copy-header-and-position count-lines-p)))
593
594 ;; 2. Else list headers whose pages match regexp.
595 (save-excursion
596 ;; REMOVED save-restriction AND widen FROM HERE
597 (goto-char (point-min))
598
599 ;; (a) Handle first page
600 (save-restriction
601 (narrow-to-page)
602 ;; search for selection regexp
603 (if (save-excursion (re-search-forward regexp nil t))
604 (pages-copy-header-and-position count-lines-p)))
605
606 ;; (b) Search for next page-delimiter
607 (while (re-search-forward page-delimiter nil t)
608 (save-restriction
609 (narrow-to-page)
610 ;; search for selection regexp
611 (if (save-excursion (re-search-forward regexp nil t))
612 (pages-copy-header-and-position count-lines-p)
613 )))))
614
615 (set-buffer standard-output)
616 ;; Put positions in increasing order to go with buffer.
617 (setq pages-pos-list (nreverse pages-pos-list))
618 (if (interactive-p)
619 (message "%d matching lines in: %s"
620 (length pages-pos-list) (buffer-name buffer))))
621 (pop-to-buffer pages-directory-buffer)
622 (sit-for 0) ; otherwise forward-line fails if N > window height.
623 (forward-line (if (= 0 pages-buffer-original-page)
624 1
625 pages-buffer-original-page))))
626
627(defun pages-copy-header-and-position (count-lines-p)
628 "Copy page header and its position to the Pages Directory.
629Only arg non-nil, count lines in page and insert before header.
630Used by `pages-directory' function."
631
632 (let (position line-count)
633
634 (if count-lines-p
635 (save-excursion
636 (save-restriction
637 (narrow-to-page)
638 (setq line-count (count-lines (point-min) (point-max))))))
639
640 ;; Keep track of page for later cursor positioning
641 (if (<= (point) pages-buffer-original-position)
642 (setq pages-buffer-original-page
643 (1+ pages-buffer-original-page)))
644
645 (save-excursion
646 ;; go to first non-blank char after the page-delimiter
647 (skip-chars-forward " \t\n")
648 ;; set the marker here; this the place to which the
649 ;; `pages-directory-goto' command will go
650 (setq position (make-marker))
651 (set-marker position (point))
652 (let ((start (point))
653 (end (save-excursion (end-of-line) (point))))
654 ;; change to directory buffer
655 (set-buffer standard-output)
656 ;; record page position
657 (setq pages-pos-list (cons position pages-pos-list))
658 ;; insert page header
659 (insert-buffer-substring buffer start end))
660
661 (if count-lines-p
662 (save-excursion
663 (beginning-of-line)
664 (insert (format "%3d: " line-count))))
665
666 (terpri))
667 (forward-line 1)))
668
669(defun pages-directory-mode ()
670 "Mode for handling the pages-directory buffer.
671
672Move point to one of the lines in this buffer, then use \\[pages-directory-goto] to go
673to the same line in the pages buffer."
674
675 (kill-all-local-variables)
676 (use-local-map pages-directory-map)
677 (setq major-mode 'pages-directory-mode)
678 (setq mode-name "Pages-Directory")
679 (make-local-variable 'pages-buffer)
680 (make-local-variable 'pages-pos-list)
681 (make-local-variable 'pages-directory-buffer-narrowing-p))
682
683(defun pages-directory-goto ()
684 "Go to the corresponding line in the pages buffer."
685
686;;; This function is mostly a copy of `occur-mode-goto-occurrence'
687
688 (interactive)
689 (if (or (not pages-buffer)
690 (not (buffer-name pages-buffer)))
691 (progn
692 (setq pages-buffer nil
693 pages-pos-list nil)
694 (error "Buffer in which pages were found is deleted.")))
695 (beginning-of-line)
696 (let* ((pages-number (1- (count-lines (point-min) (point))))
697 (pos (nth pages-number pages-pos-list))
698 (end-of-directory-p (eobp))
699 (narrowing-p pages-directory-buffer-narrowing-p))
700 (pop-to-buffer pages-buffer)
701 (widen)
702 (if end-of-directory-p
703 (goto-char (point-max))
704 (goto-char (marker-position pos)))
705 (if narrowing-p (narrow-to-page))))
706
707\f
708;;;; The `pages-directory-for-addresses' function and ancillary code
709
710(defvar pages-addresses-file-name "~/addresses"
711 "*Standard name for file of addresses. Entries separated by `page-delimiter'.
712Used by `pages-directory-for-addresses' function.")
713
714(defvar pages-directory-for-addresses-narrowing-p t
715 "*If non-nil, `pages-directory-goto' narrows addresses buffer to entry.")
716
717(defun pages-directory-for-addresses (&optional filename)
718 "Find addresses file and display its directory.
719By default, create and display directory of `pages-addresses-file-name'.
720Optional argument is FILENAME. In interactive use, with prefix
721argument, prompt for file name and provide completion.
722
723Move point to one of the lines in the displayed directory,
724then use C-c C-c to go to the same line in the addresses buffer."
725
726 (interactive
727 (list (if current-prefix-arg
728 (read-file-name "Filename: " pages-addresses-file-name))))
729
730 (if (interactive-p)
731 (message "Creating directory for: %s "
732 (or filename pages-addresses-file-name)))
733 (if (file-exists-p (or filename pages-addresses-file-name))
734 (progn
735 (set-buffer
736 (find-file-noselect
737 (expand-file-name
738 (or filename pages-addresses-file-name))))
739 (widen)
740 (pages-directory t nil nil)
741 (pages-directory-address-mode)
742 (setq pages-directory-buffer-narrowing-p
743 pages-directory-for-addresses-narrowing-p)
744 (delete-other-windows)
745 (save-excursion
746 (goto-char (point-min))
747 (delete-region (point) (save-excursion (end-of-line) (point)))
748 (insert
749 "=== Address List Directory: use `C-c C-c' to go to page under cursor. ===")
750 (set-buffer-modified-p nil)
751 ))
752 (error "No addresses file found!")))
753
754(defun pages-directory-address-mode ()
755 "Mode for handling the Addresses Directory buffer.
756
757Move point to one of the lines in this buffer, then use C-c C-c to go
758to the same line in the pages buffer."
759
760 (use-local-map pages-directory-map)
761 (setq major-mode 'pages-directory-address-mode)
762 (setq mode-name "Addresses Directory")
763 (make-local-variable 'pages-buffer)
764 (make-local-variable 'pages-pos-list)
765 (make-local-variable 'pages-directory-buffer-narrowing-p))
766
6594deb0
ER
767;;; page-ext.el ends here
768