(require 'texinfo)
(defvar texinfo-master-menu-header
" --- The Detailed Node Listing ---\n"
"String inserted before lower level entries in Texinfo master menu.
It comes after the chapter-level menu entries.")
(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-section-level-regexp
(regexp-opt (texinfo-filter 3 texinfo-section-list))
"Regular expression matching just the Texinfo section level headings.")
(defvar texinfo-subsection-level-regexp
(regexp-opt (texinfo-filter 4 texinfo-section-list))
"Regular expression matching just the Texinfo subsection level headings.")
(defvar texinfo-subsubsection-level-regexp
(regexp-opt (texinfo-filter 5 texinfo-section-list))
"Regular expression matching just the Texinfo subsubsection level headings.")
(defvar texinfo-update-menu-same-level-regexps
'((1 . "top[ \t]+")
(2 . (concat "\\(^@\\)\\(" texinfo-chapter-level-regexp "\\)\\>[ \t]*"))
(3 . (concat "\\(^@\\)\\(" texinfo-section-level-regexp "\\)\\>[ \t]*"))
(4 . (concat "\\(^@\\)\\(" texinfo-subsection-level-regexp "\\)\\>[ \t]+"))
(5 . (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
'((1 . "^@node [ \t]*DIR")
(2 . "^@node [ \t]*top[ \t]*\\(,\\|$\\)")
(3 .
(concat
"\\(^@\\("
texinfo-chapter-level-regexp
"\\)\\>[ \t]*\\)"))
(4 .
(concat
"\\(^@\\("
texinfo-section-level-regexp
"\\|"
texinfo-chapter-level-regexp
"\\)\\>[ \t]*\\)"))
(5 .
(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
'((1 .
(concat
"\\(^@\\("
texinfo-chapter-level-regexp
"\\|"
texinfo-section-level-regexp
"\\|"
texinfo-subsection-level-regexp
"\\|"
texinfo-subsubsection-level-regexp
"\\)\\>[ \t]*\\)"))
(2 .
(concat
"\\(^@\\("
texinfo-section-level-regexp
"\\|"
texinfo-subsection-level-regexp
"\\|"
texinfo-subsubsection-level-regexp
"\\)\\>[ \t]*\\)"))
(3 .
(concat
"\\(^@\\("
texinfo-subsection-level-regexp
"\\|"
texinfo-subsubsection-level-regexp
"\\)\\>[ \t]+\\)"))
(4 .
(concat
"\\(^@\\("
texinfo-subsubsection-level-regexp
"\\)\\>[ \t]+\\)"))
(5 . "a\\(^\\)"))
"*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.")
(defun texinfo-make-menu (&optional beginning end)
"Without any prefix argument, make or update a menu.
Make the menu for the section enclosing the node found following point.
A prefix argument 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.
Leaves trailing whitespace in a menu that lacks descriptions, so
descriptions will format well. In general, a menu should contain
descriptions, because node names and section titles are often too
short to explain a node well."
(interactive
(if prefix-arg
(list (point) (mark))))
(if (null beginning)
(let ((level (texinfo-hierarchic-level)))
(texinfo-make-one-menu level)
(message "Menu updated"))
(message "Making or updating menus in %s... " (buffer-name))
(save-excursion
(goto-char (min beginning end))
(let ((level (texinfo-hierarchic-level))
(region-end-marker (make-marker)))
(set-marker region-end-marker (max beginning end))
(save-restriction
(widen)
(while (texinfo-find-lower-level-node
level (marker-position region-end-marker))
(setq level (texinfo-hierarchic-level)) (texinfo-make-one-menu level))
(while (and (< (point) (marker-position region-end-marker))
(texinfo-find-higher-level-node
level (marker-position region-end-marker)))
(setq level (texinfo-hierarchic-level))
(forward-line 1)
(while (texinfo-find-lower-level-node
level (marker-position region-end-marker))
(setq level (texinfo-hierarchic-level)) (texinfo-make-one-menu level))))))
(message "Making or updating menus in %s...done" (buffer-name))))
(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)))
(when (texinfo-old-menu-p beginning first)
(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.
Indents the first line of descriptions, and leaves trailing whitespace
in a menu that lacks descriptions, so descriptions will format well.
In general, a menu should contain descriptions, because node names and
section titles are often too short to explain a node well."
(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
(when (search-forward texinfo-master-menu-header nil t)
(search-backward "\n@detailmenu"
(save-excursion (forward-line -3) (point))
t)
(setq master-menu-p t)
(goto-char (match-beginning 0))
(let ((end-of-detailed-menu-descriptions
(save-excursion (goto-char (texinfo-menu-end))
(beginning-of-line) (forward-char -1)
(point))))
(delete-region (point) end-of-detailed-menu-descriptions))))
(when update-all-nodes-p
(message "Updating all nodes in %s ... " (buffer-name))
(texinfo-update-node (point-min) (point-max)))
(message "Updating all menus in %s ... " (buffer-name))
(texinfo-make-menu (point-max) (point-min))
(when master-menu-p
(message "Updating the master menu in %s... " (buffer-name))
(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" "\\(\\(\\(^@c\\).*\n\\)" "\\|" "\\(^@ifinfo[ ]*\n\\)" "\\|" "\\(^@ifnottex[ ]*\n\\)" "\\)?" (eval (cdr (assoc level texinfo-update-menu-lower-regexps))))
(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.
A `@node' line starting at point does count as a match;
if the match is found there, the value is t and point does not move."
(let ((case-fold-search t))
(cond
((< level 3)
(if (re-search-forward "^@node [ \t]*top[ \t]*\\(,\\|$\\)" region-end t)
(progn (beginning-of-line) t)))
(t
(when (re-search-forward
(concat
"\\(^@node\\).*\n" "\\(\\(\\(^@c\\).*\n\\)" "\\|" "\\(^@ifinfo[ ]*\n\\)" "\\|" "\\(^@ifnottex[ ]*\n\\)" "\\)?" (eval (cdr (assoc level texinfo-update-menu-higher-regexps))))
region-end t)
(beginning-of-line) t)))))
(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)
(push (cons
(texinfo-copy-node-name)
(prog1 "" (forward-line 1)))
new-menu-list))
(nreverse 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" "\\(\\(\\(^@c\\).*\n\\)" "\\|" "\\(^@ifinfo[ ]*\n\\)" "\\|" "\\(^@ifnottex[ ]*\n\\)" "\\)?" (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-chars-forward " \t") (point))
(if (search-forward "," (line-end-position) t) (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'."
(goto-char (match-beginning 7))
(buffer-substring
(progn (forward-word 1) (skip-chars-forward " \t") (point))
(progn (end-of-line) (point))))
(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 (re-search-forward "^@menu" first 'goto-end)
t
(insert "\n\n") (forward-line -2) nil))
(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 ((end-of-menu (texinfo-menu-end)))
(dolist (new-menu new-menu-list new-menu-list)
(save-excursion (when (re-search-forward
(concat "\\* \\(" (regexp-quote (car new-menu)) "::"
"\\|"
".*: " (regexp-quote (car new-menu)) "[.,\t\n]"
"\\)"
) end-of-menu
t)
(setcdr new-menu (texinfo-menu-copy-old-description end-of-menu)))))))
(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 ((end-of-menu (texinfo-menu-end)))
(dolist (new-menu new-menu-list new-menu-list)
(save-excursion (if (re-search-forward
(concat "\\* " "\\(.*\\): " (regexp-quote (car new-menu))
"[.,\t\n]")
end-of-menu
t)
(setcar
new-menu (cons (buffer-substring (match-beginning 1) (match-end 1))
(car new-menu))))))))
(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 ]+")
(if (and (looking-at "\\(\\w+\\|@\\)")
(not (looking-at
"\\(^\\* \\|^@detailmenu\\|^@end menu\\|^@ignore\\)")))
(buffer-substring
(point)
(save-excursion
(re-search-forward "\\(^\\* \\|^@ignore\\|^@end menu\\)" end-of-menu t)
(forward-line -1)
(end-of-line) (point)))
""))
(defun texinfo-menu-end ()
"Return position of end of menu, but don't move 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."
(re-search-backward "^@menu" beginning)
(delete-region (point)
(save-excursion
(re-search-forward "^@end menu" first)
(point))))
(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 descriptions, if any, to the value of
texinfo-column-for-description. Indenting leaves trailing whitespace
in a menu that lacks descriptions, so descriptions will format well.
In general, a menu should contain descriptions, because node names and
section titles are often too short to explain a node well.
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")
(dolist (menu menu-list)
(insert "* ")
(let ((node-part (car menu)))
(if (stringp node-part)
(insert (format "%s::" node-part))
(insert (format "%s: %s." (car node-part) (cdr node-part)))))
(when (cdr menu)
(indent-to texinfo-column-for-description 2)
(insert (format "%s" (cdr menu))))
(insert "\n")) (insert "@end menu")
(let ((level (texinfo-hierarchic-level)))
(message
"Updated level \"%s\" menu following node: %s ... " level node-name)))
(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
((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))))
((search-forward ":" (save-excursion (end-of-line) (point)) t)
(skip-chars-forward " \t")
(setq beginning (point))
(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))))
(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")))
(if (re-search-forward
(concat
"^@node[ \t]+"
(regexp-quote node-name)
".*\n" "\\("
"\\(\\(^@c \\|^@comment\\).*\n\\)" "\\|" "\\(^@ifinfo[ ]*\n\\)" "\\|" "\\(^@ifnottex[ ]*\n\\)" "\\)?" )
nil t)
(setq title
(buffer-substring
(progn (forward-word 1)
(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")))
(end-of-line)
(delete-region
(point)
(save-excursion (skip-chars-backward " \t") (point)))
(indent-to texinfo-column-for-description 2)
(save-excursion (insert title))))
(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."))
(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 (goto-char (texinfo-menu-end))
(beginning-of-line)
(point)))
(when (re-search-forward "\\* \\(.*::\\|.*: [^.,\t\n]+[.,\t]\\)"
(texinfo-menu-end)
t)
(let ((beginning-white-space (point)))
(skip-chars-forward " \t") (if (looking-at "\\(@\\|\\w\\)+") (progn
(delete-region beginning-white-space (point))
(indent-to-column to-column-number)))))
(forward-line 1)
(setq beginning-of-next-line (point)))))
(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-existing 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.
Indents the first line of descriptions, and leaves trailing whitespace
in a menu that lacks descriptions, so descriptions will format well.
In general, a menu should contain descriptions, because node names and
section titles are often too short to explain a node well."
(interactive "P")
(let ((case-fold-search t))
(widen)
(goto-char (point-min))
(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 (search-forward texinfo-master-menu-header first-chapter t)
(progn
(search-backward "\n@detailmenu"
(save-excursion (forward-line -3) (point))
t)
(goto-char (match-beginning 0))
(let ((end-of-detailed-menu-descriptions
(save-excursion (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))
(texinfo-update-node (point-min) (point-max))
(message "Updating all menus in %s ... " (buffer-name))
(texinfo-make-menu (point-min) (point-max))))
(message "Now making the master menu in %s... " (buffer-name))
(goto-char (point-min))
(texinfo-insert-master-menu-list
(texinfo-master-menu-list))
(save-excursion
(goto-char (point-min))
(if (search-forward texinfo-master-menu-header nil t)
(progn
(goto-char (match-beginning 0))
(search-backward "\n@detailmenu"
(save-excursion (forward-line -3) (point))
t)
(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)
(push (list (texinfo-copy-menu) (texinfo-copy-menu-title))
master-menu-list))
(nreverse 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))
(unless (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))))
(unless (re-search-forward "^@menu" first-chapter t)
(error "Buffer lacks ordinary `Top' menu in which to insert master")))
(beginning-of-line)
(delete-region (point)
(save-excursion (re-search-forward "^@end menu") (point)))
(save-excursion
(let (master-menu-inserted-p)
(insert "\n@menu\n")
(message "Inserting chapter menu entry: %s ... "
(car (car master-menu-list)))
(dolist (entry (reverse (car (car master-menu-list))))
(insert "* " entry "\n"))
(setq master-menu-list (cdr master-menu-list))
(if (car (car master-menu-list))
(progn (setq master-menu-inserted-p t)
(insert (concat "\n@detailmenu\n"
texinfo-master-menu-header))))
(dolist (menu master-menu-list)
(message "Inserting menu for %s .... " (cadr menu))
(insert "\n" (cadr menu) "\n\n")
(dolist (entry (reverse (car menu)))
(insert "* " entry "\n")))
(if master-menu-inserted-p
(insert "\n@end detailmenu"))
(insert "\n@end menu\n\n"))))
(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"
"\\|" texinfo-section-types-regexp "\\)")
nil
t)
(progn
(beginning-of-line)
(forward-word 1) (skip-chars-forward " \t") (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)) (last-entry (save-excursion (goto-char end-of-menu)
(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)
(push (buffer-substring
(point)
(save-excursion
(re-search-forward "\\(^\\* \\|^@e\\)" nil t)
(- (point) 3)))
this-menu-list)))
this-menu-list))
(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]*\\(,\\|$\\)"
nil
t)
"top")
((re-search-forward texinfo-section-types-regexp nil t)
(buffer-substring-no-properties
(progn (beginning-of-line) (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))
(cadr (assoc
(texinfo-specific-section-type)
texinfo-section-list))))
(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))
(cond
((< level 3)
(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" "\\(\\(\\(^@c\\).*\n\\)" "\\|" "\\(^@ifinfo[ ]*\n\\)" "\\|" "\\(^@ifnottex[ ]*\n\\)" "\\)?" (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" "\\(\\(\\(^@c\\).*\n\\)" "\\|" "\\(^@ifinfo[ ]*\n\\)" "\\|" "\\(^@ifnottex[ ]*\n\\)" "\\)?" (eval
(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)))
(defun texinfo-update-node (&optional beginning end)
"Without any prefix argument, update the node in which point is located.
Interactively, a prefix argument means to operate on the region.
The functions for creating or updating nodes and menus, and their
keybindings, are:
texinfo-update-node (&optional beginning end) \\[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
(if prefix-arg
(list (point) (mark))))
(if (null beginning)
(let ((auto-fill-function 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."))
(let ((auto-fill-function nil))
(save-excursion
(save-restriction
(narrow-to-region beginning end)
(goto-char (point-min))
(while (re-search-forward "^@node" (point-max) t)
(beginning-of-line)
(texinfo-update-the-node))
(goto-char (point-max))
(message "Done...nodes updated in region. You may save the buffer."))))))
(defun texinfo-every-node-update ()
"Update every node in a Texinfo file."
(interactive)
(save-excursion
(texinfo-update-node (point-min) (point-max))
(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 (eq level 1)
(texinfo-top-pointer-case)
(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
(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)))
(forward-word 1) (skip-chars-forward " \t") (if (not (looking-at "[^,\t\n ]+")) (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) (if (re-search-forward
(concat
"\\(^@node\\).*\n"
(concat
"\\(\\("
"\\(^@c\\).*\n\\)"
"\\|"
"\\(^@ifinfo[ ]*\n\\)"
"\\|"
"\\(^@ifnottex[ ]*\n\\)"
"\\)?")
(eval
(cdr (assoc level texinfo-update-menu-same-level-regexps))))
end
t)
'normal
'no-pointer))
((eq direction 'previous)
(if (re-search-backward
(concat
"\\("
"\\(^@node\\).*\n"
(concat
"\\(\\("
"\\(^@c\\).*\n\\)"
"\\|"
"\\(^@ifinfo[ ]*\n\\)"
"\\|"
"\\(^@ifnottex[ ]*\n\\)"
"\\)?")
(eval
(cdr (assoc level texinfo-update-menu-same-level-regexps)))
"\\|"
"\\(^@node\\).*\n"
(concat
"\\(\\("
"\\(^@c\\).*\n\\)"
"\\|"
"\\(^@ifinfo[ ]*\n\\)"
"\\|"
"\\(^@ifnottex[ ]*\n\\)"
"\\)?")
(eval
(cdr (assoc level texinfo-update-menu-higher-regexps)))
"\\|"
"^@node [ \t]*top[ \t]*\\(,\\|$\\)"
"\\)")
beginning
t)
'normal
'no-pointer))
((eq direction 'up)
(if (re-search-backward
(concat
"\\("
"\\(^@node\\).*\n"
(concat
"\\(\\("
"\\(^@c\\).*\n\\)"
"\\|"
"\\(^@ifinfo[ ]*\n\\)"
"\\|"
"\\(^@ifnottex[ ]*\n\\)"
"\\)?")
(eval (cdr (assoc level texinfo-update-menu-higher-regexps)))
"\\|"
"^@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) (re-search-backward "^@node" (save-excursion (forward-line -3))
t)
(setq name (texinfo-copy-node-name)))
((eq kind 'no-pointer)
(setq name " "))) 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))))
(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)
(let ((auto-fill-function 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."))
(let ((auto-fill-function 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 (eq level 1)
(texinfo-top-pointer-case)
(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-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)))))
(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) (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)))
(point-min)
t)
'normal
'no-pointer))
(t
(error "texinfo-sequential-find-pointer: lack proper arguments")))))
(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")
(let (beginning-marker end-marker title last-section-position)
(push-mark end t)
(setq end-marker (mark-marker))
(goto-char beginning)
(while (re-search-forward
texinfo-section-types-regexp
end-marker
'end)
(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))))))
(if (re-search-backward
"^@node"
(or last-section-position
(save-excursion (forward-line -2) (point))) t)
(forward-word 1) (beginning-of-line) (insert "@node\n")
(backward-char 1)) (if title-p
(progn
(skip-chars-forward " \t")
(if (not (looking-at "[^,\t\n ]+"))
(progn
(beginning-of-line)
(forward-word 1)
(insert " " title)
(message "Inserted title %s ... " title)))))
(re-search-forward texinfo-section-types-regexp
(save-excursion (forward-line 3) (point)) t)
(setq last-section-position (point))
(forward-line 1))
(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."))))
(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
(set-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)
(let ((title
(buffer-substring
(progn (forward-word 1) (skip-chars-forward " \t") (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.
However, when an included file does not have any node lines in
it, this command does not try to create a menu entry for it.
Consequently, you can include any file, such as a version or an
update file without node lines, not just files that are
chapters."
(let ((case-fold-search t)
menu-list next-node-name previous-node-name files-with-node-lines)
(while files
(set-buffer (find-file-noselect (car files)))
(widen)
(goto-char (point-min))
(when (re-search-forward "^@node" nil t)
(setq files-with-node-lines (cons (car files) files-with-node-lines)))
(setq files (cdr files)))
(setq files-with-node-lines (nreverse files-with-node-lines))
(set-buffer (find-file-noselect (car (cdr files-with-node-lines))))
(widen)
(goto-char (point-min))
(re-search-forward "^@node" nil t)
(beginning-of-line)
(texinfo-check-for-node-name)
(setq next-node-name (texinfo-copy-node-name))
(push (cons next-node-name (prog1 "" (forward-line 1)))
menu-list)
(set-buffer (find-file-noselect (pop files-with-node-lines)))
(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")
(while files-with-node-lines
(if (not (cdr files-with-node-lines))
(setq next-node-name "")
(set-buffer (find-file-noselect (car (cdr files-with-node-lines))))
(widen)
(goto-char (point-min))
(re-search-forward "^@node" nil t)
(beginning-of-line)
(texinfo-check-for-node-name)
(setq next-node-name (texinfo-copy-node-name))
(push (cons next-node-name (prog1 "" (forward-line 1)))
menu-list))
(set-buffer (find-file-noselect (car files-with-node-lines)))
(goto-char (point-min))
(beginning-of-line)
(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 ", Top")
(beginning-of-line)
(setq previous-node-name (texinfo-copy-node-name))
(setq files-with-node-lines (cdr files-with-node-lines)))
(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")
(dolist (entry menu-list)
(insert "* ")
(let ((node-part (car entry)))
(if (stringp node-part)
(insert (format "%s::" node-part))
(insert (format "%s: %s." (car node-part) (cdr node-part)))))
(when (cdr entry)
(indent-to texinfo-column-for-description 2)
(insert (format "%s" (cdr entry))))
(insert "\n")) (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)
(dolist (file files-list)
(set-buffer (find-file-noselect file))
(message "Working on: %s " (current-buffer))
(goto-char (point-min))
(setq master-menu-list
(append master-menu-list (texinfo-master-menu-list))))
master-menu-list)))
(defun texinfo-multiple-files-update
(outer-file &optional make-master-menu update-everything)
"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)) ((numberp current-prefix-arg) '(t t)))))
(let* ((included-file-list (texinfo-multi-file-included-list outer-file))
(files included-file-list)
next-node-name
previous-node-name
(main-menu-list (texinfo-multi-file-update files update-everything)))
(set-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)))
(progn
(texinfo-incorporate-descriptions main-menu-list)
(beginning-of-line)
(delete-region
(point)
(save-excursion (re-search-forward "^@end menu") (point)))
(texinfo-multi-files-insert-main-menu main-menu-list))
(texinfo-multi-files-insert-main-menu main-menu-list))
(if make-master-menu
(progn
(goto-char (point-min))
(if (search-forward texinfo-master-menu-header nil t)
(progn
(goto-char (match-beginning 0))
(search-backward "\n@detailmenu"
(save-excursion (forward-line -3) (point))
t)
(let ((end-of-detailed-menu-descriptions
(save-excursion (goto-char (texinfo-menu-end))
(beginning-of-line) (forward-char -1)
(point))))
(delete-region (point) end-of-detailed-menu-descriptions))))
(texinfo-insert-master-menu-list
(texinfo-multi-file-master-menu-list
included-file-list)))))
(save-excursion
(goto-char (point-min))
(re-search-forward "^@menu")
(forward-line -1)
(insert "\n") (delete-blank-lines)
(re-search-forward "^@end menu")
(forward-line 1)
(insert "\n") (delete-blank-lines))
(message "Multiple files updated."))
(provide 'texnfo-upd)