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