1 ;;; muse-context.el --- publish entries in ConTeXt or PDF format
3 ;; Copyright (C) 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
5 ;; Author: Jean Magnan de Bornier (jean@bornier.net)
6 ;; Created: 16-Apr-2007
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 ;; This file when loaded allows you to publish .muse files as ConTeXt
14 ;; files or as pdf files, using respectively the "context" and
15 ;; "context-pdf" styles. It is far from being perfect, so any feedback
16 ;; will be welcome and any mistake hopefully fixed.
20 ;; Jean Magnan de Bornier, who based this file on muse-latex.el and
21 ;; made the context, context-pdf, context-slides, and
22 ;; context-slides-pdf Muse publishing styles.
28 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
30 ;; Muse ConTeXt Publishing
32 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
34 (require 'muse-publish
)
36 (defgroup muse-context nil
37 "Rules for marking up a Muse file as a ConTeXt article."
40 (defcustom muse-context-extension
".tex"
41 "Default file extension for publishing ConTeXt files."
45 (defcustom muse-context-pdf-extension
".pdf"
46 "Default file extension for publishing ConTeXt files to PDF."
50 (defcustom muse-context-pdf-program
"texexec --pdf"
51 "The program that is called to generate PDF content from ConTeXt content."
55 (defcustom muse-context-pdf-cruft
'(".pgf" ".tmp" ".tui" ".tuo" ".toc" ".log")
56 "Extensions of files to remove after generating PDF output successfully."
60 (defcustom muse-context-header
61 "\\setupinteraction [state=start]
64 <lisp>(muse-context-setup-bibliography)</lisp>
65 \\setuppublications[]\n
66 \\setuppublicationlist[]\n\\setupcite[]\n
68 \\startalignment[center]
70 {\\tfd <lisp>(muse-publishing-directive \"title\")</lisp>}
72 {\\tfa <lisp>(muse-publishing-directive \"author\")</lisp>}
74 {\\tfa <lisp>(muse-publishing-directive \"date\")</lisp>}
78 <lisp>(and muse-publish-generate-contents
79 (not muse-context-permit-contents-tag)
80 \"\\\\placecontent\n\\\\page[yes]\")</lisp>\n\n"
81 "Header used for publishing ConTeXt files. This may be text or a filename."
85 (defcustom muse-context-footer
"<lisp>(muse-context-bibliography)</lisp>
87 "Footer used for publishing ConTeXt files. This may be text or a filename."
91 (defcustom muse-context-markup-regexps
93 (10000 "\\([0-9]+\\)-\\([0-9]+\\)" 0 "\\1--\\2")
95 ;; be careful of closing quote pairs
96 (10100 "\"'" 0 "\"\\\\-'"))
97 "List of markup regexps for identifying regions in a Muse page.
98 For more on the structure of this list, see `muse-publish-markup-regexps'."
99 :type
'(repeat (choice
100 (list :tag
"Markup rule"
102 (choice regexp symbol
)
104 (choice string function symbol
))
106 :group
'muse-context
)
108 (defcustom muse-context-markup-functions
109 '((table . muse-context-markup-table
))
110 "An alist of style types to custom functions for that kind of text.
111 For more on the structure of this list, see
112 `muse-publish-markup-functions'."
113 :type
'(alist :key-type symbol
:value-type function
)
114 :group
'muse-context
)
116 (defcustom muse-context-markup-strings
117 '((image-with-desc .
"\\placefigure[][]{%3%}{\\externalfigure[%1%.%2%]}")
118 (image .
"\\placefigure[][]{}{\\externalfigure[%s.%s]}")
119 (image-link .
"\\useURL[aa][%s][][%1%] \\from[aa]")
120 (anchor-ref .
"\\goto{%2%}{}[%1%]")
121 (url .
"\\useURL[aa][%s][][%s] \\from[aa]")
122 (url-and-desc .
"\\useURL[bb][%s][][%s]\\from[bb]\\footnote{%1%}")
123 (link .
"\\goto{%2%}[program(%1%)]\\footnote{%1%}")
124 (link-and-anchor .
"\\useexternaldocument[%4%][%4%][] \\at{%3%, page}{}[%4%::%2%]\\footnote{%1%}")
125 (email-addr .
"\\useURL[mail][mailto:%s][][%s]\\from[mail]")
126 (anchor .
"\\reference[%s] ")
128 (comment-begin .
"\\doifmode{comment}{")
130 (rule .
"\\blank[medium]\\hrule\\blank[medium]")
131 (no-break-space .
"~")
132 (enddots .
"\\ldots ")
136 (chapter .
"\\chapter{")
138 (section .
"\\section{")
140 (subsection .
"\\subsection{")
141 (subsection-end .
"}")
142 (subsubsection .
"\\subsubsection{")
143 (subsubsection-end .
"}")
144 (section-other .
"\\subsubsubject{")
145 (section-other-end .
"}")
146 (footnote .
"\\footnote{")
148 (footnotetext .
"\\footnotetext[%d]{")
149 (begin-underline .
"\\underbar{")
150 (end-underline .
"}")
151 (begin-literal .
"\\type{")
153 (begin-emph .
"{\\em ")
155 (begin-more-emph .
"{\\bf ")
156 (end-more-emph .
"}")
157 (begin-most-emph .
"{\\bf {\\em ")
158 (end-most-emph .
"}}")
159 (begin-example .
"\\starttyping")
160 (end-example .
"\\stoptyping")
161 (begin-center .
"\\startalignment[center]\n")
162 (end-center .
"\n\\stopalignment")
163 (begin-quote .
"\\startquotation\n")
164 (end-quote .
"\n\\stopquotation")
165 (begin-cite .
"\\cite[authoryear][")
166 (begin-cite-author .
"\\cite[author][")
167 (begin-cite-year .
"\\cite[year][")
169 (begin-uli .
"\\startitemize\n")
170 (end-uli .
"\n\\stopitemize")
171 (begin-uli-item .
"\\item ")
172 (begin-oli .
"\\startitemize[n]\n")
173 (end-oli .
"\n\\stopitemize")
174 (begin-oli-item .
"\\item ")
175 (begin-dl .
"\\startitemize\n")
176 (end-dl .
"\n\\stopitemize")
177 (begin-ddt .
"\\head ")
179 (begin-verse .
"\\blank[big]")
180 (end-verse-line .
"\\par")
181 (verse-space .
"\\fixedspaces ~~")
182 (end-verse .
"\\blank[big]"))
183 "Strings used for marking up text.
184 These cover the most basic kinds of markup, the handling of which
185 differs little between the various styles."
186 :type
'(alist :key-type symbol
:value-type string
)
187 :group
'muse-context
)
189 (defcustom muse-context-slides-header
190 "\\usemodule[<lisp>(if (string-equal (muse-publishing-directive \"module\") nil) \"pre-01\" (muse-publishing-directive \"module\"))</lisp>]
193 \\setupinteraction [state=start]
195 \\TitlePage { <lisp>(muse-publishing-directive \"title\")</lisp>
197 \\tfa <lisp>(muse-publishing-directive \"author\")</lisp>
199 \\tfa <lisp>(muse-publishing-directive \"date\")</lisp>}"
200 "Header for publishing a presentation (slides) using ConTeXt.
201 Any of the predefined modules, which are available in the
202 tex/context/base directory, can be used by writing a \"module\"
203 directive at the top of the muse file; if no such directive is
204 provided, module pre-01 is used. Alternatively, you can use your
205 own style (\"mystyle\", in this example) by replacing
206 \"\\usemodule[]\" with \"\\input mystyle\".
208 This may be text or a filename."
210 :group
'muse-context
)
212 (defcustom muse-context-slides-markup-strings
213 '((section .
"\\Topic {")
214 (subsection .
"\\page \n{\\bf ")
215 (subsubsection .
"{\\em "))
216 "Strings used for marking up text in ConTeXt slides."
217 :type
'(alist :key-type symbol
:value-type string
)
218 :group
'muse-context
)
220 (defcustom muse-context-markup-specials-document
221 '((?
\\ .
"\\textbackslash{}")
222 (?\_ .
"\\textunderscore{}")
223 (?\
< .
"\\switchtobodyfont[small]")
224 (?\
> .
"\\switchtobodyfont[big]")
234 "A table of characters which must be represented specially.
235 These are applied to the entire document, sans already-escaped
237 :type
'(alist :key-type character
:value-type string
)
238 :group
'muse-context
)
240 (defcustom muse-context-markup-specials-example
242 "A table of characters which must be represented specially.
243 These are applied to <example> regions.
245 With the default interpretation of <example> regions, no specials
247 :type
'(alist :key-type character
:value-type string
)
248 :group
'muse-context
)
250 (defcustom muse-context-markup-specials-literal
252 "A table of characters which must be represented specially.
253 This applies to =monospaced text= and <code> regions."
254 :type
'(alist :key-type character
:value-type string
)
255 :group
'muse-context
)
257 (defcustom muse-context-markup-specials-url
258 '((?
\\ .
"\\textbackslash")
268 "A table of characters which must be represented specially.
269 These are applied to URLs."
270 :type
'(alist :key-type character
:value-type string
)
271 :group
'muse-context
)
273 (defcustom muse-context-markup-specials-image
274 '((?
\\ .
"\\textbackslash") ; cannot find suitable replacement
282 (?\
# .
"\\#") ; cannot find suitable replacement
284 "A table of characters which must be represented specially.
285 These are applied to image filenames."
286 :type
'(alist :key-type character
:value-type string
)
287 :group
'muse-context
)
289 (defun muse-context-decide-specials (context)
290 "Determine the specials to escape, depending on the CONTEXT argument."
291 (cond ((memq context
'(underline emphasis document url-desc verbatim
293 muse-context-markup-specials-document
)
295 muse-context-markup-specials-image
)
296 ((memq context
'(email url
))
297 muse-context-markup-specials-url
)
298 ((eq context
'literal
)
299 muse-context-markup-specials-literal
)
300 ((eq context
'example
)
301 muse-context-markup-specials-example
)
302 (t (error "Invalid context argument '%s' in muse-context" context
))))
304 (defun muse-context-markup-table ()
305 (let* ((table-info (muse-publish-table-fields (match-beginning 0)
307 (row-len (car table-info
))
308 (field-list (cdr table-info
)))
310 (muse-insert-markup "\\starttable[|"
311 (mapconcat 'symbol-name
(make-vector row-len
'l
)
312 "|") "|]\n \\HL\n \\VL ")
313 (dolist (fields field-list
)
314 (let ((type (car fields
)))
315 (setq fields
(cdr fields
))
317 (muse-insert-markup ""))
318 (insert (car fields
))
319 (setq fields
(cdr fields
))
320 (dolist (field fields
)
321 (muse-insert-markup " \\VL ")
323 (muse-insert-markup "\\VL\\NR\n \\HL\n \\VL ")
325 (muse-insert-markup " "))))
326 (muse-insert-markup "\\stoptable\n")
327 (while (search-backward "VL \\stoptable" nil t
)
328 (replace-match "stoptable" nil t
)))))
330 (defun muse-context-fixup-dquotes ()
331 "Fixup double quotes."
332 (goto-char (point-min))
334 (while (search-forward "\"" nil t
)
335 (unless (get-text-property (match-beginning 0) 'read-only
)
337 (eq (char-before) ?
\n))
346 (defcustom muse-context-permit-contents-tag nil
347 "If nil, ignore <contents> tags. Otherwise, insert table of contents.
349 Most of the time, it is best to have a table of contents on the
350 first page, with a new page immediately following. To make this
351 work with documents published in both HTML and ConTeXt, we need to
352 ignore the <contents> tag.
354 If you don't agree with this, then set this option to non-nil,
355 and it will do what you expect."
357 :group
'muse-context
)
359 (defun muse-context-fixup-citations ()
360 "Replace semicolons in multi-head citations with colons."
361 (goto-char (point-min))
362 (while (re-search-forward "\\\\cite.?\\[" nil t
)
363 (let ((start (point))
364 (end (re-search-forward "]")))
366 (narrow-to-region start end
)
367 (goto-char (point-min))
368 (while (re-search-forward ";" nil t
)
369 (replace-match ","))))))
371 (defun muse-context-munge-buffer ()
372 (muse-context-fixup-dquotes)
373 (muse-context-fixup-citations)
374 (when (and muse-context-permit-contents-tag
375 muse-publish-generate-contents
)
376 (goto-char (car muse-publish-generate-contents
))
377 (muse-insert-markup "\\placecontent")))
379 (defun muse-context-bibliography ()
381 (goto-char (point-min))
382 (if (re-search-forward "\\\\cite.?\\[" nil t
)
383 "\\completepublications[criterium=all]"
386 (defun muse-context-setup-bibliography ()
388 (goto-char (point-min))
389 (if (re-search-forward "\\\\cite.?\\[" nil t
)
391 "\\usemodule[bibltx]\n\\setupbibtex [database="
392 (muse-publishing-directive "bibsource") "]")
395 (defun muse-context-pdf-browse-file (file)
396 (shell-command (concat "open " file
)))
398 (defun muse-context-pdf-generate (file output-path final-target
)
400 #'muse-publish-transform-output
401 file output-path final-target
"PDF"
403 (lambda (file output-path
)
404 (let* ((fnd (file-name-directory output-path
))
405 (command (format "%s \"%s\""
406 muse-context-pdf-program
407 (file-relative-name file fnd
)))
409 (default-directory fnd
)
411 ;; XEmacs can sometimes return a non-number result. We'll err
412 ;; on the side of caution by continuing to attempt to generate
413 ;; the PDF if this happens and treat the final result as
415 (while (and (< times
2)
416 (or (not (numberp result
))
418 ;; table of contents takes 2 passes
420 ;; (muse-replace-regexp-in-string
421 ;; "\\.tex\\'" ".toc" file t t))
423 (setq result
(shell-command command
)
425 (if (or (not (numberp result
))
429 muse-context-pdf-cruft
))
431 (muse-define-style "context"
432 :suffix
'muse-context-extension
433 :regexps
'muse-context-markup-regexps
434 :functions
'muse-context-markup-functions
435 :strings
'muse-context-markup-strings
436 :specials
'muse-context-decide-specials
437 :after
'muse-context-munge-buffer
438 :header
'muse-context-header
439 :footer
'muse-context-footer
442 (muse-derive-style "context-pdf" "context"
443 :final
'muse-context-pdf-generate
444 :browser
'muse-context-pdf-browse-file
445 :link-suffix
'muse-context-pdf-extension
446 :osuffix
'muse-context-pdf-extension
)
448 (muse-derive-style "context-slides" "context"
449 :header
'muse-context-slides-header
450 :strings
'muse-context-slides-markup-strings
)
452 (muse-derive-style "context-slides-pdf" "context-pdf"
453 :header
'muse-context-slides-header
454 :strings
'muse-context-slides-markup-strings
)
456 (provide 'muse-context
)
458 ;;; muse-context.el ends here