muse-publish: Implement muse-publish-enable-dangerous-tags.
[muse-el.git] / lisp / muse-texinfo.el
blob3b5a618f40262c3aeb1714be59445d7c55213c78
1 ;;; muse-texinfo.el --- publish entries to Texinfo format or PDF
3 ;; Copyright (C) 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
5 ;; This file is part of Emacs Muse. It is not part of GNU Emacs.
7 ;; Emacs Muse is free software; you can redistribute it and/or modify
8 ;; it under the terms of the GNU General Public License as published
9 ;; by the Free Software Foundation; either version 3, or (at your
10 ;; option) any later version.
12 ;; Emacs Muse is distributed in the hope that it will be useful, but
13 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
14 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 ;; General Public License for more details.
17 ;; You should have received a copy of the GNU General Public License
18 ;; along with Emacs Muse; see the file COPYING. If not, write to the
19 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 ;; Boston, MA 02110-1301, USA.
22 ;;; Commentary:
24 ;;; Contributors:
26 ;;; Code:
28 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
30 ;; Muse Texinfo Publishing
32 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
34 (require 'muse-publish)
35 (require 'muse-latex)
36 (require 'texnfo-upd)
38 (defgroup muse-texinfo nil
39 "Rules for marking up a Muse file as a Texinfo article."
40 :group 'muse-publish)
42 (defcustom muse-texinfo-process-natively nil
43 "If non-nil, use the Emacs `texinfmt' module to make Info files."
44 :type 'boolean
45 :require 'texinfmt
46 :group 'muse-texinfo)
48 (defcustom muse-texinfo-extension ".texi"
49 "Default file extension for publishing Texinfo files."
50 :type 'string
51 :group 'muse-texinfo)
53 (defcustom muse-texinfo-info-extension ".info"
54 "Default file extension for publishing Info files."
55 :type 'string
56 :group 'muse-texinfo)
58 (defcustom muse-texinfo-pdf-extension ".pdf"
59 "Default file extension for publishing PDF files."
60 :type 'string
61 :group 'muse-texinfo)
63 (defcustom muse-texinfo-header
64 "\\input texinfo @c -*-texinfo-*-
66 @setfilename <lisp>(concat (muse-page-name) \".info\")</lisp>
67 @settitle <lisp>(muse-publishing-directive \"title\")</lisp>
69 @documentencoding iso-8859-1
71 @iftex
72 @finalout
73 @end iftex
75 @titlepage
76 @title <lisp>(muse-publishing-directive \"title\")</lisp>
77 @author <lisp>(muse-publishing-directive \"author\")</lisp>
78 @end titlepage
80 <lisp>(and muse-publish-generate-contents \"@contents\")</lisp>
82 @node Top, Overview, , (dir)
83 @top Overview
84 @c Page published by Emacs Muse begins here\n\n"
85 "Text to prepend to a Muse page being published as Texinfo.
86 This may be text or a filename.
87 It may contain <lisp> markup tags."
88 :type 'string
89 :group 'muse-texinfo)
91 (defcustom muse-texinfo-footer
92 "\n@c Page published by Emacs Muse ends here
93 @bye\n"
94 "Text to append to a Muse page being published as Texinfo.
95 This may be text or a filename.
96 It may contain <lisp> markup tags."
97 :type 'string
98 :group 'muse-texinfo)
100 (defcustom muse-texinfo-markup-regexps nil
101 "List of markup rules for publishing a Muse page to Texinfo.
102 For more on the structure of this list, see `muse-publish-markup-regexps'."
103 :type '(repeat (choice
104 (list :tag "Markup rule"
105 integer
106 (choice regexp symbol)
107 integer
108 (choice string function symbol))
109 function))
110 :group 'muse-texinfo)
112 (defcustom muse-texinfo-markup-functions
113 '((table . muse-texinfo-markup-table)
114 (heading . muse-texinfo-markup-heading))
115 "An alist of style types to custom functions for that kind of text.
116 For more on the structure of this list, see
117 `muse-publish-markup-functions'."
118 :type '(alist :key-type symbol :value-type function)
119 :group 'muse-texinfo)
121 (defcustom muse-texinfo-markup-strings
122 '((image-with-desc . "@center @image{%1%, , , %3%, %2%}@*\n@center %3%")
123 (image . "@noindent @image{%s, , , , %s}")
124 (image-link . "@uref{%s, %s.%s}")
125 (anchor-ref . "@ref{%s, %s}")
126 (url . "@uref{%s, %s}")
127 (link . "@ref{Top, %2%, , %1%, }")
128 (link-and-anchor . "@ref{%3%, %2%, , %1%, %3%}")
129 (email-addr . "@email{%s}")
130 (anchor . "@anchor{%s} ")
131 (emdash . "---")
132 (comment-begin . "@ignore\n")
133 (comment-end . "\n@end ignore\n")
134 (rule . "@sp 1")
135 (no-break-space . "@w{ }")
136 (line-break . "@*")
137 (enddots . "@enddots{}")
138 (dots . "@dots{}")
139 (section . "@chapter ")
140 (subsection . "@section ")
141 (subsubsection . "@subsection ")
142 (section-other . "@subsubheading ")
143 (footnote . "@footnote{")
144 (footnote-end . "}")
145 (begin-underline . "_")
146 (end-underline . "_")
147 (begin-literal . "@samp{")
148 (end-literal . "}")
149 (begin-emph . "@emph{")
150 (end-emph . "}")
151 (begin-more-emph . "@strong{")
152 (end-more-emph . "}")
153 (begin-most-emph . "@strong{@emph{")
154 (end-most-emph . "}}")
155 (begin-verse . "@display\n")
156 (end-verse-line . "")
157 (verse-space . "@ @ ")
158 (end-verse . "\n@end display")
159 (begin-example . "@example\n")
160 (end-example . "\n@end example")
161 (begin-center . "@quotation\n")
162 (end-center . "\n@end quotation")
163 (begin-quote . "@quotation\n")
164 (end-quote . "\n@end quotation")
165 (begin-cite . "")
166 (begin-cite-author . "")
167 (begin-cite-year . "")
168 (end-cite . "")
169 (begin-uli . "@itemize @bullet\n")
170 (end-uli . "\n@end itemize")
171 (begin-uli-item . "@item\n")
172 (begin-oli . "@enumerate\n")
173 (end-oli . "\n@end enumerate")
174 (begin-oli-item . "@item\n")
175 (begin-dl . "@table @strong\n")
176 (end-dl . "\n@end table")
177 (begin-ddt . "@item "))
178 "Strings used for marking up text.
179 These cover the most basic kinds of markup, the handling of which
180 differs little between the various styles."
181 :type '(alist :key-type symbol :value-type string)
182 :group 'muse-texinfo)
184 (defcustom muse-texinfo-markup-specials
185 '((?@ . "@@")
186 (?{ . "@{")
187 (?} . "@}"))
188 "A table of characters which must be represented specially."
189 :type '(alist :key-type character :value-type string)
190 :group 'muse-texinfo)
192 (defcustom muse-texinfo-markup-specials-url
193 '((?@ . "@@")
194 (?{ . "@{")
195 (?} . "@}")
196 (?, . "@comma{}"))
197 "A table of characters which must be represented specially.
198 These are applied to URLs."
199 :type '(alist :key-type character :value-type string)
200 :group 'muse-texinfo)
202 (defun muse-texinfo-decide-specials (context)
203 "Determine the specials to escape, depending on CONTEXT."
204 (cond ((memq context '(underline literal emphasis email url url-desc image
205 footnote))
206 muse-texinfo-markup-specials-url)
207 (t muse-texinfo-markup-specials)))
209 (defun muse-texinfo-markup-table ()
210 (let* ((table-info (muse-publish-table-fields (match-beginning 0)
211 (match-end 0)))
212 (row-len (car table-info))
213 (field-list (cdr table-info)))
214 (when table-info
215 (muse-insert-markup "@multitable @columnfractions")
216 (dotimes (field row-len)
217 (muse-insert-markup " " (number-to-string (/ 1.0 row-len))))
218 (dolist (fields field-list)
219 (let ((type (car fields)))
220 (unless (eq type 'hline)
221 (setq fields (cdr fields))
222 (if (= type 2)
223 (muse-insert-markup "\n@headitem ")
224 (muse-insert-markup "\n@item "))
225 (insert (car fields))
226 (setq fields (cdr fields))
227 (dolist (field fields)
228 (muse-insert-markup " @tab ")
229 (insert field)))))
230 (muse-insert-markup "\n@end multitable")
231 (insert ?\n))))
233 (defun muse-texinfo-remove-links (string)
234 "Remove explicit links from STRING, replacing them with the link
235 description.
237 If no description exists for the link, use the link itself."
238 (let ((start nil))
239 (while (setq start (string-match muse-explicit-link-regexp string
240 start))
241 (setq string
242 (replace-match (or (match-string 2 string)
243 (match-string 1 string))
244 t t string)))
245 string))
247 (defun muse-texinfo-protect-wikiwords (start end)
248 "Protect all wikiwords from START to END from further processing."
249 (and (boundp 'muse-wiki-wikiword-regexp)
250 (featurep 'muse-wiki)
251 (save-excursion
252 (goto-char start)
253 (while (re-search-forward muse-wiki-wikiword-regexp end t)
254 (muse-publish-mark-read-only (match-beginning 0)
255 (match-end 0))))))
257 (defun muse-texinfo-markup-heading ()
258 (save-excursion
259 (muse-publish-markup-heading))
260 (let* ((eol (muse-line-end-position))
261 (orig-heading (buffer-substring (point) eol))
262 (beg (point)))
263 (delete-region (point) eol)
264 ;; don't allow links to be published in headings
265 (insert (muse-texinfo-remove-links orig-heading))
266 (muse-texinfo-protect-wikiwords beg (point))))
268 (defun muse-texinfo-munge-buffer ()
269 (muse-latex-fixup-dquotes)
270 (texinfo-insert-node-lines (point-min) (point-max) t)
271 (texinfo-all-menus-update t))
273 (defun muse-texinfo-pdf-browse-file (file)
274 (shell-command (concat "open " file)))
276 (defun muse-texinfo-info-generate (file output-path final-target)
277 ;; The version of `texinfmt.el' that comes with Emacs 21 doesn't
278 ;; support @documentencoding, so hack it in.
279 (when (and (not (featurep 'xemacs))
280 (eq emacs-major-version 21))
281 (put 'documentencoding 'texinfo-format
282 'texinfo-discard-line-with-args))
283 ;; Most versions of `texinfmt.el' do not support @headitem, so hack
284 ;; it in.
285 (unless (get 'headitem 'texinfo-format)
286 (put 'headitem 'texinfo-format 'texinfo-multitable-item))
287 (muse-publish-transform-output
288 file output-path final-target "Info"
289 (function
290 (lambda (file output-path)
291 (if muse-texinfo-process-natively
292 (save-window-excursion
293 (save-excursion
294 (find-file file)
295 (let ((inhibit-read-only t))
296 (texinfo-format-buffer))
297 (save-buffer)
298 (kill-buffer (current-buffer))
299 (let ((buf (get-file-buffer file)))
300 (with-current-buffer buf
301 (set-buffer-modified-p nil)
302 (kill-buffer (current-buffer))))
304 (let ((result (shell-command
305 (concat "makeinfo --enable-encoding --output="
306 output-path " " file))))
307 (if (or (not (numberp result))
308 (eq result 0))
310 nil)))))))
312 (defun muse-texinfo-pdf-generate (file output-path final-target)
313 (let ((muse-latex-pdf-program "pdftex")
314 (muse-latex-pdf-cruft '(".aux" ".cp" ".fn" ".ky" ".log" ".pg" ".toc"
315 ".tp" ".vr")))
316 (muse-latex-pdf-generate file output-path final-target)))
318 ;;; Register the Muse TEXINFO Publishers
320 (muse-define-style "texi"
321 :suffix 'muse-texinfo-extension
322 :regexps 'muse-texinfo-markup-regexps
323 :functions 'muse-texinfo-markup-functions
324 :strings 'muse-texinfo-markup-strings
325 :specials 'muse-texinfo-decide-specials
326 :after 'muse-texinfo-munge-buffer
327 :header 'muse-texinfo-header
328 :footer 'muse-texinfo-footer
329 :browser 'find-file)
331 (muse-derive-style "info" "texi"
332 :final 'muse-texinfo-info-generate
333 :link-suffix 'muse-texinfo-info-extension
334 :osuffix 'muse-texinfo-info-extension
335 :browser 'info)
337 (muse-derive-style "info-pdf" "texi"
338 :final 'muse-texinfo-pdf-generate
339 :link-suffix 'muse-texinfo-pdf-extension
340 :osuffix 'muse-texinfo-pdf-extension
341 :browser 'muse-texinfo-pdf-browse-file)
343 (provide 'muse-texinfo)
345 ;;; muse-texinfo.el ends here