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