texinfmt.el 153 KB
Newer Older
1
;;; texinfmt.el --- format Texinfo files into Info files
Richard M. Stallman's avatar
Richard M. Stallman committed
2

3
;; Copyright (C) 1985, 1986, 1988, 1990, 1991, 1992, 1993, 
Andreas Schwab's avatar
Andreas Schwab committed
4
;;               1994, 1995, 1996, 1997, 1998, 2000, 2001
5
;;    Free Software Foundation, Inc.
Brian Preble's avatar
Brian Preble committed
6

Andreas Schwab's avatar
Andreas Schwab committed
7
;; Maintainer: Robert J. Chassell <bug-texinfo@gnu.org>
8
;; Keywords: maint, tex, docs
Eric S. Raymond's avatar
Eric S. Raymond committed
9

Richard M. Stallman's avatar
Richard M. Stallman committed
10
;; This file is part of GNU Emacs.
Brian Preble's avatar
Brian Preble committed
11 12 13

;; GNU Emacs is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
Eric S. Raymond's avatar
Eric S. Raymond committed
14
;; the Free Software Foundation; either version 2, or (at your option)
Brian Preble's avatar
Brian Preble committed
15 16 17 18 19 20 21 22
;; any later version.

;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
Erik Naggum's avatar
Erik Naggum committed
23 24 25
;; along with GNU Emacs; see the file COPYING.  If not, write to the
;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.
Brian Preble's avatar
Brian Preble committed
26

27 28
;;; Commentary:

29
;;; Code:
Eric S. Raymond's avatar
Eric S. Raymond committed
30

31
;;; Emacs lisp functions to convert Texinfo files to Info files.
Brian Preble's avatar
Brian Preble committed
32

33 34 35 36 37 38 39
(or (fboundp 'defgroup)
    (defmacro defgroup (&rest ignore) nil))

(or (fboundp 'defcustom)
    (defmacro defcustom (var value doc &rest ignore)
      `(defvar ,var ,value ,doc)))

40
(defvar texinfmt-version "2.38 of 3 July 1998")
41 42 43 44 45 46 47 48 49 50 51 52 53

(defun texinfmt-version (&optional here)
  "Show the version of texinfmt.el in the minibuffer.
If optional argument HERE is non-nil, insert info at point."
  (interactive "P")
  (let ((version-string 
         (format "Version of \`texinfmt.el\': %s" texinfmt-version)))
    (if here 
        (insert version-string)
      (if (interactive-p)
          (message "%s" version-string)
        version-string))))

54 55 56 57 58

;;; Variable definitions

(require 'texinfo)          ; So `texinfo-footnote-style' is defined.
(require 'texnfo-upd)       ; So `texinfo-section-types-regexp' is defined.
Eric S. Raymond's avatar
Eric S. Raymond committed
59

Brian Preble's avatar
Brian Preble committed
60 61 62 63 64 65 66 67 68 69
(defvar texinfo-format-syntax-table nil)

(defvar texinfo-vindex)
(defvar texinfo-findex)
(defvar texinfo-cindex)
(defvar texinfo-pindex)
(defvar texinfo-tindex)
(defvar texinfo-kindex)
(defvar texinfo-last-node)
(defvar texinfo-node-names)
70
(defvar texinfo-enclosure-list)
71
(defvar texinfo-alias-list)
72
(defvar texinfo-fold-nodename-case nil)
73

74 75 76 77 78 79 80 81 82 83 84 85 86 87
(defvar texinfo-command-start)
(defvar texinfo-command-end)
(defvar texinfo-command-name)
(defvar texinfo-defun-type)
(defvar texinfo-last-node-pos)
(defvar texinfo-stack)
(defvar texinfo-short-index-cmds-alist)
(defvar texinfo-short-index-format-cmds-alist)
(defvar texinfo-format-filename)
(defvar texinfo-footnote-number)
(defvar texinfo-start-of-header)
(defvar texinfo-end-of-header)
(defvar texinfo-raisesections-alist)
(defvar texinfo-lowersections-alist)
88 89

;;; Syntax table
Brian Preble's avatar
Brian Preble committed
90 91 92 93

(if texinfo-format-syntax-table
    nil
  (setq texinfo-format-syntax-table (make-syntax-table))
94 95
  (modify-syntax-entry ?\" " " texinfo-format-syntax-table)
  (modify-syntax-entry ?\\ " " texinfo-format-syntax-table)
Brian Preble's avatar
Brian Preble committed
96 97 98 99 100 101 102 103 104 105
  (modify-syntax-entry ?@ "\\" texinfo-format-syntax-table)
  (modify-syntax-entry ?\^q "\\" texinfo-format-syntax-table)
  (modify-syntax-entry ?\[ "." texinfo-format-syntax-table)
  (modify-syntax-entry ?\] "." texinfo-format-syntax-table)
  (modify-syntax-entry ?\( "." texinfo-format-syntax-table)
  (modify-syntax-entry ?\) "." texinfo-format-syntax-table)
  (modify-syntax-entry ?{ "(}" texinfo-format-syntax-table)
  (modify-syntax-entry ?} "){" texinfo-format-syntax-table)
  (modify-syntax-entry ?\' "." texinfo-format-syntax-table))

106 107 108

;;; Top level buffer and region formatting functions

109
;;;###autoload
110
(defun texinfo-format-buffer (&optional nosplit)
Brian Preble's avatar
Brian Preble committed
111 112
  "Process the current buffer as texinfo code, into an Info file.
The Info file output is generated in a buffer visiting the Info file
113
name specified in the @setfilename command.
Brian Preble's avatar
Brian Preble committed
114 115 116 117 118

Non-nil argument (prefix, if interactive) means don't make tag table
and don't split the file if large.  You can use Info-tagify and
Info-split to do these manually."
  (interactive "P")
119 120
  (let ((lastmessage "Formatting Info file...")
	(coding-system-for-write buffer-file-coding-system))
Brian Preble's avatar
Brian Preble committed
121
    (message lastmessage)
122
    (widen)
Brian Preble's avatar
Brian Preble committed
123
    (texinfo-format-buffer-1)
124 125
    (Info-tagify)
    (if nosplit
Brian Preble's avatar
Brian Preble committed
126 127 128 129 130 131 132 133
        nil
      (if (> (buffer-size) 100000)
          (progn
            (message (setq lastmessage "Splitting Info file..."))
            (Info-split))))
    (message (concat lastmessage
                     (if (interactive-p) "done.  Now save it." "done.")))))

134 135 136
(defvar texinfo-region-buffer-name "*Info Region*"
  "*Name of the temporary buffer used by \\[texinfo-format-region].")

137
;;;###autoload
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
(defun texinfo-format-region (region-beginning region-end)
  "Convert the current region of the Texinfo file to Info format.
This lets you see what that part of the file will look like in Info.
The command is bound to \\[texinfo-format-region].  The text that is
converted to Info is stored in a temporary buffer."
  (interactive "r")
  (message "Converting region to Info format...")
  (let (texinfo-command-start
        texinfo-command-end
        texinfo-command-name
        texinfo-vindex
        texinfo-findex
        texinfo-cindex
        texinfo-pindex
        texinfo-tindex
        texinfo-kindex
        texinfo-stack
        (texinfo-format-filename "")
        texinfo-example-start
        texinfo-last-node-pos
        texinfo-last-node
        texinfo-node-names
        (texinfo-footnote-number 0)
        last-input-buffer
        (fill-column-for-info fill-column)
        (input-buffer (current-buffer))
        (input-directory default-directory)
        (header-text "")
        (header-beginning 1)
        (header-end 1))
    
;;; Copy lines between beginning and end of header lines, 
;;;    if any, or else copy the `@setfilename' line, if any.
    (save-excursion
        (save-restriction
          (widen)
          (goto-char (point-min))
          (let ((search-end (save-excursion (forward-line 100) (point))))
            (if (or
                 ;; Either copy header text.
                 (and 
                  (prog1 
180
                      (search-forward tex-start-of-header search-end t)
181 182 183 184
                    (forward-line 1)
                    ;; Mark beginning of header.
                    (setq header-beginning (point)))
                  (prog1 
185
                      (search-forward tex-end-of-header nil t)
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231
                    (beginning-of-line)
                    ;; Mark end of header
                    (setq header-end (point))))
                 ;; Or copy @filename line.
                 (prog2
                  (goto-char (point-min))
                  (search-forward "@setfilename" search-end t)
                  (beginning-of-line)
                  (setq header-beginning (point))
                  (forward-line 1)
                  (setq header-end (point))))
                
                ;; Copy header  
                (setq header-text
                      (buffer-substring
                       (min header-beginning region-beginning)
                       header-end))))))

;;; Find a buffer to use.
    (switch-to-buffer (get-buffer-create texinfo-region-buffer-name))
    (erase-buffer)
    ;; Insert the header into the buffer.
    (insert header-text)
    ;; Insert the region into the buffer.
    (insert-buffer-substring
     input-buffer
     (max region-beginning header-end)
     region-end)
    ;; Make sure region ends in a newline.
    (or (= (preceding-char) ?\n)
        (insert "\n"))
    
    (goto-char (point-min))
    (texinfo-mode)
    (message "Converting region to Info format...")
    (setq fill-column fill-column-for-info)
    ;; Install a syntax table useful for scanning command operands.
    (set-syntax-table texinfo-format-syntax-table)

    ;; Insert @include files so `texinfo-raise-lower-sections' can
    ;; work on them without losing track of multiple
    ;; @raise/@lowersections commands. 
    (while (re-search-forward "^@include" nil t)
      (setq texinfo-command-end (point))
      (let ((filename (concat input-directory
                              (texinfo-parse-line-arg))))
232
        (re-search-backward "^@include")
233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265
        (delete-region (point) (save-excursion (forward-line 1) (point)))
        (message "Reading included file: %s" filename)
        (save-excursion
          (save-restriction
            (narrow-to-region
             (point)
             (+ (point) (car (cdr (insert-file-contents filename)))))
            (goto-char (point-min))
            ;; Remove `@setfilename' line from included file, if any,
            ;; so @setfilename command not duplicated.
            (if (re-search-forward 
                 "^@setfilename" (save-excursion (forward-line 100) (point)) t)
                (progn
                  (beginning-of-line)
                  (delete-region
                   (point) (save-excursion (forward-line 1) (point)))))))))

    ;; Raise or lower level of each section, if necessary.
    (goto-char (point-min))
    (texinfo-raise-lower-sections)
    ;; Append @refill to appropriate paragraphs for filling.
    (goto-char (point-min))
    (texinfo-append-refill)
    ;; If the region includes the effective end of the data,
    ;; discard everything after that.
    (goto-char (point-max))
    (if (re-search-backward "^@bye" nil t)
        (delete-region (point) (point-max)))
    ;; Make sure buffer ends in a newline.
    (or (= (preceding-char) ?\n)
        (insert "\n"))
    ;; Don't use a previous value of texinfo-enclosure-list.
    (setq texinfo-enclosure-list nil)
266
    (setq texinfo-alias-list nil)
267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306

    (goto-char (point-min))
    (if (looking-at "\\\\input[ \t]+texinfo")
        (delete-region (point) (save-excursion (forward-line 1) (point))))

    ;; Insert Info region title text.
    (goto-char (point-min))
    (if (search-forward 
         "@setfilename" (save-excursion (forward-line 100) (point)) t)
        (progn
          (setq texinfo-command-end (point))
          (beginning-of-line)
          (setq texinfo-command-start (point))
          (let ((arg (texinfo-parse-arg-discard)))
            (insert " "
              texinfo-region-buffer-name
              " buffer for:  `") 
            (insert (file-name-nondirectory (expand-file-name arg)))
            (insert "',        -*-Text-*-\n")))
      ;; Else no `@setfilename' line
      (insert " "
              texinfo-region-buffer-name
              " buffer                       -*-Text-*-\n"))
    (insert "produced by `texinfo-format-region'\n"
            "from a region in: "
            (if (buffer-file-name input-buffer)
                  (concat "`"
                          (file-name-sans-versions
                           (file-name-nondirectory
                            (buffer-file-name input-buffer)))
                          "'")
                (concat "buffer `" (buffer-name input-buffer) "'"))
              "\nusing `texinfmt.el' version "
              texinfmt-version
              ".\n\n")

    ;; Now convert for real.
    (goto-char (point-min))
    (texinfo-format-scan)
    (goto-char (point-min))
307 308
    (Info-tagify input-buffer)
    (goto-char (point-min))
309 310
    (message "Done.")))

311
;;;###autoload
312
(defun texi2info (&optional nosplit)
313 314 315 316 317 318 319 320 321
  "Convert the current buffer (written in Texinfo code) into an Info file.
The Info file output is generated in a buffer visiting the Info file
names specified in the @setfilename command.

This function automatically updates all node pointers and menus, and
creates a master menu.  This work is done on a temporary buffer that
is automatically removed when the Info file is created.  The original
Texinfo source buffer is not changed.

322 323
Non-nil argument (prefix, if interactive) means don't split the file
if large.  You can use Info-split to do this manually."
324 325 326 327 328 329 330 331 332
  (interactive "P")
  (let ((temp-buffer (concat  "*--" (buffer-name) "--temporary-buffer*" )))
    (message "First updating nodes and menus, then creating Info file.")
    ;;  (sit-for 2)
    (copy-to-buffer temp-buffer (point-min) (point-max))
    (switch-to-buffer temp-buffer)
    (texinfo-master-menu t)
    (message "Now creating Info file.")
    (sit-for 2)
333
    (texinfo-format-buffer nosplit)
334 335 336
    (save-buffer)
    (kill-buffer temp-buffer)))

Brian Preble's avatar
Brian Preble committed
337

338 339
;;; Primary internal formatting function for the whole buffer.

Brian Preble's avatar
Brian Preble committed
340 341 342 343 344 345 346
(defun texinfo-format-buffer-1 ()
  (let (texinfo-format-filename
        texinfo-example-start
        texinfo-command-start
        texinfo-command-end
        texinfo-command-name
        texinfo-last-node
347
        texinfo-last-node-pos
Brian Preble's avatar
Brian Preble committed
348 349 350 351 352 353 354 355
        texinfo-vindex
        texinfo-findex
        texinfo-cindex
        texinfo-pindex
        texinfo-tindex
        texinfo-kindex
        texinfo-stack
        texinfo-node-names
356
        (texinfo-footnote-number 0)
Brian Preble's avatar
Brian Preble committed
357 358
        last-input-buffer
        outfile
359
        (fill-column-for-info fill-column)
Brian Preble's avatar
Brian Preble committed
360 361
        (input-buffer (current-buffer))
        (input-directory default-directory))
362
    (setq texinfo-enclosure-list nil)
363
    (setq texinfo-alias-list nil)
Brian Preble's avatar
Brian Preble committed
364 365
    (save-excursion
      (goto-char (point-min))
366
      (or (search-forward "@setfilename" nil t)
367
          (error "Texinfo file needs an `@setfilename FILENAME' line"))
Brian Preble's avatar
Brian Preble committed
368 369
      (setq texinfo-command-end (point))
      (setq outfile (texinfo-parse-line-arg)))
370

Brian Preble's avatar
Brian Preble committed
371 372
    (find-file outfile)
    (texinfo-mode)
373 374 375 376 377 378
    (erase-buffer)

    (message "Formatting Info file: %s" outfile)
    (setq texinfo-format-filename
          (file-name-nondirectory (expand-file-name outfile)))

379
    (setq fill-column fill-column-for-info)
Brian Preble's avatar
Brian Preble committed
380
    (set-syntax-table texinfo-format-syntax-table)
381

Brian Preble's avatar
Brian Preble committed
382
    (insert-buffer-substring input-buffer)
383 384 385 386 387 388 389 390 391 392
    (message "Converting %s to Info format..." (buffer-name input-buffer))
    
    ;; Insert @include files so `texinfo-raise-lower-sections' can
    ;; work on them without losing track of multiple
    ;; @raise/@lowersections commands. 
    (goto-char (point-min))
    (while (re-search-forward "^@include" nil t)
      (setq texinfo-command-end (point))
      (let ((filename (concat input-directory
                              (texinfo-parse-line-arg))))
393
        (re-search-backward "^@include")
394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416
        (delete-region (point) (save-excursion (forward-line 1) (point)))
        (message "Reading included file: %s" filename)
        (save-excursion
          (save-restriction
            (narrow-to-region
             (point)
             (+ (point) (car (cdr (insert-file-contents filename)))))
            (goto-char (point-min))
            ;; Remove `@setfilename' line from included file, if any,
            ;; so @setfilename command not duplicated.
            (if (re-search-forward 
                 "^@setfilename"
                 (save-excursion (forward-line 100) (point)) t)
                (progn
                  (beginning-of-line)
                  (delete-region
                   (point) (save-excursion (forward-line 1) (point)))))))))
    ;; Raise or lower level of each section, if necessary.
    (goto-char (point-min))
    (texinfo-raise-lower-sections)
    ;; Append @refill to appropriate paragraphs
    (goto-char (point-min))
    (texinfo-append-refill)
Brian Preble's avatar
Brian Preble committed
417 418 419 420 421 422 423 424 425 426 427 428 429 430
    (goto-char (point-min))
    (search-forward "@setfilename")
    (beginning-of-line)
    (delete-region (point-min) (point))
    ;; Remove @bye at end of file, if it is there.
    (goto-char (point-max))
    (if (search-backward "@bye" nil t)
        (delete-region (point) (point-max)))
    ;; Make sure buffer ends in a newline.
    (or (= (preceding-char) ?\n)
        (insert "\n"))
    ;; Scan the whole buffer, converting to Info format.
    (texinfo-format-scan)
    (goto-char (point-min))
431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449
    ;; Insert info about how this file was made.
    (insert "Info file: "
            texinfo-format-filename ",    -*-Text-*-\n"
            "produced by `texinfo-format-buffer'\n"
            ;; Date string removed so that regression testing is easier.
            ;; "on "
            ;; (insert (format-time-string "%e %b %Y")) " "
            "from file"
            (if (buffer-file-name input-buffer)
                (concat " `"
                        (file-name-sans-versions
                         (file-name-nondirectory
                          (buffer-file-name input-buffer)))
                        "'")
              (concat "buffer `" (buffer-name input-buffer) "'"))
            "\nusing `texinfmt.el' version "
            texinfmt-version
            ".\n\n")
    ;; Return data for indices.
Brian Preble's avatar
Brian Preble committed
450 451 452 453
    (list outfile
          texinfo-vindex texinfo-findex texinfo-cindex
          texinfo-pindex texinfo-tindex texinfo-kindex)))

454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469

;;; Perform non-@-command file conversions: quotes and hyphens

(defun texinfo-format-convert (min max)
  ;; Convert left and right quotes to typewriter font quotes.
  (goto-char min)
  (while (search-forward "``" max t)
    (replace-match "\""))
  (goto-char min)
  (while (search-forward "''" max t)
    (replace-match "\""))
  ;; Convert three hyphens in a row to two.
  (goto-char min)
  (while (re-search-forward "\\( \\|\\w\\)\\(---\\)\\( \\|\\w\\)" max t)
    (delete-region (1+ (match-beginning 2)) (+ 2 (match-beginning
    2)))))
Brian Preble's avatar
Brian Preble committed
470

471 472 473

;;; Handle paragraph filling

474 475
;; Keep as concatinated lists for ease of maintenance

476
(defvar texinfo-no-refill-regexp
477 478 479
  (concat
   "^@"
   "\\("
480
   "direntry\\|"
481 482
   "lisp\\|"
   "smalllisp\\|"
483 484
   "example\\|"
   "smallexample\\|"
485
   "display\\|"
486
   "smalldisplay\\|"
487
   "format\\|"
488
   "smallformat\\|"
489 490 491 492 493 494 495 496 497 498
   "flushleft\\|"
   "flushright\\|"
   "menu\\|"
   "multitable\\|"
   "titlepage\\|"
   "iftex\\|"
   "ifhtml\\|"
   "tex\\|"
   "html"
   "\\)")
499 500
  "Regexp specifying environments in which paragraphs are not filled.")

501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533
(defvar texinfo-accent-commands
  (concat
   "@^\\|"
   "@`\\|"
   "@'\\|"
   "@\"\\|"
   "@,\\|"
   "@=\\|"
   "@~\\|"
   "@OE{\\|"
   "@oe{\\|"
   "@AA{\\|"
   "@aa{\\|"
   "@AE{\\|"
   "@ae{\\|"
   "@ss{\\|"
   "@questiondown{\\|"
   "@exclamdown{\\|"
   "@L{\\|"
   "@l{\\|"
   "@O{\\|"
   "@o{\\|"
   "@dotaccent{\\|"
   "@ubaraccent{\\|"
   "@d{\\|"
   "@H{\\|"
   "@ringaccent{\\|"
   "@tieaccent{\\|"
   "@u{\\|"
   "@v{\\|"
   "@dotless{"
   ))

534
(defvar texinfo-part-of-para-regexp
535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572
  (concat
   "^@"
   "\\("
   "b{\\|"
   "bullet{\\|"
   "cite{\\|"
   "code{\\|"
   "email{\\|"
   "emph{\\|"
   "equiv{\\|"
   "error{\\|"
   "expansion{\\|"
   "file{\\|"
   "i{\\|"
   "inforef{\\|"
   "kbd{\\|"
   "key{\\|"
   "lisp{\\|"
   "minus{\\|"
   "point{\\|"
   "print{\\|"
   "pxref{\\|"
   "r{\\|"
   "ref{\\|"
   "result{\\|"
   "samp{\\|"
   "sc{\\|"
   "t{\\|"
   "TeX{\\|"
   "today{\\|"
   "url{\\|"
   "var{\\|"
   "w{\\|"
   "xref{\\|"
   "@-\\|"    ; @- is a descretionary hyphen (not an accent) (a noop).
   texinfo-accent-commands
   "\\)"
   )
573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608
  "Regexp specifying @-commands found within paragraphs.")

(defun texinfo-append-refill ()
  "Append @refill at end of each paragraph that should be filled.
Do not append @refill to paragraphs within @example and similar environments.  
Do not append @refill to paragraphs containing @w{TEXT} or @*."

  ;; It is necessary to append @refill before other processing because
  ;; the other processing removes information that tells Texinfo
  ;; whether the text should or should not be filled.
  
  (while (< (point) (point-max))
    (let ((refill-blank-lines "^[ \t\n]*$")
          (case-fold-search nil))       ; Don't confuse @TeX and @tex....
      (beginning-of-line)
      ;; 1. Skip over blank lines;
      ;;    skip over lines beginning with @-commands, 
      ;;    but do not skip over lines
      ;;      that are no-refill environments such as @example or
      ;;      that begin with within-paragraph @-commands such as @code.
      (while (and (looking-at (concat "^@\\|^\\\\\\|" refill-blank-lines))
                  (not (looking-at 
                        (concat
                         "\\(" 
                         texinfo-no-refill-regexp
                         "\\|" 
                         texinfo-part-of-para-regexp
                         "\\)")))
                  (< (point) (point-max)))
        (forward-line 1))
      ;; 2. Skip over @example and similar no-refill environments.
      (if (looking-at texinfo-no-refill-regexp)
          (let ((environment
                 (buffer-substring (match-beginning 1) (match-end 1))))
            (progn (re-search-forward (concat "^@end " environment) nil t)
                   (forward-line 1)))
609 610 611
        ;; Else
        ;; 3. Do not refill a paragraph containing @w or @*, or ending
        ;;    with @<newline> followed by a newline.
612 613
        (if  (or
              (>= (point) (point-max))
614 615 616 617 618 619
              (re-search-forward 
               "@w{\\|@\\*\\|@\n\n" 
               (save-excursion
                 (forward-paragraph)
                 (forward-line 1)
                 (point)) t))
620 621 622 623 624
            ;; Go to end of paragraph and do nothing.
            (forward-paragraph) 
          ;; 4. Else go to end of paragraph and insert @refill
          (forward-paragraph)
          (forward-line -1)
Karl Heuer's avatar
Karl Heuer committed
625 626 627 628 629
	  (let ((line-beg (point)))
	    (end-of-line)
	    (delete-region
	     (point)
	     (save-excursion (skip-chars-backward " \t") (point)))
630 631 632
	    (forward-char 1)
	    (unless (re-search-backward "@c[ \t\n]\\|@comment[ \t\n]" line-beg t)
	      (forward-char -1))
Karl Heuer's avatar
Karl Heuer committed
633 634
	    (unless (re-search-backward "@refill\\|@bye" line-beg t)
	      (insert "@refill")))
635
          (forward-line 1))))))
Brian Preble's avatar
Brian Preble committed
636

637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761

;;; Handle `@raisesections' and `@lowersections' commands

;; These commands change the hierarchical level of chapter structuring
;; commands. 
;;    
;; @raisesections changes @subsection to @section,
;;                        @section    to @chapter,
;;                        etc.
;;
;; @lowersections changes @chapter    to @section
;;                        @subsection to @subsubsection,
;;                        etc.
;;
;; An @raisesections/@lowersections command changes only those
;; structuring commands that follow the @raisesections/@lowersections
;; command.
;;
;; Repeated @raisesections/@lowersections continue to raise or lower
;; the heading level.
;; 
;; An @lowersections command cancels an @raisesections command, and
;; vice versa.
;;
;; You cannot raise or lower "beyond" chapters or subsubsections, but
;; trying to do so does not elicit an error---you just get more
;; headings that mean the same thing as you keep raising or lowering
;; (for example, after a single @raisesections, both @chapter and
;; @section produce chapter headings).

(defun texinfo-raise-lower-sections ()
  "Raise or lower the hierarchical level of chapters, sections, etc. 

This function acts according to `@raisesections' and `@lowersections'
commands in the Texinfo file.

For example, an `@lowersections' command is useful if you wish to
include what is written as an outer or standalone Texinfo file in
another Texinfo file as an inner, included file.  The `@lowersections'
command changes chapters to sections, sections to subsections and so
on.

@raisesections changes @subsection to @section,
                       @section    to @chapter,
                       @heading    to @chapheading,
                       etc.

@lowersections changes @chapter    to @section,
                       @subsection to @subsubsection,
                       @heading    to @subheading,
                       etc.

An `@raisesections' or `@lowersections' command changes only those
structuring commands that follow the `@raisesections' or
`@lowersections' command.

An `@lowersections' command cancels an `@raisesections' command, and
vice versa.

Repeated use of the commands continue to raise or lower the hierarchical
level a step at a time.

An attempt to raise above `chapters' reproduces chapter commands; an
attempt to lower below subsubsections reproduces subsubsection
commands."
  
  ;; `texinfo-section-types-regexp' is defined in `texnfo-upd.el';
  ;; it is a regexp matching chapter, section, other headings
  ;; (but not the top node).

  (let (type (level 0))
    (while 
        (re-search-forward
         (concat
          "\\(\\(^@\\(raise\\|lower\\)sections\\)\\|\\("
          texinfo-section-types-regexp
          "\\)\\)")
         nil t)
      (beginning-of-line)
      (save-excursion (setq type (read (current-buffer))))
      (cond 
       
       ;; 1. Increment level
       ((eq type '@raisesections)
        (setq level (1+ level))
        (delete-region
         (point) (save-excursion (forward-line 1) (point))))
       
       ;; 2. Decrement level
       ((eq type '@lowersections)
        (setq level (1- level))
        (delete-region
         (point) (save-excursion (forward-line 1) (point))))
       
       ;; Now handle structuring commands
       ((cond
         
         ;; 3. Raise level when positive
         ((> level 0)
          (let ((count level)
                (new-level type))
            (while (> count 0)
              (setq new-level
                    (cdr (assq new-level texinfo-raisesections-alist)))
              (setq count (1- count)))
            (kill-word 1)
            (insert (symbol-name new-level))))
         
         ;; 4. Do nothing except move point when level is zero
         ((= level 0) (forward-line 1))
         
         ;; 5. Lower level when positive
         ((< level 0)
          (let ((count level)
                (new-level type))
            (while (< count 0)
              (setq new-level
                    (cdr (assq new-level texinfo-lowersections-alist)))
              (setq count (1+ count)))
            (kill-word 1)
            (insert (symbol-name new-level))))))))))

(defvar texinfo-raisesections-alist
  '((@chapter . @chapter)             ; Cannot go higher
    (@unnumbered . @unnumbered)
762
    (@centerchap . @unnumbered)
763 764 765 766

    (@majorheading . @majorheading)
    (@chapheading . @chapheading)
    (@appendix . @appendix)
Brian Preble's avatar
Brian Preble committed
767
    
768 769 770 771
    (@section . @chapter)
    (@unnumberedsec . @unnumbered)
    (@heading . @chapheading)
    (@appendixsec . @appendix)
Brian Preble's avatar
Brian Preble committed
772
    
773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790
    (@subsection . @section)
    (@unnumberedsubsec . @unnumberedsec)
    (@subheading . @heading)
    (@appendixsubsec . @appendixsec)
    
    (@subsubsection . @subsection)
    (@unnumberedsubsubsec . @unnumberedsubsec)
    (@subsubheading . @subheading)
    (@appendixsubsubsec . @appendixsubsec))
  "*An alist of next higher levels for chapters, sections. etc.
For example, section to chapter, subsection to section.
Used by `texinfo-raise-lower-sections'.
The keys specify types of section; the values correspond to the next
higher types.")

(defvar texinfo-lowersections-alist
  '((@chapter . @section)  
    (@unnumbered . @unnumberedsec)
791
    (@centerchap . @unnumberedsec)
792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814
    (@majorheading . @heading)
    (@chapheading . @heading)
    (@appendix . @appendixsec)
    
    (@section . @subsection)
    (@unnumberedsec . @unnumberedsubsec)
    (@heading . @subheading)
    (@appendixsec . @appendixsubsec)
    
    (@subsection . @subsubsection)
    (@unnumberedsubsec . @unnumberedsubsubsec)
    (@subheading . @subsubheading)
    (@appendixsubsec . @appendixsubsubsec)
    
    (@subsubsection . @subsubsection) ; Cannot go lower.
    (@unnumberedsubsubsec . @unnumberedsubsubsec)
    (@subsubheading . @subsubheading)
    (@appendixsubsubsec . @appendixsubsubsec))
  "*An alist of next lower levels for chapters, sections. etc.
For example, chapter to section, section to subsection.
Used by `texinfo-raise-lower-sections'.
The keys specify types of section; the values correspond to the next
lower types.")
Brian Preble's avatar
Brian Preble committed
815 816


817 818 819
;;; Perform those texinfo-to-info conversions that apply to the whole input
;;; uniformly.

Brian Preble's avatar
Brian Preble committed
820
(defun texinfo-format-scan ()
821 822 823 824
  (texinfo-format-convert (point-min) (point-max))
  ;; Scan for @-commands.
  (goto-char (point-min))
  (while (search-forward "@" nil t)
825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863
    ;;
    ;; These are the single-character accent commands: @^ @` @' @" @= @~
    ;; In Info, they are simply quoted and the @ deleted.
    ;; Other single-character commands:
    ;; @* forces a line break, 
    ;; @- is a discretionary hyphenation point; does nothing in Info.
    ;; @<space>, @<tab>, @<newline> each produce a single space,
    ;;    unless followed by a newline.
    ;;   
    ;; Old version 2.34 expression: (looking-at "[@{}^'` *\"?!]")
    (if (looking-at "[@{}^'`\"=~ \t\n*?!-]")
        ;; @*, causes a line break.
        (cond 
         ;; @*, a line break
         ((= (following-char) ?*)
          ;; remove command
          (delete-region (1- (point)) (1+ (point)))
          ;; insert return if not at end of line;
          ;; else line is already broken.
          (if (not (= (following-char) ?\n))
              (insert ?\n)))      
         ;; @-, deleted
         ((= (following-char) ?-)
          (delete-region (1- (point)) (1+ (point))))
         ;; @<space>, @<tab>, @<newline>: produce a single space,
         ;;    unless followed by a newline.
         ((= (following-char) ? )
          (delete-region (1- (point)) (1+ (point)))
          ;; insert single space if not at end of line;
          ;; else line is already broken.
          (if (not (= (following-char) ?\n))
              (insert ? )))      
         ((= (following-char) ?\t)
          (delete-region (1- (point)) (1+ (point)))
          ;; insert single space if not at end of line;
          ;; else line is already broken.
          (if (not (= (following-char) ?\n))
              (insert ? )))
         ;; following char is a carriage return
864
         ((= (following-char) ?\n)
865 866 867 868 869 870 871 872 873
          ;; remove command
          (delete-region (1- (point)) (1+ (point)))
          ;; insert single space if not at end of line;
          ;; else line is already broken.
          (if (not (= (following-char) ?\n))
              (insert ? )))
         ;; Otherwise: the other characters are simply quoted.  Delete the @.
         (t
         (delete-char -1)
Eli Zaretskii's avatar
Eli Zaretskii committed
874
	 ;; Be compatible with makeinfo: if @' and its ilk are
875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890
	 ;; followed by a @ without a brace, barf.
	 (if (looking-at "[\"'^`~=]")
	     (progn
	       (if (= (char-after (1+ (point))) ?@)
		   (error "Use braces to give a command as an argument to @%c"
			  (following-char)))
	       (forward-char 1)
	       ;; @' etc. can optionally accept their argument in
	       ;; braces (makeinfo supports that).
	       (when (looking-at "{")
		 (let ((start (point)))
		   (forward-list 1)
		   (delete-char -1)
		   (goto-char start)
		   (delete-char 1))))
	   (forward-char 1))))
891 892 893 894 895 896
      ;; @ is followed by a command-word; find the end of the word.
      (setq texinfo-command-start (1- (point)))
      (if (= (char-syntax (following-char)) ?w)
          (forward-word 1)
        (forward-char 1))
      (setq texinfo-command-end (point))
Karl Heuer's avatar
Karl Heuer committed
897 898 899 900 901
      ;; Detect the case of two @-commands in a row;
      ;; process just the first one.
      (goto-char (1+ texinfo-command-start))
      (skip-chars-forward "^@" texinfo-command-end)
      (setq texinfo-command-end (point))
902
      ;; Handle let aliasing
903
      (setq texinfo-command-name
904 905 906 907 908 909
            (let (trial
                  (cmdname 
                   (buffer-substring
                    (1+ texinfo-command-start) texinfo-command-end)))
              (while (setq trial (assoc cmdname texinfo-alias-list))
                (setq cmdname (cdr trial)))
910 911
            (intern cmdname)))
      ;; Call the handler for this command.
912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928
      (let ((enclosure-type
             (assoc
              (symbol-name texinfo-command-name)
              texinfo-enclosure-list)))
        (if enclosure-type
            (progn
              (insert
               (car (car (cdr enclosure-type))) 
               (texinfo-parse-arg-discard)
               (car (cdr (car (cdr enclosure-type)))))
              (goto-char texinfo-command-start))
          (let ((cmd (get texinfo-command-name 'texinfo-format)))
            (if cmd (funcall cmd) (texinfo-unsupported)))))))
  
  (cond (texinfo-stack
         (goto-char (nth 2 (car texinfo-stack)))
         (error "Unterminated @%s" (car (car texinfo-stack))))))
Brian Preble's avatar
Brian Preble committed
929 930 931 932 933 934 935 936 937 938 939

(put 'begin 'texinfo-format 'texinfo-format-begin)
(defun texinfo-format-begin ()
  (texinfo-format-begin-end 'texinfo-format))

(put 'end 'texinfo-format 'texinfo-format-end)
(defun texinfo-format-end ()
  (texinfo-format-begin-end 'texinfo-end))

(defun texinfo-format-begin-end (prop)
  (setq texinfo-command-name (intern (texinfo-parse-line-arg)))
940 941 942
  (let ((cmd (get texinfo-command-name prop)))
    (if cmd (funcall cmd)
      (texinfo-unsupported))))
Brian Preble's avatar
Brian Preble committed
943

944 945
;;; Parsing functions

Brian Preble's avatar
Brian Preble committed
946
(defun texinfo-parse-line-arg ()
947 948 949 950 951
  "Return argument of @-command as string.
Argument is separated from command either by a space or by a brace.  
If a space, return rest of line, with beginning and ending white
space removed.  If a brace, return string between braces.
Leave point after argument."
Brian Preble's avatar
Brian Preble committed
952 953 954
  (goto-char texinfo-command-end)
  (let ((start (point)))
    (cond ((looking-at " ")
955 956 957
           (skip-chars-forward " ")
           (setq start (point))
           (end-of-line)
Brian Preble's avatar
Brian Preble committed
958
           (skip-chars-backward " ")
959 960 961 962 963 964 965 966 967
           (delete-region (point) (progn (end-of-line) (point)))
           (setq texinfo-command-end (1+ (point))))
          ((looking-at "{")
           (setq start (1+ (point)))
           (forward-list 1)
           (setq texinfo-command-end (point))
           (forward-char -1))
          (t
           (error "Invalid texinfo command arg format")))
Brian Preble's avatar
Brian Preble committed
968
    (prog1 (buffer-substring start (point))
969
           (if (eolp) (forward-char 1)))))
Brian Preble's avatar
Brian Preble committed
970 971 972 973

(defun texinfo-parse-expanded-arg ()
  (goto-char texinfo-command-end)
  (let ((start (point))
974
        marker)
Brian Preble's avatar
Brian Preble committed
975
    (cond ((looking-at " ")
976 977 978 979 980 981 982 983 984 985 986
           (skip-chars-forward " ")
           (setq start (point))
           (end-of-line)
           (setq texinfo-command-end (1+ (point))))
          ((looking-at "{")
           (setq start (1+ (point)))
           (forward-list 1)
           (setq texinfo-command-end (point))
           (forward-char -1))
          (t
           (error "Invalid texinfo command arg format")))
Brian Preble's avatar
Brian Preble committed
987 988 989 990 991
    (setq marker (move-marker (make-marker) texinfo-command-end))
    (texinfo-format-expand-region start (point))
    (setq texinfo-command-end (marker-position marker))
    (move-marker marker nil)
    (prog1 (buffer-substring start (point))
992
           (if (eolp) (forward-char 1)))))
Brian Preble's avatar
Brian Preble committed
993 994 995 996 997

(defun texinfo-format-expand-region (start end)
  (save-restriction
    (narrow-to-region start end)
    (let (texinfo-command-start
998 999 1000
          texinfo-command-end
          texinfo-command-name
          texinfo-stack)
Brian Preble's avatar
Brian Preble committed
1001 1002 1003 1004
      (texinfo-format-scan))
    (goto-char (point-max))))

(defun texinfo-parse-arg-discard ()
1005
  "Delete command and argument; return argument of command."
Brian Preble's avatar
Brian Preble committed
1006
  (prog1 (texinfo-parse-line-arg)
1007
         (texinfo-discard-command)))
Brian Preble's avatar
Brian Preble committed
1008 1009 1010 1011 1012 1013 1014 1015 1016 1017

(defun texinfo-discard-command ()
  (delete-region texinfo-command-start texinfo-command-end))

(defun texinfo-optional-braces-discard ()
  "Discard braces following command, if any."
  (goto-char texinfo-command-end)
  (let ((start (point)))
    (cond ((looking-at "[ \t]*\n"))     ; do nothing
          ((looking-at "{")             ; remove braces, if any
1018 1019 1020
           (forward-list 1)
           (setq texinfo-command-end (point)))
          (t
Brian Preble's avatar
Brian Preble committed
1021 1022 1023 1024 1025 1026
           (error
            "Invalid `texinfo-optional-braces-discard' format \(need braces?\)")))
    (delete-region texinfo-command-start texinfo-command-end)))

(defun texinfo-format-parse-line-args ()
  (let ((start (1- (point)))
1027 1028
        next beg end
        args)
Brian Preble's avatar
Brian Preble committed
1029 1030 1031 1032 1033 1034 1035 1036 1037 1038
    (skip-chars-forward " ")
    (while (not (eolp))
      (setq beg (point))
      (re-search-forward "[\n,]")
      (setq next (point))
      (if (bolp) (setq next (1- next)))
      (forward-char -1)
      (skip-chars-backward " ")
      (setq end (point))
      (setq args (cons (if (> end beg) (buffer-substring beg end))
1039
                       args))
Brian Preble's avatar
Brian Preble committed
1040 1041 1042 1043 1044 1045 1046 1047
      (goto-char next)
      (skip-chars-forward " "))
    (if (eolp) (forward-char 1))
    (setq texinfo-command-end (point))
    (nreverse args)))

(defun texinfo-format-parse-args ()
  (let ((start (1- (point)))
1048 1049
        next beg end
        args)
Brian Preble's avatar
Brian Preble committed
1050 1051 1052 1053 1054
    (search-forward "{")
    (save-excursion
      (texinfo-format-expand-region 
       (point)
       (save-excursion (up-list 1) (1- (point)))))
1055 1056 1057 1058
    ;; The following does not handle cross references of the form:
    ;; `@xref{bullet, , @code{@@bullet}@{@}}.' because the
    ;; re-search-forward finds the first right brace after the second
    ;; comma. 
Brian Preble's avatar
Brian Preble committed
1059 1060 1061 1062 1063 1064 1065 1066 1067
    (while (/= (preceding-char) ?\})
      (skip-chars-forward " \t\n")
      (setq beg (point))
      (re-search-forward "[},]")
      (setq next (point))
      (forward-char -1)
      (skip-chars-backward " \t\n")
      (setq end (point))
      (cond ((< beg end)
1068 1069 1070
             (goto-char beg)
             (while (search-forward "\n" end t)
               (replace-match " "))))
Brian Preble's avatar
Brian Preble committed
1071
      (setq args (cons (if (> end beg) (buffer-substring beg end))
1072
                       args))
Brian Preble's avatar
Brian Preble committed
1073
      (goto-char next))
1074
    ;;(if (eolp) (forward-char 1))
Brian Preble's avatar
Brian Preble committed
1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088
    (setq texinfo-command-end (point))
    (nreverse args)))

(defun texinfo-format-parse-defun-args ()
  (goto-char texinfo-command-end)
  (let ((start (point)))
    (end-of-line)
    (setq texinfo-command-end (1+ (point)))
    (let ((marker (move-marker (make-marker) texinfo-command-end)))
      (texinfo-format-expand-region start (point))
      (setq texinfo-command-end (marker-position marker))
      (move-marker marker nil))
    (goto-char start)
    (let ((args '())
1089
          beg end)
Brian Preble's avatar
Brian Preble committed
1090 1091
      (skip-chars-forward " ")
      (while (not (eolp))
1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102
        (cond ((looking-at "{")
               (setq beg (1+ (point)))
               (forward-list 1)
               (setq end (1- (point))))
              (t
               (setq beg (point))
               (re-search-forward "[\n ]")
               (forward-char -1)
               (setq end (point))))
        (setq args (cons (buffer-substring beg end) args))
        (skip-chars-forward " "))
Brian Preble's avatar
Brian Preble committed
1103 1104 1105
      (forward-char 1)
      (nreverse args))))

1106 1107 1108 1109
(defun texinfo-discard-line ()
  (goto-char texinfo-command-end)
  (skip-chars-forward " \t")
  (or (eolp)
1110
      (error "Extraneous text at end of command line"))
1111 1112
  (goto-char texinfo-command-start)
  (or (bolp)
1113
      (error "Extraneous text at beginning of command line"))
1114 1115 1116 1117 1118 1119 1120 1121
  (delete-region (point) (progn (forward-line 1) (point))))

(defun texinfo-discard-line-with-args ()
  (goto-char texinfo-command-start)
  (delete-region (point) (progn (forward-line 1) (point))))


;;; @setfilename
Brian Preble's avatar
Brian Preble committed
1122

1123 1124 1125
;; Only `texinfo-format-buffer' handles @setfilename with this
;; definition; `texinfo-format-region' handles @setfilename, if any,
;; specially. 
Brian Preble's avatar
Brian Preble committed
1126 1127
(put 'setfilename 'texinfo-format 'texinfo-format-setfilename)
(defun texinfo-format-setfilename ()
1128
  (texinfo-parse-arg-discard))
1129

1130
;;; @node, @menu, @detailmenu
Brian Preble's avatar
Brian Preble committed
1131 1132

(put 'node 'texinfo-format 'texinfo-format-node)
1133
(put 'nwnode 'texinfo-format 'texinfo-format-node)
Brian Preble's avatar
Brian Preble committed
1134 1135
(defun texinfo-format-node ()
  (let* ((args (texinfo-format-parse-line-args))
1136 1137 1138 1139
         (name (nth 0 args))
         (next (nth 1 args))
         (prev (nth 2 args))
         (up (nth 3 args)))
Brian Preble's avatar
Brian Preble committed
1140 1141
    (texinfo-discard-command)
    (setq texinfo-last-node name)
1142
    (let ((tem (if texinfo-fold-nodename-case (downcase name) name)))
Brian Preble's avatar
Brian Preble committed
1143
      (if (assoc tem texinfo-node-names)
1144 1145
          (error "Duplicate node name: %s" name)
        (setq texinfo-node-names (cons (list tem) texinfo-node-names))))
Brian Preble's avatar
Brian Preble committed
1146
    (setq texinfo-footnote-number 0)
1147 1148
    ;; insert "\n\^_" unconditionally since this is what info is looking for
    (insert "\n\^_\nFile: " texinfo-format-filename
1149 1150 1151
            ", Node: " name)
    (if next
        (insert ", Next: " next))
Brian Preble's avatar
Brian Preble committed
1152
    (if prev
1153
        (insert ", Prev: " prev))
Brian Preble's avatar
Brian Preble committed
1154
    (if up
1155 1156 1157
        (insert ", Up: " up))
    (insert ?\n)
    (setq texinfo-last-node-pos (point))))
Brian Preble's avatar
Brian Preble committed
1158

1159 1160 1161 1162 1163
(put 'anchor 'texinfo-format 'texinfo-anchor)
(defun texinfo-anchor ()
  (let (anchor-string 
        (here (- (point) 7))  ; save location of beginning of `@anchor'
        (arg (texinfo-parse-arg-discard)))
1164 1165
    (if (looking-at " ")      ; since a space may be left after -discard
      (delete-char 1))
1166 1167 1168 1169 1170 1171 1172 1173 1174 1175
    (forward-paragraph) 
    (let ((end (point)))
      (if (save-excursion 
            (backward-word 1)
            (search-forward "@refill" end t))
          (setq anchor-string "@anchor-yes-refill")
        (setq anchor-string "@anchor-no-refill")))
      (goto-char here)
      (insert anchor-string "{" arg "}")))

Brian Preble's avatar
Brian Preble committed
1176 1177 1178 1179 1180 1181
(put 'menu 'texinfo-format 'texinfo-format-menu)
(defun texinfo-format-menu ()
  (texinfo-discard-line)
  (insert "* Menu:\n\n"))

(put 'menu 'texinfo-end 'texinfo-discard-command)
1182

1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199
;; The @detailmenu should be removed eventually.

;; According to Karl Berry, 31 August 1996:
;; 
;; You don't like, I don't like it.  I agree, it would be better just to
;; fix the bug [in `makeinfo'].  ..  At this point, since inserting those
;; two commands in the Elisp fn is trivial, I don't especially want to
;; expend more effort...
;; 
;; I added a couple sentences of documentation to the manual (putting the
;; blame on makeinfo where it belongs :-().

(put 'detailmenu 'texinfo-format 'texinfo-discard-line)
(put 'detailmenu 'texinfo-end 'texinfo-discard-command)

;; (Also see `texnfo-upd.el')

1200 1201

;;; Cross references
Brian Preble's avatar
Brian Preble committed
1202

1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219
;; @xref {NODE, FNAME, NAME, FILE, DOCUMENT}
;; -> *Note FNAME: (FILE)NODE
;;   If FILE is missing,
;;    *Note FNAME: NODE
;;   If FNAME is empty and NAME is present
;;    *Note NAME: Node
;;   If both NAME and FNAME are missing
;;    *Note NODE::
;;   texinfo ignores the DOCUMENT argument.
;; -> See section <xref to NODE> [NAME, else NODE], page <xref to NODE>
;;   If FILE is specified, (FILE)NODE is used for xrefs.
;;   If fifth argument DOCUMENT is specified, produces
;;    See section <xref to NODE> [NAME, else NODE], page <xref to NODE>
;;    of DOCUMENT

;; @ref             a reference that does not put `See' or `see' in
;;                  the hardcopy and is the same as @xref in Info
Brian Preble's avatar
Brian Preble committed
1220 1221 1222 1223 1224 1225 1226 1227 1228
(put 'ref 'texinfo-format 'texinfo-format-xref)

(put 'xref 'texinfo-format 'texinfo-format-xref)
(defun texinfo-format-xref ()
  (let ((args (texinfo-format-parse-args)))
    (texinfo-discard-command)
    (insert "*Note ")
    (let ((fname (or (nth 1 args) (nth 2 args))))
      (if (null (or fname (nth 3 args)))
1229 1230 1231 1232
          (insert (car args) "::")
        (insert (or fname (car args)) ": ")
        (if (nth 3 args)
            (insert "(" (nth 3 args) ")"))
1233
        (and (car args) (insert (car args)))))))
Brian Preble's avatar
Brian Preble committed
1234 1235 1236 1237 1238

(put 'pxref 'texinfo-format 'texinfo-format-pxref)
(defun texinfo-format-pxref ()
  (texinfo-format-xref)
  (or (save-excursion
1239 1240
        (forward-char -2)
        (looking-at "::"))
Brian Preble's avatar
Brian Preble committed
1241 1242
      (insert ".")))

1243 1244 1245
;; @inforef{NODE, FNAME, FILE}
;; Like @xref{NODE, FNAME,,FILE} in texinfo.
;; In Tex, generates "See Info file FILE, node NODE"
Brian Preble's avatar
Brian Preble committed
1246 1247 1248 1249 1250 1251 1252 1253
(put 'inforef 'texinfo-format 'texinfo-format-inforef)
(defun texinfo-format-inforef ()
  (let ((args (texinfo-format-parse-args)))
    (texinfo-discard-command)
    (if (nth 1 args)
        (insert "*Note " (nth 1 args) ": (" (nth 2 args) ")" (car args))
      (insert "*Note " "(" (nth 2 args) ")" (car args) "::"))))

1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273

;;; URL Reference: @uref

;; @uref produces a reference to a uniform resource locator (URL).  
;; It takes one mandatory argument, the URL, and one optional argument, 
;; the text to display (the default is the URL itself).  

(put 'uref 'texinfo-format 'texinfo-format-uref)
(defun texinfo-format-uref ()
  "Format URL and optional URL-TITLE.
Insert ` ... ' around URL if no URL-TITLE argument; 
otherwise, insert URL-TITLE followed by URL in parentheses."
  (let ((args (texinfo-format-parse-args)))
    (texinfo-discard-command)
    ;; if url-title 
    (if (nth 1 args)
        (insert  (nth 1 args) " (" (nth 0 args) ")")
      (insert "`" (nth 0 args) "'"))
    (goto-char texinfo-command-start)))

1274 1275 1276 1277

;;; Section headings

(put 'majorheading 'texinfo-format 'texinfo-format-chapter)
Brian Preble's avatar
Brian Preble committed
1278 1279 1280 1281 1282 1283
(put 'chapheading 'texinfo-format 'texinfo-format-chapter)
(put 'ichapter 'texinfo-format 'texinfo-format-chapter)
(put 'chapter 'texinfo-format 'texinfo-format-chapter)
(put 'iappendix 'texinfo-format 'texinfo-format-chapter)
(put 'appendix 'texinfo-format 'texinfo-format-chapter)
(put 'iunnumbered 'texinfo-format 'texinfo-format-chapter)
1284
(put 'top 'texinfo-format 'texinfo-format-chapter)
Brian Preble's avatar
Brian Preble committed
1285
(put 'unnumbered 'texinfo-format 'texinfo-format-chapter)
1286
(put 'centerchap 'texinfo-format 'texinfo-format-chapter)
Brian Preble's avatar
Brian Preble committed
1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334
(defun texinfo-format-chapter ()
  (texinfo-format-chapter-1 ?*))

(put 'heading 'texinfo-format 'texinfo-format-section)
(put 'isection 'texinfo-format 'texinfo-format-section)
(put 'section 'texinfo-format 'texinfo-format-section)
(put 'iappendixsection 'texinfo-format 'texinfo-format-section)
(put 'appendixsection 'texinfo-format 'texinfo-format-section)
(put 'iappendixsec 'texinfo-format 'texinfo-format-section)
(put 'appendixsec 'texinfo-format 'texinfo-format-section)
(put 'iunnumberedsec 'texinfo-format 'texinfo-format-section)
(put 'unnumberedsec 'texinfo-format 'texinfo-format-section)
(defun texinfo-format-section ()
  (texinfo-format-chapter-1 ?=))

(put 'subheading 'texinfo-format 'texinfo-format-subsection)
(put 'isubsection 'texinfo-format 'texinfo-format-subsection)
(put 'subsection 'texinfo-format 'texinfo-format-subsection)
(put 'iappendixsubsec 'texinfo-format 'texinfo-format-subsection)
(put 'appendixsubsec 'texinfo-format 'texinfo-format-subsection)
(put 'iunnumberedsubsec 'texinfo-format 'texinfo-format-subsection)
(put 'unnumberedsubsec 'texinfo-format 'texinfo-format-subsection)
(defun texinfo-format-subsection ()
  (texinfo-format-chapter-1 ?-))

(put 'subsubheading 'texinfo-format 'texinfo-format-subsubsection)
(put 'isubsubsection 'texinfo-format 'texinfo-format-subsubsection)
(put 'subsubsection 'texinfo-format 'texinfo-format-subsubsection)
(put 'iappendixsubsubsec 'texinfo-format 'texinfo-format-subsubsection)
(put 'appendixsubsubsec 'texinfo-format 'texinfo-format-subsubsection)
(put 'iunnumberedsubsubsec 'texinfo-format 'texinfo-format-subsubsection)
(put 'unnumberedsubsubsec 'texinfo-format 'texinfo-format-subsubsection)
(defun texinfo-format-subsubsection ()
  (texinfo-format-chapter-1 ?.))

(defun texinfo-format-chapter-1 (belowchar)
  (let ((arg (texinfo-parse-arg-discard)))
    (message "Formatting: %s ... " arg)   ; So we can see where we are.
    (insert ?\n arg ?\n "@SectionPAD " belowchar ?\n)
    (forward-line -2)))

(put 'SectionPAD 'texinfo-format 'texinfo-format-sectionpad)
(defun texinfo-format-sectionpad ()
  (let ((str (texinfo-parse-arg-discard)))
    (forward-char -1)
    (let ((column (current-column)))
      (forward-char 1)
      (while (> column 0)
1335 1336
        (insert str)
        (setq column (1- column))))
Brian Preble's avatar
Brian Preble committed
1337 1338
    (insert ?\n)))

1339

1340 1341
;;; Space controlling commands:  @. and @:, and the soft hyphen.

Brian Preble's avatar
Brian Preble committed
1342 1343 1344 1345 1346 1347 1348 1349 1350
(put '\. 'texinfo-format 'texinfo-format-\.)
(defun texinfo-format-\. ()
  (texinfo-discard-command)
  (insert "."))

(put '\: 'texinfo-format 'texinfo-format-\:)
(defun texinfo-format-\: ()
  (texinfo-discard-command))

1351 1352 1353 1354
(put '\- 'texinfo-format 'texinfo-format-soft-hyphen)
(defun texinfo-format-soft-hyphen ()
  (texinfo-discard-command))

1355 1356 1357

;;; @center, @sp, and @br

Brian Preble's avatar
Brian Preble committed
1358 1359
(put 'center 'texinfo-format 'texinfo-format-center)
(defun texinfo-format-center ()
1360 1361 1362 1363 1364 1365 1366 1367
  (let ((arg (texinfo-parse-expanded-arg)))
    (texinfo-discard-command)
    (insert arg)
    (insert ?\n)
    (save-restriction
      (goto-char (1- (point)))
      (let ((indent-tabs-mode nil))
        (center-line)))))
Brian Preble's avatar
Brian Preble committed
1368 1369 1370 1371

(put 'sp 'texinfo-format 'texinfo-format-sp)
(defun texinfo-format-sp ()
  (let* ((arg (texinfo-parse-arg-discard))
1372
         (num (read arg)))
Brian Preble's avatar
Brian Preble committed
1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386
    (insert-char ?\n num)))

(put 'br 'texinfo-format 'texinfo-format-paragraph-break)
(defun texinfo-format-paragraph-break ()
  "Force a paragraph break.
If used within a line, follow `@br' with braces."
  (texinfo-optional-braces-discard)
  ;; insert one return if at end of line;
  ;; else insert two returns, to generate a blank line.
  (if (= (following-char) ?\n)
      (insert ?\n)
    (insert-char ?\n 2)))


1387
;;; @footnote  and  @footnotestyle
Brian Preble's avatar
Brian Preble committed
1388

1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411
;; In Texinfo, footnotes are created with the `@footnote' command.
;; This command is followed immediately by a left brace, then by the text of
;; the footnote, and then by a terminating right brace.  The
;; template for a footnote is:
;; 
;;      @footnote{TEXT}
;;
;; Info has two footnote styles:
;; 
;;    * In the End of node style, all the footnotes for a single node
;;      are placed at the end of that node.  The footnotes are
;;      separated from the rest of the node by a line of dashes with
;;      the word `Footnotes' within it.
;; 
;;    * In the Separate node style, all the footnotes for a single node
;;      are placed in an automatically constructed node of their own.

;; Footnote style is specified by the @footnotestyle command, either
;;    @footnotestyle separate
;; or
;;    @footnotestyle end
;; 
;; The default is  separate
1412 1413 1414

(defvar texinfo-footnote-style "separate" 
  "Footnote style, either separate or end.")
Brian Preble's avatar
Brian Preble committed
1415

1416 1417 1418 1419 1420
(put 'footnotestyle 'texinfo-format 'texinfo-footnotestyle)
(defun texinfo-footnotestyle ()
  "Specify whether footnotes are at end of node or in separate nodes.
Argument is either end or separate."
  (setq texinfo-footnote-style (texinfo-parse-arg-discard)))
Brian Preble's avatar
Brian Preble committed
1421 1422 1423

(defvar texinfo-footnote-number)

1424
(put 'footnote 'texinfo-format 'texinfo-format-footnote)
Brian Preble's avatar
Brian Preble committed
1425
(defun texinfo-format-footnote ()
1426 1427
  "Format a footnote in either end of node or separate node style.
The   texinfo-footnote-style  variable controls which style is used."
Brian Preble's avatar
Brian Preble committed
1428
  (setq texinfo-footnote-number (1+ texinfo-footnote-number))
1429 1430 1431 1432
  (cond ((string= texinfo-footnote-style "end")
         (texinfo-format-end-node))
        ((string= texinfo-footnote-style "separate")
         (texinfo-format-separate-node))))
Brian Preble's avatar
Brian Preble committed
1433

1434 1435
(defun texinfo-format-separate-node ()
  "Format footnote in Separate node style, with notes in own node.
Brian Preble's avatar
Brian Preble committed
1436 1437
The node is constructed automatically."
  (let* (start
1438
         (arg (texinfo-parse-line-arg))
Brian Preble's avatar
Brian Preble committed
1439 1440 1441
         (node-name-beginning
          (save-excursion
            (re-search-backward
1442
             "^File: \\w+\\(\\w\\|\\s_\\|\\.\\|,\\)*[ \t]+Node:")
Brian Preble's avatar
Brian Preble committed
1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454
            (match-end 0)))
         (node-name
          (save-excursion
            (buffer-substring
             (progn (goto-char node-name-beginning) ; skip over node command
                    (skip-chars-forward " \t")  ; and over spaces
                    (point))
             (if (search-forward
                  ","
                  (save-excursion (end-of-line) (point)) t) ; bound search
                 (1- (point))
               (end-of-line) (point))))))
1455 1456 1457 1458 1459
    (texinfo-discard-command)  ; remove or insert whitespace, as needed
    (delete-region (save-excursion (skip-chars-backward " \t\n") (point))
                   (point))
    (insert (format " (%d) (*Note %s-Footnotes::)"
                    texinfo-footnote-number node-name))
Brian Preble's avatar
Brian Preble committed
1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485
    (fill-paragraph nil)
    (save-excursion
    (if (re-search-forward "^@node" nil 'move)
        (forward-line -1))

    ;; two cases: for the first footnote, we must insert a node header;
    ;; for the second and subsequent footnotes, we need only insert 
    ;; the text of the  footnote.

    (if (save-excursion
         (re-search-backward
          (concat node-name "-Footnotes, Up: ")
          node-name-beginning
          t))
        (progn   ; already at least one footnote
          (setq start (point))
          (insert (format "\n(%d)  %s\n" texinfo-footnote-number arg))
          (fill-region start (point)))
      ;; else not yet a footnote
      (insert "\n\^_\nFile: "  texinfo-format-filename
              "  Node: " node-name "-Footnotes, Up: " node-name "\n")
      (setq start (point))
      (insert (format "\n(%d)  %s\n" texinfo-footnote-number arg))
      (fill-region start (point))))))

(defun texinfo-format-end-node ()
1486
  "Format footnote in the End of node style, with notes at end of node."
Brian Preble's avatar
Brian Preble committed
1487
  (let (start
1488 1489 1490 1491 1492
        (arg (texinfo-parse-line-arg)))
    (texinfo-discard-command)  ; remove or insert whitespace, as needed
    (delete-region (save-excursion (skip-chars-backward " \t\n") (point))
                   (point))
    (insert (format " (%d) " texinfo-footnote-number))
Brian Preble's avatar
Brian Preble committed
1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506
    (fill-paragraph nil)
    (save-excursion
      (if (search-forward "\n--------- Footnotes ---------\n" nil t)
          (progn ; already have footnote, put new one before end of node
            (if (re-search-forward "^@node" nil 'move)
                (forward-line -1))
            (setq start (point))
            (insert (format "\n(%d)  %s\n" texinfo-footnote-number arg))
            (fill-region start (point)))
        ;; else no prior footnote
        (if (re-search-forward "^@node" nil 'move)
            (forward-line -1))
        (insert "\n--------- Footnotes ---------\n")
        (setq start (point))
1507
        (insert (format "\n(%d)  %s\n" texinfo-footnote-number arg))))))
Brian Preble's avatar
Brian Preble committed
1508 1509


1510 1511
;;; @itemize, @enumerate, and similar commands

Brian Preble's avatar
Brian Preble committed
1512 1513 1514 1515 1516 1517 1518 1519 1520
;; @itemize pushes (itemize "COMMANDS" STARTPOS) on texinfo-stack.
;; @enumerate pushes (enumerate 0 STARTPOS).
;; @item dispatches to the texinfo-item prop of the first elt of the list.
;; For itemize, this puts in and rescans the COMMANDS.
;; For enumerate, this increments the number and puts it in.
;; In either case, it puts a Backspace at the front of the line
;; which marks it not to be indented later.
;; All other lines get indented by 5 when the @end is reached.

1521 1522 1523 1524
(defvar texinfo-stack-depth 0
  "Count of number of unpopped texinfo-push-stack calls.
Used by @refill indenting command to avoid indenting within lists, etc.")

Brian Preble's avatar
Brian Preble committed
1525
(defun texinfo-push-stack (check arg)