summaryrefslogtreecommitdiff
path: root/gnu/usr.bin/texinfo/emacs/texnfo-upd.el
diff options
context:
space:
mode:
Diffstat (limited to 'gnu/usr.bin/texinfo/emacs/texnfo-upd.el')
-rw-r--r--gnu/usr.bin/texinfo/emacs/texnfo-upd.el2046
1 files changed, 2046 insertions, 0 deletions
diff --git a/gnu/usr.bin/texinfo/emacs/texnfo-upd.el b/gnu/usr.bin/texinfo/emacs/texnfo-upd.el
new file mode 100644
index 00000000000..f84cdd51496
--- /dev/null
+++ b/gnu/usr.bin/texinfo/emacs/texnfo-upd.el
@@ -0,0 +1,2046 @@
+;;; Texinfo mode utilities for updating nodes and menus in Texinfo files.
+;;; Copyright 1989, 1990, 1991, 1992 Free Software Foundation
+
+;; Author: Robert J. Chassell
+;; Maintainer: bug-texinfo@prep.ai.mit.edu
+;; Keywords: maint, tex, docs
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs; see the file COPYING. If not, write to
+;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+;;; Commentary:
+
+;;; Known bug: update commands fail to ignore @ignore.
+
+;;; Summary: how to use the updating commands
+
+; The node and menu updating functions automatically
+
+; * insert missing `@node' lines,
+; * insert the `Next', `Previous' and `Up' pointers of a node,
+; * insert or update the menu for a section,
+; * create a master menu for a Texinfo source file.
+;
+; Passed an argument, the `texinfo-update-node' and
+; `texinfo-make-menu' functions do their jobs in the region.
+;
+; In brief, the functions for creating or updating nodes and menus, are:
+;
+; texinfo-update-node (&optional region-p)
+; texinfo-every-node-update ()
+; texinfo-sequential-node-update (&optional region-p)
+;
+; texinfo-make-menu (&optional region-p)
+; texinfo-all-menus-update ()
+; texinfo-master-menu ()
+;
+; texinfo-insert-node-lines (&optional title-p)
+;
+; texinfo-indent-menu-description (column &optional region-p)
+
+; The `texinfo-column-for-description' variable specifies the column to
+; which menu descriptions are indented.
+
+; Texinfo file structure
+; ----------------------
+
+; To use the updating commands, you must structure your Texinfo file
+; hierarchically. Each `@node' line, with the exception of the top
+; node, must be accompanied by some kind of section line, such as an
+; `@chapter' or `@section' line. Each node-line/section-line
+; combination must look like this:
+
+; @node Lists and Tables, Cross References, Structuring, Top
+; @comment node-name, next, previous, up
+; @chapter Making Lists and Tables
+
+; or like this (without the `@comment' line):
+
+; @node Lists and Tables, Cross References, Structuring, Top
+; @chapter Making Lists and Tables
+
+; If the file has a `top' node, it must be called `top' or `Top' and
+; be the first node in the file.
+
+
+;;; The update node functions described in detail
+
+; The `texinfo-update-node' function without an argument inserts
+; the correct next, previous and up pointers for the node in which
+; point is located (i.e., for the node preceding point).
+
+; With an argument, the `texinfo-update-node' function inserts the
+; correct next, previous and up pointers for the nodes inside the
+; region.
+
+; It does not matter whether the `@node' line has pre-existing
+; `Next', `Previous', or `Up' pointers in it. They are removed.
+
+; The `texinfo-every-node-update' function runs `texinfo-update-node'
+; on the whole buffer.
+
+; The `texinfo-sequential-node-update' function inserts the
+; immediately following and preceding node into the `Next' or
+; `Previous' pointers regardless of their hierarchical level. This is
+; only useful for certain kinds of text, like a novel, which you go
+; through sequentially.
+
+
+;;; The menu making functions described in detail
+
+; The `texinfo-make-menu' function without an argument creates or
+; updates a menu for the section encompassing the node that follows
+; point. With an argument, it makes or updates menus for the nodes
+; within or part of the marked region.
+
+; Whenever an existing menu is updated, the descriptions from
+; that menu are incorporated into the new menu. This is done by copying
+; descriptions from the existing menu to the entries in the new menu
+; that have the same node names. If the node names are different, the
+; descriptions are not copied to the new menu.
+
+; Menu entries that refer to other Info files are removed since they
+; are not a node within current buffer. This is a deficiency.
+
+; The `texinfo-all-menus-update' function runs `texinfo-make-menu'
+; on the whole buffer.
+
+; The `texinfo-master-menu' function creates an extended menu located
+; after the top node. (The file must have a top node.) The function
+; first updates all the regular menus in the buffer (incorporating the
+; descriptions from pre-existing menus), and then constructs a master
+; menu that includes every entry from every other menu. (However, the
+; function cannot update an already existing master menu; if one
+; exists, it must be removed before calling the function.)
+
+; The `texinfo-indent-menu-description' function indents every
+; description in the menu following point, to the specified column.
+; Non-nil argument (prefix, if interactive) means indent every
+; description in every menu in the region. This function does not
+; indent second and subsequent lines of a multi-line description.
+
+; The `texinfo-insert-node-lines' function inserts `@node' before the
+; `@chapter', `@section', and such like lines of a region in a Texinfo
+; file where the `@node' lines are missing.
+;
+; With a non-nil argument (prefix, if interactive), the function not
+; only inserts `@node' lines but also inserts the chapter or section
+; titles as the names of the corresponding nodes; and inserts titles
+; as node names in pre-existing `@node' lines that lack names.
+;
+; Since node names should be more concise than section or chapter
+; titles, node names so inserted will need to be edited manually.
+
+
+;;; Code:
+
+;;; The menu making functions
+
+(defun texinfo-make-menu (&optional region-p)
+ "Without any prefix argument, make or update a menu.
+Make the menu for the section enclosing the node found following point.
+
+Non-nil argument (prefix, if interactive) means make or update menus
+for nodes within or part of the marked region.
+
+Whenever a menu exists, and is being updated, the descriptions that
+are associated with node names in the pre-existing menu are
+incorporated into the new menu. Otherwise, the nodes' section titles
+are inserted as descriptions."
+
+ (interactive "P")
+ (if (not region-p)
+ (let ((level (texinfo-hierarchic-level)))
+ (texinfo-make-one-menu level)
+ (message "Done...updated the menu. You may save the buffer."))
+ ;; else
+ (message "Making or updating menus in %s... " (buffer-name))
+ (let ((beginning (region-beginning))
+ (region-end (region-end))
+ (level (progn ; find section type following point
+ (goto-char (region-beginning))
+ (texinfo-hierarchic-level))))
+ (if (= region-end beginning)
+ (error "Please mark a region!"))
+ (save-excursion
+ (save-restriction
+ (widen)
+
+ (while (texinfo-find-lower-level-node level region-end)
+ (setq level (texinfo-hierarchic-level)) ; new, lower level
+ (texinfo-make-one-menu level))
+
+ (while (and (< (point) region-end)
+ (texinfo-find-higher-level-node level region-end))
+ (setq level (texinfo-hierarchic-level))
+ (while (texinfo-find-lower-level-node level region-end)
+ (setq level (texinfo-hierarchic-level)) ; new, lower level
+ (texinfo-make-one-menu level))))))
+ (message "Done...updated menus. You may save the buffer.")))
+
+(defun texinfo-make-one-menu (level)
+ "Make a menu of all the appropriate nodes in this section.
+`Appropriate nodes' are those associated with sections that are
+at the level specified by LEVEL. Point is left at the end of menu."
+ (let*
+ ((case-fold-search t)
+ (beginning
+ (save-excursion
+ (goto-char (texinfo-update-menu-region-beginning level))
+ (end-of-line)
+ (point)))
+ (end (texinfo-update-menu-region-end level))
+ (first (texinfo-menu-first-node beginning end))
+ (node-name (progn
+ (goto-char beginning)
+ (beginning-of-line)
+ (texinfo-copy-node-name)))
+ (new-menu-list (texinfo-make-menu-list beginning end level)))
+ (if (texinfo-old-menu-p beginning first)
+ (progn
+ (texinfo-incorporate-descriptions new-menu-list)
+ (texinfo-incorporate-menu-entry-names new-menu-list)
+ (texinfo-delete-old-menu beginning first)))
+ (texinfo-insert-menu new-menu-list node-name)))
+
+(defun texinfo-all-menus-update (&optional update-all-nodes-p)
+ "Update every regular menu in a Texinfo file.
+Update pre-existing master menu, if there is one.
+
+If called with a non-nil argument, this function first updates all the
+nodes in the buffer before updating the menus."
+ (interactive "P")
+ (let ((case-fold-search t)
+ master-menu-p)
+ (save-excursion
+ (push-mark (point-max) t)
+ (goto-char (point-min))
+ (message "Checking for a master menu in %s ... "(buffer-name))
+ (save-excursion
+ (if (re-search-forward texinfo-master-menu-header nil t)
+ ;; Remove detailed master menu listing
+ (progn
+ (setq master-menu-p t)
+ (goto-char (match-beginning 0))
+ (let ((end-of-detailed-menu-descriptions
+ (save-excursion ; beginning of end menu line
+ (goto-char (texinfo-menu-end))
+ (beginning-of-line) (forward-char -1)
+ (point))))
+ (delete-region (point) end-of-detailed-menu-descriptions)))))
+
+ (if update-all-nodes-p
+ (progn
+ (message "Updating all nodes in %s ... " (buffer-name))
+ (sleep-for 2)
+ (push-mark (point-max) t)
+ (goto-char (point-min))
+ ;; Using the mark to pass bounds this way
+ ;; is kludgy, but it's not worth fixing. -- rms.
+ (let ((mark-active t))
+ (texinfo-update-node t))))
+
+ (message "Updating all menus in %s ... " (buffer-name))
+ (sleep-for 2)
+ (push-mark (point-max) t)
+ (goto-char (point-min))
+ ;; Using the mark to pass bounds this way
+ ;; is kludgy, but it's not worth fixing. -- rms.
+ (let ((mark-active t))
+ (texinfo-make-menu t))
+
+ (if master-menu-p
+ (progn
+ (message "Updating the master menu in %s... " (buffer-name))
+ (sleep-for 2)
+ (texinfo-master-menu nil))))
+
+ (message "Done...updated all the menus. You may save the buffer.")))
+
+(defun texinfo-find-lower-level-node (level region-end)
+ "Search forward from point for node at any level lower than LEVEL.
+Search is limited to the end of the marked region, REGION-END,
+and to the end of the menu region for the level.
+
+Return t if the node is found, else nil. Leave point at the beginning
+of the node if one is found; else do not move point."
+ (let ((case-fold-search t))
+ (if (and (< (point) region-end)
+ (re-search-forward
+ (concat
+ "\\(^@node\\).*\n" ; match node line
+ "\\(\\(\\(^@c\\).*\n\\)" ; match comment line, if any
+ "\\|" ; or
+ "\\(^@ifinfo[ ]*\n\\)\\)?" ; ifinfo line, if any
+ (eval (cdr (assoc level texinfo-update-menu-lower-regexps))))
+ ;; the next higher level node marks the end of this
+ ;; section, and no lower level node will be found beyond
+ ;; this position even if region-end is farther off
+ (texinfo-update-menu-region-end level)
+ t))
+ (goto-char (match-beginning 1)))))
+
+(defun texinfo-find-higher-level-node (level region-end)
+ "Search forward from point for node at any higher level than argument LEVEL.
+Search is limited to the end of the marked region, REGION-END.
+
+Return t if the node is found, else nil. Leave point at the beginning
+of the node if one is found; else do not move point."
+ (let ((case-fold-search t))
+ (cond
+ ((or (string-equal "top" level) (string-equal "chapter" level))
+ (if (re-search-forward "^@node [ \t]*top[ \t]*\\(,\\|$\\)" region-end t)
+ (progn (beginning-of-line) t)))
+ (t
+ (if (re-search-forward
+ (concat
+ "\\(^@node\\).*\n" ; match node line
+ "\\(\\(\\(^@c\\).*\n\\)" ; match comment line, if any
+ "\\|" ; or
+ "\\(^@ifinfo[ ]*\n\\)\\)?" ; ifinfo line, if any
+ (eval (cdr (assoc level texinfo-update-menu-higher-regexps))))
+ region-end t)
+ (progn (beginning-of-line) t))))))
+
+
+;;; Making the list of new menu entries
+
+(defun texinfo-make-menu-list (beginning end level)
+ "Make a list of node names and their descriptions.
+Point is left at the end of the menu region, but the menu is not inserted.
+
+First argument is position from which to start making menu list;
+second argument is end of region in which to try to locate entries;
+third argument is the level of the nodes that are the entries.
+
+Node names and descriptions are dotted pairs of strings. Each pair is
+an element of the list. If the description does not exist, the
+element consists only of the node name."
+ (goto-char beginning)
+ (let (new-menu-list)
+ (while (texinfo-menu-locate-entry-p level end)
+ (setq new-menu-list
+ (cons (cons
+ (texinfo-copy-node-name)
+ (prog1 "" (forward-line 1)))
+ ;; Use following to insert section titles automatically.
+ ;; (texinfo-copy-section-title))
+ new-menu-list)))
+ (reverse new-menu-list)))
+
+(defun texinfo-menu-locate-entry-p (level search-end)
+ "Find a node that will be part of menu for this section.
+First argument is a string such as \"section\" specifying the general
+hierarchical level of the menu; second argument is a position
+specifying the end of the search.
+
+The function returns t if the node is found, else nil. It searches
+forward from point, and leaves point at the beginning of the node.
+
+The function finds entries of the same type. Thus `subsections' and
+`unnumberedsubsecs' will appear in the same menu."
+ (let ((case-fold-search t))
+ (if (re-search-forward
+ (concat
+ "\\(^@node\\).*\n" ; match node line
+ "\\(\\(\\(^@c\\).*\n\\)" ; match comment line, if any
+ "\\|" ; or
+ "\\(^@ifinfo[ ]*\n\\)\\)?" ; ifinfo line, if any
+ (eval
+ (cdr (assoc level texinfo-update-menu-same-level-regexps))))
+ search-end
+ t)
+ (goto-char (match-beginning 1)))))
+
+(defun texinfo-copy-node-name ()
+ "Return the node name as a string.
+
+Start with point at the beginning of the node line; copy the text
+after the node command up to the first comma on the line, if any, and
+return the text as a string. Leaves point at the beginning of the
+line. If there is no node name, returns an empty string."
+
+ (save-excursion
+ (buffer-substring
+ (progn (forward-word 1) ; skip over node command
+ (skip-chars-forward " \t") ; and over spaces
+ (point))
+ (if (search-forward
+ ","
+ (save-excursion (end-of-line) (point)) t) ; bound search
+ (1- (point))
+ (end-of-line) (point)))))
+
+(defun texinfo-copy-section-title ()
+ "Return the title of the section as a string.
+The title is used as a description line in the menu when one does not
+already exist.
+
+Move point to the beginning of the appropriate section line by going
+to the start of the text matched by last regexp searched for, which
+must have been done by `texinfo-menu-locate-entry-p'."
+
+ ;; could use the same re-search as in `texinfo-menu-locate-entry-p'
+ ;; instead of using `match-beginning'; such a variation would be
+ ;; more general, but would waste information already collected
+
+ (goto-char (match-beginning 7)) ; match section name
+
+ (buffer-substring
+ (progn (forward-word 1) ; skip over section type
+ (skip-chars-forward " \t") ; and over spaces
+ (point))
+ (progn (end-of-line) (point))))
+
+
+;;; Handling the old menu
+
+(defun texinfo-old-menu-p (beginning first)
+ "Move point to the beginning of the menu for this section, if any.
+Otherwise move point to the end of the first node of this section.
+Return t if a menu is found, nil otherwise.
+
+First argument is the position of the beginning of the section in which
+the menu will be located; second argument is the position of the first
+node within the section.
+
+If no menu is found, the function inserts two newlines just before the
+end of the section, and leaves point there where a menu ought to be."
+ (goto-char beginning)
+ (if (not (re-search-forward "^@menu" first 'goto-end))
+ (progn (insert "\n\n") (forward-line -2) nil)
+ t))
+
+(defun texinfo-incorporate-descriptions (new-menu-list)
+ "Copy the old menu line descriptions that exist to the new menu.
+
+Point must be at beginning of old menu.
+
+If the node-name of the new menu is found in the old menu, insert the
+old description into the new entry.
+
+For this function, the new menu is a list made up of lists of dotted
+pairs in which the first element of the pair is the node name and the
+second element the description. The new menu is changed destructively.
+The old menu is the menu as it appears in the texinfo file."
+
+ (let ((new-menu-list-pointer new-menu-list)
+ (end-of-menu (texinfo-menu-end)))
+ (while new-menu-list
+ (save-excursion ; keep point at beginning of menu
+ (if (re-search-forward
+ ;; Existing nodes can have the form
+ ;; * NODE NAME:: DESCRIPTION
+ ;; or
+ ;; * MENU ITEM: NODE NAME. DESCRIPTION.
+ ;;
+ ;; Recognize both when looking for the description.
+ (concat "\\* \\(" ; so only menu entries are found
+ (car (car new-menu-list)) "::"
+ "\\|"
+ ".*: " (car (car new-menu-list)) "[.,\t\n]"
+ "\\)"
+ ) ; so only complete entries are found
+ end-of-menu
+ t)
+ (setcdr (car new-menu-list)
+ (texinfo-menu-copy-old-description end-of-menu))))
+ (setq new-menu-list (cdr new-menu-list)))
+ (setq new-menu-list new-menu-list-pointer)))
+
+(defun texinfo-incorporate-menu-entry-names (new-menu-list)
+ "Copy any old menu entry names to the new menu.
+
+Point must be at beginning of old menu.
+
+If the node-name of the new menu entry cannot be found in the old
+menu, do nothing.
+
+For this function, the new menu is a list made up of lists of dotted
+pairs in which the first element of the pair is the node name and the
+second element is the description (or nil).
+
+If we find an existing menu entry name, we change the first element of
+the pair to be another dotted pair in which the car is the menu entry
+name and the cdr is the node name.
+
+NEW-MENU-LIST is changed destructively. The old menu is the menu as it
+appears in the texinfo file."
+
+ (let ((new-menu-list-pointer new-menu-list)
+ (end-of-menu (texinfo-menu-end)))
+ (while new-menu-list
+ (save-excursion ; keep point at beginning of menu
+ (if (re-search-forward
+ ;; Existing nodes can have the form
+ ;; * NODE NAME:: DESCRIPTION
+ ;; or
+ ;; * MENU ITEM: NODE NAME. DESCRIPTION.
+ ;;
+ ;; We're interested in the second case.
+ (concat "\\* " ; so only menu entries are found
+ "\\(.*\\): " (car (car new-menu-list)) "[.,\t\n]")
+ end-of-menu
+ t)
+ (setcar
+ (car new-menu-list) ; replace the node name
+ (cons (buffer-substring (match-beginning 1) (match-end 1))
+ (car (car new-menu-list)))))
+ (setq new-menu-list (cdr new-menu-list))))
+ (setq new-menu-list new-menu-list-pointer)))
+
+(defun texinfo-menu-copy-old-description (end-of-menu)
+ "Return description field of old menu line as string.
+Point must be located just after the node name. Point left before description.
+Single argument, END-OF-MENU, is position limiting search."
+ (skip-chars-forward "[:.,\t\n ]+")
+ ;; don't copy a carriage return at line beginning with asterisk!
+ ;; do copy a description that begins with an `@'!
+ ;; !! Known bug: does not copy descriptions starting with ^|\{?* etc.
+ (if (and (looking-at "\\(\\w+\\|@\\)")
+ (not (looking-at "\\(^\\* \\|^@end menu\\)")))
+ (buffer-substring
+ (point)
+ (save-excursion
+ (re-search-forward "\\(^\\* \\|^@end menu\\)" end-of-menu t)
+ (forward-line -1)
+ (end-of-line) ; go to end of last description line
+ (point)))
+ ""))
+
+(defun texinfo-menu-end ()
+ "Return position of end of menu. Does not change location of point.
+Signal an error if not end of menu."
+ (save-excursion
+ (if (re-search-forward "^@end menu" nil t)
+ (point)
+ (error "Menu does not have an end."))))
+
+(defun texinfo-delete-old-menu (beginning first)
+ "Delete the old menu. Point must be in or after menu.
+First argument is position of the beginning of the section in which
+the menu will be located; second argument is the position of the first
+node within the section."
+ ;; No third arg to search, so error if search fails.
+ (re-search-backward "^@menu" beginning)
+ (delete-region (point)
+ (save-excursion
+ (re-search-forward "^@end menu" first)
+ (point))))
+
+
+;;; Inserting new menu
+
+;; try 32, but perhaps 24 is better
+(defvar texinfo-column-for-description 32
+ "*Column at which descriptions start in a Texinfo menu.")
+
+(defun texinfo-insert-menu (menu-list node-name)
+ "Insert formatted menu at point.
+Indents the first line of the description, if any, to the value of
+texinfo-column-for-description.
+
+MENU-LIST has form:
+
+ \(\(\"node-name1\" . \"description\"\)
+ \(\"node-name2\" . \"description\"\) ... \)
+
+However, the description field might be nil.
+
+Also, the node-name field might itself be a dotted pair (call it P) of
+strings instead of just a string. In that case, the car of P
+is the menu entry name, and the cdr of P is the node name."
+
+ (insert "@menu\n")
+ (while menu-list
+ ;; Every menu entry starts with a star and a space.
+ (insert "* ")
+
+ ;; Insert the node name (and menu entry name, if present).
+ (let ((node-part (car (car menu-list))))
+ (if (stringp node-part)
+ ;; "Double colon" entry line; menu entry and node name are the same,
+ (insert (format "%s::" node-part))
+ ;; "Single colon" entry line; menu entry and node name are different.
+ (insert (format "%s: %s." (car node-part) (cdr node-part)))))
+
+ ;; Insert the description, if present.
+ (if (cdr (car menu-list))
+ (progn
+ ;; Move to right place.
+ (indent-to texinfo-column-for-description 2)
+ ;; Insert description.
+ (insert (format "%s" (cdr (car menu-list))))))
+
+ (insert "\n") ; end this menu entry
+ (setq menu-list (cdr menu-list)))
+ (insert "@end menu")
+ (message
+ "Updated \"%s\" level menu following node: %s ... " level node-name))
+
+
+;;; Starting menu descriptions by inserting titles
+
+(defun texinfo-start-menu-description ()
+ "In this menu entry, insert the node's section title as a description.
+Position point at beginning of description ready for editing.
+Do not insert a title if the line contains an existing description.
+
+You will need to edit the inserted text since a useful description
+complements the node name rather than repeats it as a title does."
+
+ (interactive)
+ (let (beginning end node-name title)
+ (save-excursion
+ (beginning-of-line)
+ (if (search-forward "* " (save-excursion (end-of-line) (point)) t)
+ (progn (skip-chars-forward " \t")
+ (setq beginning (point)))
+ (error "This is not a line in a menu!"))
+
+ (cond
+ ;; "Double colon" entry line; menu entry and node name are the same,
+ ((search-forward "::" (save-excursion (end-of-line) (point)) t)
+ (if (looking-at "[ \t]*[^ \t\n]+")
+ (error "Descriptive text already exists."))
+ (skip-chars-backward ": \t")
+ (setq node-name (buffer-substring beginning (point))))
+
+ ;; "Single colon" entry line; menu entry and node name are different.
+ ((search-forward ":" (save-excursion (end-of-line) (point)) t)
+ (skip-chars-forward " \t")
+ (setq beginning (point))
+ ;; Menu entry line ends in a period, comma, or tab.
+ (if (re-search-forward "[.,\t]"
+ (save-excursion (forward-line 1) (point)) t)
+ (progn
+ (if (looking-at "[ \t]*[^ \t\n]+")
+ (error "Descriptive text already exists."))
+ (skip-chars-backward "., \t")
+ (setq node-name (buffer-substring beginning (point))))
+ ;; Menu entry line ends in a return.
+ (re-search-forward ".*\n"
+ (save-excursion (forward-line 1) (point)) t)
+ (skip-chars-backward " \t\n")
+ (setq node-name (buffer-substring beginning (point)))
+ (if (= 0 (length node-name))
+ (error "No node name on this line.")
+ (insert "."))))
+ (t (error "No node name on this line.")))
+ ;; Search for node that matches node name, and copy the section title.
+ (if (re-search-forward
+ (concat
+ "^@node[ \t]+"
+ node-name
+ ".*\n" ; match node line
+ "\\("
+ "\\(\\(^@c \\|^@comment\\).*\n\\)" ; match comment line, if any
+ "\\|" ; or
+ "\\(^@ifinfo[ ]*\n\\)" ; ifinfo line, if any
+ "\\)?")
+ nil t)
+ (progn
+ (setq title
+ (buffer-substring
+ ;; skip over section type
+ (progn (forward-word 1)
+ ;; and over spaces
+ (skip-chars-forward " \t")
+ (point))
+ (progn (end-of-line)
+ (skip-chars-backward " \t")
+ (point)))))
+ (error "Cannot find node to match node name in menu entry.")))
+ ;; Return point to the menu and insert the title.
+ (end-of-line)
+ (delete-region
+ (point)
+ (save-excursion (skip-chars-backward " \t") (point)))
+ (indent-to texinfo-column-for-description 2)
+ (save-excursion (insert title))))
+
+
+;;; Handling description indentation
+
+; Since the make-menu functions indent descriptions, these functions
+; are useful primarily for indenting a single menu specially.
+
+(defun texinfo-indent-menu-description (column &optional region-p)
+ "Indent every description in menu following point to COLUMN.
+Non-nil argument (prefix, if interactive) means indent every
+description in every menu in the region. Does not indent second and
+subsequent lines of a multi-line description."
+
+ (interactive
+ "nIndent menu descriptions to (column number): \nP")
+ (save-excursion
+ (save-restriction
+ (widen)
+ (if (not region-p)
+ (progn
+ (re-search-forward "^@menu")
+ (texinfo-menu-indent-description column)
+ (message
+ "Indented descriptions in menu. You may save the buffer."))
+ ;;else
+ (message "Indenting every menu description in region... ")
+ (goto-char (region-beginning))
+ (while (and (< (point) (region-end))
+ (texinfo-locate-menu-p))
+ (forward-line 1)
+ (texinfo-menu-indent-description column))
+ (message "Indenting done. You may save the buffer.")))))
+
+(defun texinfo-menu-indent-description (to-column-number)
+ "Indent the Texinfo file menu description to TO-COLUMN-NUMBER.
+Start with point just after the word `menu' in the `@menu' line and
+leave point on the line before the `@end menu' line. Does not indent
+second and subsequent lines of a multi-line description."
+ (let* ((beginning-of-next-line (point)))
+ (while (< beginning-of-next-line
+ (save-excursion ; beginning of end menu line
+ (goto-char (texinfo-menu-end))
+ (beginning-of-line)
+ (point)))
+
+ (if (re-search-forward "\\* \\(.*::\\|.*: [^.,\t\n]+[.,\t]\\)"
+ (texinfo-menu-end)
+ t)
+ (progn
+ (let ((beginning-white-space (point)))
+ (skip-chars-forward " \t") ; skip over spaces
+ (if (looking-at "\\(@\\|\\w\\)+") ; if there is text
+ (progn
+ ;; remove pre-existing indentation
+ (delete-region beginning-white-space (point))
+ (indent-to-column to-column-number))))))
+ ;; position point at beginning of next line
+ (forward-line 1)
+ (setq beginning-of-next-line (point)))))
+
+
+;;; Making the master menu
+
+(defun texinfo-master-menu (update-all-nodes-menus-p)
+ "Make a master menu for a whole Texinfo file.
+Non-nil argument (prefix, if interactive) means first update all
+existing nodes and menus. Remove pre-existing master menu, if there is one.
+
+This function creates a master menu that follows the top node. The
+master menu includes every entry from all the other menus. It
+replaces any existing ordinary menu that follows the top node.
+
+If called with a non-nil argument, this function first updates all the
+menus in the buffer (incorporating descriptions from pre-existing
+menus) before it constructs the master menu.
+
+The function removes the detailed part of an already existing master
+menu. This action depends on the pre-exisitng master menu using the
+standard `texinfo-master-menu-header'.
+
+The master menu has the following format, which is adapted from the
+recommendation in the Texinfo Manual:
+
+ * The first part contains the major nodes in the Texinfo file: the
+ nodes for the chapters, chapter-like sections, and the major
+ appendices. This includes the indices, so long as they are in
+ chapter-like sections, such as unnumbered sections.
+
+ * The second and subsequent parts contain a listing of the other,
+ lower level menus, in order. This way, an inquirer can go
+ directly to a particular node if he or she is searching for
+ specific information.
+
+Each of the menus in the detailed node listing is introduced by the
+title of the section containing the menu."
+
+ (interactive "P")
+ (let ((case-fold-search t))
+ (widen)
+ (goto-char (point-min))
+
+ ;; Move point to location after `top'.
+ (if (not (re-search-forward "^@node [ \t]*top[ \t]*\\(,\\|$\\)" nil t))
+ (error "This buffer needs a Top node!"))
+
+ (let ((first-chapter
+ (save-excursion
+ (or (re-search-forward "^@node" nil t)
+ (error "Too few nodes for a master menu!"))
+ (point))))
+ (if (re-search-forward texinfo-master-menu-header first-chapter t)
+ ;; Remove detailed master menu listing
+ (progn
+ (goto-char (match-beginning 0))
+ (let ((end-of-detailed-menu-descriptions
+ (save-excursion ; beginning of end menu line
+ (goto-char (texinfo-menu-end))
+ (beginning-of-line) (forward-char -1)
+ (point))))
+ (delete-region (point) end-of-detailed-menu-descriptions)))))
+
+ (if update-all-nodes-menus-p
+ (progn
+ (message "Making a master menu in %s ...first updating all nodes... "
+ (buffer-name))
+ (sleep-for 2)
+ (push-mark (point-max) t)
+ (goto-char (point-min))
+ (texinfo-update-node t)
+
+ (message "Updating all menus in %s ... " (buffer-name))
+ (sleep-for 2)
+ (push-mark (point-max) t)
+ (goto-char (point-min))
+ (texinfo-make-menu t)))
+
+ (message "Now making the master menu in %s... " (buffer-name))
+ (sleep-for 2)
+ (goto-char (point-min))
+ (texinfo-insert-master-menu-list
+ (texinfo-master-menu-list))
+
+ ;; Remove extra newlines that texinfo-insert-master-menu-list
+ ;; may have inserted.
+
+ (save-excursion
+ (goto-char (point-min))
+
+ (if (re-search-forward texinfo-master-menu-header nil t)
+ (progn
+ (goto-char (match-beginning 0))
+ (insert "\n")
+ (delete-blank-lines)
+ (goto-char (point-min))))
+
+ (re-search-forward "^@menu")
+ (forward-line -1)
+ (delete-blank-lines)
+
+ (re-search-forward "^@end menu")
+ (forward-line 1)
+ (delete-blank-lines))
+
+ (message
+ "Done...completed making master menu. You may save the buffer.")))
+
+(defun texinfo-master-menu-list ()
+ "Return a list of menu entries and header lines for the master menu.
+
+Start with the menu for chapters and indices and then find each
+following menu and the title of the node preceding that menu.
+
+The master menu list has this form:
+
+ \(\(\(... \"entry-1-2\" \"entry-1\"\) \"title-1\"\)
+ \(\(... \"entry-2-2\" \"entry-2-1\"\) \"title-2\"\)
+ ...\)
+
+However, there does not need to be a title field."
+
+ (let (master-menu-list)
+ (while (texinfo-locate-menu-p)
+ (setq master-menu-list
+ (cons (list
+ (texinfo-copy-menu)
+ (texinfo-copy-menu-title))
+ master-menu-list)))
+ (reverse master-menu-list)))
+
+(defun texinfo-insert-master-menu-list (master-menu-list)
+ "Format and insert the master menu in the current buffer."
+ (goto-char (point-min))
+ ;; Insert a master menu only after `Top' node and before next node
+ ;; \(or include file if there is no next node\).
+ (if (not (re-search-forward "^@node [ \t]*top[ \t]*\\(,\\|$\\)" nil t))
+ (error "This buffer needs a Top node!"))
+ (let ((first-chapter
+ (save-excursion (re-search-forward "^@node\\|^@include") (point))))
+ (if (not (re-search-forward "^@menu" first-chapter t))
+ (error
+ "Buffer lacks ordinary `Top' menu in which to insert master.")))
+ (beginning-of-line)
+ (delete-region ; buffer must have ordinary top menu
+ (point)
+ (save-excursion (re-search-forward "^@end menu") (point)))
+
+ (save-excursion ; leave point at beginning of menu
+ ;; Handle top of menu
+ (insert "\n@menu\n")
+ ;; Insert chapter menu entries
+ (setq this-very-menu-list (reverse (car (car master-menu-list))))
+ ;; Tell user what is going on.
+ (message "Inserting chapter menu entry: %s ... " this-very-menu-list)
+ (while this-very-menu-list
+ (insert "* " (car this-very-menu-list) "\n")
+ (setq this-very-menu-list (cdr this-very-menu-list)))
+
+ (setq master-menu-list (cdr master-menu-list))
+
+ ;; Only insert detailed master menu if there is one....
+ (if (car (car master-menu-list))
+ (insert texinfo-master-menu-header))
+
+ ;; Now, insert all the other menus
+
+ ;; The menu master-menu-list has a form like this:
+ ;; ((("beta" "alpha") "title-A")
+ ;; (("delta" "gamma") "title-B"))
+
+ (while master-menu-list
+
+ (message
+ "Inserting menu for %s .... " (car (cdr (car master-menu-list))))
+ ;; insert title of menu section
+ (insert "\n" (car (cdr (car master-menu-list))) "\n\n")
+
+ ;; insert each menu entry
+ (setq this-very-menu-list (reverse (car (car master-menu-list))))
+ (while this-very-menu-list
+ (insert "* " (car this-very-menu-list) "\n")
+ (setq this-very-menu-list (cdr this-very-menu-list)))
+
+ (setq master-menu-list (cdr master-menu-list)))
+
+ ;; Finish menu
+ (insert "@end menu\n\n")))
+
+(defvar texinfo-master-menu-header
+ "\n --- The Detailed Node Listing ---\n"
+ "String inserted before lower level entries in Texinfo master menu.
+It comes after the chapter-level menu entries.")
+
+(defun texinfo-locate-menu-p ()
+ "Find the next menu in the texinfo file.
+If found, leave point after word `menu' on the `@menu' line, and return t.
+If a menu is not found, do not move point and return nil."
+ (re-search-forward "\\(^@menu\\)" nil t))
+
+(defun texinfo-copy-menu-title ()
+ "Return the title of the section preceding the menu as a string.
+If such a title cannot be found, return an empty string. Do not move
+point."
+ (let ((case-fold-search t))
+ (save-excursion
+ (if (re-search-backward
+ (concat
+ "\\(^@top"
+ "\\|" ; or
+ texinfo-section-types-regexp ; all other section types
+ "\\)")
+ nil
+ t)
+ (progn
+ (beginning-of-line)
+ (forward-word 1) ; skip over section type
+ (skip-chars-forward " \t") ; and over spaces
+ (buffer-substring
+ (point)
+ (progn (end-of-line) (point))))
+ ""))))
+
+(defun texinfo-copy-menu ()
+ "Return the entries of an existing menu as a list.
+Start with point just after the word `menu' in the `@menu' line
+and leave point on the line before the `@end menu' line."
+ (let* (this-menu-list
+ (end-of-menu (texinfo-menu-end)) ; position of end of `@end menu'
+ (last-entry (save-excursion ; position of beginning of
+ ; last `* ' entry
+ (goto-char end-of-menu)
+ ;; handle multi-line description
+ (if (not (re-search-backward "^\* " nil t))
+ (error "No entries in menu."))
+ (point))))
+ (while (< (point) last-entry)
+ (if (re-search-forward "^\* " end-of-menu t)
+ (progn
+ (setq this-menu-list
+ (cons
+ (buffer-substring
+ (point)
+ ;; copy multi-line descriptions
+ (save-excursion
+ (re-search-forward "\\(^\* \\|^@e\\)" nil t)
+ (- (point) 3)))
+ this-menu-list)))))
+ this-menu-list))
+
+
+;;; Determining the hierarchical level in the texinfo file
+
+(defun texinfo-specific-section-type ()
+ "Return the specific type of next section, as a string.
+For example, \"unnumberedsubsec\". Return \"top\" for top node.
+
+Searches forward for a section. Hence, point must be before the
+section whose type will be found. Does not move point. Signal an
+error if the node is not the top node and a section is not found."
+ (let ((case-fold-search t))
+ (save-excursion
+ (cond
+ ((re-search-forward "^@node [ \t]*top[ \t]*\\(,\\|$\\)"
+;;; Following search limit by cph but causes a bug
+;;; (save-excursion
+;;; (end-of-line)
+;;; (point))
+ nil
+ t)
+ "top")
+ ((re-search-forward texinfo-section-types-regexp nil t)
+ (buffer-substring (progn (beginning-of-line) ; copy its name
+ (1+ (point)))
+ (progn (forward-word 1)
+ (point))))
+ (t
+ (error
+ "texinfo-specific-section-type: Chapter or section not found."))))))
+
+(defun texinfo-hierarchic-level ()
+ "Return the general hierarchal level of the next node in a texinfo file.
+Thus, a subheading or appendixsubsec is of type subsection."
+ (let ((case-fold-search t))
+ (cdr (assoc
+ (texinfo-specific-section-type)
+ texinfo-section-to-generic-alist))))
+
+
+;;; Locating the major positions
+
+(defun texinfo-update-menu-region-beginning (level)
+ "Locate beginning of higher level section this section is within.
+Return position of the beginning of the node line; do not move point.
+Thus, if this level is subsection, searches backwards for section node.
+Only argument is a string of the general type of section."
+ (let ((case-fold-search t))
+ ;; !! Known bug: if section immediately follows top node, this
+ ;; returns the beginning of the buffer as the beginning of the
+ ;; higher level section.
+ (cond
+ ((or (string-equal "top" level)
+ (string-equal "chapter" level))
+ (save-excursion
+ (goto-char (point-min))
+ (re-search-forward "^@node [ \t]*top[ \t]*\\(,\\|$\\)" nil t)
+ (beginning-of-line)
+ (point)))
+ (t
+ (save-excursion
+ (re-search-backward
+ (concat
+ "\\(^@node\\).*\n" ; match node line
+ "\\(\\(\\(^@c\\).*\n\\)" ; match comment line, if any
+ "\\|" ; or
+ "\\(^@ifinfo[ ]*\n\\)\\)?" ; ifinfo line, if any
+ (eval
+ (cdr (assoc level texinfo-update-menu-higher-regexps))))
+ nil
+ 'goto-beginning)
+ (point))))))
+
+(defun texinfo-update-menu-region-end (level)
+ "Locate end of higher level section this section is within.
+Return position; do not move point. Thus, if this level is a
+subsection, find the node for the section this subsection is within.
+If level is top or chapter, returns end of file. Only argument is a
+string of the general type of section."
+ (let ((case-fold-search t))
+ (save-excursion
+ (if (re-search-forward
+ (concat
+ "\\(^@node\\).*\n" ; match node line
+ "\\(\\(\\(^@c\\).*\n\\)" ; match comment line, if any
+ "\\|" ; or
+ "\\(^@ifinfo[ ]*\n\\)\\)?" ; ifinfo line, if any
+ (eval
+ ;; Never finds end of level above chapter so goes to end.
+ (cdr (assoc level texinfo-update-menu-higher-regexps))))
+ nil
+ 'goto-end)
+ (match-beginning 1)
+ (point-max)))))
+
+(defun texinfo-menu-first-node (beginning end)
+ "Locate first node of the section the menu will be placed in.
+Return position; do not move point.
+The menu will be located just before this position.
+
+First argument is the position of the beginning of the section in
+which the menu will be located; second argument is the position of the
+end of that region; it limits the search."
+
+ (save-excursion
+ (goto-char beginning)
+ (forward-line 1)
+ (re-search-forward "^@node" end t)
+ (beginning-of-line)
+ (point)))
+
+
+;;; Alists and regular expressions for defining hierarchical levels
+
+(defvar texinfo-section-to-generic-alist
+ '(("top" . "top")
+
+ ("chapter" . "chapter")
+ ("unnumbered" . "chapter")
+ ("majorheading" . "chapter")
+ ("chapheading" . "chapter")
+ ("appendix" . "chapter")
+
+ ("section" . "section")
+ ("unnumberedsec" . "section")
+ ("heading" . "section")
+ ("appendixsec" . "section")
+
+ ("subsection" . "subsection")
+ ("unnumberedsubsec" . "subsection")
+ ("subheading" . "subsection")
+ ("appendixsubsec" . "subsection")
+
+ ("subsubsection" . "subsubsection")
+ ("unnumberedsubsubsec" . "subsubsection")
+ ("subsubheading" . "subsubsection")
+ ("appendixsubsubsec" . "subsubsection"))
+ "*An alist of specific and corresponding generic Texinfo section types.
+The keys are strings specifying specific types of section; the values
+are strings of their corresponding general types.")
+
+;; We used to look for just sub, but that found @subtitle.
+(defvar texinfo-section-types-regexp
+ "^@\\(chapter \\|sect\\|subs\\|subh\\|unnum\\|major\\|chapheading \\|heading \\|appendix\\)"
+ "Regexp matching chapter, section, other headings (but not the top node).")
+
+(defvar texinfo-chapter-level-regexp
+ "chapter\\|unnumbered \\|appendix \\|majorheading\\|chapheading"
+ "Regular expression matching just the Texinfo chapter level headings.")
+
+(defvar texinfo-section-level-regexp
+ "section\\|unnumberedsec\\|heading \\|appendixsec"
+ "Regular expression matching just the Texinfo section level headings.")
+
+(defvar texinfo-subsection-level-regexp
+ "subsection\\|unnumberedsubsec\\|subheading\\|appendixsubsec"
+ "Regular expression matching just the Texinfo subsection level headings.")
+
+(defvar texinfo-subsubsection-level-regexp
+ "subsubsection\\|unnumberedsubsubsec\\|subsubheading\\|appendixsubsubsec"
+ "Regular expression matching just the Texinfo subsubsection level headings.")
+
+(defvar texinfo-update-menu-same-level-regexps
+ '(("top" . "top[ \t]+")
+ ("chapter" .
+ (concat "\\(^@\\)\\(" texinfo-chapter-level-regexp "\\)[ \t]*"))
+ ("section" .
+ (concat "\\(^@\\)\\(" texinfo-section-level-regexp "\\)[ \t]*"))
+ ("subsection" .
+ (concat "\\(^@\\)\\(" texinfo-subsection-level-regexp "\\)[ \t]+"))
+ ("subsubsection" .
+ (concat "\\(^@\\)\\(" texinfo-subsubsection-level-regexp "\\)[ \t]+")))
+ "*Regexps for searching for same level sections in a Texinfo file.
+The keys are strings specifying the general hierarchical level in the
+document; the values are regular expressions.")
+
+(defvar texinfo-update-menu-higher-regexps
+ '(("top" . "^@node [ \t]*DIR")
+ ("chapter" . "^@node [ \t]*top[ \t]*\\(,\\|$\\)")
+ ("section" .
+ (concat
+ "\\(^@\\("
+ texinfo-chapter-level-regexp
+ "\\)[ \t]*\\)"))
+ ("subsection" .
+ (concat
+ "\\(^@\\("
+ texinfo-section-level-regexp
+ "\\|"
+ texinfo-chapter-level-regexp
+ "\\)[ \t]*\\)"))
+ ("subsubsection" .
+ (concat
+ "\\(^@\\("
+ texinfo-subsection-level-regexp
+ "\\|"
+ texinfo-section-level-regexp
+ "\\|"
+ texinfo-chapter-level-regexp
+ "\\)[ \t]*\\)")))
+ "*Regexps for searching for higher level sections in a Texinfo file.
+The keys are strings specifying the general hierarchical level in the
+document; the values are regular expressions.")
+
+(defvar texinfo-update-menu-lower-regexps
+ '(("top" .
+ (concat
+ "\\(^@\\("
+ texinfo-chapter-level-regexp
+ "\\|"
+ texinfo-section-level-regexp
+ "\\|"
+ texinfo-subsection-level-regexp
+ "\\|"
+ texinfo-subsubsection-level-regexp
+ "\\)[ \t]*\\)"))
+ ("chapter" .
+ (concat
+ "\\(^@\\("
+ texinfo-section-level-regexp
+ "\\|"
+ texinfo-subsection-level-regexp
+ "\\|"
+ texinfo-subsubsection-level-regexp
+ "\\)[ \t]*\\)"))
+ ("section" .
+ (concat
+ "\\(^@\\("
+ texinfo-subsection-level-regexp
+ "\\|"
+ texinfo-subsubsection-level-regexp
+ "\\)[ \t]+\\)"))
+ ("subsection" .
+ (concat
+ "\\(^@\\("
+ texinfo-subsubsection-level-regexp
+ "\\)[ \t]+\\)"))
+ ("subsubsection" . "nothing lower"))
+ "*Regexps for searching for lower level sections in a Texinfo file.
+The keys are strings specifying the general hierarchical level in the
+document; the values are regular expressions.")
+
+
+;;; Updating a node
+
+;;;###autoload
+(defun texinfo-update-node (&optional region-p)
+ "Without any prefix argument, update the node in which point is located.
+Non-nil argument (prefix, if interactive) means update the nodes in the
+marked region.
+
+The functions for creating or updating nodes and menus, and their
+keybindings, are:
+
+ texinfo-update-node (&optional region-p) \\[texinfo-update-node]
+ texinfo-every-node-update () \\[texinfo-every-node-update]
+ texinfo-sequential-node-update (&optional region-p)
+
+ texinfo-make-menu (&optional region-p) \\[texinfo-make-menu]
+ texinfo-all-menus-update () \\[texinfo-all-menus-update]
+ texinfo-master-menu ()
+
+ texinfo-indent-menu-description (column &optional region-p)
+
+The `texinfo-column-for-description' variable specifies the column to
+which menu descriptions are indented. Its default value is 32."
+
+ (interactive "P")
+ (if (not region-p)
+ ;; update a single node
+ (let ((auto-fill-function nil) (auto-fill-hook nil))
+ (if (not (re-search-backward "^@node" (point-min) t))
+ (error "Node line not found before this position."))
+ (texinfo-update-the-node)
+ (message "Done...updated the node. You may save the buffer."))
+ ;; else
+ (let ((auto-fill-function nil)
+ (auto-fill-hook nil)
+ (beginning (region-beginning))
+ (end (region-end)))
+ (if (= end beginning)
+ (error "Please mark a region!"))
+ (save-restriction
+ (narrow-to-region beginning end)
+ (goto-char beginning)
+ (push-mark (point) t)
+ (while (re-search-forward "^@node" (point-max) t)
+ (beginning-of-line)
+ (texinfo-update-the-node))
+ (message "Done...updated nodes in region. You may save the buffer.")))))
+
+;;;###autoload
+(defun texinfo-every-node-update ()
+ "Update every node in a Texinfo file."
+ (interactive)
+ (save-excursion
+ (push-mark (point-max) t)
+ (goto-char (point-min))
+ ;; Using the mark to pass bounds this way
+ ;; is kludgy, but it's not worth fixing. -- rms.
+ (let ((mark-active t))
+ (texinfo-update-node t))
+ (message "Done...updated every node. You may save the buffer.")))
+
+(defun texinfo-update-the-node ()
+ "Update one node. Point must be at the beginning of node line.
+Leave point at the end of the node line."
+ (texinfo-check-for-node-name)
+ (texinfo-delete-existing-pointers)
+ (message "Updating node: %s ... " (texinfo-copy-node-name))
+ (save-restriction
+ (widen)
+ (let*
+ ((case-fold-search t)
+ (level (texinfo-hierarchic-level))
+ (beginning (texinfo-update-menu-region-beginning level))
+ (end (texinfo-update-menu-region-end level)))
+ (if (string-equal level "top")
+ (texinfo-top-pointer-case)
+ ;; else
+ (texinfo-insert-pointer beginning end level 'next)
+ (texinfo-insert-pointer beginning end level 'previous)
+ (texinfo-insert-pointer beginning end level 'up)
+ (texinfo-clean-up-node-line)))))
+
+(defun texinfo-top-pointer-case ()
+ "Insert pointers in the Top node. This is a special case.
+
+The `Next' pointer is a pointer to a chapter or section at a lower
+hierarchical level in the file. The `Previous' and `Up' pointers are
+to `(dir)'. Point must be at the beginning of the node line, and is
+left at the end of the node line."
+
+ (texinfo-clean-up-node-line)
+ (insert ", "
+ (save-excursion
+ ;; There may be an @chapter or other such command between
+ ;; the top node line and the next node line, as a title
+ ;; for an `ifinfo' section. This @chapter command must
+ ;; must be skipped. So the procedure is to search for
+ ;; the next `@node' line, and then copy its name.
+ (if (re-search-forward "^@node" nil t)
+ (progn
+ (beginning-of-line)
+ (texinfo-copy-node-name))
+ " "))
+ ", (dir), (dir)"))
+
+(defun texinfo-check-for-node-name ()
+ "Determine whether the node has a node name. Prompt for one if not.
+Point must be at beginning of node line. Does not move point."
+ (save-excursion
+ (let ((initial (texinfo-copy-next-section-title)))
+ ;; This is not clean. Use `interactive' to read the arg.
+ (forward-word 1) ; skip over node command
+ (skip-chars-forward " \t") ; and over spaces
+ (if (not (looking-at "[^,\t\n ]+")) ; regexp based on what Info looks for
+ ; alternatively, use "[a-zA-Z]+"
+ (let ((node-name
+ (read-from-minibuffer
+ "Node name (use no @, commas, colons, or apostrophes): "
+ initial)))
+ (insert " " node-name))))))
+
+(defun texinfo-delete-existing-pointers ()
+ "Delete `Next', `Previous', and `Up' pointers.
+Starts from the current position of the cursor, and searches forward
+on the line for a comma and if one is found, deletes the rest of the
+line, including the comma. Leaves point at beginning of line."
+ (let ((eol-point (save-excursion (end-of-line) (point))))
+ (if (search-forward "," eol-point t)
+ (delete-region (1- (point)) eol-point)))
+ (beginning-of-line))
+
+(defun texinfo-find-pointer (beginning end level direction)
+ "Move point to section associated with next, previous, or up pointer.
+Return type of pointer (either 'normal or 'no-pointer).
+
+The first and second arguments bound the search for a pointer to the
+beginning and end, respectively, of the enclosing higher level
+section. The third argument is a string specifying the general kind
+of section such as \"chapter\ or \"section\". When looking for the
+`Next' pointer, the section found will be at the same hierarchical
+level in the Texinfo file; when looking for the `Previous' pointer,
+the section found will be at the same or higher hierarchical level in
+the Texinfo file; when looking for the `Up' pointer, the section found
+will be at some level higher in the Texinfo file. The fourth argument
+\(one of 'next, 'previous, or 'up\) specifies whether to find the
+`Next', `Previous', or `Up' pointer."
+ (let ((case-fold-search t))
+ (cond ((eq direction 'next)
+ (forward-line 3) ; skip over current node
+ ;; Search for section commands accompanied by node lines;
+ ;; ignore section commands in the middle of nodes.
+ (if (re-search-forward
+ ;; A `Top' node is never a next pointer, so won't find it.
+ (concat
+ ;; Match node line.
+ "\\(^@node\\).*\n"
+ ;; Match comment or ifinfo line, if any
+ "\\(\\(\\(^@c\\).*\n\\)\\|\\(^@ifinfo[ ]*\n\\)\\)?"
+ (eval
+ (cdr (assoc level texinfo-update-menu-same-level-regexps))))
+ end
+ t)
+ 'normal
+ 'no-pointer))
+ ((eq direction 'previous)
+ (if (re-search-backward
+ (concat
+ "\\("
+ ;; Match node line.
+ "\\(^@node\\).*\n"
+ ;; Match comment or ifinfo line, if any
+ "\\(\\(\\(^@c\\).*\n\\)\\|\\(^@ifinfo[ ]*\n\\)\\)?"
+ (eval
+ (cdr (assoc level texinfo-update-menu-same-level-regexps)))
+ "\\|"
+ ;; Match node line.
+ "\\(^@node\\).*\n"
+ ;; Match comment or ifinfo line, if any
+ "\\(\\(\\(^@c\\).*\n\\)\\|\\(^@ifinfo[ ]*\n\\)\\)?"
+ (eval
+ (cdr (assoc level texinfo-update-menu-higher-regexps)))
+ "\\|"
+ ;; Handle `Top' node specially.
+ "^@node [ \t]*top[ \t]*\\(,\\|$\\)"
+ "\\)")
+ beginning
+ t)
+ 'normal
+ 'no-pointer))
+ ((eq direction 'up)
+ (if (re-search-backward
+ (concat
+ "\\("
+ ;; Match node line.
+ "\\(^@node\\).*\n"
+ ;; Match comment or ifinfo line, if any
+ "\\(\\(\\(^@c\\).*\n\\)\\|\\(^@ifinfo[ ]*\n\\)\\)?"
+ (eval (cdr (assoc level texinfo-update-menu-higher-regexps)))
+ "\\|"
+ ;; Handle `Top' node specially.
+ "^@node [ \t]*top[ \t]*\\(,\\|$\\)"
+ "\\)")
+ (save-excursion
+ (goto-char beginning)
+ (beginning-of-line)
+ (point))
+ t)
+ 'normal
+ 'no-pointer))
+ (t
+ (error "texinfo-find-pointer: lack proper arguments")))))
+
+(defun texinfo-pointer-name (kind)
+ "Return the node name preceding the section command.
+The argument is the kind of section, either normal or no-pointer."
+ (let (name)
+ (cond ((eq kind 'normal)
+ (end-of-line) ; this handles prev node top case
+ (re-search-backward ; when point is already
+ "^@node" ; at the beginning of @node line
+ (save-excursion (forward-line -3))
+ t)
+ (setq name (texinfo-copy-node-name)))
+ ((eq kind 'no-pointer)
+ (setq name " "))) ; put a blank in the pointer slot
+ name))
+
+(defun texinfo-insert-pointer (beginning end level direction)
+ "Insert the `Next', `Previous' or `Up' node name at point.
+Move point forward.
+
+The first and second arguments bound the search for a pointer to the
+beginning and end, respectively, of the enclosing higher level
+section. The third argument is the hierarchical level of the Texinfo
+file, a string such as \"section\". The fourth argument is direction
+towards which the pointer is directed, one of `next, `previous, or
+'up."
+
+ (end-of-line)
+ (insert
+ ", "
+ (save-excursion
+ (texinfo-pointer-name
+ (texinfo-find-pointer beginning end level direction)))))
+
+(defun texinfo-clean-up-node-line ()
+ "Remove extra commas, if any, at end of node line."
+ (end-of-line)
+ (skip-chars-backward ", ")
+ (delete-region (point) (save-excursion (end-of-line) (point))))
+
+
+;;; Updating nodes sequentially
+; These sequential update functions insert `Next' or `Previous'
+; pointers that point to the following or preceding nodes even if they
+; are at higher or lower hierarchical levels. This means that if a
+; section contains one or more subsections, the section's `Next'
+; pointer will point to the subsection and not the following section.
+; (The subsection to which `Next' points will most likely be the first
+; item on the section's menu.)
+
+;;;###autoload
+(defun texinfo-sequential-node-update (&optional region-p)
+ "Update one node (or many) in a Texinfo file with sequential pointers.
+
+This function causes the `Next' or `Previous' pointer to point to the
+immediately preceding or following node, even if it is at a higher or
+lower hierarchical level in the document. Continually pressing `n' or
+`p' takes you straight through the file.
+
+Without any prefix argument, update the node in which point is located.
+Non-nil argument (prefix, if interactive) means update the nodes in the
+marked region.
+
+This command makes it awkward to navigate among sections and
+subsections; it should be used only for those documents that are meant
+to be read like a novel rather than a reference, and for which the
+Info `g*' command is inadequate."
+
+ (interactive "P")
+ (if (not region-p)
+ ;; update a single node
+ (let ((auto-fill-function nil) (auto-fill-hook nil))
+ (if (not (re-search-backward "^@node" (point-min) t))
+ (error "Node line not found before this position."))
+ (texinfo-sequentially-update-the-node)
+ (message
+ "Done...sequentially updated the node . You may save the buffer."))
+ ;; else
+ (let ((auto-fill-function nil)
+ (auto-fill-hook nil)
+ (beginning (region-beginning))
+ (end (region-end)))
+ (if (= end beginning)
+ (error "Please mark a region!"))
+ (save-restriction
+ (narrow-to-region beginning end)
+ (goto-char beginning)
+ (push-mark (point) t)
+ (while (re-search-forward "^@node" (point-max) t)
+ (beginning-of-line)
+ (texinfo-sequentially-update-the-node))
+ (message
+ "Done...updated the nodes in sequence. You may save the buffer.")))))
+
+(defun texinfo-sequentially-update-the-node ()
+ "Update one node such that the pointers are sequential.
+A `Next' or `Previous' pointer points to any preceding or following node,
+regardless of its hierarchical level."
+
+ (texinfo-check-for-node-name)
+ (texinfo-delete-existing-pointers)
+ (message
+ "Sequentially updating node: %s ... " (texinfo-copy-node-name))
+ (save-restriction
+ (widen)
+ (let*
+ ((case-fold-search t)
+ (level (texinfo-hierarchic-level)))
+ (if (string-equal level "top")
+ (texinfo-top-pointer-case)
+ ;; else
+ (texinfo-sequentially-insert-pointer level 'next)
+ (texinfo-sequentially-insert-pointer level 'previous)
+ (texinfo-sequentially-insert-pointer level 'up)
+ (texinfo-clean-up-node-line)))))
+
+(defun texinfo-sequentially-find-pointer (level direction)
+ "Find next or previous pointer sequentially in Texinfo file, or up pointer.
+Move point to section associated with the pointer. Find point even if
+it is in a different section.
+
+Return type of pointer (either 'normal or 'no-pointer).
+
+The first argument is a string specifying the general kind of section
+such as \"chapter\ or \"section\". The section found will be at the
+same hierarchical level in the Texinfo file, or, in the case of the up
+pointer, some level higher. The second argument (one of 'next,
+'previous, or 'up) specifies whether to find the `Next', `Previous',
+or `Up' pointer."
+ (let ((case-fold-search t))
+ (cond ((eq direction 'next)
+ (forward-line 3) ; skip over current node
+ (if (re-search-forward
+ texinfo-section-types-regexp
+ (point-max)
+ t)
+ 'normal
+ 'no-pointer))
+ ((eq direction 'previous)
+ (if (re-search-backward
+ texinfo-section-types-regexp
+ (point-min)
+ t)
+ 'normal
+ 'no-pointer))
+ ((eq direction 'up)
+ (if (re-search-backward
+ (eval (cdr (assoc level texinfo-update-menu-higher-regexps)))
+ beginning
+ t)
+ 'normal
+ 'no-pointer))
+ (t
+ (error "texinfo-sequential-find-pointer: lack proper arguments")))))
+
+(defun texinfo-sequentially-insert-pointer (level direction)
+ "Insert the `Next', `Previous' or `Up' node name at point.
+Move point forward.
+
+The first argument is the hierarchical level of the Texinfo file, a
+string such as \"section\". The second argument is direction, one of
+`next, `previous, or 'up."
+
+ (end-of-line)
+ (insert
+ ", "
+ (save-excursion
+ (texinfo-pointer-name
+ (texinfo-sequentially-find-pointer level direction)))))
+
+
+;;; Inserting `@node' lines
+; The `texinfo-insert-node-lines' function inserts `@node' lines as needed
+; before the `@chapter', `@section', and such like lines of a region
+; in a Texinfo file.
+
+(defun texinfo-insert-node-lines (beginning end &optional title-p)
+ "Insert missing `@node' lines in region of Texinfo file.
+Non-nil argument (prefix, if interactive) means also to insert the
+section titles as node names; and also to insert the section titles as
+node names in pre-existing @node lines that lack names."
+ (interactive "r\nP")
+
+ ;; Use marker; after inserting node lines, leave point at end of
+ ;; region and mark at beginning.
+
+ (let (beginning-marker end-marker title last-section-position)
+
+ ;; Save current position on mark ring and set mark to end.
+ (push-mark end t)
+ (setq end-marker (mark-marker))
+
+ (goto-char beginning)
+ (while (re-search-forward
+ texinfo-section-types-regexp
+ end-marker
+ 'end)
+ ;; Copy title if desired.
+ (if title-p
+ (progn
+ (beginning-of-line)
+ (forward-word 1)
+ (skip-chars-forward " \t")
+ (setq title (buffer-substring
+ (point)
+ (save-excursion (end-of-line) (point))))))
+ ;; Insert node line if necessary.
+ (if (re-search-backward
+ "^@node"
+ ;; Avoid finding previous node line if node lines are close.
+ (or last-section-position
+ (save-excursion (forward-line -2) (point))) t)
+ ;; @node is present, and point at beginning of that line
+ (forward-word 1) ; Leave point just after @node.
+ ;; Else @node missing; insert one.
+ (beginning-of-line) ; Beginning of `@section' line.
+ (insert "@node\n")
+ (backward-char 1)) ; Leave point just after `@node'.
+ ;; Insert title if desired.
+ (if title-p
+ (progn
+ (skip-chars-forward " \t")
+ ;; Use regexp based on what info looks for
+ ;; (alternatively, use "[a-zA-Z]+");
+ ;; this means we only insert a title if none exists.
+ (if (not (looking-at "[^,\t\n ]+"))
+ (progn
+ (beginning-of-line)
+ (forward-word 1)
+ (insert " " title)
+ (message "Inserted title %s ... " title)))))
+ ;; Go forward beyond current section title.
+ (re-search-forward texinfo-section-types-regexp
+ (save-excursion (forward-line 3) (point)) t)
+ (setq last-section-position (point))
+ (forward-line 1))
+
+ ;; Leave point at end of region, mark at beginning.
+ (set-mark beginning)
+
+ (if title-p
+ (message
+ "Done inserting node lines and titles. You may save the buffer.")
+ (message "Done inserting node lines. You may save the buffer."))))
+
+
+;;; Update and create menus for multi-file Texinfo sources
+
+;; 1. M-x texinfo-multiple-files-update
+;;
+;; Read the include file list of an outer Texinfo file and
+;; update all highest level nodes in the files listed and insert a
+;; main menu in the outer file after its top node.
+
+;; 2. C-u M-x texinfo-multiple-files-update
+;;
+;; Same as 1, but insert a master menu. (Saves reupdating lower
+;; level menus and nodes.) This command simply reads every menu,
+;; so if the menus are wrong, the master menu will be wrong.
+;; Similarly, if the lower level node pointers are wrong, they
+;; will stay wrong.
+
+;; 3. C-u 2 M-x texinfo-multiple-files-update
+;;
+;; Read the include file list of an outer Texinfo file and
+;; update all nodes and menus in the files listed and insert a
+;; master menu in the outer file after its top node.
+
+;;; Note: these functions:
+;;;
+;;; * Do not save or delete any buffers. You may fill up your memory.
+;;; * Do not handle any pre-existing nodes in outer file.
+;;; Hence, you may need a file for indices.
+
+
+;;; Auxiliary functions for multiple file updating
+
+(defun texinfo-multi-file-included-list (outer-file)
+ "Return a list of the included files in OUTER-FILE."
+ (let ((included-file-list (list outer-file))
+ start)
+ (save-excursion
+ (switch-to-buffer (find-file-noselect outer-file))
+ (widen)
+ (goto-char (point-min))
+ (while (re-search-forward "^@include" nil t)
+ (skip-chars-forward " \t")
+ (setq start (point))
+ (end-of-line)
+ (skip-chars-backward " \t")
+ (setq included-file-list
+ (cons (buffer-substring start (point))
+ included-file-list)))
+ (nreverse included-file-list))))
+
+(defun texinfo-copy-next-section-title ()
+ "Return the name of the immediately following section as a string.
+
+Start with point at the beginning of the node line. Leave point at the
+same place. If there is no title, returns an empty string."
+
+ (save-excursion
+ (end-of-line)
+ (let ((node-end (or
+ (save-excursion
+ (if (re-search-forward "\\(^@node\\)" nil t)
+ (match-beginning 0)))
+ (point-max))))
+ (if (re-search-forward texinfo-section-types-regexp node-end t)
+ (progn
+ (beginning-of-line)
+ ;; copy title
+ (let ((title
+ (buffer-substring
+ (progn (forward-word 1) ; skip over section type
+ (skip-chars-forward " \t") ; and over spaces
+ (point))
+ (progn (end-of-line) (point)))))
+ title))
+ ""))))
+
+(defun texinfo-multi-file-update (files &optional update-everything)
+ "Update first node pointers in each file in FILES.
+Return a list of the node names.
+
+The first file in the list is an outer file; the remaining are
+files included in the outer file with `@include' commands.
+
+If optional arg UPDATE-EVERYTHING non-nil, update every menu and
+pointer in each of the included files.
+
+Also update the `Top' level node pointers of the outer file.
+
+Requirements:
+
+ * the first file in the FILES list must be the outer file,
+ * each of the included files must contain exactly one highest
+ hierarchical level node,
+ * this node must be the first node in the included file,
+ * each highest hierarchical level node must be of the same type.
+
+Thus, normally, each included file contains one, and only one,
+chapter."
+
+; The menu-list has the form:
+;
+; \(\(\"node-name1\" . \"title1\"\)
+; \(\"node-name2\" . \"title2\"\) ... \)
+;
+; However, there does not need to be a title field and this function
+; does not fill it; however a comment tells you how to do so.
+; You would use the title field if you wanted to insert titles in the
+; description slot of a menu as a description.
+
+ (let ((case-fold-search t)
+ menu-list)
+
+ ;; Find the name of the first node of the first included file.
+ (switch-to-buffer (find-file-noselect (car (cdr files))))
+ (widen)
+ (goto-char (point-min))
+ (if (not (re-search-forward "^@node" nil t))
+ (error "No `@node' line found in %s !" (buffer-name)))
+ (beginning-of-line)
+ (texinfo-check-for-node-name)
+ (setq next-node-name (texinfo-copy-node-name))
+
+ (setq menu-list
+ (cons (cons
+ next-node-name
+ (prog1 "" (forward-line 1)))
+ ;; Use following to insert section titles automatically.
+ ;; (texinfo-copy-next-section-title)
+ menu-list))
+
+ ;; Go to outer file
+ (switch-to-buffer (find-file-noselect (car files)))
+ (goto-char (point-min))
+ (if (not (re-search-forward "^@node [ \t]*top[ \t]*\\(,\\|$\\)" nil t))
+ (error "This buffer needs a Top node!"))
+ (beginning-of-line)
+ (texinfo-delete-existing-pointers)
+ (end-of-line)
+ (insert ", " next-node-name ", (dir), (dir)")
+ (beginning-of-line)
+ (setq previous-node-name "Top")
+ (setq files (cdr files))
+
+ (while files
+
+ (if (not (cdr files))
+ ;; No next file
+ (setq next-node-name "")
+ ;; Else,
+ ;; find the name of the first node in the next file.
+ (switch-to-buffer (find-file-noselect (car (cdr files))))
+ (widen)
+ (goto-char (point-min))
+ (if (not (re-search-forward "^@node" nil t))
+ (error "No `@node' line found in %s !" (buffer-name)))
+ (beginning-of-line)
+ (texinfo-check-for-node-name)
+ (setq next-node-name (texinfo-copy-node-name))
+ (setq menu-list
+ (cons (cons
+ next-node-name
+ (prog1 "" (forward-line 1)))
+ ;; Use following to insert section titles automatically.
+ ;; (texinfo-copy-next-section-title)
+ menu-list)))
+
+ ;; Go to node to be updated.
+ (switch-to-buffer (find-file-noselect (car files)))
+ (goto-char (point-min))
+ (if (not (re-search-forward "^@node" nil t))
+ (error "No `@node' line found in %s !" (buffer-name)))
+ (beginning-of-line)
+
+ ;; Update other menus and nodes if requested.
+ (if update-everything (texinfo-all-menus-update t))
+
+ (beginning-of-line)
+ (texinfo-delete-existing-pointers)
+ (end-of-line)
+ (insert ", " next-node-name ", " previous-node-name ", " up-node-name)
+
+ (beginning-of-line)
+ (setq previous-node-name (texinfo-copy-node-name))
+
+ (setq files (cdr files)))
+ (nreverse menu-list)))
+
+(defun texinfo-multi-files-insert-main-menu (menu-list)
+ "Insert formatted main menu at point.
+Indents the first line of the description, if any, to the value of
+texinfo-column-for-description."
+
+ (insert "@menu\n")
+ (while menu-list
+ ;; Every menu entry starts with a star and a space.
+ (insert "* ")
+
+ ;; Insert the node name (and menu entry name, if present).
+ (let ((node-part (car (car menu-list))))
+ (if (stringp node-part)
+ ;; "Double colon" entry line; menu entry and node name are the same,
+ (insert (format "%s::" node-part))
+ ;; "Single colon" entry line; menu entry and node name are different.
+ (insert (format "%s: %s." (car node-part) (cdr node-part)))))
+
+ ;; Insert the description, if present.
+ (if (cdr (car menu-list))
+ (progn
+ ;; Move to right place.
+ (indent-to texinfo-column-for-description 2)
+ ;; Insert description.
+ (insert (format "%s" (cdr (car menu-list))))))
+
+ (insert "\n") ; end this menu entry
+ (setq menu-list (cdr menu-list)))
+ (insert "@end menu"))
+
+(defun texinfo-multi-file-master-menu-list (files-list)
+ "Return master menu list from files in FILES-LIST.
+Menu entries in each file collected using `texinfo-master-menu-list'.
+
+The first file in FILES-LIST must be the outer file; the others must
+be the files included within it. A main menu must already exist."
+ (save-excursion
+ (let (master-menu-list)
+ (while files-list
+ (switch-to-buffer (find-file-noselect (car files-list)))
+ (message "Working on: %s " (current-buffer))
+ (goto-char (point-min))
+ (setq master-menu-list
+ (append master-menu-list (texinfo-master-menu-list)))
+ (setq files-list (cdr files-list)))
+ master-menu-list)))
+
+
+;;; The multiple-file update function
+
+(defun texinfo-multiple-files-update
+ (outer-file &optional update-everything make-master-menu)
+ "Update first node pointers in each file included in OUTER-FILE;
+create or update the `Top' level node pointers and the main menu in
+the outer file that refers to such nodes. This does not create or
+update menus or pointers within the included files.
+
+With optional MAKE-MASTER-MENU argument (prefix arg, if interactive),
+insert a master menu in OUTER-FILE in addition to creating or updating
+pointers in the first @node line in each included file and creating or
+updating the `Top' level node pointers of the outer file. This does
+not create or update other menus and pointers within the included
+files.
+
+With optional UPDATE-EVERYTHING argument (numeric prefix arg, if
+interactive), update all the menus and all the `Next', `Previous', and
+`Up' pointers of all the files included in OUTER-FILE before inserting
+a master menu in OUTER-FILE. Also, update the `Top' level node
+pointers of OUTER-FILE.
+
+Notes:
+
+ * this command does NOT save any files--you must save the
+ outer file and any modified, included files.
+
+ * except for the `Top' node, this command does NOT handle any
+ pre-existing nodes in the outer file; hence, indices must be
+ enclosed in an included file.
+
+Requirements:
+
+ * each of the included files must contain exactly one highest
+ hierarchical level node,
+ * this highest node must be the first node in the included file,
+ * each highest hierarchical level node must be of the same type.
+
+Thus, normally, each included file contains one, and only one,
+chapter."
+
+ (interactive (cons
+ (read-string
+ "Name of outer `include' file: "
+ (buffer-file-name))
+ (cond ((not current-prefix-arg)
+ '(nil nil))
+ ((listp current-prefix-arg)
+ '(t nil)) ; make-master-menu
+ ((numberp current-prefix-arg)
+ '(t t)) ; update-everything
+ )))
+
+ (let* ((included-file-list (texinfo-multi-file-included-list outer-file))
+ (files included-file-list)
+ main-menu-list
+ next-node-name
+ previous-node-name
+ (up-node-name "Top"))
+
+;;; Update the pointers
+;;; and collect the names of the nodes and titles
+ (setq main-menu-list (texinfo-multi-file-update files update-everything))
+
+;;; Insert main menu
+
+ ;; Go to outer file
+ (switch-to-buffer (find-file-noselect (car included-file-list)))
+ (if (texinfo-old-menu-p
+ (point-min)
+ (save-excursion
+ (re-search-forward "^@include")
+ (beginning-of-line)
+ (point)))
+
+ ;; If found, leave point after word `menu' on the `@menu' line.
+ (progn
+ (texinfo-incorporate-descriptions main-menu-list)
+ ;; Delete existing menu.
+ (beginning-of-line)
+ (delete-region
+ (point)
+ (save-excursion (re-search-forward "^@end menu") (point)))
+ ;; Insert main menu
+ (texinfo-multi-files-insert-main-menu main-menu-list))
+
+ ;; Else no current menu; insert it before `@include'
+ (texinfo-multi-files-insert-main-menu main-menu-list))
+
+;;; Insert master menu
+
+ (if make-master-menu
+ (progn
+ ;; First, removing detailed part of any pre-existing master menu
+ (goto-char (point-min))
+ (if (re-search-forward texinfo-master-menu-header nil t)
+ ;; Remove detailed master menu listing
+ (progn
+ (goto-char (match-beginning 0))
+ (let ((end-of-detailed-menu-descriptions
+ (save-excursion ; beginning of end menu line
+ (goto-char (texinfo-menu-end))
+ (beginning-of-line) (forward-char -1)
+ (point))))
+ (delete-region (point) end-of-detailed-menu-descriptions))))
+
+ ;; Create a master menu and insert it
+ (texinfo-insert-master-menu-list
+ (texinfo-multi-file-master-menu-list
+ included-file-list)))))
+
+ ;; Remove unwanted extra lines.
+ (save-excursion
+ (goto-char (point-min))
+
+ (re-search-forward "^@menu")
+ (forward-line -1)
+ (insert "\n") ; Ensure at least one blank line.
+ (delete-blank-lines)
+
+ (re-search-forward "^@end menu")
+ (forward-line 1)
+ (insert "\n") ; Ensure at least one blank line.
+ (delete-blank-lines))
+
+ (message "Multiple files updated."))
+
+
+;;; Place `provide' at end of file.
+(provide 'texnfo-upd)
+
+;;; texnfo-upd.el ends here