(ispell-alternate-dictionary): Add /usr/share/lib/dict/words, for Irix.
[bpt/emacs.git] / lisp / textmodes / texnfo-upd.el
CommitLineData
be010748 1;;; texnfo-upd.el --- utilities for updating nodes and menus in Texinfo files
1337cb42 2
be010748 3;; Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
7e1335cf 4
d1f9f441 5;; Author: Robert J. Chassell
5762abec 6;; Maintainer: bug-texinfo@gnu.org
d7b4d18f 7;; Keywords: maint, tex, docs
7e1335cf 8
7e1335cf
RC
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
e5d77022 13;; the Free Software Foundation; either version 2, or (at your option)
7e1335cf
RC
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
b578f267
EN
22;; along with GNU Emacs; see the file COPYING. If not, write to the
23;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
24;; Boston, MA 02111-1307, USA.
7e1335cf 25
22a89ee8 26;;; Commentary:
7e1335cf 27
b578f267
EN
28;; Known bug: update commands fail to ignore @ignore.
29
30;; Summary: how to use the updating commands
31
32;; The node and menu updating functions automatically
33
34;; * insert missing `@node' lines,
35;; * insert the `Next', `Previous' and `Up' pointers of a node,
d1f9f441 36;; * insert or update the menu for a section,
b578f267
EN
37;; * create a master menu for a Texinfo source file.
38;;
78897d3d 39;; With a prefix argument, the `texinfo-update-node' and
b578f267
EN
40;; `texinfo-make-menu' functions do their jobs in the region.
41;;
42;; In brief, the functions for creating or updating nodes and menus, are:
d1f9f441
RS
43;;
44;; texinfo-update-node (&optional beginning end)
45;; texinfo-every-node-update ()
b578f267 46;; texinfo-sequential-node-update (&optional region-p)
d1f9f441
RS
47;;
48;; texinfo-make-menu (&optional beginning end)
49;; texinfo-all-menus-update ()
b578f267
EN
50;; texinfo-master-menu ()
51;;
52;; texinfo-insert-node-lines (&optional title-p)
d1f9f441 53;;
b578f267
EN
54;; texinfo-indent-menu-description (column &optional region-p)
55
56;; The `texinfo-column-for-description' variable specifies the column to
d1f9f441 57;; which menu descriptions are indented.
b578f267
EN
58
59;; Texinfo file structure
60;; ----------------------
61
62;; To use the updating commands, you must structure your Texinfo file
63;; hierarchically. Each `@node' line, with the exception of the top
64;; node, must be accompanied by some kind of section line, such as an
65;; `@chapter' or `@section' line. Each node-line/section-line
66;; combination must look like this:
67
68;; @node Lists and Tables, Cross References, Structuring, Top
69;; @comment node-name, next, previous, up
70;; @chapter Making Lists and Tables
71
72;; or like this (without the `@comment' line):
73
74;; @node Lists and Tables, Cross References, Structuring, Top
75;; @chapter Making Lists and Tables
76
77;; If the file has a `top' node, it must be called `top' or `Top' and
78;; be the first node in the file.
7e1335cf
RC
79
80\f
daa6abb8 81;;; The update node functions described in detail
7e1335cf 82
78897d3d 83;; The `texinfo-update-node' command with no prefix argument inserts
b578f267
EN
84;; the correct next, previous and up pointers for the node in which
85;; point is located (i.e., for the node preceding point).
7e1335cf 86
78897d3d 87;; With prefix argument, the `texinfo-update-node' function inserts the
b578f267
EN
88;; correct next, previous and up pointers for the nodes inside the
89;; region.
7e1335cf 90
b578f267
EN
91;; It does not matter whether the `@node' line has pre-existing
92;; `Next', `Previous', or `Up' pointers in it. They are removed.
7e1335cf 93
b578f267
EN
94;; The `texinfo-every-node-update' function runs `texinfo-update-node'
95;; on the whole buffer.
7e1335cf 96
b578f267
EN
97;; The `texinfo-sequential-node-update' function inserts the
98;; immediately following and preceding node into the `Next' or
99;; `Previous' pointers regardless of their hierarchical level. This is
100;; only useful for certain kinds of text, like a novel, which you go
101;; through sequentially.
daa6abb8
RS
102
103\f
104;;; The menu making functions described in detail
7e1335cf 105
b578f267
EN
106;; The `texinfo-make-menu' function without an argument creates or
107;; updates a menu for the section encompassing the node that follows
108;; point. With an argument, it makes or updates menus for the nodes
109;; within or part of the marked region.
110
111;; Whenever an existing menu is updated, the descriptions from
112;; that menu are incorporated into the new menu. This is done by copying
113;; descriptions from the existing menu to the entries in the new menu
114;; that have the same node names. If the node names are different, the
115;; descriptions are not copied to the new menu.
116
117;; Menu entries that refer to other Info files are removed since they
118;; are not a node within current buffer. This is a deficiency.
119
120;; The `texinfo-all-menus-update' function runs `texinfo-make-menu'
121;; on the whole buffer.
122
123;; The `texinfo-master-menu' function creates an extended menu located
124;; after the top node. (The file must have a top node.) The function
125;; first updates all the regular menus in the buffer (incorporating the
126;; descriptions from pre-existing menus), and then constructs a master
127;; menu that includes every entry from every other menu. (However, the
128;; function cannot update an already existing master menu; if one
129;; exists, it must be removed before calling the function.)
130
131;; The `texinfo-indent-menu-description' function indents every
132;; description in the menu following point, to the specified column.
133;; Non-nil argument (prefix, if interactive) means indent every
134;; description in every menu in the region. This function does not
135;; indent second and subsequent lines of a multi-line description.
136
137;; The `texinfo-insert-node-lines' function inserts `@node' before the
138;; `@chapter', `@section', and such like lines of a region in a Texinfo
139;; file where the `@node' lines are missing.
d1f9f441 140;;
b578f267
EN
141;; With a non-nil argument (prefix, if interactive), the function not
142;; only inserts `@node' lines but also inserts the chapter or section
143;; titles as the names of the corresponding nodes; and inserts titles
144;; as node names in pre-existing `@node' lines that lack names.
d1f9f441 145;;
b578f267
EN
146;; Since node names should be more concise than section or chapter
147;; titles, node names so inserted will need to be edited manually.
7e1335cf 148
d1f9f441 149\f
daa6abb8
RS
150;;; Code:
151
6f602bd0 152(require 'texinfo)
80216a47 153
80216a47 154
155b48df
RS
155(defvar texinfo-master-menu-header
156 " --- The Detailed Node Listing ---\n"
157 "String inserted before lower level entries in Texinfo master menu.
158It comes after the chapter-level menu entries.")
159
78897d3d 160(defun texinfo-make-menu (&optional beginning end)
7e1335cf
RC
161 "Without any prefix argument, make or update a menu.
162Make the menu for the section enclosing the node found following point.
163
78897d3d 164A prefix argument means make or update menus
7e1335cf
RC
165for nodes within or part of the marked region.
166
167Whenever a menu exists, and is being updated, the descriptions that
168are associated with node names in the pre-existing menu are
169incorporated into the new menu. Otherwise, the nodes' section titles
170are inserted as descriptions."
d1f9f441 171
78897d3d
RS
172 (interactive
173 (if prefix-arg
174 (list (point) (mark))))
175 (if (null beginning)
7e1335cf 176 (let ((level (texinfo-hierarchic-level)))
91c6f26e
KH
177 (texinfo-make-one-menu level)
178 (message "Menu updated"))
7e1335cf 179 ;; else
daa6abb8 180 (message "Making or updating menus in %s... " (buffer-name))
78897d3d
RS
181 (save-excursion
182 (goto-char (min beginning end))
183 ;; find section type following point
184 (let ((level (texinfo-hierarchic-level))
91c6f26e
KH
185 (region-end-marker (make-marker)))
186 (set-marker region-end-marker (max beginning end))
187 (save-restriction
188 (widen)
d1f9f441 189
91c6f26e
KH
190 (while (texinfo-find-lower-level-node
191 level (marker-position region-end-marker))
192 (setq level (texinfo-hierarchic-level)) ; new, lower level
193 (texinfo-make-one-menu level))
d1f9f441 194
91c6f26e
KH
195 (while (and (< (point) (marker-position region-end-marker))
196 (texinfo-find-higher-level-node
197 level (marker-position region-end-marker)))
198 (setq level (texinfo-hierarchic-level))
af584472
RS
199 ;; Don't allow texinfo-find-higher-level-node
200 ;; to find the same node again.
201 (forward-line 1)
91c6f26e
KH
202 (while (texinfo-find-lower-level-node
203 level (marker-position region-end-marker))
204 (setq level (texinfo-hierarchic-level)) ; new, lower level
205 (texinfo-make-one-menu level))))))
78897d3d 206 (message "Making or updating menus in %s...done" (buffer-name))))
7e1335cf
RC
207
208(defun texinfo-make-one-menu (level)
209 "Make a menu of all the appropriate nodes in this section.
d1f9f441 210`Appropriate nodes' are those associated with sections that are
7e1335cf
RC
211at the level specified by LEVEL. Point is left at the end of menu."
212 (let*
213 ((case-fold-search t)
82ac4b77
JB
214 (beginning
215 (save-excursion
216 (goto-char (texinfo-update-menu-region-beginning level))
217 (end-of-line)
218 (point)))
7e1335cf
RC
219 (end (texinfo-update-menu-region-end level))
220 (first (texinfo-menu-first-node beginning end))
221 (node-name (progn
91c6f26e
KH
222 (goto-char beginning)
223 (beginning-of-line)
224 (texinfo-copy-node-name)))
7e1335cf
RC
225 (new-menu-list (texinfo-make-menu-list beginning end level)))
226 (if (texinfo-old-menu-p beginning first)
91c6f26e
KH
227 (progn
228 (texinfo-incorporate-descriptions new-menu-list)
229 (texinfo-incorporate-menu-entry-names new-menu-list)
230 (texinfo-delete-old-menu beginning first)))
7e1335cf
RC
231 (texinfo-insert-menu new-menu-list node-name)))
232
233(defun texinfo-all-menus-update (&optional update-all-nodes-p)
234 "Update every regular menu in a Texinfo file.
daa6abb8 235Update pre-existing master menu, if there is one.
7e1335cf
RC
236
237If called with a non-nil argument, this function first updates all the
238nodes in the buffer before updating the menus."
239 (interactive "P")
daa6abb8 240 (let ((case-fold-search t)
91c6f26e 241 master-menu-p)
7e1335cf 242 (save-excursion
daa6abb8
RS
243 (push-mark (point-max) t)
244 (goto-char (point-min))
245 (message "Checking for a master menu in %s ... "(buffer-name))
246 (save-excursion
91c6f26e
KH
247 (if (search-forward texinfo-master-menu-header nil t)
248 (progn
249 ;; Check if @detailmenu kludge is used;
250 ;; if so, leave point before @detailmenu.
251 (search-backward "\n@detailmenu"
06cc857d
RS
252 (save-excursion (forward-line -3) (point))
253 t)
254 ;; Remove detailed master menu listing
91c6f26e
KH
255 (setq master-menu-p t)
256 (goto-char (match-beginning 0))
257 (let ((end-of-detailed-menu-descriptions
258 (save-excursion ; beginning of end menu line
259 (goto-char (texinfo-menu-end))
260 (beginning-of-line) (forward-char -1)
261 (point))))
262 (delete-region (point) end-of-detailed-menu-descriptions)))))
d1f9f441 263
daa6abb8 264 (if update-all-nodes-p
91c6f26e
KH
265 (progn
266 (message "Updating all nodes in %s ... " (buffer-name))
78897d3d 267 (texinfo-update-node (point-min) (point-max))))
d1f9f441
RS
268
269 (message "Updating all menus in %s ... " (buffer-name))
78897d3d 270 (texinfo-make-menu (point-max) (point-min))
d1f9f441 271
daa6abb8 272 (if master-menu-p
91c6f26e
KH
273 (progn
274 (message "Updating the master menu in %s... " (buffer-name))
91c6f26e 275 (texinfo-master-menu nil))))
d1f9f441 276
7e1335cf
RC
277 (message "Done...updated all the menus. You may save the buffer.")))
278
279(defun texinfo-find-lower-level-node (level region-end)
280 "Search forward from point for node at any level lower than LEVEL.
d1f9f441 281Search is limited to the end of the marked region, REGION-END,
7e1335cf
RC
282and to the end of the menu region for the level.
283
284Return t if the node is found, else nil. Leave point at the beginning
285of the node if one is found; else do not move point."
daa6abb8
RS
286 (let ((case-fold-search t))
287 (if (and (< (point) region-end)
91c6f26e
KH
288 (re-search-forward
289 (concat
290 "\\(^@node\\).*\n" ; match node line
291 "\\(\\(\\(^@c\\).*\n\\)" ; match comment line, if any
292 "\\|" ; or
293 "\\(^@ifinfo[ ]*\n\\)\\)?" ; ifinfo line, if any
294 (eval (cdr (assoc level texinfo-update-menu-lower-regexps))))
295 ;; the next higher level node marks the end of this
296 ;; section, and no lower level node will be found beyond
297 ;; this position even if region-end is farther off
298 (texinfo-update-menu-region-end level)
299 t))
300 (goto-char (match-beginning 1)))))
7e1335cf
RC
301
302(defun texinfo-find-higher-level-node (level region-end)
303 "Search forward from point for node at any higher level than argument LEVEL.
304Search is limited to the end of the marked region, REGION-END.
305
306Return t if the node is found, else nil. Leave point at the beginning
af584472
RS
307of the node if one is found; else do not move point.
308
309A `@node' line starting at point does count as a match;
310if the match is found there, the value is t and point does not move."
311
daa6abb8
RS
312 (let ((case-fold-search t))
313 (cond
6f602bd0 314 ((< level 3)
daa6abb8 315 (if (re-search-forward "^@node [ \t]*top[ \t]*\\(,\\|$\\)" region-end t)
91c6f26e 316 (progn (beginning-of-line) t)))
daa6abb8
RS
317 (t
318 (if (re-search-forward
91c6f26e
KH
319 (concat
320 "\\(^@node\\).*\n" ; match node line
321 "\\(\\(\\(^@c\\).*\n\\)" ; match comment line, if any
322 "\\|" ; or
323 "\\(^@ifinfo[ ]*\n\\)\\)?" ; ifinfo line, if any
324 (eval (cdr (assoc level texinfo-update-menu-higher-regexps))))
325 region-end t)
326 (progn (beginning-of-line) t))))))
7e1335cf
RC
327
328\f
daa6abb8 329;;; Making the list of new menu entries
7e1335cf
RC
330
331(defun texinfo-make-menu-list (beginning end level)
332 "Make a list of node names and their descriptions.
333Point is left at the end of the menu region, but the menu is not inserted.
334
d1f9f441 335First argument is position from which to start making menu list;
7e1335cf
RC
336second argument is end of region in which to try to locate entries;
337third argument is the level of the nodes that are the entries.
338
339Node names and descriptions are dotted pairs of strings. Each pair is
340an element of the list. If the description does not exist, the
341element consists only of the node name."
342 (goto-char beginning)
343 (let (new-menu-list)
344 (while (texinfo-menu-locate-entry-p level end)
d1f9f441 345 (setq new-menu-list
91c6f26e
KH
346 (cons (cons
347 (texinfo-copy-node-name)
348 (prog1 "" (forward-line 1)))
349 ;; Use following to insert section titles automatically.
350 ;; (texinfo-copy-section-title))
351 new-menu-list)))
7e1335cf
RC
352 (reverse new-menu-list)))
353
354(defun texinfo-menu-locate-entry-p (level search-end)
355 "Find a node that will be part of menu for this section.
356First argument is a string such as \"section\" specifying the general
daa6abb8 357hierarchical level of the menu; second argument is a position
7e1335cf
RC
358specifying the end of the search.
359
360The function returns t if the node is found, else nil. It searches
361forward from point, and leaves point at the beginning of the node.
362
363The function finds entries of the same type. Thus `subsections' and
364`unnumberedsubsecs' will appear in the same menu."
daa6abb8
RS
365 (let ((case-fold-search t))
366 (if (re-search-forward
91c6f26e
KH
367 (concat
368 "\\(^@node\\).*\n" ; match node line
369 "\\(\\(\\(^@c\\).*\n\\)" ; match comment line, if any
370 "\\|" ; or
371 "\\(^@ifinfo[ ]*\n\\)\\)?" ; ifinfo line, if any
372 (eval
373 (cdr (assoc level texinfo-update-menu-same-level-regexps))))
374 search-end
375 t)
376 (goto-char (match-beginning 1)))))
7e1335cf
RC
377
378(defun texinfo-copy-node-name ()
379 "Return the node name as a string.
380
381Start with point at the beginning of the node line; copy the text
382after the node command up to the first comma on the line, if any, and
383return the text as a string. Leaves point at the beginning of the
384line. If there is no node name, returns an empty string."
d1f9f441 385
7e1335cf
RC
386 (save-excursion
387 (buffer-substring
388 (progn (forward-word 1) ; skip over node command
91c6f26e
KH
389 (skip-chars-forward " \t") ; and over spaces
390 (point))
7e1335cf 391 (if (search-forward
91c6f26e
KH
392 ","
393 (save-excursion (end-of-line) (point)) t) ; bound search
394 (1- (point))
7e1335cf
RC
395 (end-of-line) (point)))))
396
397(defun texinfo-copy-section-title ()
398 "Return the title of the section as a string.
399The title is used as a description line in the menu when one does not
400already exist.
401
402Move point to the beginning of the appropriate section line by going
403to the start of the text matched by last regexp searched for, which
404must have been done by `texinfo-menu-locate-entry-p'."
405
406 ;; could use the same re-search as in `texinfo-menu-locate-entry-p'
407 ;; instead of using `match-beginning'; such a variation would be
408 ;; more general, but would waste information already collected
409
d1f9f441 410 (goto-char (match-beginning 7)) ; match section name
7e1335cf
RC
411
412 (buffer-substring
413 (progn (forward-word 1) ; skip over section type
91c6f26e
KH
414 (skip-chars-forward " \t") ; and over spaces
415 (point))
7e1335cf
RC
416 (progn (end-of-line) (point))))
417
418\f
daa6abb8 419;;; Handling the old menu
7e1335cf
RC
420
421(defun texinfo-old-menu-p (beginning first)
422 "Move point to the beginning of the menu for this section, if any.
423Otherwise move point to the end of the first node of this section.
424Return t if a menu is found, nil otherwise.
425
426First argument is the position of the beginning of the section in which
427the menu will be located; second argument is the position of the first
428node within the section.
429
430If no menu is found, the function inserts two newlines just before the
431end of the section, and leaves point there where a menu ought to be."
432 (goto-char beginning)
433 (if (not (re-search-forward "^@menu" first 'goto-end))
434 (progn (insert "\n\n") (forward-line -2) nil)
435 t))
436
437(defun texinfo-incorporate-descriptions (new-menu-list)
438 "Copy the old menu line descriptions that exist to the new menu.
439
440Point must be at beginning of old menu.
441
daa6abb8
RS
442If the node-name of the new menu is found in the old menu, insert the
443old description into the new entry.
7e1335cf
RC
444
445For this function, the new menu is a list made up of lists of dotted
446pairs in which the first element of the pair is the node name and the
daa6abb8 447second element the description. The new menu is changed destructively.
06cc857d 448The old menu is the menu as it appears in the Texinfo file."
d1f9f441 449
7e1335cf 450 (let ((new-menu-list-pointer new-menu-list)
91c6f26e 451 (end-of-menu (texinfo-menu-end)))
7e1335cf 452 (while new-menu-list
d1f9f441 453 (save-excursion ; keep point at beginning of menu
91c6f26e
KH
454 (if (re-search-forward
455 ;; Existing nodes can have the form
456 ;; * NODE NAME:: DESCRIPTION
457 ;; or
458 ;; * MENU ITEM: NODE NAME. DESCRIPTION.
459 ;;
460 ;; Recognize both when looking for the description.
461 (concat "\\* \\(" ; so only menu entries are found
462 (regexp-quote (car (car new-menu-list))) "::"
463 "\\|"
464 ".*: " (regexp-quote (car (car new-menu-list))) "[.,\t\n]"
465 "\\)"
466 ) ; so only complete entries are found
467 end-of-menu
468 t)
469 (setcdr (car new-menu-list)
470 (texinfo-menu-copy-old-description end-of-menu))))
d1f9f441 471 (setq new-menu-list (cdr new-menu-list)))
7e1335cf
RC
472 (setq new-menu-list new-menu-list-pointer)))
473
daa6abb8
RS
474(defun texinfo-incorporate-menu-entry-names (new-menu-list)
475 "Copy any old menu entry names to the new menu.
476
477Point must be at beginning of old menu.
478
479If the node-name of the new menu entry cannot be found in the old
480menu, do nothing.
481
482For this function, the new menu is a list made up of lists of dotted
483pairs in which the first element of the pair is the node name and the
484second element is the description (or nil).
485
486If we find an existing menu entry name, we change the first element of
487the pair to be another dotted pair in which the car is the menu entry
488name and the cdr is the node name.
489
490NEW-MENU-LIST is changed destructively. The old menu is the menu as it
491appears in the texinfo file."
d1f9f441 492
daa6abb8 493 (let ((new-menu-list-pointer new-menu-list)
91c6f26e 494 (end-of-menu (texinfo-menu-end)))
daa6abb8 495 (while new-menu-list
d1f9f441 496 (save-excursion ; keep point at beginning of menu
91c6f26e
KH
497 (if (re-search-forward
498 ;; Existing nodes can have the form
499 ;; * NODE NAME:: DESCRIPTION
500 ;; or
501 ;; * MENU ITEM: NODE NAME. DESCRIPTION.
502 ;;
503 ;; We're interested in the second case.
504 (concat "\\* " ; so only menu entries are found
ca722adb
KH
505 "\\(.*\\): " (regexp-quote (car (car new-menu-list)))
506 "[.,\t\n]")
91c6f26e
KH
507 end-of-menu
508 t)
509 (setcar
510 (car new-menu-list) ; replace the node name
511 (cons (buffer-substring (match-beginning 1) (match-end 1))
512 (car (car new-menu-list)))))
daa6abb8
RS
513 (setq new-menu-list (cdr new-menu-list))))
514 (setq new-menu-list new-menu-list-pointer)))
515
7e1335cf
RC
516(defun texinfo-menu-copy-old-description (end-of-menu)
517 "Return description field of old menu line as string.
518Point must be located just after the node name. Point left before description.
519Single argument, END-OF-MENU, is position limiting search."
520 (skip-chars-forward "[:.,\t\n ]+")
521 ;; don't copy a carriage return at line beginning with asterisk!
522 ;; do copy a description that begins with an `@'!
daa6abb8 523 ;; !! Known bug: does not copy descriptions starting with ^|\{?* etc.
d1f9f441 524 (if (and (looking-at "\\(\\w+\\|@\\)")
91c6f26e 525 (not (looking-at "\\(^\\* \\|^@end menu\\)")))
7e1335cf
RC
526 (buffer-substring
527 (point)
528 (save-excursion
91c6f26e
KH
529 (re-search-forward "\\(^\\* \\|^@end menu\\)" end-of-menu t)
530 (forward-line -1)
531 (end-of-line) ; go to end of last description line
532 (point)))
7e1335cf
RC
533 ""))
534
535(defun texinfo-menu-end ()
06cc857d 536 "Return position of end of menu, but don't move point.
7e1335cf
RC
537Signal an error if not end of menu."
538 (save-excursion
539 (if (re-search-forward "^@end menu" nil t)
91c6f26e 540 (point)
e8af40ee 541 (error "Menu does not have an end"))))
7e1335cf
RC
542
543(defun texinfo-delete-old-menu (beginning first)
544 "Delete the old menu. Point must be in or after menu.
545First argument is position of the beginning of the section in which
546the menu will be located; second argument is the position of the first
547node within the section."
548 ;; No third arg to search, so error if search fails.
549 (re-search-backward "^@menu" beginning)
550 (delete-region (point)
91c6f26e
KH
551 (save-excursion
552 (re-search-forward "^@end menu" first)
553 (point))))
7e1335cf
RC
554
555\f
daa6abb8 556;;; Inserting new menu
7e1335cf
RC
557
558;; try 32, but perhaps 24 is better
559(defvar texinfo-column-for-description 32
560 "*Column at which descriptions start in a Texinfo menu.")
561
562(defun texinfo-insert-menu (menu-list node-name)
563 "Insert formatted menu at point.
564Indents the first line of the description, if any, to the value of
565texinfo-column-for-description.
566
567MENU-LIST has form:
568
d1f9f441 569 \(\(\"node-name1\" . \"description\"\)
daa6abb8 570 \(\"node-name2\" . \"description\"\) ... \)
7e1335cf 571
daa6abb8
RS
572However, the description field might be nil.
573
574Also, the node-name field might itself be a dotted pair (call it P) of
575strings instead of just a string. In that case, the car of P
576is the menu entry name, and the cdr of P is the node name."
d1f9f441 577
7e1335cf
RC
578 (insert "@menu\n")
579 (while menu-list
daa6abb8
RS
580 ;; Every menu entry starts with a star and a space.
581 (insert "* ")
d1f9f441 582
daa6abb8
RS
583 ;; Insert the node name (and menu entry name, if present).
584 (let ((node-part (car (car menu-list))))
585 (if (stringp node-part)
91c6f26e
KH
586 ;; "Double colon" entry line; menu entry and node name are the same,
587 (insert (format "%s::" node-part))
588 ;; "Single colon" entry line; menu entry and node name are different.
589 (insert (format "%s: %s." (car node-part) (cdr node-part)))))
d1f9f441 590
daa6abb8
RS
591 ;; Insert the description, if present.
592 (if (cdr (car menu-list))
91c6f26e
KH
593 (progn
594 ;; Move to right place.
595 (indent-to texinfo-column-for-description 2)
596 ;; Insert description.
597 (insert (format "%s" (cdr (car menu-list))))))
daa6abb8
RS
598
599 (insert "\n") ; end this menu entry
7e1335cf
RC
600 (setq menu-list (cdr menu-list)))
601 (insert "@end menu")
d1f9f441 602 (message
daa6abb8 603 "Updated \"%s\" level menu following node: %s ... " level node-name))
7e1335cf
RC
604
605\f
daa6abb8
RS
606;;; Starting menu descriptions by inserting titles
607
608(defun texinfo-start-menu-description ()
d1f9f441 609 "In this menu entry, insert the node's section title as a description.
daa6abb8
RS
610Position point at beginning of description ready for editing.
611Do not insert a title if the line contains an existing description.
612
613You will need to edit the inserted text since a useful description
614complements the node name rather than repeats it as a title does."
d1f9f441 615
daa6abb8
RS
616 (interactive)
617 (let (beginning end node-name title)
618 (save-excursion
d1f9f441 619 (beginning-of-line)
daa6abb8 620 (if (search-forward "* " (save-excursion (end-of-line) (point)) t)
91c6f26e
KH
621 (progn (skip-chars-forward " \t")
622 (setq beginning (point)))
623 (error "This is not a line in a menu!"))
d1f9f441 624
daa6abb8 625 (cond
91c6f26e 626 ;; "Double colon" entry line; menu entry and node name are the same,
daa6abb8 627 ((search-forward "::" (save-excursion (end-of-line) (point)) t)
91c6f26e 628 (if (looking-at "[ \t]*[^ \t\n]+")
e8af40ee 629 (error "Descriptive text already exists"))
91c6f26e
KH
630 (skip-chars-backward ": \t")
631 (setq node-name (buffer-substring beginning (point))))
d1f9f441 632
daa6abb8
RS
633 ;; "Single colon" entry line; menu entry and node name are different.
634 ((search-forward ":" (save-excursion (end-of-line) (point)) t)
91c6f26e
KH
635 (skip-chars-forward " \t")
636 (setq beginning (point))
637 ;; Menu entry line ends in a period, comma, or tab.
638 (if (re-search-forward "[.,\t]"
639 (save-excursion (forward-line 1) (point)) t)
640 (progn
641 (if (looking-at "[ \t]*[^ \t\n]+")
e8af40ee 642 (error "Descriptive text already exists"))
91c6f26e
KH
643 (skip-chars-backward "., \t")
644 (setq node-name (buffer-substring beginning (point))))
645 ;; Menu entry line ends in a return.
646 (re-search-forward ".*\n"
647 (save-excursion (forward-line 1) (point)) t)
648 (skip-chars-backward " \t\n")
649 (setq node-name (buffer-substring beginning (point)))
650 (if (= 0 (length node-name))
e8af40ee 651 (error "No node name on this line")
91c6f26e 652 (insert "."))))
e8af40ee 653 (t (error "No node name on this line")))
daa6abb8
RS
654 ;; Search for node that matches node name, and copy the section title.
655 (if (re-search-forward
91c6f26e
KH
656 (concat
657 "^@node[ \t]+"
658 (regexp-quote node-name)
659 ".*\n" ; match node line
660 "\\("
661 "\\(\\(^@c \\|^@comment\\).*\n\\)" ; match comment line, if any
662 "\\|" ; or
663 "\\(^@ifinfo[ ]*\n\\)" ; ifinfo line, if any
664 "\\)?")
665 nil t)
666 (progn
667 (setq title
668 (buffer-substring
669 ;; skip over section type
670 (progn (forward-word 1)
671 ;; and over spaces
672 (skip-chars-forward " \t")
673 (point))
674 (progn (end-of-line)
675 (skip-chars-backward " \t")
676 (point)))))
e8af40ee 677 (error "Cannot find node to match node name in menu entry")))
daa6abb8
RS
678 ;; Return point to the menu and insert the title.
679 (end-of-line)
680 (delete-region
681 (point)
682 (save-excursion (skip-chars-backward " \t") (point)))
683 (indent-to texinfo-column-for-description 2)
684 (save-excursion (insert title))))
685
686\f
687;;; Handling description indentation
7e1335cf 688
06cc857d
RS
689;; Since the make-menu functions indent descriptions, these functions
690;; are useful primarily for indenting a single menu specially.
7e1335cf
RC
691
692(defun texinfo-indent-menu-description (column &optional region-p)
d1f9f441 693 "Indent every description in menu following point to COLUMN.
7e1335cf
RC
694Non-nil argument (prefix, if interactive) means indent every
695description in every menu in the region. Does not indent second and
696subsequent lines of a multi-line description."
d1f9f441 697
7e1335cf
RC
698 (interactive
699 "nIndent menu descriptions to (column number): \nP")
700 (save-excursion
701 (save-restriction
702 (widen)
703 (if (not region-p)
91c6f26e
KH
704 (progn
705 (re-search-forward "^@menu")
706 (texinfo-menu-indent-description column)
707 (message
708 "Indented descriptions in menu. You may save the buffer."))
709 ;;else
710 (message "Indenting every menu description in region... ")
711 (goto-char (region-beginning))
712 (while (and (< (point) (region-end))
713 (texinfo-locate-menu-p))
714 (forward-line 1)
715 (texinfo-menu-indent-description column))
716 (message "Indenting done. You may save the buffer.")))))
7e1335cf
RC
717
718(defun texinfo-menu-indent-description (to-column-number)
719 "Indent the Texinfo file menu description to TO-COLUMN-NUMBER.
720Start with point just after the word `menu' in the `@menu' line and
721leave point on the line before the `@end menu' line. Does not indent
722second and subsequent lines of a multi-line description."
723 (let* ((beginning-of-next-line (point)))
724 (while (< beginning-of-next-line
91c6f26e
KH
725 (save-excursion ; beginning of end menu line
726 (goto-char (texinfo-menu-end))
727 (beginning-of-line)
728 (point)))
daa6abb8 729
d1f9f441 730 (if (re-search-forward "\\* \\(.*::\\|.*: [^.,\t\n]+[.,\t]\\)"
91c6f26e
KH
731 (texinfo-menu-end)
732 t)
733 (progn
734 (let ((beginning-white-space (point)))
735 (skip-chars-forward " \t") ; skip over spaces
736 (if (looking-at "\\(@\\|\\w\\)+") ; if there is text
737 (progn
738 ;; remove pre-existing indentation
739 (delete-region beginning-white-space (point))
740 (indent-to-column to-column-number))))))
7e1335cf 741 ;; position point at beginning of next line
d1f9f441 742 (forward-line 1)
7e1335cf
RC
743 (setq beginning-of-next-line (point)))))
744
745\f
daa6abb8 746;;; Making the master menu
7e1335cf
RC
747
748(defun texinfo-master-menu (update-all-nodes-menus-p)
749 "Make a master menu for a whole Texinfo file.
750Non-nil argument (prefix, if interactive) means first update all
751existing nodes and menus. Remove pre-existing master menu, if there is one.
752
753This function creates a master menu that follows the top node. The
754master menu includes every entry from all the other menus. It
755replaces any existing ordinary menu that follows the top node.
756
757If called with a non-nil argument, this function first updates all the
758menus in the buffer (incorporating descriptions from pre-existing
759menus) before it constructs the master menu.
760
761The function removes the detailed part of an already existing master
9687a051 762menu. This action depends on the pre-existing master menu using the
7e1335cf
RC
763standard `texinfo-master-menu-header'.
764
765The master menu has the following format, which is adapted from the
766recommendation in the Texinfo Manual:
767
768 * The first part contains the major nodes in the Texinfo file: the
769 nodes for the chapters, chapter-like sections, and the major
770 appendices. This includes the indices, so long as they are in
771 chapter-like sections, such as unnumbered sections.
772
773 * The second and subsequent parts contain a listing of the other,
774 lower level menus, in order. This way, an inquirer can go
775 directly to a particular node if he or she is searching for
776 specific information.
777
778Each of the menus in the detailed node listing is introduced by the
779title of the section containing the menu."
d1f9f441 780
7e1335cf 781 (interactive "P")
daa6abb8
RS
782 (let ((case-fold-search t))
783 (widen)
784 (goto-char (point-min))
d1f9f441 785
daa6abb8
RS
786 ;; Move point to location after `top'.
787 (if (not (re-search-forward "^@node [ \t]*top[ \t]*\\(,\\|$\\)" nil t))
91c6f26e 788 (error "This buffer needs a Top node!"))
d1f9f441
RS
789
790 (let ((first-chapter
91c6f26e
KH
791 (save-excursion
792 (or (re-search-forward "^@node" nil t)
793 (error "Too few nodes for a master menu!"))
794 (point))))
155b48df 795 (if (search-forward texinfo-master-menu-header first-chapter t)
91c6f26e
KH
796 (progn
797 ;; Check if @detailmenu kludge is used;
798 ;; if so, leave point before @detailmenu.
799 (search-backward "\n@detailmenu"
06cc857d
RS
800 (save-excursion (forward-line -3) (point))
801 t)
802 ;; Remove detailed master menu listing
91c6f26e
KH
803 (goto-char (match-beginning 0))
804 (let ((end-of-detailed-menu-descriptions
805 (save-excursion ; beginning of end menu line
806 (goto-char (texinfo-menu-end))
807 (beginning-of-line) (forward-char -1)
808 (point))))
809 (delete-region (point) end-of-detailed-menu-descriptions)))))
d1f9f441 810
daa6abb8 811 (if update-all-nodes-menus-p
91c6f26e
KH
812 (progn
813 (message "Making a master menu in %s ...first updating all nodes... "
814 (buffer-name))
91c6f26e 815 (texinfo-update-node (point-min) (point-max))
d1f9f441 816
91c6f26e 817 (message "Updating all menus in %s ... " (buffer-name))
91c6f26e 818 (texinfo-make-menu (point-min) (point-max))))
d1f9f441 819
daa6abb8 820 (message "Now making the master menu in %s... " (buffer-name))
7e1335cf 821 (goto-char (point-min))
daa6abb8
RS
822 (texinfo-insert-master-menu-list
823 (texinfo-master-menu-list))
d1f9f441 824
daa6abb8
RS
825 ;; Remove extra newlines that texinfo-insert-master-menu-list
826 ;; may have inserted.
d1f9f441 827
daa6abb8
RS
828 (save-excursion
829 (goto-char (point-min))
d1f9f441 830
155b48df 831 (if (search-forward texinfo-master-menu-header nil t)
91c6f26e
KH
832 (progn
833 (goto-char (match-beginning 0))
834 ;; Check if @detailmenu kludge is used;
835 ;; if so, leave point before @detailmenu.
836 (search-backward "\n@detailmenu"
06cc857d
RS
837 (save-excursion (forward-line -3) (point))
838 t)
91c6f26e
KH
839 (insert "\n")
840 (delete-blank-lines)
841 (goto-char (point-min))))
daa6abb8
RS
842
843 (re-search-forward "^@menu")
844 (forward-line -1)
845 (delete-blank-lines)
d1f9f441 846
daa6abb8
RS
847 (re-search-forward "^@end menu")
848 (forward-line 1)
849 (delete-blank-lines))
d1f9f441 850
daa6abb8
RS
851 (message
852 "Done...completed making master menu. You may save the buffer.")))
7e1335cf
RC
853
854(defun texinfo-master-menu-list ()
855 "Return a list of menu entries and header lines for the master menu.
856
857Start with the menu for chapters and indices and then find each
858following menu and the title of the node preceding that menu.
859
860The master menu list has this form:
861
862 \(\(\(... \"entry-1-2\" \"entry-1\"\) \"title-1\"\)
863 \(\(... \"entry-2-2\" \"entry-2-1\"\) \"title-2\"\)
864 ...\)
865
866However, there does not need to be a title field."
867
868 (let (master-menu-list)
869 (while (texinfo-locate-menu-p)
d1f9f441 870 (setq master-menu-list
91c6f26e
KH
871 (cons (list
872 (texinfo-copy-menu)
873 (texinfo-copy-menu-title))
874 master-menu-list)))
7e1335cf
RC
875 (reverse master-menu-list)))
876
877(defun texinfo-insert-master-menu-list (master-menu-list)
878 "Format and insert the master menu in the current buffer."
879 (goto-char (point-min))
daa6abb8
RS
880 ;; Insert a master menu only after `Top' node and before next node
881 ;; \(or include file if there is no next node\).
882 (if (not (re-search-forward "^@node [ \t]*top[ \t]*\\(,\\|$\\)" nil t))
883 (error "This buffer needs a Top node!"))
884 (let ((first-chapter
91c6f26e 885 (save-excursion (re-search-forward "^@node\\|^@include") (point))))
daa6abb8 886 (if (not (re-search-forward "^@menu" first-chapter t))
91c6f26e
KH
887 (error
888 "Buffer lacks ordinary `Top' menu in which to insert master.")))
7e1335cf 889 (beginning-of-line)
daa6abb8 890 (delete-region ; buffer must have ordinary top menu
d1f9f441 891 (point)
daa6abb8 892 (save-excursion (re-search-forward "^@end menu") (point)))
d1f9f441
RS
893
894 (save-excursion
895 ;; `master-menu-inserted-p' is a kludge to tell
06cc857d
RS
896 ;; whether to insert @end detailmenu (see bleow)
897 (let (master-menu-inserted-p)
898 ;; Handle top of menu
899 (insert "\n@menu\n")
900 ;; Insert chapter menu entries
901 (setq this-very-menu-list (reverse (car (car master-menu-list))))
902 ;; Tell user what is going on.
903 (message "Inserting chapter menu entry: %s ... " this-very-menu-list)
904 (while this-very-menu-list
91c6f26e
KH
905 (insert "* " (car this-very-menu-list) "\n")
906 (setq this-very-menu-list (cdr this-very-menu-list)))
d1f9f441 907
06cc857d 908 (setq master-menu-list (cdr master-menu-list))
d1f9f441 909
06cc857d
RS
910 ;; Only insert detailed master menu if there is one....
911 (if (car (car master-menu-list))
91c6f26e
KH
912 (progn (setq master-menu-inserted-p t)
913 (insert (concat "\n@detailmenu\n"
eae582fe 914 texinfo-master-menu-header))))
06cc857d
RS
915
916 ;; @detailmenu added 5 Sept 1996 to `texinfo-master-menu-header'
917 ;; at Karl Berry's request to avert a bug in `makeinfo';
918 ;; all agree this is a bad kludge and should eventually be removed.
919 ;; @detailmenu ... @end detailmenu is a noop in `texinfmt.el'.
920 ;; See @end detailmenu below;
921 ;; also see `texinfo-all-menus-update' above, `texinfo-master-menu',
922 ;; `texinfo-multiple-files-update'.
923
924 ;; Now, insert all the other menus
d1f9f441 925
06cc857d
RS
926 ;; The menu master-menu-list has a form like this:
927 ;; ((("beta" "alpha") "title-A")
928 ;; (("delta" "gamma") "title-B"))
d1f9f441 929
06cc857d 930 (while master-menu-list
d1f9f441 931
91c6f26e
KH
932 (message
933 "Inserting menu for %s .... " (car (cdr (car master-menu-list))))
934 ;; insert title of menu section
935 (insert "\n" (car (cdr (car master-menu-list))) "\n\n")
d1f9f441 936
91c6f26e
KH
937 ;; insert each menu entry
938 (setq this-very-menu-list (reverse (car (car master-menu-list))))
939 (while this-very-menu-list
940 (insert "* " (car this-very-menu-list) "\n")
941 (setq this-very-menu-list (cdr this-very-menu-list)))
d1f9f441 942
91c6f26e 943 (setq master-menu-list (cdr master-menu-list)))
d1f9f441 944
06cc857d
RS
945 ;; Finish menu
946
947 ;; @detailmenu (see note above)
948 ;; Only insert @end detailmenu if a master menu was inserted.
949 (if master-menu-inserted-p
91c6f26e 950 (insert "\n@end detailmenu"))
06cc857d 951 (insert "\n@end menu\n\n"))))
7e1335cf 952
7e1335cf
RC
953(defun texinfo-locate-menu-p ()
954 "Find the next menu in the texinfo file.
955If found, leave point after word `menu' on the `@menu' line, and return t.
956If a menu is not found, do not move point and return nil."
957 (re-search-forward "\\(^@menu\\)" nil t))
958
959(defun texinfo-copy-menu-title ()
960 "Return the title of the section preceding the menu as a string.
961If such a title cannot be found, return an empty string. Do not move
962point."
daa6abb8
RS
963 (let ((case-fold-search t))
964 (save-excursion
965 (if (re-search-backward
91c6f26e
KH
966 (concat
967 "\\(^@top"
968 "\\|" ; or
969 texinfo-section-types-regexp ; all other section types
970 "\\)")
971 nil
972 t)
973 (progn
974 (beginning-of-line)
975 (forward-word 1) ; skip over section type
976 (skip-chars-forward " \t") ; and over spaces
977 (buffer-substring
978 (point)
979 (progn (end-of-line) (point))))
980 ""))))
7e1335cf
RC
981
982(defun texinfo-copy-menu ()
983 "Return the entries of an existing menu as a list.
984Start with point just after the word `menu' in the `@menu' line
985and leave point on the line before the `@end menu' line."
986 (let* (this-menu-list
91c6f26e
KH
987 (end-of-menu (texinfo-menu-end)) ; position of end of `@end menu'
988 (last-entry (save-excursion ; position of beginning of
989 ; last `* ' entry
990 (goto-char end-of-menu)
991 ;; handle multi-line description
992 (if (not (re-search-backward "^\\* " nil t))
e8af40ee 993 (error "No entries in menu"))
91c6f26e 994 (point))))
7e1335cf 995 (while (< (point) last-entry)
c0fbcada 996 (if (re-search-forward "^\\* " end-of-menu t)
91c6f26e
KH
997 (progn
998 (setq this-menu-list
999 (cons
1000 (buffer-substring
1001 (point)
1002 ;; copy multi-line descriptions
1003 (save-excursion
1004 (re-search-forward "\\(^\\* \\|^@e\\)" nil t)
1005 (- (point) 3)))
1006 this-menu-list)))))
7e1335cf
RC
1007 this-menu-list))
1008
1009\f
daa6abb8 1010;;; Determining the hierarchical level in the texinfo file
7e1335cf 1011
d1f9f441 1012(defun texinfo-specific-section-type ()
7e1335cf
RC
1013 "Return the specific type of next section, as a string.
1014For example, \"unnumberedsubsec\". Return \"top\" for top node.
1015
1016Searches forward for a section. Hence, point must be before the
1017section whose type will be found. Does not move point. Signal an
1018error if the node is not the top node and a section is not found."
daa6abb8
RS
1019 (let ((case-fold-search t))
1020 (save-excursion
1021 (cond
1022 ((re-search-forward "^@node [ \t]*top[ \t]*\\(,\\|$\\)"
1023;;; Following search limit by cph but causes a bug
1024;;; (save-excursion
1025;;; (end-of-line)
1026;;; (point))
91c6f26e
KH
1027 nil
1028 t)
1029 "top")
daa6abb8 1030 ((re-search-forward texinfo-section-types-regexp nil t)
91c6f26e 1031 (buffer-substring-no-properties
7007e1e3
RS
1032 (progn (beginning-of-line) ; copy its name
1033 (1+ (point)))
1034 (progn (forward-word 1)
1035 (point))))
daa6abb8 1036 (t
91c6f26e
KH
1037 (error
1038 "texinfo-specific-section-type: Chapter or section not found."))))))
7e1335cf
RC
1039
1040(defun texinfo-hierarchic-level ()
1041 "Return the general hierarchal level of the next node in a texinfo file.
1042Thus, a subheading or appendixsubsec is of type subsection."
daa6abb8 1043 (let ((case-fold-search t))
6f602bd0 1044 (cadr (assoc
91c6f26e 1045 (texinfo-specific-section-type)
6f602bd0 1046 texinfo-section-list))))
7e1335cf
RC
1047
1048\f
daa6abb8 1049;;; Locating the major positions
7e1335cf 1050
d1f9f441 1051(defun texinfo-update-menu-region-beginning (level)
7e1335cf
RC
1052 "Locate beginning of higher level section this section is within.
1053Return position of the beginning of the node line; do not move point.
1054Thus, if this level is subsection, searches backwards for section node.
1055Only argument is a string of the general type of section."
daa6abb8
RS
1056 (let ((case-fold-search t))
1057 ;; !! Known bug: if section immediately follows top node, this
1058 ;; returns the beginning of the buffer as the beginning of the
1059 ;; higher level section.
1060 (cond
6f602bd0 1061 ((< level 3)
daa6abb8 1062 (save-excursion
91c6f26e
KH
1063 (goto-char (point-min))
1064 (re-search-forward "^@node [ \t]*top[ \t]*\\(,\\|$\\)" nil t)
1065 (beginning-of-line)
1066 (point)))
daa6abb8
RS
1067 (t
1068 (save-excursion
91c6f26e
KH
1069 (re-search-backward
1070 (concat
1071 "\\(^@node\\).*\n" ; match node line
1072 "\\(\\(\\(^@c\\).*\n\\)" ; match comment line, if any
1073 "\\|" ; or
1074 "\\(^@ifinfo[ ]*\n\\)\\)?" ; ifinfo line, if any
1075 (eval
1076 (cdr (assoc level texinfo-update-menu-higher-regexps))))
1077 nil
1078 'goto-beginning)
1079 (point))))))
7e1335cf 1080
d1f9f441 1081(defun texinfo-update-menu-region-end (level)
7e1335cf
RC
1082 "Locate end of higher level section this section is within.
1083Return position; do not move point. Thus, if this level is a
1084subsection, find the node for the section this subsection is within.
1085If level is top or chapter, returns end of file. Only argument is a
1086string of the general type of section."
daa6abb8
RS
1087 (let ((case-fold-search t))
1088 (save-excursion
1089 (if (re-search-forward
91c6f26e
KH
1090 (concat
1091 "\\(^@node\\).*\n" ; match node line
1092 "\\(\\(\\(^@c\\).*\n\\)" ; match comment line, if any
1093 "\\|" ; or
1094 "\\(^@ifinfo[ ]*\n\\)\\)?" ; ifinfo line, if any
1095 (eval
1096 ;; Never finds end of level above chapter so goes to end.
1097 (cdr (assoc level texinfo-update-menu-higher-regexps))))
1098 nil
1099 'goto-end)
1100 (match-beginning 1)
1101 (point-max)))))
7e1335cf
RC
1102
1103(defun texinfo-menu-first-node (beginning end)
d1f9f441 1104 "Locate first node of the section the menu will be placed in.
7e1335cf 1105Return position; do not move point.
d1f9f441 1106The menu will be located just before this position.
7e1335cf
RC
1107
1108First argument is the position of the beginning of the section in
1109which the menu will be located; second argument is the position of the
1110end of that region; it limits the search."
d1f9f441 1111
7e1335cf
RC
1112 (save-excursion
1113 (goto-char beginning)
1114 (forward-line 1)
1115 (re-search-forward "^@node" end t)
1116 (beginning-of-line)
1117 (point)))
1118
1119\f
daa6abb8 1120;; We used to look for just sub, but that found @subtitle.
7e1335cf 1121(defvar texinfo-section-types-regexp
daa6abb8 1122 "^@\\(chapter \\|sect\\|subs\\|subh\\|unnum\\|major\\|chapheading \\|heading \\|appendix\\)"
7e1335cf
RC
1123 "Regexp matching chapter, section, other headings (but not the top node).")
1124
d1f9f441 1125(defvar texinfo-section-level-regexp
6f602bd0 1126 (regexp-opt (texinfo-filter 3 texinfo-section-list))
7e1335cf
RC
1127 "Regular expression matching just the Texinfo section level headings.")
1128
d1f9f441 1129(defvar texinfo-subsection-level-regexp
6f602bd0 1130 (regexp-opt (texinfo-filter 4 texinfo-section-list))
7e1335cf
RC
1131 "Regular expression matching just the Texinfo subsection level headings.")
1132
1133(defvar texinfo-subsubsection-level-regexp
6f602bd0 1134 (regexp-opt (texinfo-filter 5 texinfo-section-list))
7e1335cf
RC
1135 "Regular expression matching just the Texinfo subsubsection level headings.")
1136
1137(defvar texinfo-update-menu-same-level-regexps
6f602bd0
SM
1138 '((1 . "top[ \t]+")
1139 (2 . (concat "\\(^@\\)\\(" texinfo-chapter-level-regexp "\\)\\>[ \t]*"))
1140 (3 . (concat "\\(^@\\)\\(" texinfo-section-level-regexp "\\)\\>[ \t]*"))
1141 (4 . (concat "\\(^@\\)\\(" texinfo-subsection-level-regexp "\\)\\>[ \t]+"))
1142 (5 . (concat "\\(^@\\)\\(" texinfo-subsubsection-level-regexp "\\)\\>[ \t]+")))
7e1335cf
RC
1143 "*Regexps for searching for same level sections in a Texinfo file.
1144The keys are strings specifying the general hierarchical level in the
1145document; the values are regular expressions.")
1146
1147(defvar texinfo-update-menu-higher-regexps
6f602bd0
SM
1148 '((1 . "^@node [ \t]*DIR")
1149 (2 . "^@node [ \t]*top[ \t]*\\(,\\|$\\)")
1150 (3 .
d1f9f441 1151 (concat
7e1335cf
RC
1152 "\\(^@\\("
1153 texinfo-chapter-level-regexp
6f602bd0
SM
1154 "\\)\\>[ \t]*\\)"))
1155 (4 .
d1f9f441 1156 (concat
7e1335cf
RC
1157 "\\(^@\\("
1158 texinfo-section-level-regexp
1159 "\\|"
1160 texinfo-chapter-level-regexp
6f602bd0
SM
1161 "\\)\\>[ \t]*\\)"))
1162 (5 .
d1f9f441 1163 (concat
7e1335cf
RC
1164 "\\(^@\\("
1165 texinfo-subsection-level-regexp
1166 "\\|"
1167 texinfo-section-level-regexp
1168 "\\|"
1169 texinfo-chapter-level-regexp
6f602bd0 1170 "\\)\\>[ \t]*\\)")))
7e1335cf
RC
1171 "*Regexps for searching for higher level sections in a Texinfo file.
1172The keys are strings specifying the general hierarchical level in the
1173document; the values are regular expressions.")
1174
1175(defvar texinfo-update-menu-lower-regexps
6f602bd0 1176 '((1 .
d1f9f441 1177 (concat
7e1335cf
RC
1178 "\\(^@\\("
1179 texinfo-chapter-level-regexp
1180 "\\|"
1181 texinfo-section-level-regexp
1182 "\\|"
1183 texinfo-subsection-level-regexp
1184 "\\|"
1185 texinfo-subsubsection-level-regexp
6f602bd0
SM
1186 "\\)\\>[ \t]*\\)"))
1187 (2 .
d1f9f441 1188 (concat
7e1335cf
RC
1189 "\\(^@\\("
1190 texinfo-section-level-regexp
1191 "\\|"
1192 texinfo-subsection-level-regexp
1193 "\\|"
1194 texinfo-subsubsection-level-regexp
6f602bd0
SM
1195 "\\)\\>[ \t]*\\)"))
1196 (3 .
d1f9f441 1197 (concat
7e1335cf
RC
1198 "\\(^@\\("
1199 texinfo-subsection-level-regexp
1200 "\\|"
1201 texinfo-subsubsection-level-regexp
6f602bd0
SM
1202 "\\)\\>[ \t]+\\)"))
1203 (4 .
d1f9f441 1204 (concat
7e1335cf
RC
1205 "\\(^@\\("
1206 texinfo-subsubsection-level-regexp
6f602bd0 1207 "\\)\\>[ \t]+\\)"))
40153a94
SM
1208 ;; There's nothing below 5, use a bogus regexp that can't match.
1209 (5 . "a\\(^\\)"))
7e1335cf
RC
1210 "*Regexps for searching for lower level sections in a Texinfo file.
1211The keys are strings specifying the general hierarchical level in the
1212document; the values are regular expressions.")
1213
1214\f
daa6abb8 1215;;; Updating a node
7e1335cf 1216
78897d3d 1217(defun texinfo-update-node (&optional beginning end)
7e1335cf 1218 "Without any prefix argument, update the node in which point is located.
78897d3d 1219Interactively, a prefix argument means to operate on the region.
7e1335cf
RC
1220
1221The functions for creating or updating nodes and menus, and their
1222keybindings, are:
1223
78897d3d 1224 texinfo-update-node (&optional beginning end) \\[texinfo-update-node]
7e1335cf
RC
1225 texinfo-every-node-update () \\[texinfo-every-node-update]
1226 texinfo-sequential-node-update (&optional region-p)
1227
1228 texinfo-make-menu (&optional region-p) \\[texinfo-make-menu]
1229 texinfo-all-menus-update () \\[texinfo-all-menus-update]
1230 texinfo-master-menu ()
1231
1232 texinfo-indent-menu-description (column &optional region-p)
1233
1234The `texinfo-column-for-description' variable specifies the column to
daa6abb8 1235which menu descriptions are indented. Its default value is 32."
d1f9f441 1236
78897d3d
RS
1237 (interactive
1238 (if prefix-arg
1239 (list (point) (mark))))
1240 (if (null beginning)
1241 ;; Update a single node.
fe3371ef 1242 (let ((auto-fill-function nil) (auto-fill-hook nil))
91c6f26e
KH
1243 (if (not (re-search-backward "^@node" (point-min) t))
1244 (error "Node line not found before this position"))
1245 (texinfo-update-the-node)
1246 (message "Done...updated the node. You may save the buffer."))
7e1335cf 1247 ;; else
e5d77022 1248 (let ((auto-fill-function nil)
78897d3d
RS
1249 (auto-fill-hook nil))
1250 (save-excursion
1251 (save-restriction
1252 (narrow-to-region beginning end)
1253 (goto-char (point-min))
1254 (while (re-search-forward "^@node" (point-max) t)
d1f9f441 1255 (beginning-of-line)
78897d3d
RS
1256 (texinfo-update-the-node))
1257 (goto-char (point-max))
1258 (message "Done...nodes updated in region. You may save the buffer."))))))
7e1335cf
RC
1259
1260(defun texinfo-every-node-update ()
1261 "Update every node in a Texinfo file."
1262 (interactive)
1263 (save-excursion
78897d3d 1264 (texinfo-update-node (point-min) (point-max))
7e1335cf
RC
1265 (message "Done...updated every node. You may save the buffer.")))
1266
1267(defun texinfo-update-the-node ()
d1f9f441 1268 "Update one node. Point must be at the beginning of node line.
7e1335cf
RC
1269Leave point at the end of the node line."
1270 (texinfo-check-for-node-name)
1271 (texinfo-delete-existing-pointers)
1272 (message "Updating node: %s ... " (texinfo-copy-node-name))
1273 (save-restriction
1274 (widen)
1275 (let*
91c6f26e
KH
1276 ((case-fold-search t)
1277 (level (texinfo-hierarchic-level))
1278 (beginning (texinfo-update-menu-region-beginning level))
1279 (end (texinfo-update-menu-region-end level)))
6f602bd0 1280 (if (eq level 1)
91c6f26e
KH
1281 (texinfo-top-pointer-case)
1282 ;; else
1283 (texinfo-insert-pointer beginning end level 'next)
1284 (texinfo-insert-pointer beginning end level 'previous)
1285 (texinfo-insert-pointer beginning end level 'up)
1286 (texinfo-clean-up-node-line)))))
7e1335cf
RC
1287
1288(defun texinfo-top-pointer-case ()
1289 "Insert pointers in the Top node. This is a special case.
1290
1291The `Next' pointer is a pointer to a chapter or section at a lower
1292hierarchical level in the file. The `Previous' and `Up' pointers are
1293to `(dir)'. Point must be at the beginning of the node line, and is
1294left at the end of the node line."
1295
1296 (texinfo-clean-up-node-line)
d1f9f441 1297 (insert ", "
91c6f26e
KH
1298 (save-excursion
1299 ;; There may be an @chapter or other such command between
1300 ;; the top node line and the next node line, as a title
1301 ;; for an `ifinfo' section. This @chapter command must
1302 ;; must be skipped. So the procedure is to search for
1303 ;; the next `@node' line, and then copy its name.
1304 (if (re-search-forward "^@node" nil t)
1305 (progn
1306 (beginning-of-line)
1307 (texinfo-copy-node-name))
1308 " "))
1309 ", (dir), (dir)"))
7e1335cf
RC
1310
1311(defun texinfo-check-for-node-name ()
1312 "Determine whether the node has a node name. Prompt for one if not.
1313Point must be at beginning of node line. Does not move point."
1314 (save-excursion
daa6abb8
RS
1315 (let ((initial (texinfo-copy-next-section-title)))
1316 ;; This is not clean. Use `interactive' to read the arg.
1317 (forward-word 1) ; skip over node command
1318 (skip-chars-forward " \t") ; and over spaces
1319 (if (not (looking-at "[^,\t\n ]+")) ; regexp based on what Info looks for
91c6f26e
KH
1320 ; alternatively, use "[a-zA-Z]+"
1321 (let ((node-name
1322 (read-from-minibuffer
1323 "Node name (use no @, commas, colons, or apostrophes): "
1324 initial)))
1325 (insert " " node-name))))))
7e1335cf
RC
1326
1327(defun texinfo-delete-existing-pointers ()
d1f9f441 1328 "Delete `Next', `Previous', and `Up' pointers.
7e1335cf
RC
1329Starts from the current position of the cursor, and searches forward
1330on the line for a comma and if one is found, deletes the rest of the
1331line, including the comma. Leaves point at beginning of line."
2db10f13
KH
1332 (let ((eol-point (save-excursion (end-of-line) (point))))
1333 (if (search-forward "," eol-point t)
91c6f26e 1334 (delete-region (1- (point)) eol-point)))
7e1335cf
RC
1335 (beginning-of-line))
1336
1337(defun texinfo-find-pointer (beginning end level direction)
1338 "Move point to section associated with next, previous, or up pointer.
06cc857d 1339Return type of pointer (either `normal' or `no-pointer').
7e1335cf
RC
1340
1341The first and second arguments bound the search for a pointer to the
1342beginning and end, respectively, of the enclosing higher level
1343section. The third argument is a string specifying the general kind
d460a763 1344of section such as \"chapter\" or \"section\". When looking for the
7e1335cf
RC
1345`Next' pointer, the section found will be at the same hierarchical
1346level in the Texinfo file; when looking for the `Previous' pointer,
1347the section found will be at the same or higher hierarchical level in
1348the Texinfo file; when looking for the `Up' pointer, the section found
1349will be at some level higher in the Texinfo file. The fourth argument
1350\(one of 'next, 'previous, or 'up\) specifies whether to find the
1351`Next', `Previous', or `Up' pointer."
daa6abb8
RS
1352 (let ((case-fold-search t))
1353 (cond ((eq direction 'next)
91c6f26e
KH
1354 (forward-line 3) ; skip over current node
1355 ;; Search for section commands accompanied by node lines;
1356 ;; ignore section commands in the middle of nodes.
1357 (if (re-search-forward
1358 ;; A `Top' node is never a next pointer, so won't find it.
1359 (concat
1360 ;; Match node line.
1361 "\\(^@node\\).*\n"
1362 ;; Match comment or ifinfo line, if any
1363 "\\(\\(\\(^@c\\).*\n\\)\\|\\(^@ifinfo[ ]*\n\\)\\)?"
1364 (eval
1365 (cdr (assoc level texinfo-update-menu-same-level-regexps))))
1366 end
1367 t)
1368 'normal
1369 'no-pointer))
1370 ((eq direction 'previous)
1371 (if (re-search-backward
1372 (concat
1373 "\\("
1374 ;; Match node line.
1375 "\\(^@node\\).*\n"
1376 ;; Match comment or ifinfo line, if any
1377 "\\(\\(\\(^@c\\).*\n\\)\\|\\(^@ifinfo[ ]*\n\\)\\)?"
1378 (eval
1379 (cdr (assoc level texinfo-update-menu-same-level-regexps)))
1380 "\\|"
1381 ;; Match node line.
1382 "\\(^@node\\).*\n"
1383 ;; Match comment or ifinfo line, if any
1384 "\\(\\(\\(^@c\\).*\n\\)\\|\\(^@ifinfo[ ]*\n\\)\\)?"
1385 (eval
1386 (cdr (assoc level texinfo-update-menu-higher-regexps)))
1387 "\\|"
1388 ;; Handle `Top' node specially.
1389 "^@node [ \t]*top[ \t]*\\(,\\|$\\)"
1390 "\\)")
1391 beginning
1392 t)
1393 'normal
1394 'no-pointer))
1395 ((eq direction 'up)
1396 (if (re-search-backward
1397 (concat
1398 "\\("
1399 ;; Match node line.
1400 "\\(^@node\\).*\n"
1401 ;; Match comment or ifinfo line, if any
1402 "\\(\\(\\(^@c\\).*\n\\)\\|\\(^@ifinfo[ ]*\n\\)\\)?"
1403 (eval (cdr (assoc level texinfo-update-menu-higher-regexps)))
1404 "\\|"
1405 ;; Handle `Top' node specially.
1406 "^@node [ \t]*top[ \t]*\\(,\\|$\\)"
1407 "\\)")
1408 (save-excursion
1409 (goto-char beginning)
1410 (beginning-of-line)
1411 (point))
1412 t)
1413 'normal
1414 'no-pointer))
1415 (t
1416 (error "texinfo-find-pointer: lack proper arguments")))))
7e1335cf
RC
1417
1418(defun texinfo-pointer-name (kind)
1419 "Return the node name preceding the section command.
06cc857d 1420The argument is the kind of section, either `normal' or `no-pointer'."
7e1335cf
RC
1421 (let (name)
1422 (cond ((eq kind 'normal)
91c6f26e
KH
1423 (end-of-line) ; this handles prev node top case
1424 (re-search-backward ; when point is already
1425 "^@node" ; at the beginning of @node line
1426 (save-excursion (forward-line -3))
1427 t)
1428 (setq name (texinfo-copy-node-name)))
7e1335cf 1429 ((eq kind 'no-pointer)
91c6f26e
KH
1430 ;; Don't need to put a blank in the pointer slot,
1431 ;; since insert "' " always has a space
7e1335cf
RC
1432 (setq name " "))) ; put a blank in the pointer slot
1433 name))
1434
1435(defun texinfo-insert-pointer (beginning end level direction)
1436 "Insert the `Next', `Previous' or `Up' node name at point.
d1f9f441 1437Move point forward.
7e1335cf
RC
1438
1439The first and second arguments bound the search for a pointer to the
1440beginning and end, respectively, of the enclosing higher level
1441section. The third argument is the hierarchical level of the Texinfo
1442file, a string such as \"section\". The fourth argument is direction
06cc857d 1443towards which the pointer is directed, one of `next', `previous', or `up'."
7e1335cf
RC
1444
1445 (end-of-line)
1446 (insert
1447 ", "
1448 (save-excursion
1449 (texinfo-pointer-name
1450 (texinfo-find-pointer beginning end level direction)))))
1451
1452(defun texinfo-clean-up-node-line ()
1453 "Remove extra commas, if any, at end of node line."
1454 (end-of-line)
1455 (skip-chars-backward ", ")
1456 (delete-region (point) (save-excursion (end-of-line) (point))))
1457
1458\f
daa6abb8 1459;;; Updating nodes sequentially
06cc857d
RS
1460;; These sequential update functions insert `Next' or `Previous'
1461;; pointers that point to the following or preceding nodes even if they
1462;; are at higher or lower hierarchical levels. This means that if a
1463;; section contains one or more subsections, the section's `Next'
1464;; pointer will point to the subsection and not the following section.
1465;; (The subsection to which `Next' points will most likely be the first
1466;; item on the section's menu.)
7e1335cf
RC
1467
1468(defun texinfo-sequential-node-update (&optional region-p)
1469 "Update one node (or many) in a Texinfo file with sequential pointers.
1470
1471This function causes the `Next' or `Previous' pointer to point to the
1472immediately preceding or following node, even if it is at a higher or
1473lower hierarchical level in the document. Continually pressing `n' or
1474`p' takes you straight through the file.
1475
1476Without any prefix argument, update the node in which point is located.
1477Non-nil argument (prefix, if interactive) means update the nodes in the
1478marked region.
1479
1480This command makes it awkward to navigate among sections and
1481subsections; it should be used only for those documents that are meant
1482to be read like a novel rather than a reference, and for which the
1483Info `g*' command is inadequate."
d1f9f441 1484
7e1335cf
RC
1485 (interactive "P")
1486 (if (not region-p)
fe3371ef
RS
1487 ;; update a single node
1488 (let ((auto-fill-function nil) (auto-fill-hook nil))
91c6f26e 1489 (if (not (re-search-backward "^@node" (point-min) t))
e8af40ee 1490 (error "Node line not found before this position"))
91c6f26e
KH
1491 (texinfo-sequentially-update-the-node)
1492 (message
1493 "Done...sequentially updated the node . You may save the buffer."))
7e1335cf 1494 ;; else
e5d77022 1495 (let ((auto-fill-function nil)
fe3371ef 1496 (auto-fill-hook nil)
91c6f26e
KH
1497 (beginning (region-beginning))
1498 (end (region-end)))
7e1335cf 1499 (if (= end beginning)
91c6f26e 1500 (error "Please mark a region!"))
7e1335cf 1501 (save-restriction
91c6f26e
KH
1502 (narrow-to-region beginning end)
1503 (goto-char beginning)
1504 (push-mark (point) t)
1505 (while (re-search-forward "^@node" (point-max) t)
1506 (beginning-of-line)
1507 (texinfo-sequentially-update-the-node))
1508 (message
1509 "Done...updated the nodes in sequence. You may save the buffer.")))))
7e1335cf
RC
1510
1511(defun texinfo-sequentially-update-the-node ()
d1f9f441 1512 "Update one node such that the pointers are sequential.
7e1335cf
RC
1513A `Next' or `Previous' pointer points to any preceding or following node,
1514regardless of its hierarchical level."
1515
6f602bd0
SM
1516 (texinfo-check-for-node-name)
1517 (texinfo-delete-existing-pointers)
1518 (message
1519 "Sequentially updating node: %s ... " (texinfo-copy-node-name))
1520 (save-restriction
1521 (widen)
1522 (let* ((case-fold-search t)
1523 (level (texinfo-hierarchic-level)))
1524 (if (eq level 1)
1525 (texinfo-top-pointer-case)
1526 ;; else
1527 (texinfo-sequentially-insert-pointer level 'next)
1528 (texinfo-sequentially-insert-pointer level 'previous)
1529 (texinfo-sequentially-insert-pointer level 'up)
1530 (texinfo-clean-up-node-line)))))
7e1335cf
RC
1531
1532(defun texinfo-sequentially-find-pointer (level direction)
1533 "Find next or previous pointer sequentially in Texinfo file, or up pointer.
1534Move point to section associated with the pointer. Find point even if
1535it is in a different section.
1536
06cc857d 1537Return type of pointer (either `normal' or `no-pointer').
7e1335cf
RC
1538
1539The first argument is a string specifying the general kind of section
d460a763 1540such as \"chapter\" or \"section\". The section found will be at the
7e1335cf 1541same hierarchical level in the Texinfo file, or, in the case of the up
06cc857d
RS
1542pointer, some level higher. The second argument (one of `next',
1543`previous', or `up') specifies whether to find the `Next', `Previous',
7e1335cf 1544or `Up' pointer."
d1f9f441 1545 (let ((case-fold-search t))
daa6abb8 1546 (cond ((eq direction 'next)
91c6f26e
KH
1547 (forward-line 3) ; skip over current node
1548 (if (re-search-forward
1549 texinfo-section-types-regexp
1550 (point-max)
1551 t)
1552 'normal
1553 'no-pointer))
1554 ((eq direction 'previous)
1555 (if (re-search-backward
1556 texinfo-section-types-regexp
1557 (point-min)
1558 t)
1559 'normal
1560 'no-pointer))
1561 ((eq direction 'up)
1562 (if (re-search-backward
1563 (eval (cdr (assoc level texinfo-update-menu-higher-regexps)))
1564 beginning
1565 t)
1566 'normal
1567 'no-pointer))
1568 (t
1569 (error "texinfo-sequential-find-pointer: lack proper arguments")))))
7e1335cf
RC
1570
1571(defun texinfo-sequentially-insert-pointer (level direction)
1572 "Insert the `Next', `Previous' or `Up' node name at point.
d1f9f441 1573Move point forward.
7e1335cf
RC
1574
1575The first argument is the hierarchical level of the Texinfo file, a
1576string such as \"section\". The second argument is direction, one of
06cc857d 1577`next', `previous', or `up'."
7e1335cf
RC
1578
1579 (end-of-line)
1580 (insert
1581 ", "
1582 (save-excursion
1583 (texinfo-pointer-name
1584 (texinfo-sequentially-find-pointer level direction)))))
1585
1586\f
daa6abb8 1587;;; Inserting `@node' lines
06cc857d
RS
1588;; The `texinfo-insert-node-lines' function inserts `@node' lines as needed
1589;; before the `@chapter', `@section', and such like lines of a region
1590;; in a Texinfo file.
7e1335cf 1591
daa6abb8 1592(defun texinfo-insert-node-lines (beginning end &optional title-p)
7e1335cf
RC
1593 "Insert missing `@node' lines in region of Texinfo file.
1594Non-nil argument (prefix, if interactive) means also to insert the
1595section titles as node names; and also to insert the section titles as
06cc857d 1596node names in pre-existing `@node' lines that lack names."
daa6abb8
RS
1597 (interactive "r\nP")
1598
1599 ;; Use marker; after inserting node lines, leave point at end of
1600 ;; region and mark at beginning.
1601
1602 (let (beginning-marker end-marker title last-section-position)
1603
1604 ;; Save current position on mark ring and set mark to end.
d1f9f441
RS
1605 (push-mark end t)
1606 (setq end-marker (mark-marker))
daa6abb8
RS
1607
1608 (goto-char beginning)
1609 (while (re-search-forward
91c6f26e
KH
1610 texinfo-section-types-regexp
1611 end-marker
1612 'end)
daa6abb8
RS
1613 ;; Copy title if desired.
1614 (if title-p
91c6f26e
KH
1615 (progn
1616 (beginning-of-line)
1617 (forward-word 1)
1618 (skip-chars-forward " \t")
1619 (setq title (buffer-substring
1620 (point)
1621 (save-excursion (end-of-line) (point))))))
daa6abb8
RS
1622 ;; Insert node line if necessary.
1623 (if (re-search-backward
91c6f26e
KH
1624 "^@node"
1625 ;; Avoid finding previous node line if node lines are close.
1626 (or last-section-position
1627 (save-excursion (forward-line -2) (point))) t)
1628 ;; @node is present, and point at beginning of that line
1629 (forward-word 1) ; Leave point just after @node.
1630 ;; Else @node missing; insert one.
1631 (beginning-of-line) ; Beginning of `@section' line.
1632 (insert "@node\n")
1633 (backward-char 1)) ; Leave point just after `@node'.
daa6abb8
RS
1634 ;; Insert title if desired.
1635 (if title-p
91c6f26e
KH
1636 (progn
1637 (skip-chars-forward " \t")
1638 ;; Use regexp based on what info looks for
1639 ;; (alternatively, use "[a-zA-Z]+");
1640 ;; this means we only insert a title if none exists.
1641 (if (not (looking-at "[^,\t\n ]+"))
1642 (progn
1643 (beginning-of-line)
1644 (forward-word 1)
1645 (insert " " title)
1646 (message "Inserted title %s ... " title)))))
daa6abb8 1647 ;; Go forward beyond current section title.
d1f9f441 1648 (re-search-forward texinfo-section-types-regexp
91c6f26e 1649 (save-excursion (forward-line 3) (point)) t)
daa6abb8
RS
1650 (setq last-section-position (point))
1651 (forward-line 1))
1652
1653 ;; Leave point at end of region, mark at beginning.
1654 (set-mark beginning)
1655
1656 (if title-p
7e1335cf
RC
1657 (message
1658 "Done inserting node lines and titles. You may save the buffer.")
daa6abb8 1659 (message "Done inserting node lines. You may save the buffer."))))
7e1335cf
RC
1660
1661\f
daa6abb8 1662;;; Update and create menus for multi-file Texinfo sources
7e1335cf 1663
d1f9f441 1664;; 1. M-x texinfo-multiple-files-update
7e1335cf
RC
1665;;
1666;; Read the include file list of an outer Texinfo file and
1667;; update all highest level nodes in the files listed and insert a
1668;; main menu in the outer file after its top node.
1669
d1f9f441 1670;; 2. C-u M-x texinfo-multiple-files-update
7e1335cf
RC
1671;;
1672;; Same as 1, but insert a master menu. (Saves reupdating lower
1673;; level menus and nodes.) This command simply reads every menu,
1674;; so if the menus are wrong, the master menu will be wrong.
1675;; Similarly, if the lower level node pointers are wrong, they
1676;; will stay wrong.
1677
d1f9f441 1678;; 3. C-u 2 M-x texinfo-multiple-files-update
7e1335cf
RC
1679;;
1680;; Read the include file list of an outer Texinfo file and
1681;; update all nodes and menus in the files listed and insert a
1682;; master menu in the outer file after its top node.
1683
1684;;; Note: these functions:
1685;;;
1686;;; * Do not save or delete any buffers. You may fill up your memory.
d1f9f441 1687;;; * Do not handle any pre-existing nodes in outer file.
7e1335cf
RC
1688;;; Hence, you may need a file for indices.
1689
1690\f
daa6abb8 1691;;; Auxiliary functions for multiple file updating
7e1335cf
RC
1692
1693(defun texinfo-multi-file-included-list (outer-file)
1694 "Return a list of the included files in OUTER-FILE."
1695 (let ((included-file-list (list outer-file))
91c6f26e 1696 start)
7e1335cf
RC
1697 (save-excursion
1698 (switch-to-buffer (find-file-noselect outer-file))
1699 (widen)
1700 (goto-char (point-min))
1701 (while (re-search-forward "^@include" nil t)
91c6f26e
KH
1702 (skip-chars-forward " \t")
1703 (setq start (point))
1704 (end-of-line)
1705 (skip-chars-backward " \t")
1706 (setq included-file-list
1707 (cons (buffer-substring start (point))
1708 included-file-list)))
7e1335cf
RC
1709 (nreverse included-file-list))))
1710
1711(defun texinfo-copy-next-section-title ()
1712 "Return the name of the immediately following section as a string.
1713
1714Start with point at the beginning of the node line. Leave point at the
1715same place. If there is no title, returns an empty string."
1716
1717 (save-excursion
1718 (end-of-line)
d1f9f441 1719 (let ((node-end (or
91c6f26e
KH
1720 (save-excursion
1721 (if (re-search-forward "\\(^@node\\)" nil t)
1722 (match-beginning 0)))
1723 (point-max))))
daa6abb8 1724 (if (re-search-forward texinfo-section-types-regexp node-end t)
91c6f26e
KH
1725 (progn
1726 (beginning-of-line)
1727 ;; copy title
1728 (let ((title
1729 (buffer-substring
1730 (progn (forward-word 1) ; skip over section type
1731 (skip-chars-forward " \t") ; and over spaces
1732 (point))
1733 (progn (end-of-line) (point)))))
1734 title))
1735 ""))))
7e1335cf
RC
1736
1737(defun texinfo-multi-file-update (files &optional update-everything)
1738 "Update first node pointers in each file in FILES.
daa6abb8 1739Return a list of the node names.
7e1335cf
RC
1740
1741The first file in the list is an outer file; the remaining are
1742files included in the outer file with `@include' commands.
1743
1744If optional arg UPDATE-EVERYTHING non-nil, update every menu and
1745pointer in each of the included files.
1746
1747Also update the `Top' level node pointers of the outer file.
1748
1749Requirements:
1750
1751 * the first file in the FILES list must be the outer file,
1752 * each of the included files must contain exactly one highest
d1f9f441 1753 hierarchical level node,
7e1335cf
RC
1754 * this node must be the first node in the included file,
1755 * each highest hierarchical level node must be of the same type.
1756
06cc857d 1757Thus, normally, each included file contains one, and only one, chapter."
7e1335cf 1758
06cc857d 1759;; The menu-list has the form:
d1f9f441
RS
1760;;
1761;; \(\(\"node-name1\" . \"title1\"\)
06cc857d 1762;; \(\"node-name2\" . \"title2\"\) ... \)
d1f9f441 1763;;
06cc857d
RS
1764;; However, there does not need to be a title field and this function
1765;; does not fill it; however a comment tells you how to do so.
1766;; You would use the title field if you wanted to insert titles in the
1767;; description slot of a menu as a description.
d1f9f441 1768
daa6abb8 1769 (let ((case-fold-search t)
91c6f26e 1770 menu-list)
d1f9f441 1771
7e1335cf
RC
1772 ;; Find the name of the first node of the first included file.
1773 (switch-to-buffer (find-file-noselect (car (cdr files))))
1774 (widen)
1775 (goto-char (point-min))
1776 (if (not (re-search-forward "^@node" nil t))
91c6f26e 1777 (error "No `@node' line found in %s !" (buffer-name)))
7e1335cf
RC
1778 (beginning-of-line)
1779 (texinfo-check-for-node-name)
1780 (setq next-node-name (texinfo-copy-node-name))
d1f9f441 1781
7e1335cf 1782 (setq menu-list
91c6f26e
KH
1783 (cons (cons
1784 next-node-name
1785 (prog1 "" (forward-line 1)))
1786 ;; Use following to insert section titles automatically.
1787 ;; (texinfo-copy-next-section-title)
1788 menu-list))
daa6abb8 1789
7e1335cf
RC
1790 ;; Go to outer file
1791 (switch-to-buffer (find-file-noselect (car files)))
1792 (goto-char (point-min))
82ac4b77 1793 (if (not (re-search-forward "^@node [ \t]*top[ \t]*\\(,\\|$\\)" nil t))
91c6f26e 1794 (error "This buffer needs a Top node!"))
7e1335cf
RC
1795 (beginning-of-line)
1796 (texinfo-delete-existing-pointers)
1797 (end-of-line)
1798 (insert ", " next-node-name ", (dir), (dir)")
1799 (beginning-of-line)
1800 (setq previous-node-name "Top")
1801 (setq files (cdr files))
d1f9f441 1802
7e1335cf 1803 (while files
d1f9f441 1804
7e1335cf 1805 (if (not (cdr files))
91c6f26e
KH
1806 ;; No next file
1807 (setq next-node-name "")
1808 ;; Else,
1809 ;; find the name of the first node in the next file.
1810 (switch-to-buffer (find-file-noselect (car (cdr files))))
1811 (widen)
1812 (goto-char (point-min))
1813 (if (not (re-search-forward "^@node" nil t))
1814 (error "No `@node' line found in %s !" (buffer-name)))
1815 (beginning-of-line)
1816 (texinfo-check-for-node-name)
1817 (setq next-node-name (texinfo-copy-node-name))
1818 (setq menu-list
1819 (cons (cons
1820 next-node-name
1821 (prog1 "" (forward-line 1)))
1822 ;; Use following to insert section titles automatically.
1823 ;; (texinfo-copy-next-section-title)
1824 menu-list)))
7e1335cf
RC
1825
1826 ;; Go to node to be updated.
1827 (switch-to-buffer (find-file-noselect (car files)))
1828 (goto-char (point-min))
1829 (if (not (re-search-forward "^@node" nil t))
91c6f26e 1830 (error "No `@node' line found in %s !" (buffer-name)))
7e1335cf 1831 (beginning-of-line)
d1f9f441 1832
daa6abb8
RS
1833 ;; Update other menus and nodes if requested.
1834 (if update-everything (texinfo-all-menus-update t))
1835
1836 (beginning-of-line)
7e1335cf
RC
1837 (texinfo-delete-existing-pointers)
1838 (end-of-line)
1839 (insert ", " next-node-name ", " previous-node-name ", " up-node-name)
d1f9f441 1840
7e1335cf
RC
1841 (beginning-of-line)
1842 (setq previous-node-name (texinfo-copy-node-name))
d1f9f441 1843
7e1335cf
RC
1844 (setq files (cdr files)))
1845 (nreverse menu-list)))
1846
1847(defun texinfo-multi-files-insert-main-menu (menu-list)
1848 "Insert formatted main menu at point.
1849Indents the first line of the description, if any, to the value of
06cc857d 1850`texinfo-column-for-description'."
7e1335cf
RC
1851
1852 (insert "@menu\n")
1853 (while menu-list
daa6abb8
RS
1854 ;; Every menu entry starts with a star and a space.
1855 (insert "* ")
d1f9f441 1856
daa6abb8
RS
1857 ;; Insert the node name (and menu entry name, if present).
1858 (let ((node-part (car (car menu-list))))
1859 (if (stringp node-part)
91c6f26e
KH
1860 ;; "Double colon" entry line; menu entry and node name are the same,
1861 (insert (format "%s::" node-part))
1862 ;; "Single colon" entry line; menu entry and node name are different.
1863 (insert (format "%s: %s." (car node-part) (cdr node-part)))))
d1f9f441 1864
daa6abb8
RS
1865 ;; Insert the description, if present.
1866 (if (cdr (car menu-list))
91c6f26e
KH
1867 (progn
1868 ;; Move to right place.
1869 (indent-to texinfo-column-for-description 2)
1870 ;; Insert description.
1871 (insert (format "%s" (cdr (car menu-list))))))
daa6abb8
RS
1872
1873 (insert "\n") ; end this menu entry
7e1335cf
RC
1874 (setq menu-list (cdr menu-list)))
1875 (insert "@end menu"))
1876
7e1335cf
RC
1877(defun texinfo-multi-file-master-menu-list (files-list)
1878 "Return master menu list from files in FILES-LIST.
1879Menu entries in each file collected using `texinfo-master-menu-list'.
1880
1881The first file in FILES-LIST must be the outer file; the others must
1882be the files included within it. A main menu must already exist."
1883 (save-excursion
1884 (let (master-menu-list)
1885 (while files-list
91c6f26e
KH
1886 (switch-to-buffer (find-file-noselect (car files-list)))
1887 (message "Working on: %s " (current-buffer))
1888 (goto-char (point-min))
1889 (setq master-menu-list
1890 (append master-menu-list (texinfo-master-menu-list)))
1891 (setq files-list (cdr files-list)))
7e1335cf
RC
1892 master-menu-list)))
1893
1894\f
daa6abb8 1895;;; The multiple-file update function
7e1335cf
RC
1896
1897(defun texinfo-multiple-files-update
1898 (outer-file &optional update-everything make-master-menu)
1899 "Update first node pointers in each file included in OUTER-FILE;
daa6abb8
RS
1900create or update the `Top' level node pointers and the main menu in
1901the outer file that refers to such nodes. This does not create or
1902update menus or pointers within the included files.
7e1335cf
RC
1903
1904With optional MAKE-MASTER-MENU argument (prefix arg, if interactive),
daa6abb8
RS
1905insert a master menu in OUTER-FILE in addition to creating or updating
1906pointers in the first @node line in each included file and creating or
1907updating the `Top' level node pointers of the outer file. This does
1908not create or update other menus and pointers within the included
1909files.
7e1335cf
RC
1910
1911With optional UPDATE-EVERYTHING argument (numeric prefix arg, if
1912interactive), update all the menus and all the `Next', `Previous', and
1913`Up' pointers of all the files included in OUTER-FILE before inserting
daa6abb8
RS
1914a master menu in OUTER-FILE. Also, update the `Top' level node
1915pointers of OUTER-FILE.
7e1335cf 1916
d1f9f441 1917Notes:
7e1335cf
RC
1918
1919 * this command does NOT save any files--you must save the
1920 outer file and any modified, included files.
1921
1922 * except for the `Top' node, this command does NOT handle any
1923 pre-existing nodes in the outer file; hence, indices must be
1924 enclosed in an included file.
1925
1926Requirements:
1927
1928 * each of the included files must contain exactly one highest
d1f9f441 1929 hierarchical level node,
7e1335cf
RC
1930 * this highest node must be the first node in the included file,
1931 * each highest hierarchical level node must be of the same type.
1932
1933Thus, normally, each included file contains one, and only one,
1934chapter."
d1f9f441 1935
daa6abb8 1936 (interactive (cons
91c6f26e
KH
1937 (read-string
1938 "Name of outer `include' file: "
1939 (buffer-file-name))
1940 (cond ((not current-prefix-arg)
1941 '(nil nil))
1942 ((listp current-prefix-arg)
1943 '(t nil)) ; make-master-menu
1944 ((numberp current-prefix-arg)
1945 '(t t)) ; update-everything
1946 )))
7e1335cf
RC
1947
1948 (let* ((included-file-list (texinfo-multi-file-included-list outer-file))
91c6f26e
KH
1949 (files included-file-list)
1950 main-menu-list
1951 next-node-name
1952 previous-node-name
1953 (up-node-name "Top"))
7e1335cf 1954
d1f9f441 1955;;; Update the pointers
7e1335cf
RC
1956;;; and collect the names of the nodes and titles
1957 (setq main-menu-list (texinfo-multi-file-update files update-everything))
1958
1959;;; Insert main menu
1960
1961 ;; Go to outer file
1962 (switch-to-buffer (find-file-noselect (car included-file-list)))
1963 (if (texinfo-old-menu-p
1964 (point-min)
1965 (save-excursion
91c6f26e
KH
1966 (re-search-forward "^@include")
1967 (beginning-of-line)
1968 (point)))
7e1335cf
RC
1969
1970 ;; If found, leave point after word `menu' on the `@menu' line.
1971 (progn
91c6f26e
KH
1972 (texinfo-incorporate-descriptions main-menu-list)
1973 ;; Delete existing menu.
1974 (beginning-of-line)
1975 (delete-region
1976 (point)
1977 (save-excursion (re-search-forward "^@end menu") (point)))
1978 ;; Insert main menu
1979 (texinfo-multi-files-insert-main-menu main-menu-list))
7e1335cf
RC
1980
1981 ;; Else no current menu; insert it before `@include'
1982 (texinfo-multi-files-insert-main-menu main-menu-list))
1983
1984;;; Insert master menu
1985
1986 (if make-master-menu
1987 (progn
91c6f26e
KH
1988 ;; First, removing detailed part of any pre-existing master menu
1989 (goto-char (point-min))
1990 (if (search-forward texinfo-master-menu-header nil t)
1991 (progn
1992 (goto-char (match-beginning 0))
06cc857d
RS
1993 ;; Check if @detailmenu kludge is used;
1994 ;; if so, leave point before @detailmenu.
d1f9f441 1995 (search-backward "\n@detailmenu"
06cc857d
RS
1996 (save-excursion (forward-line -3) (point))
1997 t)
1998 ;; Remove detailed master menu listing
91c6f26e
KH
1999 (let ((end-of-detailed-menu-descriptions
2000 (save-excursion ; beginning of end menu line
2001 (goto-char (texinfo-menu-end))
2002 (beginning-of-line) (forward-char -1)
2003 (point))))
2004 (delete-region (point) end-of-detailed-menu-descriptions))))
2005
2006 ;; Create a master menu and insert it
2007 (texinfo-insert-master-menu-list
2008 (texinfo-multi-file-master-menu-list
2009 included-file-list)))))
daa6abb8
RS
2010
2011 ;; Remove unwanted extra lines.
2012 (save-excursion
2013 (goto-char (point-min))
d1f9f441 2014
daa6abb8
RS
2015 (re-search-forward "^@menu")
2016 (forward-line -1)
2017 (insert "\n") ; Ensure at least one blank line.
2018 (delete-blank-lines)
d1f9f441 2019
daa6abb8
RS
2020 (re-search-forward "^@end menu")
2021 (forward-line 1)
2022 (insert "\n") ; Ensure at least one blank line.
2023 (delete-blank-lines))
2024
7e1335cf
RC
2025 (message "Multiple files updated."))
2026
daa6abb8
RS
2027\f
2028;;; Place `provide' at end of file.
49116ac0
JB
2029(provide 'texnfo-upd)
2030
d501f516 2031;;; texnfo-upd.el ends here