manual: Update description for muse-context-slides-header
[muse-el.git] / lisp / muse-context.el
blob84f2a19a0212e78ebc5b6f1729cc55245dc579fa
1 ;;; muse-context.el --- publish entries in ConTeXt or PDF format
3 ;; Copyright (C) 2007 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.
18 ;;; Author:
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.
24 ;; 16 Avril 2007
26 ;;; Code:
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."
38 :group 'muse-publish)
40 (defcustom muse-context-extension ".tex"
41 "Default file extension for publishing ConTeXt files."
42 :type 'string
43 :group 'muse-context)
45 (defcustom muse-context-pdf-extension ".pdf"
46 "Default file extension for publishing ConTeXt files to PDF."
47 :type 'string
48 :group 'muse-context)
50 (defcustom muse-context-pdf-program "texexec --pdf"
51 "The program that is called to generate PDF content from ConTeXt content."
52 :type 'string
53 :group 'muse-context)
55 (defcustom muse-context-pdf-cruft '(".pgf" ".tmp" ".tui" ".tuo" ".toc" ".log")
56 "Extensions of files to remove after generating PDF output successfully."
57 :type 'string
58 :group 'muse-context)
60 (defcustom muse-context-header
61 "\\setupinteraction [state=start]
62 \\usemodule[tikz]
63 \\usemodule[bib]\n
64 <lisp>(muse-context-setup-bibliography)</lisp>
65 \\setuppublications[]\n
66 \\setuppublicationlist[]\n\\setupcite[]\n
67 \\starttext
68 \\startalignment[center]
69 \\blank[2*big]
70 {\\tfd <lisp>(muse-publishing-directive \"title\")</lisp>}
71 \\blank[3*medium]
72 {\\tfa <lisp>(muse-publishing-directive \"author\")</lisp>}
73 \\blank[2*medium]
74 {\\tfa <lisp>(muse-publishing-directive \"date\")</lisp>}
75 \\blank[3*medium]
76 \\stopalignment
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."
82 :type 'string
83 :group 'muse-context)
85 (defcustom muse-context-footer "<lisp>(muse-context-bibliography)</lisp>
86 \\stoptext\n"
87 "Footer used for publishing ConTeXt files. This may be text or a filename."
88 :type 'string
89 :group 'muse-context)
91 (defcustom muse-context-markup-regexps
92 `(;; numeric ranges
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"
101 integer
102 (choice regexp symbol)
103 integer
104 (choice string function symbol))
105 function))
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] ")
127 (emdash . "---")
128 (comment-begin . "\\doifmode{comment}{")
129 (comment-end . "}")
130 (rule . "\\blank[medium]\\hrule\\blank[medium]")
131 (no-break-space . "~")
132 (enddots . "\\ldots ")
133 (dots . "\\dots ")
134 (part . "\\part{")
135 (part-end . "}")
136 (chapter . "\\chapter{")
137 (chapter-end . "}")
138 (section . "\\section{")
139 (section-end . "}")
140 (subsection . "\\subsection{")
141 (subsection-end . "}")
142 (subsubsection . "\\subsubsection{")
143 (subsubsection-end . "}")
144 (section-other . "\\subsubsubject{")
145 (section-other-end . "}")
146 (footnote . "\\footnote{")
147 (footnote-end . "}")
148 (footnotetext . "\\footnotetext[%d]{")
149 (begin-underline . "\\underbar{")
150 (end-underline . "}")
151 (begin-literal . "\\type{")
152 (end-literal . "}")
153 (begin-emph . "{\\em ")
154 (end-emph . "}")
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][")
168 (end-cite . "]")
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 ")
178 (end-ddt . "\n")
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>]
191 \\usemodule[tikz]
192 \\usemodule[newmat]
193 \\setupinteraction [state=start]
194 \\starttext
195 \\TitlePage { <lisp>(muse-publishing-directive \"title\")</lisp>
196 \\blank[3*medium]
197 \\tfa <lisp>(muse-publishing-directive \"author\")</lisp>
198 \\blank[2*medium]
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."
209 :type 'string
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]")
225 (?^ . "\\^")
226 (?\~ . "\\~")
227 (?\@ . "\\@")
228 (?\$ . "\\$")
229 (?\% . "\\%")
230 (?\{ . "\\{")
231 (?\} . "\\}")
232 (?\& . "\\&")
233 (?\# . "\\#"))
234 "A table of characters which must be represented specially.
235 These are applied to the entire document, sans already-escaped
236 regions."
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
246 need to be escaped."
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")
259 (?\_ . "\\_")
260 (?\< . "\\<")
261 (?\> . "\\>")
262 (?\$ . "\\$")
263 (?\% . "\\%")
264 (?\{ . "\\{")
265 (?\} . "\\}")
266 (?\& . "\\&")
267 (?\# . "\\#"))
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
275 (?\< . "\\<")
276 (?\> . "\\>")
277 (?\$ . "\\$")
278 (?\% . "\\%")
279 (?\{ . "\\{")
280 (?\} . "\\}")
281 (?\& . "\\&")
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))
292 muse-context-markup-specials-document)
293 ((eq context 'image)
294 muse-context-markup-specials-image)
295 ((memq context '(email url))
296 muse-context-markup-specials-url)
297 ((eq context 'literal)
298 muse-context-markup-specials-literal)
299 ((eq context 'example)
300 muse-context-markup-specials-example)
301 (t (error "Invalid context argument '%s' in muse-context" context))))
303 (defun muse-context-markup-table ()
304 (let* ((table-info (muse-publish-table-fields (match-beginning 0)
305 (match-end 0)))
306 (row-len (car table-info))
307 (field-list (cdr table-info)))
308 (when table-info
309 (muse-insert-markup "\\starttable[|"
310 (mapconcat 'symbol-name (make-vector row-len 'l)
311 "|") "|]\n \\HL\n \\VL ")
312 (dolist (fields field-list)
313 (let ((type (car fields)))
314 (setq fields (cdr fields))
315 (when (= type 3)
316 (muse-insert-markup ""))
317 (insert (car fields))
318 (setq fields (cdr fields))
319 (dolist (field fields)
320 (muse-insert-markup " \\VL ")
321 (insert field))
322 (muse-insert-markup "\\VL\\NR\n \\HL\n \\VL ")
323 (when (= type 2)
324 (muse-insert-markup " "))))
325 (muse-insert-markup "\\stoptable\n")
326 (while (search-backward "VL \\stoptable" nil t)
327 (replace-match "stoptable" nil t)))))
329 (defun muse-context-fixup-dquotes ()
330 "Fixup double quotes."
331 (goto-char (point-min))
332 (let ((open t))
333 (while (search-forward "\"" nil t)
334 (unless (get-text-property (match-beginning 0) 'read-only)
335 (when (or (bobp)
336 (eq (char-before) ?\n))
337 (setq open t))
338 (if open
339 (progn
340 (replace-match "``")
341 (setq open nil))
342 (replace-match "''")
343 (setq open t))))))
345 (defcustom muse-context-permit-contents-tag nil
346 "If nil, ignore <contents> tags. Otherwise, insert table of contents.
348 Most of the time, it is best to have a table of contents on the
349 first page, with a new page immediately following. To make this
350 work with documents published in both HTML and ConTeXt, we need to
351 ignore the <contents> tag.
353 If you don't agree with this, then set this option to non-nil,
354 and it will do what you expect."
355 :type 'boolean
356 :group 'muse-context)
358 (defun muse-context-fixup-citations ()
359 "Replace semicolons in multi-head citations with colons."
360 (goto-char (point-min))
361 (while (re-search-forward "\\\\cite.?\\[" nil t)
362 (let ((start (point))
363 (end (re-search-forward "]")))
364 (save-restriction
365 (narrow-to-region start end)
366 (goto-char (point-min))
367 (while (re-search-forward ";" nil t)
368 (replace-match ","))))))
370 (defun muse-context-munge-buffer ()
371 (muse-context-fixup-dquotes)
372 (muse-context-fixup-citations)
373 (when (and muse-context-permit-contents-tag
374 muse-publish-generate-contents)
375 (goto-char (car muse-publish-generate-contents))
376 (muse-insert-markup "\\placecontent")))
378 (defun muse-context-bibliography ()
379 (save-excursion
380 (goto-char (point-min))
381 (if (re-search-forward "\\\\cite.?\\[" nil t)
382 "\\completepublications[criterium=all]"
383 "")))
385 (defun muse-context-setup-bibliography ()
386 (save-excursion
387 (goto-char (point-min))
388 (if (re-search-forward "\\\\cite.?\\[" nil t)
389 (concat
390 "\\usemodule[bibltx]\n\\setupbibtex [database="
391 (muse-publishing-directive "bibsource") "]")
392 "")))
394 (defun muse-context-pdf-browse-file (file)
395 (shell-command (concat "open " file)))
397 (defun muse-context-pdf-generate (file output-path final-target)
398 (apply
399 #'muse-publish-transform-output
400 file output-path final-target "PDF"
401 (function
402 (lambda (file output-path)
403 (let* ((fnd (file-name-directory output-path))
404 (command (format "cd \"%s\"; %s \"%s\""
405 fnd muse-context-pdf-program
406 (file-relative-name file fnd)))
407 (times 0)
408 result)
409 ;; XEmacs can sometimes return a non-number result. We'll err
410 ;; on the side of caution by continuing to attempt to generate
411 ;; the PDF if this happens and treat the final result as
412 ;; successful.
413 (while (and (< times 2)
414 (or (not (numberp result))
415 (not (eq result 0))
416 ;; table of contents takes 2 passes
417 ;; (file-readable-p
418 ;; (muse-replace-regexp-in-string
419 ;; "\\.tex\\'" ".toc" file t t))
421 (setq result (shell-command command)
422 times (1+ times)))
423 (if (or (not (numberp result))
424 (eq result 0))
426 nil))))
427 muse-context-pdf-cruft))
429 (muse-define-style "context"
430 :suffix 'muse-context-extension
431 :regexps 'muse-context-markup-regexps
432 :functions 'muse-context-markup-functions
433 :strings 'muse-context-markup-strings
434 :specials 'muse-context-decide-specials
435 :after 'muse-context-munge-buffer
436 :header 'muse-context-header
437 :footer 'muse-context-footer
438 :browser 'find-file)
440 (muse-derive-style "context-pdf" "context"
441 :final 'muse-context-pdf-generate
442 :browser 'muse-context-pdf-browse-file
443 :link-suffix 'muse-context-pdf-extension
444 :osuffix 'muse-context-pdf-extension)
446 (muse-derive-style "context-slides" "context"
447 :header 'muse-context-slides-header
448 :strings 'muse-context-slides-markup-strings)
450 (muse-derive-style "context-slides-pdf" "context-pdf"
451 :header 'muse-context-slides-header
452 :strings 'muse-context-slides-markup-strings)
454 (provide 'muse-context)
456 ;;; muse-context.el ends here