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