root/trunk/lisp/textmodes/texinfmt.el

Revision 4220, 158.3 kB (checked in by miyoshi, 9 months ago)

Sync up with Emacs22.2.

  • Property svn:eol-style set to LF
Line 
1 ;;; texinfmt.el --- format Texinfo files into Info files
2
3 ;; Copyright (C) 1985, 1986, 1988, 1990, 1991, 1992, 1993,
4 ;;   1994, 1995, 1996, 1997, 1998, 2000, 2001, 2002, 2003,
5 ;;   2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
6
7 ;; Maintainer: Robert J. Chassell <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 3, 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 ;;; Code:
30
31 ;;; Emacs lisp functions to convert Texinfo files to Info files.
32
33 (or (fboundp 'defgroup)
34     (defmacro defgroup (&rest ignore) nil))
35
36 (or (fboundp 'defcustom)
37     (defmacro defcustom (var value doc &rest ignore)
38       `(defvar ,var ,value ,doc)))
39
40 (defvar texinfmt-version "2.42 of  7 Jul 2006")
41
42 (defun texinfmt-version (&optional here)
43   "Show the version of texinfmt.el in the minibuffer.
44 If optional argument HERE is non-nil, insert info at point."
45   (interactive "P")
46   (let ((version-string
47          (format "Version of \`texinfmt.el\': %s" texinfmt-version)))
48     (if here
49         (insert version-string)
50       (if (interactive-p)
51           (message "%s" version-string)
52         version-string))))
53
54
55 ;;; Variable definitions
56
57 (require 'texinfo)          ; So `texinfo-footnote-style' is defined.
58 (require 'texnfo-upd)       ; So `texinfo-section-types-regexp' is defined.
59
60 (defvar texinfo-format-syntax-table nil)
61
62 (defvar texinfo-vindex)
63 (defvar texinfo-findex)
64 (defvar texinfo-cindex)
65 (defvar texinfo-pindex)
66 (defvar texinfo-tindex)
67 (defvar texinfo-kindex)
68 (defvar texinfo-last-node)
69 (defvar texinfo-node-names)
70 (defvar texinfo-enclosure-list)
71 (defvar texinfo-alias-list)
72 (defvar texinfo-fold-nodename-case nil)
73
74 (defvar texinfo-command-start)
75 (defvar texinfo-command-end)
76 (defvar texinfo-command-name)
77 (defvar texinfo-defun-type)
78 (defvar texinfo-last-node-pos)
79 (defvar texinfo-stack)
80 (defvar texinfo-short-index-cmds-alist)
81 (defvar texinfo-short-index-format-cmds-alist)
82 (defvar texinfo-format-filename)
83 (defvar texinfo-footnote-number)
84 (defvar texinfo-start-of-header)
85 (defvar texinfo-end-of-header)
86 (defvar texinfo-raisesections-alist)
87 (defvar texinfo-lowersections-alist)
88
89 ;;; Syntax table
90
91 (if texinfo-format-syntax-table
92     nil
93   (setq texinfo-format-syntax-table (make-syntax-table))
94   (modify-syntax-entry ?\" " " texinfo-format-syntax-table)
95   (modify-syntax-entry ?\\ " " texinfo-format-syntax-table)
96   (modify-syntax-entry ?@ "\\" texinfo-format-syntax-table)
97   (modify-syntax-entry ?\^q "\\" texinfo-format-syntax-table)
98   (modify-syntax-entry ?\[ "." texinfo-format-syntax-table)
99   (modify-syntax-entry ?\] "." texinfo-format-syntax-table)
100   (modify-syntax-entry ?\( "." texinfo-format-syntax-table)
101   (modify-syntax-entry ?\) "." texinfo-format-syntax-table)
102   (modify-syntax-entry ?{ "(}" texinfo-format-syntax-table)
103   (modify-syntax-entry ?} "){" texinfo-format-syntax-table)
104   (modify-syntax-entry ?\' "." texinfo-format-syntax-table))
105
106
107 ;;; Top level buffer and region formatting functions
108
109 ;;;###autoload
110 (defun texinfo-format-buffer (&optional nosplit)
111   "Process the current buffer as texinfo code, into an Info file.
112 The Info file output is generated in a buffer visiting the Info file
113 name specified in the @setfilename command.
114
115 Non-nil argument (prefix, if interactive) means don't make tag table
116 and don't split the file if large.  You can use Info-tagify and
117 Info-split to do these manually."
118   (interactive "P")
119   (let ((lastmessage "Formatting Info file...")
120         (coding-system-for-write buffer-file-coding-system))
121     (message lastmessage)
122     (widen)
123     (texinfo-format-buffer-1)
124     (Info-tagify)
125     (if nosplit
126         nil
127       (if (> (buffer-size) 100000)
128           (progn
129             (message (setq lastmessage "Splitting Info file..."))
130             (Info-split))))
131     (message (concat lastmessage
132                      (if (interactive-p) "done.  Now save it." "done.")))))
133
134 (defvar texinfo-region-buffer-name "*Info Region*"
135   "*Name of the temporary buffer used by \\[texinfo-format-region].")
136
137 (defvar texinfo-pre-format-hook nil
138   "Hook called before the conversion of the Texinfo file to Info format.
139 The functions on this hook are called with argument BUFFER, the buffer
140 containing the Texinfo file.")
141
142 ;; These come from tex-mode.el.
143 (defvar tex-start-of-header)
144 (defvar tex-end-of-header)
145
146 ;;;###autoload
147 (defun texinfo-format-region (region-beginning region-end)
148   "Convert the current region of the Texinfo file to Info format.
149 This lets you see what that part of the file will look like in Info.
150 The command is bound to \\[texinfo-format-region].  The text that is
151 converted to Info is stored in a temporary buffer."
152   (interactive "r")
153   (message "Converting region to Info format...")
154   (let (texinfo-command-start
155         texinfo-command-end
156         texinfo-command-name
157         texinfo-vindex
158         texinfo-findex
159         texinfo-cindex
160         texinfo-pindex
161         texinfo-tindex
162         texinfo-kindex
163         texinfo-stack
164         (texinfo-format-filename "")
165         texinfo-example-start
166         texinfo-last-node-pos
167         texinfo-last-node
168         texinfo-node-names
169         (texinfo-footnote-number 0)
170         last-input-buffer
171         (fill-column-for-info fill-column)
172         (input-buffer (current-buffer))
173         (input-directory default-directory)
174         (header-text "")
175         (header-beginning 1)
176         (header-end 1))
177
178 ;;; Copy lines between beginning and end of header lines,
179 ;;;    if any, or else copy the `@setfilename' line, if any.
180     (save-excursion
181         (save-restriction
182           (widen)
183           (goto-char (point-min))
184           (let ((search-end (save-excursion (forward-line 100) (point))))
185             (if (or
186                  ;; Either copy header text.
187                  (and
188                   (prog1
189                       (search-forward tex-start-of-header search-end t)
190                     (forward-line 1)
191                     ;; Mark beginning of header.
192                     (setq header-beginning (point)))
193                   (prog1
194                       (search-forward tex-end-of-header nil t)
195                     (beginning-of-line)
196                     ;; Mark end of header
197                     (setq header-end (point))))
198                  ;; Or copy @filename line.
199                  (prog2
200                   (goto-char (point-min))
201                   (search-forward "@setfilename" search-end t)
202                   (beginning-of-line)
203                   (setq header-beginning (point))
204                   (forward-line 1)
205                   (setq header-end (point))))
206
207                 ;; Copy header
208                 (setq header-text
209                       (buffer-substring-no-properties
210                        (min header-beginning region-beginning)
211                        header-end))))))
212
213 ;;; Find a buffer to use.
214     (switch-to-buffer (get-buffer-create texinfo-region-buffer-name))
215     (setq buffer-read-only t)
216     (let ((inhibit-read-only t))
217     (erase-buffer)
218     ;; Insert the header into the buffer.
219     (insert header-text)
220     ;; Insert the region into the buffer.
221     (insert-buffer-substring
222      input-buffer
223      (max region-beginning header-end)
224      region-end)
225     (run-hook-with-args 'texinfo-pre-format-hook input-buffer)
226     ;; Make sure region ends in a newline.
227     (or (= (preceding-char) ?\n)
228         (insert "\n"))
229
230     (goto-char (point-min))
231     (texinfo-mode)
232     (message "Converting region to Info format...")
233     (setq fill-column fill-column-for-info)
234     ;; Install a syntax table useful for scanning command operands.
235     (set-syntax-table texinfo-format-syntax-table)
236
237     ;; Insert @include files so `texinfo-raise-lower-sections' can
238     ;; work on them without losing track of multiple
239     ;; @raise/@lowersections commands.
240     (while (re-search-forward "^@include" nil t)
241       (setq texinfo-command-end (point))
242       (let ((filename (concat input-directory
243                               (texinfo-parse-line-arg))))
244         (re-search-backward "^@include")
245         (delete-region (point) (save-excursion (forward-line 1) (point)))
246         (message "Reading included file: %s" filename)
247         (save-excursion
248           (save-restriction
249             (narrow-to-region
250              (point)
251              (+ (point) (car (cdr (insert-file-contents filename)))))
252             (goto-char (point-min))
253             ;; Remove `@setfilename' line from included file, if any,
254             ;; so @setfilename command not duplicated.
255             (if (re-search-forward "^@setfilename" (line-end-position 100) t)
256                 (delete-region (line-beginning-position 1)
257                                (line-beginning-position 2)))))))
258
259     ;; Raise or lower level of each section, if necessary.
260     (goto-char (point-min))
261     (texinfo-raise-lower-sections)
262     ;; Append @refill to appropriate paragraphs for filling.
263     (goto-char (point-min))
264     (texinfo-append-refill)
265     ;; If the region includes the effective end of the data,
266     ;; discard everything after that.
267     (goto-char (point-max))
268     (if (re-search-backward "^@bye" nil t)
269         (delete-region (point) (point-max)))
270     ;; Make sure buffer ends in a newline.
271     (or (= (preceding-char) ?\n)
272         (insert "\n"))
273     ;; Don't use a previous value of texinfo-enclosure-list.
274     (setq texinfo-enclosure-list nil)
275     (setq texinfo-alias-list nil)
276
277     (goto-char (point-min))
278     (if (looking-at "\\\\input[ \t]+texinfo")
279         (delete-region (point) (line-beginning-position 2)))
280
281     ;; Insert Info region title text.
282     (goto-char (point-min))
283     (if (search-forward
284          "@setfilename" (save-excursion (forward-line 100) (point)) t)
285         (progn
286           (setq texinfo-command-end (point))
287           (beginning-of-line)
288           (setq texinfo-command-start (point))
289           (let ((arg (texinfo-parse-arg-discard)))
290             (insert " "
291               texinfo-region-buffer-name
292               " buffer for:  `")
293             (insert (file-name-nondirectory (expand-file-name arg)))
294             (insert "',        -*-Text-*-\n")))
295       ;; Else no `@setfilename' line
296       (insert " "
297               texinfo-region-buffer-name
298               " buffer                       -*-Text-*-\n"))
299     (insert "produced by `texinfo-format-region'\n"
300             "from a region in: "
301             (if (buffer-file-name input-buffer)
302                   (concat "`"
303                           (file-name-sans-versions
304                            (file-name-nondirectory
305                             (buffer-file-name input-buffer)))
306                           "'")
307                 (concat "buffer `" (buffer-name input-buffer) "'"))
308               "\nusing `texinfmt.el' version "
309               texinfmt-version
310               ".\n\n")
311
312     ;; Now convert for real.
313     (goto-char (point-min))
314     (texinfo-format-scan)
315     (goto-char (point-min))
316     (Info-tagify input-buffer)
317     (goto-char (point-min))
318     (message "Done."))))
319
320 ;;;###autoload
321 (defun texi2info (&optional nosplit)
322   "Convert the current buffer (written in Texinfo code) into an Info file.
323 The Info file output is generated in a buffer visiting the Info file
324 names specified in the @setfilename command.
325
326 This function automatically updates all node pointers and menus, and
327 creates a master menu.  This work is done on a temporary buffer that
328 is automatically removed when the Info file is created.  The original
329 Texinfo source buffer is not changed.
330
331 Non-nil argument (prefix, if interactive) means don't split the file
332 if large.  You can use Info-split to do this manually."
333   (interactive "P")
334   (let ((temp-buffer (concat  "*--" (buffer-name) "--temporary-buffer*" )))
335     (message "First updating nodes and menus, then creating Info file.")
336     ;;  (sit-for 2)
337     (copy-to-buffer temp-buffer (point-min) (point-max))
338     (switch-to-buffer temp-buffer)
339     (texinfo-master-menu t)
340     (message "Now creating Info file.")
341     (sit-for 2)
342     (texinfo-format-buffer nosplit)
343     (save-buffer)
344     (kill-buffer temp-buffer)))
345
346
347 ;;; Primary internal formatting function for the whole buffer.
348
349 (defun texinfo-format-buffer-1 ()
350   (let (texinfo-format-filename
351         texinfo-example-start
352         texinfo-command-start
353         texinfo-command-end
354         texinfo-command-name
355         texinfo-last-node
356         texinfo-last-node-pos
357         texinfo-vindex
358         texinfo-findex
359         texinfo-cindex
360         texinfo-pindex
361         texinfo-tindex
362         texinfo-kindex
363         texinfo-stack
364         texinfo-node-names
365         (texinfo-footnote-number 0)
366         last-input-buffer
367         outfile
368         (fill-column-for-info fill-column)
369         (input-buffer (current-buffer))
370         (input-directory default-directory))
371     (setq texinfo-enclosure-list nil)
372     (setq texinfo-alias-list nil)
373     (save-excursion
374       (goto-char (point-min))
375       (or (search-forward "@setfilename" nil t)
376           (error "Texinfo file needs an `@setfilename FILENAME' line"))
377       (setq texinfo-command-end (point))
378       (setq outfile (texinfo-parse-line-arg)))
379
380     (find-file outfile)
381     (texinfo-mode)
382     (erase-buffer)
383     (buffer-disable-undo)
384
385     (message "Formatting Info file: %s" outfile)
386     (setq texinfo-format-filename
387           (file-name-nondirectory (expand-file-name outfile)))
388
389     (setq fill-column fill-column-for-info)
390     (set-syntax-table texinfo-format-syntax-table)
391
392     (insert-buffer-substring input-buffer)
393     (run-hook-with-args 'texinfo-pre-format-hook input-buffer)
394     (message "Converting %s to Info format..." (buffer-name input-buffer))
395
396     ;; Insert @include files so `texinfo-raise-lower-sections' can
397     ;; work on them without losing track of multiple
398     ;; @raise/@lowersections commands.
399     (goto-char (point-min))
400     (while (re-search-forward "^@include" nil t)
401       (setq texinfo-command-end (point))
402       (let ((filename (concat input-directory
403                               (texinfo-parse-line-arg))))
404         (re-search-backward "^@include")
405         (delete-region (point) (line-beginning-position 2))
406         (message "Reading included file: %s" filename)
407         (save-excursion
408           (save-restriction
409             (narrow-to-region
410              (point)
411              (+ (point) (car (cdr (insert-file-contents filename)))))
412             (goto-char (point-min))
413             ;; Remove `@setfilename' line from included file, if any,
414             ;; so @setfilename command not duplicated.
415             (if (re-search-forward "^@setfilename" (line-end-position 100) t)
416                 (delete-region (line-beginning-position 1)
417                                (line-beginning-position 2)))))))
418     ;; Raise or lower level of each section, if necessary.
419     (goto-char (point-min))
420     (texinfo-raise-lower-sections)
421     ;; Append @refill to appropriate paragraphs
422     (goto-char (point-min))
423     (texinfo-append-refill)
424     (goto-char (point-min))
425     (search-forward "@setfilename")
426     (beginning-of-line)
427     (delete-region (point-min) (point))
428     ;; Remove @bye at end of file, if it is there.
429     (goto-char (point-max))
430     (if (search-backward "@bye" nil t)
431         (delete-region (point) (point-max)))
432     ;; Make sure buffer ends in a newline.
433     (or (= (preceding-char) ?\n)
434         (insert "\n"))
435     ;; Scan the whole buffer, converting to Info format.
436     (texinfo-format-scan)
437     (goto-char (point-min))
438     ;; Insert info about how this file was made.
439     (insert "Info file: "
440             texinfo-format-filename ",    -*-Text-*-\n"
441             "produced by `texinfo-format-buffer'\n"
442             ;; Date string removed so that regression testing is easier.
443             ;; "on "
444             ;; (insert (format-time-string "%e %b %Y")) " "
445             "from file"
446             (if (buffer-file-name input-buffer)
447                 (concat " `"
448                         (file-name-sans-versions
449                          (file-name-nondirectory
450                           (buffer-file-name input-buffer)))
451                         "'")
452               (concat "buffer `" (buffer-name input-buffer) "'"))
453             "\nusing `texinfmt.el' version "
454             texinfmt-version
455             ".\n\n")
456     ;; Return data for indices.
457     (list outfile
458           texinfo-vindex texinfo-findex texinfo-cindex
459           texinfo-pindex texinfo-tindex texinfo-kindex)))
460
461
462 ;;; Perform non-@-command file conversions: quotes and hyphens
463
464 (defun texinfo-format-convert (min max)
465   ;; Convert left and right quotes to typewriter font quotes.
466   (goto-char min)
467   (while (search-forward "``" max t)
468     (replace-match "\""))
469   (goto-char min)
470   (while (search-forward "''" max t)
471     (replace-match "\""))
472   ;; Convert three hyphens in a row to two.
473   (goto-char min)
474   (while (re-search-forward "\\( \\|\\w\\)\\(---\\)\\( \\|\\w\\)" max t)
475     (delete-region (1+ (match-beginning 2)) (+ 2 (match-beginning 2)))))
476
477
478 ;;; Handle paragraph filling
479
480 ;; Keep as concatinated lists for ease of maintenance
481
482 (defvar texinfo-no-refill-regexp
483   (concat
484    "^@"
485    "\\("
486    ;; add "itemize\\|"   (from experiment of 2001 Nov 28)
487    ;;     because of a problem with @end itemize@refill
488    ;;     I don't know if this causes other problems.
489    ;;     I suspect itemized lists don't get filled properly and a
490    ;;     more precise fix is required.  Bob
491    ;; commented out on 2005 Feb 28 by Bob
492    ;; "itemize\\|"
493    "direntry\\|"
494    "lisp\\|"
495    "smalllisp\\|"
496    "example\\|"
497    "smallexample\\|"
498    "display\\|"
499    "smalldisplay\\|"
500    "format\\|"
501    "smallformat\\|"
502    "flushleft\\|"
503    "flushright\\|"
504    "menu\\|"
505    "multitable\\|"
506    "titlepage\\|"
507    "iftex\\|"
508    "ifhtml\\|"
509    "tex\\|"
510    "html"
511    "\\)")
512   "Regexp specifying environments in which paragraphs are not filled.")
513
514 (defvar texinfo-accent-commands
515   (concat
516    "@^\\|"
517    "@`\\|"
518    "@'\\|"
519    "@\"\\|"
520    "@,\\|"
521    "@=\\|"
522    "@~\\|"
523    "@OE{\\|"
524    "@oe{\\|"
525    "@AA{\\|"
526    "@aa{\\|"
527    "@AE{\\|"
528    "@ae{\\|"
529    "@ss{\\|"
530    "@questiondown{\\|"
531    "@exclamdown{\\|"
532    "@L{\\|"
533    "@l{\\|"
534    "@O{\\|"
535    "@o{\\|"
536    "@dotaccent{\\|"
537    "@ubaraccent{\\|"
538    "@d{\\|"
539    "@H{\\|"
540    "@ringaccent{\\|"
541    "@tieaccent{\\|"
542    "@u{\\|"
543    "@v{\\|"
544    "@dotless{"
545    ))
546
547 (defvar texinfo-part-of-para-regexp
548   (concat
549    "^@"
550    "\\("
551    "b{\\|"
552    "bullet{\\|"
553    "cite{\\|"
554    "code{\\|"
555    "email{\\|"
556    "emph{\\|"
557    "equiv{\\|"
558    "error{\\|"
559    "expansion{\\|"
560    "file{\\|"
561    "i{\\|"
562    "inforef{\\|"
563    "kbd{\\|"
564    "key{\\|"
565    "lisp{\\|"
566    "minus{\\|"
567    "point{\\|"
568    "print{\\|"
569    "pxref{\\|"
570    "r{\\|"
571    "ref{\\|"
572    "result{\\|"
573    "samp{\\|"
574    "sc{\\|"
575    "t{\\|"
576    "TeX{\\|"
577    "today{\\|"
578    "url{\\|"
579    "var{\\|"
580    "w{\\|"
581    "xref{\\|"
582    "@-\\|"    ; @- is a descretionary hyphen (not an accent) (a noop).
583    texinfo-accent-commands
584    "\\)"
585    )
586   "Regexp specifying @-commands found within paragraphs.")
587
588 (defun texinfo-append-refill ()
589   "Append @refill at end of each paragraph that should be filled.
590 Do not append @refill to paragraphs within @example and similar environments.
591 Do not append @refill to paragraphs containing @w{TEXT} or @*."
592
593   ;; It is necessary to append @refill before other processing because
594   ;; the other processing removes information that tells Texinfo
595   ;; whether the text should or should not be filled.
596
597   (while (< (point) (point-max))
598     (let ((refill-blank-lines "^[ \t\n]*$")
599           (case-fold-search nil))       ; Don't confuse @TeX and @tex....
600       (beginning-of-line)
601       ;; 1. Skip over blank lines;
602       ;;    skip over lines beginning with @-commands,
603       ;;    but do not skip over lines
604       ;;      that are no-refill environments such as @example or
605       ;;      that begin with within-paragraph @-commands such as @code.
606       (while (and (looking-at (concat "^@\\|^\\\\\\|" refill-blank-lines))
607                   (not (looking-at
608                         (concat
609                          "\\("
610                          texinfo-no-refill-regexp
611                          "\\|"
612                          texinfo-part-of-para-regexp
613                          "\\)")))
614                   (< (point) (point-max)))
615         (forward-line 1))
616       ;; 2. Skip over @example and similar no-refill environments.
617       (if (looking-at texinfo-no-refill-regexp)
618           (let ((environment (match-string-no-properties 1)))
619             (progn (re-search-forward (concat "^@end " environment) nil t)
620                    (forward-line 1)))
621         ;; Else
622         ;; 3. Do not refill a paragraph containing @w or @*, or ending
623         ;;    with @<newline> followed by a newline.
624         (if  (or (>= (point) (point-max))
625                  (re-search-forward
626                   "@w{\\|@\\*\\|@\n\n"
627                   (save-excursion (forward-paragraph) (forward-line 1) (point))
628                   t))
629             ;; Go to end of paragraph and do nothing.
630             (forward-paragraph)
631           ;; 4. Else go to end of paragraph and insert @refill
632           (forward-paragraph)
633           (forward-line -1)
634           (let ((line-beg (point)))
635             (end-of-line)
636             (delete-region
637              (point)
638              (save-excursion (skip-chars-backward " \t") (point)))
639             (forward-char 1)
640             (unless (re-search-backward "@c[ \t\n]\\|@comment[ \t\n]" line-beg t)
641               (forward-char -1))
642             (unless (re-search-backward "@refill\\|^[ \t]*@" line-beg t)
643               (insert "@refill")))
644           (forward-line 1))))))
645
646
647 ;;; Handle `@raisesections' and `@lowersections' commands
648
649 ;; These commands change the hierarchical level of chapter structuring
650 ;; commands.
651 ;;
652 ;; @raisesections changes @subsection to @section,
653 ;;                        @section    to @chapter,
654 ;;                        etc.
655 ;;
656 ;; @lowersections changes @chapter    to @section
657 ;;                        @subsection to @subsubsection,
658 ;;                        etc.
659 ;;
660 ;; An @raisesections/@lowersections command changes only those
661 ;; structuring commands that follow the @raisesections/@lowersections
662 ;; command.
663 ;;
664 ;; Repeated @raisesections/@lowersections continue to raise or lower
665 ;; the heading level.
666 ;;
667 ;; An @lowersections command cancels an @raisesections command, and
668 ;; vice versa.
669 ;;
670 ;; You cannot raise or lower "beyond" chapters or subsubsections, but
671 ;; trying to do so does not elicit an error---you just get more
672 ;; headings that mean the same thing as you keep raising or lowering
673 ;; (for example, after a single @raisesections, both @chapter and
674 ;; @section produce chapter headings).
675
676 (defun texinfo-raise-lower-sections ()
677   "Raise or lower the hierarchical level of chapters, sections, etc.
678
679 This function acts according to `@raisesections' and `@lowersections'
680 commands in the Texinfo file.
681
682 For example, an `@lowersections' command is useful if you wish to
683 include what is written as an outer or standalone Texinfo file in
684 another Texinfo file as an inner, included file.  The `@lowersections'
685 command changes chapters to sections, sections to subsections and so
686 on.
687
688 @raisesections changes @subsection to @section,
689                        @section    to @chapter,
690                        @heading    to @chapheading,
691                        etc.
692
693 @lowersections changes @chapter    to @section,
694                        @subsection to @subsubsection,
695                        @heading    to @subheading,
696                        etc.
697
698 An `@raisesections' or `@lowersections' command changes only those
699 structuring commands that follow the `@raisesections' or
700 `@lowersections' command.
701
702 An `@lowersections' command cancels an `@raisesections' command, and
703 vice versa.
704
705 Repeated use of the commands continue to raise or lower the hierarchical
706 level a step at a time.
707
708 An attempt to raise above `chapters' reproduces chapter commands; an
709 attempt to lower below subsubsections reproduces subsubsection
710 commands."
711
712   ;; `texinfo-section-types-regexp' is defined in `texnfo-upd.el';
713   ;; it is a regexp matching chapter, section, other headings
714   ;; (but not the top node).
715
716   (let (type (level 0))
717     (while
718         (re-search-forward
719          (concat
720           "\\(\\(^@\\(raise\\|lower\\)sections\\)\\|\\("
721           texinfo-section-types-regexp
722           "\\)\\)")
723          nil t)
724       (beginning-of-line)
725       (save-excursion (setq type (read (current-buffer))))
726       (cond
727
728        ;; 1. Increment level
729        ((eq type '@raisesections)
730         (setq level (1+ level))
731         (delete-region
732          (point) (save-excursion (forward-line 1) (point))))
733
734        ;; 2. Decrement level
735        ((eq type '@lowersections)
736         (setq level (1- level))
737         (delete-region
738          (point) (save-excursion (forward-line 1) (point))))
739
740        ;; Now handle structuring commands
741        ((cond
742
743          ;; 3. Raise level when positive
744          ((> level 0)
745           (let ((count level)
746                 (new-level type))
747             (while (> count 0)
748               (setq new-level
749                     (cdr (assq new-level texinfo-raisesections-alist)))
750               (setq count (1- count)))
751             (kill-word 1)
752             (insert (symbol-name new-level))))
753
754          ;; 4. Do nothing except move point when level is zero
755          ((= level 0) (forward-line 1))
756
757          ;; 5. Lower level when positive
758          ((< level 0)
759           (let ((count level)
760                 (new-level type))
761             (while (< count 0)
762               (setq new-level
763                     (cdr (assq new-level texinfo-lowersections-alist)))
764               (setq count (1+ count)))
765             (kill-word 1)
766             (insert (symbol-name new-level))))))))))
767
768 (defvar texinfo-raisesections-alist
769   '((@chapter . @chapter)             ; Cannot go higher
770     (@unnumbered . @unnumbered)
771     (@centerchap . @unnumbered)
772
773     (@majorheading . @majorheading)
774     (@chapheading . @chapheading)
775     (@appendix . @appendix)
776
777     (@section . @chapter)
778     (@unnumberedsec . @unnumbered)
779     (@heading . @chapheading)
780     (@appendixsec . @appendix)
781
782     (@subsection . @section)
783     (@unnumberedsubsec . @unnumberedsec)
784     (@subheading . @heading)
785     (@appendixsubsec . @appendixsec)
786
787     (@subsubsection . @subsection)
788     (@unnumberedsubsubsec . @unnumberedsubsec)
789     (@subsubheading . @subheading)
790     (@appendixsubsubsec . @appendixsubsec))
791   "*An alist of next higher levels for chapters, sections. etc.
792 For example, section to chapter, subsection to section.
793 Used by `texinfo-raise-lower-sections'.
794 The keys specify types of section; the values correspond to the next
795 higher types.")
796
797 (defvar texinfo-lowersections-alist
798   '((@chapter . @section)
799     (@unnumbered . @unnumberedsec)
800     (@centerchap . @unnumberedsec)
801     (@majorheading . @heading)
802     (@chapheading . @heading)
803     (@appendix . @appendixsec)
804
805     (@section . @subsection)
806     (@unnumberedsec . @unnumberedsubsec)
807     (@heading . @subheading)
808     (@appendixsec . @appendixsubsec)
809
810