;;; texnfo-upd.el --- utilities for updating nodes and menus in Texinfo files
-;; Copyright (C) 1989, 1990, 1991, 1992, 2001, 2002, 2003, 2004,
-;; 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
+;; Copyright (C) 1989-1992, 2001-2014 Free Software Foundation, Inc.
;; Author: Robert J. Chassell
;; Maintainer: bug-texinfo@gnu.org
;;; Commentary:
-;; Known bug: update commands fail to ignore @ignore.
+;; Known bug: update commands fail to ignore @ignore, and fail to DTRT
+;; with the @if... directives (so expect trouble when the manual uses
+;; different @node lines or @menu items in @iftex and in @ifnottex).
;; Summary: how to use the updating commands
;; With a prefix argument, the `texinfo-update-node' and
;; `texinfo-make-menu' functions do their jobs in the region.
;;
+;; Important note: We do NOT recommend use of these commands to update
+;; the `Next', `Previous' and `Up' pointers on @node lines. Most
+;; manuals, including those whose Texinfo files adhere to the structure
+;; described below, don't need these pointers, because makeinfo will
+;; generate them automatically (see the node "makeinfo Pointer
+;; Creation" in the Texinfo manual). By contrast, due to known bugs
+;; described above, texinfo-update-node etc. could produce incorrect
+;; pointers, and thus make a perfectly valid Texinfo file into an
+;; invalid one. You _have_ been warned!
+;;
;; In brief, the functions for creating or updating nodes and menus, are:
;;
;; texinfo-update-node (&optional beginning end)
;; It does not matter whether the `@node' line has pre-existing
;; `Next', `Previous', or `Up' pointers in it. They are removed.
+;; Warning: Since the pre-existing pointers are replaced with the ones
+;; computed by `texinfo-update-node', and since this function has
+;; known bugs with the more advanced Texinfo features (see above), it
+;; could produce an invalid Texinfo file. You are well advised not to
+;; use this function, except if you know what you are doing and
+;; exercise extreme caution. Keep in mind that most manuals do not
+;; need the `Next', `Previous', and `Up' pointers to be present on the
+;; @node lines; makeinfo will automatically generate them when it
+;; produces the Info or HTML versions of the manual.
+
;; The `texinfo-every-node-update' function runs `texinfo-update-node'
;; on the whole buffer.
;; 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.)
+;; after the top node. (The file must have a top node.) This
+;; function works only on Texinfo files all of whose menus are
+;; present in a single file; use `texinfo-multiple-files-update' for
+;; multi-file manuals. The function constructs a master menu that
+;; includes every entry from every other menu. Use this command to
+;; create or update the @detailmenu menu after you've created or
+;; updated all the menus in the file, including the menu in the Top
+;; node, using the `texinfo-make-menu' or the `texinfo-all-menus-update'
+;; command.
;; The `texinfo-indent-menu-description' function indents every
;; description in the menu following point, to the specified column.
;; 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.
+;; titles, you will usually want to manually edit node names so inserted.
\f
;;; Code:
(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.
+ "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.")
"\\|"
texinfo-chapter-level-regexp
"\\)\\>[ \t]*\\)")))
- "*Regexps for searching for higher level sections in a Texinfo file.
+ "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.")
"\\)\\>[ \t]+\\)"))
;; There's nothing below 5, use a bogus regexp that can't match.
(5 . "a\\(^\\)"))
- "*Regexps for searching for lower level sections in a Texinfo file.
+ "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.")
"Update every regular menu in a Texinfo file.
Update pre-existing master menu, if there is one.
+Only single-file manuals are supported by this function. For
+multi-file manuals, use `texinfo-multiple-files-update'.
+
If called with a non-nil argument, this function first updates all the
-nodes in the buffer before updating the menus.
+nodes in the buffer before updating the menus. Do NOT invoke this
+command with an argument if your Texinfo file uses @node lines without
+the `Next', `Previous', and `Up' pointers!
Indents the first line of descriptions, and leaves trailing whitespace
in a menu that lacks descriptions, so descriptions will format well.
(when (search-forward texinfo-master-menu-header nil t)
;; Check if @detailmenu kludge is used;
;; if so, leave point before @detailmenu.
- (search-backward "\n@detailmenu"
- (save-excursion (forward-line -3) (point))
- t)
+ (search-backward "\n@detailmenu" (line-beginning-position -2) t)
;; Remove detailed master menu listing
(setq master-menu-p t)
(goto-char (match-beginning 0))
(point)
(save-excursion
(re-search-forward "\\(^\\* \\|^@ignore\\|^@end menu\\)" end-of-menu t)
- (forward-line -1)
- (end-of-line) ; go to end of last description line
- (point)))
+ (line-end-position 0))) ; end of last description line
""))
(defun texinfo-menu-end ()
;; try 32, but perhaps 24 is better
(defvar texinfo-column-for-description 32
- "*Column at which descriptions start in a Texinfo menu.")
+ "Column at which descriptions start in a Texinfo menu.")
(defun texinfo-insert-menu (menu-list node-name)
"Insert formatted menu at point.
(insert (format "%s: %s." (car node-part) (cdr node-part)))))
;; Insert the description, if present.
- (when (cdr menu)
+ (when (> (length (cdr menu)) 0)
;; Move to right place.
(indent-to texinfo-column-for-description 2)
;; Insert description.
(let (beginning end node-name title)
(save-excursion
(beginning-of-line)
- (if (search-forward "* " (save-excursion (end-of-line) (point)) t)
+ (if (search-forward "* " (line-end-position) 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)
+ ((search-forward "::" (line-end-position) 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)
+ ((search-forward ":" (line-end-position) 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)
+ (if (re-search-forward "[.,\t]" (line-beginning-position 2) 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)
+ (re-search-forward ".*\n" (line-beginning-position 2) t)
(skip-chars-backward " \t\n")
(setq node-name (buffer-substring beginning (point)))
(if (= 0 (length node-name))
(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'.
+Remove pre-existing master menu, if there is one.
+
+This function supports only single-file manuals. For multi-file
+manuals, use `texinfo-multiple-files-update'.
+
+This function creates or updates the @detailmenu section of a
+master menu that follows the Top node. It replaces any existing
+detailed menu that follows the top node. The detailed menu
+includes every entry from all the other menus. By default, the
+existing menus, including the menu in the Top node, are not
+updated according to the buffer contents, so all the menus should
+be updated first using `texinfo-make-menu' or
+`texinfo-all-menus-update', which see. Alternatively, invoke
+this function with a prefix argument, see below.
+
+Non-nil, non-numeric argument (C-u prefix, if interactive) means
+first update all existing menus in the buffer (incorporating
+descriptions from pre-existing menus) before it constructs the
+master menu. If the argument is numeric (e.g., \"C-u 2\"),
+update all existing nodes as well, by calling
+\`texinfo-update-node' on the entire file. Warning: do NOT
+invoke with a numeric argument if your Texinfo file uses @node
+lines without the `Next', `Previous', `Up' pointers, as the
+result could be an invalid Texinfo file!
+
+The function removes and recreates the detailed part of an already
+existing master menu. This action assumes that the pre-existing
+master menu uses the standard `texinfo-master-menu-header' for the
+detailed menu.
The master menu has the following format, which is adapted from the
recommendation in the Texinfo Manual:
(progn
;; Check if @detailmenu kludge is used;
;; if so, leave point before @detailmenu.
- (search-backward "\n@detailmenu"
- (save-excursion (forward-line -3) (point))
- t)
+ (search-backward "\n@detailmenu" (line-beginning-position -2) t)
;; Remove detailed master menu listing
(goto-char (match-beginning 0))
(let ((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))
-
+ (when (numberp update-all-nodes-menus-p)
+ (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))))
(goto-char (match-beginning 0))
;; Check if @detailmenu kludge is used;
;; if so, leave point before @detailmenu.
- (search-backward "\n@detailmenu"
- (save-excursion (forward-line -3) (point))
- t)
+ (search-backward "\n@detailmenu" (line-beginning-position -2) t)
(insert "\n")
(delete-blank-lines)
(goto-char (point-min))))
(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")))
+ (error "Buffer lacks a menu in its first node; create it, then run me again")))
(beginning-of-line)
(delete-region ; buffer must have ordinary top menu
(point)
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
- ;;(line-end-position)
- nil
- t)
- "top")
- ((re-search-forward texinfo-section-types-regexp nil t)
- (buffer-substring-no-properties
- (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"))))))
+ (let* ((case-fold-search t)
+ ;; The Texinfo manual has a second Top node inside @verbatim
+ ;; near the end, which dupes us into thinking we are at top
+ ;; level, no matter where we are when invoked. We don't
+ ;; really grok @verbatim, so we cheat: only consider us to be
+ ;; at top level if the position of the Top node we found is
+ ;; before any other sectioning command.
+ (top-pos (save-excursion
+ (re-search-forward "^@node [ \t]*top[ \t]*\\(,\\|$\\)"
+ ;; Following search limit causes a bug
+ ;;(line-end-position)
+ nil
+ t)))
+ (sec-pos (save-excursion
+ (re-search-forward texinfo-section-types-regexp nil t)))
+ sec-name)
+ (if sec-pos
+ (save-excursion
+ (goto-char sec-pos)
+ (setq sec-name (buffer-substring-no-properties
+ (progn (beginning-of-line) ; copy its name
+ (1+ (point)))
+ (progn (forward-word 1)
+ (point))))))
+ (cond
+ ((or sec-pos top-pos)
+ (if (and top-pos sec-pos)
+ (if (< top-pos sec-pos)
+ "top"
+ sec-name)
+ (or sec-name "top")))
+ (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.
+ "Return the general hierarchical 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
(save-excursion
(goto-char (point-min))
(re-search-forward "^@node [ \t]*top[ \t]*\\(,\\|$\\)" nil t)
- (beginning-of-line)
- (point)))
+ (line-beginning-position)))
(t
(save-excursion
(re-search-backward
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)))
+ (line-beginning-position)))
\f
;;; Updating a node
"Without any prefix argument, update the node in which point is located.
Interactively, a prefix argument means to operate on the region.
+Warning: do NOT use this function if your Texinfo file uses @node
+lines without the `Next', `Previous', `Up' pointers, because the
+result could be an invalid Texinfo file due to known deficiencies
+in this command: it does not support @ignore and @if* directives.
+
The functions for creating or updating nodes and menus, and their
keybindings, are:
(message "Done...nodes updated in region. You may save the buffer."))))))
(defun texinfo-every-node-update ()
- "Update every node in a Texinfo file."
+ "Update every node in a Texinfo file.
+
+Warning: do NOT use this function if your Texinfo file uses @node
+lines without the `Next', `Previous', `Up' pointers, because the
+result could be an invalid Texinfo file due to known deficiencies
+in this command: it does not support @ignore and @if* directives."
(interactive)
(save-excursion
(texinfo-update-node (point-min) (point-max))
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))))
+ (let ((eol-point (line-end-position)))
(if (search-forward "," eol-point t)
(delete-region (1- (point)) eol-point)))
(beginning-of-line))
"\\)")
(save-excursion
(goto-char beginning)
- (beginning-of-line)
- (point))
+ (line-beginning-position))
t)
'normal
'no-pointer))
(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))
+ (line-beginning-position -2)
t)
(setq name (texinfo-copy-node-name)))
((eq kind 'no-pointer)
"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))))
+ (delete-region (point) (line-end-position)))
\f
;;; Updating nodes sequentially
(skip-chars-forward " \t")
(setq title (buffer-substring
(point)
- (save-excursion (end-of-line) (point))))))
+ (line-end-position)))))
;; 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)
+ (line-beginning-position -1))
+ t)
;; @node is present, and point at beginning of that line
(forward-word 1) ; Leave point just after @node.
;; Else @node missing; insert one.
(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)
+ (line-beginning-position 4) t)
(setq last-section-position (point))
(forward-line 1))
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.
+pointers of OUTER-FILE. Do NOT invoke this command with a numeric prefix
+arg, if your files use @node lines without the `Next', `Previous', `Up'
+pointers, because this could produce invalid Texinfo files due to known
+deficiencies in `texinfo-update-node': it does not support the @ignore
+and @if... directives.
Notes:
(point-min)
(save-excursion
(re-search-forward "^@include")
- (beginning-of-line)
- (point)))
-
+ (line-beginning-position)))
;; If found, leave point after word `menu' on the `@menu' line.
(progn
(texinfo-incorporate-descriptions main-menu-list)
(goto-char (match-beginning 0))
;; Check if @detailmenu kludge is used;
;; if so, leave point before @detailmenu.
- (search-backward "\n@detailmenu"
- (save-excursion (forward-line -3) (point))
- t)
+ (search-backward "\n@detailmenu" (line-beginning-position -2) t)
;; Remove detailed master menu listing
(let ((end-of-detailed-menu-descriptions
(save-excursion ; beginning of end menu line
;; Place `provide' at end of file.
(provide 'texnfo-upd)
-;; arch-tag: d21613a5-c32f-43f4-8af4-bfb1e7455842
;;; texnfo-upd.el ends here