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