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