1 ;;; muse-latex.el --- publish entries in LaTex or PDF format
3 ;; Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009
4 ;; Free Software Foundation, Inc.
6 ;; This file is part of Emacs Muse. It is not part of GNU Emacs.
8 ;; Emacs Muse is free software; you can redistribute it and/or modify
9 ;; it under the terms of the GNU General Public License as published
10 ;; by the Free Software Foundation; either version 3, or (at your
11 ;; option) any later version.
13 ;; Emacs Muse is distributed in the hope that it will be useful, but
14 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
15 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 ;; General Public License for more details.
18 ;; You should have received a copy of the GNU General Public License
19 ;; along with Emacs Muse; see the file COPYING. If not, write to the
20 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 ;; Boston, MA 02110-1301, USA.
27 ;; Li Daobing (lidaobing AT gmail DOT com) provided CJK support.
29 ;; Trent Buck (trentbuck AT gmail DOT com) gave valuable advice for
30 ;; how to treat LaTeX specials and the like.
32 ;; Matthias Kegelmann (mathias DOT kegelmann AT sdm DOT de) provided a
33 ;; scenario where we would need to respect the <contents> tag.
35 ;; Jean Magnan de Bornier (jean AT bornier DOT net) provided the
36 ;; markup string for link-and-anchor.
38 ;; Jim Ottaway (j DOT ottaway AT lse DOT ac DOT uk) implemented slides
41 ;; Karl Berry (karl AT freefriends DOT org) suggested how to escape
42 ;; additional special characters in image filenames.
46 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
48 ;; Muse LaTeX Publishing
50 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
52 (require 'muse-publish
)
54 (defgroup muse-latex nil
55 "Rules for marking up a Muse file as a LaTeX article."
58 (defcustom muse-latex-extension
".tex"
59 "Default file extension for publishing LaTeX files."
63 (defcustom muse-latex-pdf-extension
".pdf"
64 "Default file extension for publishing LaTeX files to PDF."
68 (defcustom muse-latex-pdf-browser
"open %s"
69 "The program to use when browsing a published PDF file.
70 This should be a format string."
74 (defcustom muse-latex-pdf-program
"pdflatex"
75 "The program that is called to generate PDF content from LaTeX content."
79 (defcustom muse-latex-pdf-cruft
'(".aux" ".toc" ".out" ".log")
80 "Extensions of files to remove after generating PDF output successfully."
84 (defcustom muse-latex-header
85 "\\documentclass{article}
87 \\usepackage[english]{babel}
89 \\usepackage[utf8x]{inputenc}
90 \\usepackage[T1]{fontenc}
91 \\usepackage{hyperref}
92 \\usepackage[pdftex]{graphicx}
94 \\def\\museincludegraphics{%
99 \\includegraphics[width=0.75\\textwidth]
104 \\title{<lisp>(muse-publish-escape-specials-in-string
105 (muse-publishing-directive \"title\") 'document)</lisp>}
106 \\author{<lisp>(muse-publishing-directive \"author\")</lisp>}
107 \\date{<lisp>(muse-publishing-directive \"date\")</lisp>}
111 <lisp>(and muse-publish-generate-contents
112 (not muse-latex-permit-contents-tag)
113 \"\\\\tableofcontents\n\\\\newpage\")</lisp>\n\n"
114 "Header used for publishing LaTeX files. This may be text or a filename."
118 (defcustom muse-latex-footer
"<lisp>(muse-latex-bibliography)</lisp>
120 "Footer used for publishing LaTeX files. This may be text or a filename."
124 (defcustom muse-latexcjk-header
125 "\\documentclass{article}
128 \\usepackage{indentfirst}
129 \\usepackage[CJKbookmarks=true]{hyperref}
130 \\usepackage[pdftex]{graphicx}
133 \\begin{CJK*}<lisp>(muse-latexcjk-encoding)</lisp>
135 \\title{<lisp>(muse-publish-escape-specials-in-string
136 (muse-publishing-directive \"title\") 'document)</lisp>}
137 \\author{<lisp>(muse-publishing-directive \"author\")</lisp>}
138 \\date{<lisp>(muse-publishing-directive \"date\")</lisp>}
142 <lisp>(and muse-publish-generate-contents
143 (not muse-latex-permit-contents-tag)
144 \"\\\\tableofcontents\n\\\\newpage\")</lisp>\n\n"
145 "Header used for publishing LaTeX files (CJK). This may be text or a
150 (defcustom muse-latexcjk-footer
153 "Footer used for publishing LaTeX files (CJK). This may be text or a
158 (defcustom muse-latex-slides-header
159 "\\documentclass[ignorenonframetext]{beamer}
161 \\usepackage[english]{babel}
163 \\usepackage[utf8x]{inputenc}
164 \\usepackage[T1]{fontenc}
165 \\usepackage{hyperref}
169 \\title{<lisp>(muse-publish-escape-specials-in-string
170 (muse-publishing-directive \"title\") 'document)</lisp>}
171 \\author{<lisp>(muse-publishing-directive \"author\")</lisp>}
172 \\date{<lisp>(muse-publishing-directive \"date\")</lisp>}
176 <lisp>(and muse-publish-generate-contents
177 \"\\\\tableofcontents\n\\\\newpage\")</lisp>\n\n"
178 "Header for publishing of slides using LaTeX.
179 This may be text or a filename.
181 You must have the Beamer extension for LaTeX installed for this to work."
185 (defcustom muse-latex-lecture-notes-header
186 "\\documentclass{article}
187 \\usepackage{beamerarticle}
189 \\usepackage[english]{babel}
191 \\usepackage[utf8x]{inputenc}
192 \\usepackage[T1]{fontenc}
193 \\usepackage{hyperref}
197 \\title{<lisp>(muse-publish-escape-specials-in-string
198 (muse-publishing-directive \"title\") 'document)</lisp>}
199 \\author{<lisp>(muse-publishing-directive \"author\")</lisp>}
200 \\date{<lisp>(muse-publishing-directive \"date\")</lisp>}
204 <lisp>(and muse-publish-generate-contents
205 \"\\\\tableofcontents\n\\\\newpage\")</lisp>\n\n"
206 "Header for publishing of lecture notes using LaTeX.
207 This may be text or a filename.
209 You must have the Beamer extension for LaTeX installed for this to work."
213 (defcustom muse-latex-markup-regexps
215 (10000 "\\([0-9]+\\)-\\([0-9]+\\)" 0 "\\1--\\2")
217 ;; be careful of closing quote pairs
218 (10100 "\"'" 0 "\"\\\\-'"))
219 "List of markup regexps for identifying regions in a Muse page.
220 For more on the structure of this list, see `muse-publish-markup-regexps'."
221 :type
'(repeat (choice
222 (list :tag
"Markup rule"
224 (choice regexp symbol
)
226 (choice string function symbol
))
230 (defcustom muse-latex-markup-functions
231 '((table . muse-latex-markup-table
))
232 "An alist of style types to custom functions for that kind of text.
233 For more on the structure of this list, see
234 `muse-publish-markup-functions'."
235 :type
'(alist :key-type symbol
:value-type function
)
238 (defcustom muse-latex-markup-strings
239 '((image-with-desc .
"\\begin{figure}[h]
240 \\centering\\museincludegraphics{%s.%s}|endgroup
243 (image .
"\\begin{figure}[h]
244 \\centering\\museincludegraphics{%s.%s}|endgroup
247 \\museincludegraphics{%s.%s}|endgroup")
248 (anchor-ref .
"\\ref{%s}")
250 (url-and-desc .
"\\href{%s}{%s}\\footnote{%1%}")
251 (link .
"\\href{%s}{%s}\\footnote{%1%}")
252 (link-and-anchor .
"\\href{%1%}{%3%}\\footnote{%1%}")
253 (email-addr .
"\\verb|%s|")
254 (anchor .
"\\label{%s}")
256 (comment-begin .
"% ")
257 (rule .
"\\vspace{.5cm}\\hrule\\vspace{.5cm}")
258 (no-break-space .
"~")
259 (line-break .
"\\\\")
260 (enddots .
"\\ldots{}")
264 (chapter .
"\\chapter{")
266 (section .
"\\section{")
268 (subsection .
"\\subsection{")
269 (subsection-end .
"}")
270 (subsubsection .
"\\subsubsection{")
271 (subsubsection-end .
"}")
272 (section-other .
"\\paragraph{")
273 (section-other-end .
"}")
274 (footnote .
"\\footnote{")
276 (footnotetext .
"\\footnotetext[%d]{")
277 (begin-underline .
"\\underline{")
278 (end-underline .
"}")
279 (begin-literal .
"\\texttt{")
281 (begin-emph .
"\\emph{")
283 (begin-more-emph .
"\\textbf{")
284 (end-more-emph .
"}")
285 (begin-most-emph .
"\\textbf{\\emph{")
286 (end-most-emph .
"}}")
287 (begin-verse .
"\\begin{verse}\n")
288 (end-verse-line .
" \\\\")
289 (verse-space .
"~~~~")
290 (end-verse .
"\n\\end{verse}")
291 (begin-example .
"\\begin{quote}\n\\begin{verbatim}")
292 (end-example .
"\\end{verbatim}\n\\end{quote}")
293 (begin-center .
"\\begin{center}\n")
294 (end-center .
"\n\\end{center}")
295 (begin-quote .
"\\begin{quote}\n")
296 (end-quote .
"\n\\end{quote}")
297 (begin-cite .
"\\cite{")
298 (begin-cite-author .
"\\citet{")
299 (begin-cite-year .
"\\citet{")
301 (begin-uli .
"\\begin{itemize}\n")
302 (end-uli .
"\n\\end{itemize}")
303 (begin-uli-item .
"\\item ")
304 (begin-oli .
"\\begin{enumerate}\n")
305 (end-oli .
"\n\\end{enumerate}")
306 (begin-oli-item .
"\\item ")
307 (begin-dl .
"\\begin{description}\n")
308 (end-dl .
"\n\\end{description}")
309 (begin-ddt .
"\\item[")
310 (end-ddt .
"] \\mbox{}\n"))
311 "Strings used for marking up text.
312 These cover the most basic kinds of markup, the handling of which
313 differs little between the various styles."
314 :type
'(alist :key-type symbol
:value-type string
)
317 (defcustom muse-latex-slides-markup-tags
318 '(("slide" t t nil muse-latex-slide-tag
))
319 "A list of tag specifications, for specially marking up LaTeX slides."
320 :type
'(repeat (list (string :tag
"Markup tag")
321 (boolean :tag
"Expect closing tag" :value t
)
322 (boolean :tag
"Parse attributes" :value nil
)
323 (boolean :tag
"Nestable" :value nil
)
327 (defcustom muse-latexcjk-encoding-map
328 '((utf-8 .
"{UTF8}{song}")
329 (japanese-iso-8bit .
"[dnp]{JIS}{min}")
330 (chinese-big5 .
"{Bg5}{bsmi}")
331 (mule-utf-8 .
"{UTF8}{song}")
332 (chinese-iso-8bit .
"{GB}{song}")
333 (chinese-gbk .
"{GBK}{song}"))
334 "An alist mapping emacs coding systems to appropriate CJK codings.
335 Use the base name of the coding system (ie, without the -unix)."
336 :type
'(alist :key-type coding-system
:value-type string
)
339 (defcustom muse-latexcjk-encoding-default
"{GB}{song}"
340 "The default Emacs buffer encoding to use in published files.
341 This will be used if no special characters are found."
345 (defun muse-latexcjk-encoding ()
346 (when (boundp 'buffer-file-coding-system
)
347 (muse-latexcjk-transform-content-type buffer-file-coding-system
)))
349 (defun muse-latexcjk-transform-content-type (content-type)
350 "Using `muse-cjklatex-encoding-map', try and resolve an emacs coding
351 system to an associated CJK coding system."
352 (let ((match (and (fboundp 'coding-system-base
)
353 (assoc (coding-system-base content-type
)
354 muse-latexcjk-encoding-map
))))
357 muse-latexcjk-encoding-default
)))
359 (defcustom muse-latex-markup-specials-document
360 '((?
\\ .
"\\textbackslash{}")
361 (?\_ .
"\\textunderscore{}")
362 (?\
< .
"\\textless{}")
363 (?\
> .
"\\textgreater{}")
373 "A table of characters which must be represented specially.
374 These are applied to the entire document, sans already-escaped
376 :type
'(alist :key-type character
:value-type string
)
379 (defcustom muse-latex-markup-specials-example
381 "A table of characters which must be represented specially.
382 These are applied to <example> regions.
384 With the default interpretation of <example> regions, no specials
386 :type
'(alist :key-type character
:value-type string
)
389 (defcustom muse-latex-markup-specials-literal
391 (?
\\ .
"\\textbackslash{}")
392 (?_ .
"\\textunderscore{}")
393 (?\
< .
"\\textless{}")
394 (?\
> .
"\\textgreater{}")
403 "A table of characters which must be represented specially.
404 This applies to =monospaced text= and <code> regions."
405 :type
'(alist :key-type character
:value-type string
)
408 (defcustom muse-latex-markup-specials-url
409 '((?
\\ .
"\\textbackslash{}")
419 "A table of characters which must be represented specially.
420 These are applied to URLs."
421 :type
'(alist :key-type character
:value-type string
)
424 (defcustom muse-latex-markup-specials-image
435 "A table of characters which must be represented specially.
436 These are applied to image filenames."
437 :type
'(alist :key-type character
:value-type string
)
440 (defun muse-latex-decide-specials (context)
441 "Determine the specials to escape, depending on CONTEXT."
442 (cond ((memq context
'(underline emphasis document url-desc verbatim
444 muse-latex-markup-specials-document
)
446 muse-latex-markup-specials-image
)
447 ((memq context
'(email url
))
448 muse-latex-markup-specials-url
)
449 ((eq context
'literal
)
450 muse-latex-markup-specials-literal
)
451 ((eq context
'example
)
452 muse-latex-markup-specials-example
)
453 (t (error "Invalid context '%s' in muse-latex" context
))))
455 (defcustom muse-latex-permit-contents-tag nil
456 "If nil, ignore <contents> tags. Otherwise, insert table of contents.
458 Most of the time, it is best to have a table of contents on the
459 first page, with a new page immediately following. To make this
460 work with documents published in both HTML and LaTeX, we need to
461 ignore the <contents> tag.
463 If you don't agree with this, then set this option to non-nil,
464 and it will do what you expect."
468 (defun muse-latex-markup-table ()
469 (let* ((table-info (muse-publish-table-fields (match-beginning 0)
471 (row-len (car table-info
))
472 (field-list (cdr table-info
)))
474 (muse-insert-markup "\\begin{tabular}{" (make-string row-len ?l
) "}\n")
475 (dolist (fields field-list
)
476 (let ((type (car fields
)))
477 (setq fields
(cdr fields
))
479 (muse-insert-markup "\\hline\n")
481 (muse-insert-markup "\\hline\n"))
482 (insert (car fields
))
483 (setq fields
(cdr fields
))
484 (dolist (field fields
)
485 (muse-insert-markup " & ")
487 (muse-insert-markup " \\\\\n")
489 (muse-insert-markup "\\hline\n")))))
490 (muse-insert-markup "\\end{tabular}"))))
494 (defun muse-latex-slide-tag (beg end attrs
)
495 "Publish the <slide> tag in LaTeX.
496 This is used by the slides and lecture-notes publishing styles."
497 (let ((title (cdr (assoc "title" attrs
))))
499 (muse-insert-markup "\\begin{frame}[fragile]\n")
501 (muse-insert-markup "\\frametitle{")
503 (muse-insert-markup "}\n"))
506 (muse-insert-markup "\n\\end{frame}"))))
508 ;;; Post-publishing functions
510 (defun muse-latex-fixup-dquotes ()
511 "Fixup double quotes."
512 (goto-char (point-min))
514 (while (search-forward "\"" nil t
)
515 (unless (get-text-property (match-beginning 0) 'read-only
)
517 (eq (char-before) ?
\n))
526 (defun muse-latex-fixup-citations ()
527 "Replace semicolons in multi-head citations with colons."
528 (goto-char (point-min))
529 (while (re-search-forward "\\\\cite.?{" nil t
)
530 (let ((start (point))
531 (end (re-search-forward "}")))
533 (narrow-to-region start end
)
534 (goto-char (point-min))
535 (while (re-search-forward ";" nil t
)
536 (replace-match ","))))))
538 (defun muse-latex-fixup-headings ()
539 "Remove footnotes in headings, since LaTeX does not permit them to exist.
541 This can happen if there is a link in a heading, because by
542 default Muse will add a footnote for each link."
543 (goto-char (point-min))
544 (while (re-search-forward "^\\\\section.?{" nil t
)
546 (narrow-to-region (match-beginning 0) (muse-line-end-position))
547 (goto-char (point-min))
548 (while (re-search-forward "\\\\footnote{[^}\n]+}" nil t
)
552 (defun muse-latex-munge-buffer ()
553 (muse-latex-fixup-dquotes)
554 (muse-latex-fixup-citations)
555 (muse-latex-fixup-headings)
556 (when (and muse-latex-permit-contents-tag
557 muse-publish-generate-contents
)
558 (goto-char (car muse-publish-generate-contents
))
559 (muse-insert-markup "\\tableofcontents")))
561 (defun muse-latex-bibliography ()
563 (goto-char (point-min))
564 (if (re-search-forward "\\\\cite.?{" nil t
)
567 (muse-publishing-directive "bibsource")
571 (defun muse-latex-pdf-browse-file (file)
572 (shell-command (format muse-latex-pdf-browser file
)))
574 (defun muse-latex-pdf-generate (file output-path final-target
)
576 #'muse-publish-transform-output
577 file output-path final-target
"PDF"
579 (lambda (file output-path
)
580 (let* ((fnd (file-name-directory output-path
))
581 (command (format "%s \"%s\""
582 muse-latex-pdf-program
583 (file-relative-name file fnd
)))
585 (default-directory fnd
)
587 ;; XEmacs can sometimes return a non-number result. We'll err
588 ;; on the side of caution by continuing to attempt to generate
589 ;; the PDF if this happens and treat the final result as
591 (while (and (< times
2)
592 (or (not (numberp result
))
594 ;; table of contents takes 2 passes
596 (muse-replace-regexp-in-string
597 "\\.tex\\'" ".toc" file t t
))))
598 (setq result
(shell-command command
)
600 (if (or (not (numberp result
))
604 muse-latex-pdf-cruft
))
606 ;;; Register the Muse LATEX Publishers
608 (muse-define-style "latex"
609 :suffix
'muse-latex-extension
610 :regexps
'muse-latex-markup-regexps
611 :functions
'muse-latex-markup-functions
612 :strings
'muse-latex-markup-strings
613 :specials
'muse-latex-decide-specials
614 :before-end
'muse-latex-munge-buffer
615 :header
'muse-latex-header
616 :footer
'muse-latex-footer
619 (muse-derive-style "pdf" "latex"
620 :final
'muse-latex-pdf-generate
621 :browser
'muse-latex-pdf-browse-file
622 :link-suffix
'muse-latex-pdf-extension
623 :osuffix
'muse-latex-pdf-extension
)
625 (muse-derive-style "latexcjk" "latex"
626 :header
'muse-latexcjk-header
627 :footer
'muse-latexcjk-footer
)
629 (muse-derive-style "pdfcjk" "latexcjk"
630 :final
'muse-latex-pdf-generate
631 :browser
'muse-latex-pdf-browse-file
632 :link-suffix
'muse-latex-pdf-extension
633 :osuffix
'muse-latex-pdf-extension
)
635 (muse-derive-style "slides" "latex"
636 :header
'muse-latex-slides-header
637 :tags
'muse-latex-slides-markup-tags
)
639 (muse-derive-style "slides-pdf" "pdf"
640 :header
'muse-latex-slides-header
641 :tags
'muse-latex-slides-markup-tags
)
643 (muse-derive-style "lecture-notes" "slides"
644 :header
'muse-latex-lecture-notes-header
)
646 (muse-derive-style "lecture-notes-pdf" "slides-pdf"
647 :header
'muse-latex-lecture-notes-header
)
649 (provide 'muse-latex
)
651 ;;; muse-latex.el ends here