Commit | Line | Data |
---|---|---|
ed21c5c8 CD |
1 | ;;; org-beamer.el --- Beamer-specific LaTeX export for org-mode |
2 | ;; | |
ab422c4d | 3 | ;; Copyright (C) 2007-2013 Free Software Foundation, Inc. |
ed21c5c8 | 4 | ;; |
ed21c5c8 CD |
5 | ;; Author: Carsten Dominik <carsten.dominik AT gmail DOT com> |
6 | ;; Maintainer: Carsten Dominik <carsten.dominik AT gmail DOT com> | |
7 | ;; Keywords: org, wp, tex | |
8 | ||
9 | ;; This file is part of GNU Emacs. | |
10 | ||
11 | ;; GNU Emacs is free software: you can redistribute it and/or modify | |
12 | ;; it under the terms of the GNU General Public License as published by | |
13 | ;; the Free Software Foundation, either version 3 of the License, or | |
14 | ;; (at your option) any later version. | |
15 | ||
16 | ;; GNU Emacs is distributed in the hope that it will be useful, | |
17 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
19 | ;; GNU General Public License for more details. | |
20 | ||
21 | ;; You should have received a copy of the GNU General Public License | |
22 | ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. | |
23 | ||
24 | ;;; Commentary: | |
25 | ;; | |
26 | ;; This library implement the special treatment needed by using the | |
27 | ;; beamer class during LaTeX export. | |
28 | ||
86fbb8ca CD |
29 | ;;; Code: |
30 | ||
ed21c5c8 CD |
31 | (require 'org) |
32 | (require 'org-exp) | |
86fbb8ca | 33 | |
ed21c5c8 CD |
34 | (defvar org-export-latex-header) |
35 | (defvar org-export-latex-options-plist) | |
36 | (defvar org-export-opt-plist) | |
37 | ||
38 | (defgroup org-beamer nil | |
39 | "Options specific for using the beamer class in LaTeX export." | |
40 | :tag "Org Beamer" | |
41 | :group 'org-export-latex) | |
42 | ||
43 | (defcustom org-beamer-use-parts nil | |
44 | "" | |
45 | :group 'org-beamer | |
372d7b21 | 46 | :version "24.1" |
ed21c5c8 CD |
47 | :type 'boolean) |
48 | ||
49 | (defcustom org-beamer-frame-level 1 | |
50 | "The level that should be interpreted as a frame. | |
51 | The levels above this one will be translated into a sectioning structure. | |
52 | Setting this to 2 will allow sections, 3 will allow subsections as well. | |
86fbb8ca | 53 | You can set this to 4 as well, if you at the same time set |
ed21c5c8 CD |
54 | `org-beamer-use-parts' to make the top levels `\part'." |
55 | :group 'org-beamer | |
372d7b21 | 56 | :version "24.1" |
ed21c5c8 CD |
57 | :type '(choice |
58 | (const :tag "Frames need a BEAMER_env property" nil) | |
59 | (integer :tag "Specific level makes a frame"))) | |
60 | ||
61 | (defcustom org-beamer-frame-default-options "" | |
62 | "Default options string to use for frames, should contains the [brackets]. | |
63 | And example for this is \"[allowframebreaks]\"." | |
64 | :group 'org-beamer | |
372d7b21 | 65 | :version "24.1" |
ed21c5c8 CD |
66 | :type '(string :tag "[options]")) |
67 | ||
68 | (defcustom org-beamer-column-view-format | |
69 | "%45ITEM %10BEAMER_env(Env) %10BEAMER_envargs(Env Args) %4BEAMER_col(Col) %8BEAMER_extra(Extra)" | |
70 | "Default column view format that should be used to fill the template." | |
71 | :group 'org-beamer | |
372d7b21 | 72 | :version "24.1" |
86fbb8ca CD |
73 | :type '(choice |
74 | (const :tag "Do not insert Beamer column view format" nil) | |
75 | (string :tag "Beamer column view format"))) | |
ed21c5c8 CD |
76 | |
77 | (defcustom org-beamer-themes | |
78 | "\\usetheme{default}\\usecolortheme{default}" | |
79 | "Default string to be used for extra heading stuff in beamer presentations. | |
80 | When a beamer template is filled, this will be the default for | |
81 | BEAMER_HEADER_EXTRA, which will be inserted just before \\begin{document}." | |
82 | :group 'org-beamer | |
372d7b21 | 83 | :version "24.1" |
86fbb8ca CD |
84 | :type '(choice |
85 | (const :tag "Do not insert Beamer themes" nil) | |
86 | (string :tag "Beamer themes"))) | |
ed21c5c8 CD |
87 | |
88 | (defconst org-beamer-column-widths | |
89 | "0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 0.0 :ETC" | |
8223b1d2 | 90 | "The column widths that should be installed as allowed property values.") |
ed21c5c8 CD |
91 | |
92 | (defconst org-beamer-transitions | |
93 | "\transblindsvertical \transblindshorizontal \transboxin \transboxout \transdissolve \transduration \transglitter \transsplithorizontalin \transsplithorizontalout \transsplitverticalin \transsplitverticalout \transwipe :ETC" | |
94 | "Transitions available for beamer. | |
95 | These are just a completion help.") | |
96 | ||
97 | (defconst org-beamer-environments-default | |
98 | '(("frame" "f" "dummy- special handling hard coded" "dummy") | |
99 | ("columns" "C" "\\begin{columns}%o %% %h%x" "\\end{columns}") | |
100 | ("column" "c" "\\begin{column}%o{%h\\textwidth}%x" "\\end{column}") | |
101 | ("block" "b" "\\begin{block}%a{%h}%x" "\\end{block}") | |
102 | ("alertblock" "a" "\\begin{alertblock}%a{%h}%x" "\\end{alertblock}") | |
103 | ("verse" "v" "\\begin{verse}%a %% %h%x" "\\end{verse}") | |
104 | ("quotation" "q" "\\begin{quotation}%a %% %h%x" "\\end{quotation}") | |
105 | ("quote" "Q" "\\begin{quote}%a %% %h%x" "\\end{quote}") | |
106 | ("structureenv" "s" "\\begin{structureenv}%a %% %h%x" "\\end{structureenv}") | |
107 | ("theorem" "t" "\\begin{theorem}%a%U%x" "\\end{theorem}") | |
108 | ("definition" "d" "\\begin{definition}%a%U%x" "\\end{definition}") | |
109 | ("example" "e" "\\begin{example}%a%U%x" "\\end{example}") | |
8223b1d2 | 110 | ("exampleblock" "E" "\\begin{exampleblock}%a{%h}%x" "\\end{exampleblock}") |
ed21c5c8 CD |
111 | ("proof" "p" "\\begin{proof}%a%U%x" "\\end{proof}") |
112 | ("beamercolorbox" "o" "\\begin{beamercolorbox}%o{%h}%x" "\\end{beamercolorbox}") | |
113 | ("normal" "h" "%h" "") ; Emit the heading as normal text | |
114 | ("note" "n" "\\note%o%a{%h" "}") | |
115 | ("noteNH" "N" "\\note%o%a{" "}") ; note, ignore heading | |
116 | ("ignoreheading" "i" "%%%% %h" "")) | |
117 | "Environments triggered by properties in Beamer export. | |
118 | These are the defaults - for user definitions, see | |
119 | `org-beamer-environments-extra'. | |
86fbb8ca | 120 | \"normal\" is a special fake environment, which emit the heading as |
8223b1d2 | 121 | normal text. It is needed when an environment should be surrounded |
ed21c5c8 CD |
122 | by normal text. Since beamer export converts nodes into environments, |
123 | you need to have a node to end the environment. | |
124 | For example | |
125 | ||
126 | ** a frame | |
127 | some text | |
128 | *** Blocktitle :B_block: | |
129 | inside the block | |
130 | *** After the block :B_normal: | |
131 | continuing here | |
132 | ** next frame") | |
133 | ||
134 | (defcustom org-beamer-environments-extra nil | |
135 | "Environments triggered by tags in Beamer export. | |
136 | Each entry has 4 elements: | |
137 | ||
138 | name Name of the environment | |
139 | key Selection key for `org-beamer-select-environment' | |
86fbb8ca | 140 | open The opening template for the environment, with the following escapes |
ed21c5c8 CD |
141 | %a the action/overlay specification |
142 | %A the default action/overlay specification | |
143 | %o the options argument of the template | |
144 | %h the headline text | |
145 | %H if there is headline text, that text in {} braces | |
146 | %U if there is headline text, that text in [] brackets | |
3ab2c837 | 147 | %x the content of the BEAMER_extra property |
ed21c5c8 CD |
148 | close The closing string of the environment." |
149 | ||
150 | :group 'org-beamer | |
372d7b21 | 151 | :version "24.1" |
ed21c5c8 CD |
152 | :type '(repeat |
153 | (list | |
154 | (string :tag "Environment") | |
155 | (string :tag "Selection key") | |
156 | (string :tag "Begin") | |
157 | (string :tag "End")))) | |
158 | ||
8223b1d2 BG |
159 | (defcustom org-beamer-inherited-properties nil |
160 | "Properties that should be inherited during beamer export." | |
161 | :group 'org-beamer | |
162 | :type '(repeat | |
163 | (string :tag "Property"))) | |
164 | ||
ed21c5c8 CD |
165 | (defvar org-beamer-frame-level-now nil) |
166 | (defvar org-beamer-header-extra nil) | |
167 | (defvar org-beamer-export-is-beamer-p nil) | |
168 | (defvar org-beamer-inside-frame-at-level nil) | |
169 | (defvar org-beamer-columns-open nil) | |
170 | (defvar org-beamer-column-open nil) | |
171 | ||
172 | (defun org-beamer-cleanup-column-width (width) | |
173 | "Make sure the width is not empty, and that it has a unit." | |
174 | (setq width (org-trim (or width ""))) | |
175 | (unless (string-match "\\S-" width) (setq width "0.5")) | |
176 | (if (string-match "\\`[.0-9]+\\'" width) | |
177 | (setq width (concat width "\\textwidth"))) | |
178 | width) | |
179 | ||
180 | (defun org-beamer-open-column (&optional width opt) | |
181 | (org-beamer-close-column-maybe) | |
182 | (setq org-beamer-column-open t) | |
183 | (setq width (org-beamer-cleanup-column-width width)) | |
184 | (insert (format "\\begin{column}%s{%s}\n" (or opt "") width))) | |
185 | (defun org-beamer-close-column-maybe () | |
186 | (when org-beamer-column-open | |
187 | (setq org-beamer-column-open nil) | |
188 | (insert "\\end{column}\n"))) | |
189 | (defun org-beamer-open-columns-maybe (&optional opts) | |
190 | (unless org-beamer-columns-open | |
191 | (setq org-beamer-columns-open t) | |
192 | (insert (format "\\begin{columns}%s\n" (or opts ""))))) | |
193 | (defun org-beamer-close-columns-maybe () | |
194 | (org-beamer-close-column-maybe) | |
195 | (when org-beamer-columns-open | |
196 | (setq org-beamer-columns-open nil) | |
197 | (insert "\\end{columns}\n"))) | |
198 | ||
199 | (defun org-beamer-select-environment () | |
200 | "Select the environment to be used by beamer for this entry. | |
86fbb8ca | 201 | While this uses (for convenience) a tag selection interface, the result |
ed21c5c8 CD |
202 | of this command will be that the BEAMER_env *property* of the entry is set. |
203 | ||
204 | In addition to this, the command will also set a tag as a visual aid, but | |
205 | the tag does not have any semantic meaning." | |
206 | (interactive) | |
207 | (let* ((envs (append org-beamer-environments-extra | |
208 | org-beamer-environments-default)) | |
209 | (org-tag-alist | |
210 | (append '((:startgroup)) | |
211 | (mapcar (lambda (e) (cons (concat "B_" (car e)) | |
212 | (string-to-char (nth 1 e)))) | |
213 | envs) | |
214 | '((:endgroup)) | |
215 | '(("BMCOL" . ?|)))) | |
216 | (org-fast-tag-selection-single-key t)) | |
217 | (org-set-tags) | |
218 | (let ((tags (or (ignore-errors (org-get-tags-string)) ""))) | |
219 | (cond | |
220 | ((equal org-last-tag-selection-key ?|) | |
221 | (if (string-match ":BMCOL:" tags) | |
222 | (org-set-property "BEAMER_col" (read-string "Column width: ")) | |
223 | (org-delete-property "BEAMER_col"))) | |
224 | ((string-match (concat ":B_\\(" | |
225 | (mapconcat 'car envs "\\|") | |
226 | "\\):") | |
227 | tags) | |
228 | (org-entry-put nil "BEAMER_env" (match-string 1 tags))) | |
229 | (t (org-entry-delete nil "BEAMER_env")))))) | |
230 | ||
bdebdb64 | 231 | ;;;###autoload |
ed21c5c8 CD |
232 | (defun org-beamer-sectioning (level text) |
233 | "Return the sectioning entry for the current headline. | |
234 | LEVEL is the reduced level of the headline. | |
235 | TEXT is the text of the headline, everything except the leading stars. | |
236 | The return value is a cons cell. The car is the headline text, usually | |
237 | just TEXT, but possibly modified if options have been extracted from the | |
238 | text. The cdr is the sectioning entry, similar to what is given | |
239 | in org-export-latex-classes." | |
240 | (let* ((frame-level (or org-beamer-frame-level-now org-beamer-frame-level)) | |
241 | (default | |
242 | (if org-beamer-use-parts | |
243 | '((1 . ("\\part{%s}" . "\\part*{%s}")) | |
244 | (2 . ("\\section{%s}" . "\\section*{%s}")) | |
245 | (3 . ("\\subsection{%s}" . "\\subsection*{%s}"))) | |
246 | '((1 . ("\\section{%s}" . "\\section*{%s}")) | |
247 | (2 . ("\\subsection{%s}" . "\\subsection*{%s}"))))) | |
248 | (envs (append org-beamer-environments-extra | |
249 | org-beamer-environments-default)) | |
250 | (props (org-get-text-property-any 0 'org-props text)) | |
153ae947 | 251 | (in "") (out "") org-beamer-option org-beamer-action org-beamer-defaction org-beamer-environment org-beamer-extra |
ed21c5c8 CD |
252 | columns-option column-option |
253 | env have-text ass tmp) | |
254 | (if (= frame-level 0) (setq frame-level nil)) | |
255 | (when (and org-beamer-inside-frame-at-level | |
256 | (<= level org-beamer-inside-frame-at-level)) | |
257 | (setq org-beamer-inside-frame-at-level nil)) | |
258 | (when (setq tmp (org-beamer-assoc-not-empty "BEAMER_col" props)) | |
259 | (if (and (string-match "\\`[0-9.]+\\'" tmp) | |
260 | (or (= (string-to-number tmp) 1.0) | |
261 | (= (string-to-number tmp) 0.0))) | |
acedf35c | 262 | ;; column width 1 means close columns, go back to full width |
ed21c5c8 CD |
263 | (org-beamer-close-columns-maybe) |
264 | (when (setq ass (assoc "BEAMER_envargs" props)) | |
265 | (let (case-fold-search) | |
acedf35c | 266 | (while (string-match "C\\(\\[[^][]*\\]\\|<[^<>]*>\\)" (cdr ass)) |
ed21c5c8 CD |
267 | (setq columns-option (match-string 1 (cdr ass))) |
268 | (setcdr ass (replace-match "" t t (cdr ass)))) | |
acedf35c | 269 | (while (string-match "c\\(\\[[^][]*\\]\\|<[^<>]*>\\)" (cdr ass)) |
ed21c5c8 CD |
270 | (setq column-option (match-string 1 (cdr ass))) |
271 | (setcdr ass (replace-match "" t t (cdr ass)))))) | |
272 | (org-beamer-open-columns-maybe columns-option) | |
273 | (org-beamer-open-column tmp column-option))) | |
274 | (cond | |
275 | ((or (equal (cdr (assoc "BEAMER_env" props)) "frame") | |
276 | (and frame-level (= level frame-level))) | |
277 | ;; A frame | |
278 | (org-beamer-get-special props) | |
279 | ||
280 | (setq in (org-fill-template | |
281 | "\\begin{frame}%a%A%o%T%S%x" | |
153ae947 BG |
282 | (list (cons "a" (or org-beamer-action "")) |
283 | (cons "A" (or org-beamer-defaction "")) | |
284 | (cons "o" (or org-beamer-option org-beamer-frame-default-options "")) | |
285 | (cons "x" (if org-beamer-extra (concat "\n" org-beamer-extra) "")) | |
ed21c5c8 CD |
286 | (cons "h" "%s") |
287 | (cons "T" (if (string-match "\\S-" text) | |
288 | "\n\\frametitle{%s}" "")) | |
289 | (cons "S" (if (string-match "\\\\\\\\" text) | |
290 | "\n\\framesubtitle{%s}" "")))) | |
291 | out (copy-sequence "\\end{frame}")) | |
292 | (org-add-props out | |
293 | '(org-insert-hook org-beamer-close-columns-maybe)) | |
294 | (setq org-beamer-inside-frame-at-level level) | |
295 | (cons text (list in out in out))) | |
296 | ((and (setq env (cdr (assoc "BEAMER_env" props))) | |
297 | (setq ass (assoc env envs))) | |
298 | ;; A beamer environment selected by the BEAMER_env property | |
299 | (if (string-match "[ \t]+:[ \t]*$" text) | |
300 | (setq text (replace-match "" t t text))) | |
301 | (if (member env '("note" "noteNH")) | |
302 | ;; There should be no labels in a note, so we remove the targets | |
303 | ;; FIXME??? | |
304 | (remove-text-properties 0 (length text) '(target nil) text)) | |
305 | (org-beamer-get-special props) | |
306 | (setq text (org-trim text)) | |
307 | (setq have-text (string-match "\\S-" text)) | |
308 | (setq in (org-fill-template | |
309 | (nth 2 ass) | |
153ae947 BG |
310 | (list (cons "a" (or org-beamer-action "")) |
311 | (cons "A" (or org-beamer-defaction "")) | |
312 | (cons "o" (or org-beamer-option "")) | |
313 | (cons "x" (if org-beamer-extra (concat "\n" org-beamer-extra) "")) | |
ed21c5c8 CD |
314 | (cons "h" "%s") |
315 | (cons "H" (if have-text (concat "{" text "}") "")) | |
316 | (cons "U" (if have-text (concat "[" text "]") "")))) | |
317 | out (nth 3 ass)) | |
318 | (cond | |
319 | ((equal out "\\end{columns}") | |
320 | (setq org-beamer-columns-open t) | |
321 | (setq out (org-add-props (copy-sequence out) | |
322 | '(org-insert-hook | |
323 | (lambda () | |
324 | (org-beamer-close-column-maybe) | |
325 | (setq org-beamer-columns-open nil)))))) | |
326 | ((equal out "\\end{column}") | |
327 | (org-beamer-open-columns-maybe))) | |
328 | (cons text (list in out in out))) | |
329 | ((and (not org-beamer-inside-frame-at-level) | |
330 | (or (not frame-level) | |
331 | (< level frame-level)) | |
332 | (assoc level default)) | |
333 | ;; Normal sectioning | |
334 | (cons text (cdr (assoc level default)))) | |
335 | (t nil)))) | |
336 | ||
153ae947 BG |
337 | (defvar org-beamer-extra) |
338 | (defvar org-beamer-option) | |
339 | (defvar org-beamer-action) | |
340 | (defvar org-beamer-defaction) | |
341 | (defvar org-beamer-environment) | |
ed21c5c8 CD |
342 | (defun org-beamer-get-special (props) |
343 | "Extract an option, action, and default action string from text. | |
153ae947 BG |
344 | The variables org-beamer-option, org-beamer-action, org-beamer-defaction, |
345 | org-beamer-extra are all scoped into this function dynamically." | |
ed21c5c8 | 346 | (let (tmp) |
153ae947 BG |
347 | (setq org-beamer-environment (org-beamer-assoc-not-empty "BEAMER_env" props)) |
348 | (setq org-beamer-extra (org-beamer-assoc-not-empty "BEAMER_extra" props)) | |
349 | (when org-beamer-extra | |
350 | (setq org-beamer-extra (replace-regexp-in-string "\\\\n" "\n" org-beamer-extra))) | |
ed21c5c8 CD |
351 | (setq tmp (org-beamer-assoc-not-empty "BEAMER_envargs" props)) |
352 | (when tmp | |
353 | (setq tmp (copy-sequence tmp)) | |
354 | (if (string-match "\\[<[^][<>]*>\\]" tmp) | |
153ae947 | 355 | (setq org-beamer-defaction (match-string 0 tmp) |
ed21c5c8 CD |
356 | tmp (replace-match "" t t tmp))) |
357 | (if (string-match "\\[[^][]*\\]" tmp) | |
153ae947 | 358 | (setq org-beamer-option (match-string 0 tmp) |
ed21c5c8 CD |
359 | tmp (replace-match "" t t tmp))) |
360 | (if (string-match "<[^<>]*>" tmp) | |
153ae947 | 361 | (setq org-beamer-action (match-string 0 tmp) |
ed21c5c8 CD |
362 | tmp (replace-match "" t t tmp)))))) |
363 | ||
364 | (defun org-beamer-assoc-not-empty (elt list) | |
365 | (let ((tmp (cdr (assoc elt list)))) | |
366 | (and tmp (string-match "\\S-" tmp) tmp))) | |
367 | ||
368 | ||
369 | (defvar org-beamer-mode-map (make-sparse-keymap) | |
370 | "The keymap for `org-beamer-mode'.") | |
371 | (define-key org-beamer-mode-map "\C-c\C-b" 'org-beamer-select-environment) | |
372 | ||
bdebdb64 | 373 | ;;;###autoload |
ed21c5c8 CD |
374 | (define-minor-mode org-beamer-mode |
375 | "Special support for editing Org-mode files made to export to beamer." | |
376 | nil " Bm" nil) | |
377 | (when (fboundp 'font-lock-add-keywords) | |
378 | (font-lock-add-keywords | |
379 | 'org-mode | |
380 | '((":\\(B_[a-z]+\\|BMCOL\\):" 1 'org-beamer-tag prepend)) | |
381 | 'prepent)) | |
382 | ||
383 | (defun org-beamer-place-default-actions-for-lists () | |
384 | "Find default overlay specifications in items, and move them. | |
385 | The need to be after the begin statement of the environment." | |
386 | (when org-beamer-export-is-beamer-p | |
387 | (let (dovl) | |
388 | (goto-char (point-min)) | |
389 | (while (re-search-forward | |
afe98dfa | 390 | "^[ \t]*\\\\begin{\\(itemize\\|enumerate\\|description\\)}[ \t\n]*\\\\item\\>\\( ?\\(<[^<>\n]*>\\|\\[[^][\n*]\\]\\)\\)?[ \t]*\\S-" nil t) |
ed21c5c8 CD |
391 | (if (setq dovl (cdr (assoc "BEAMER_dovl" |
392 | (get-text-property (match-end 0) | |
393 | 'org-props)))) | |
394 | (save-excursion | |
395 | (goto-char (1+ (match-end 1))) | |
396 | (insert dovl))))))) | |
397 | ||
398 | (defun org-beamer-amend-header () | |
afe98dfa | 399 | "Add `org-beamer-header-extra' to the LaTeX header. |
ed21c5c8 CD |
400 | If the file contains the string BEAMER-HEADER-EXTRA-HERE on a line |
401 | by itself, it will be replaced with `org-beamer-header-extra'. If not, | |
402 | the value will be inserted right after the documentclass statement." | |
403 | (when (and org-beamer-export-is-beamer-p | |
404 | org-beamer-header-extra) | |
405 | (goto-char (point-min)) | |
406 | (cond | |
86fbb8ca CD |
407 | ((re-search-forward |
408 | "^[ \t]*\\[?BEAMER-HEADER-EXTRA\\(-HERE\\)?\\]?[ \t]*$" nil t) | |
ed21c5c8 CD |
409 | (replace-match org-beamer-header-extra t t) |
410 | (or (bolp) (insert "\n"))) | |
86fbb8ca CD |
411 | ((re-search-forward "^[ \t]*\\\\begin{document}" nil t) |
412 | (beginning-of-line 1) | |
ed21c5c8 CD |
413 | (insert org-beamer-header-extra) |
414 | (or (bolp) (insert "\n")))))) | |
415 | ||
e66ba1df | 416 | (defcustom org-beamer-fragile-re "\\\\\\(verb\\|lstinline\\)\\|^[ \t]*\\\\begin{\\(verbatim\\|lstlisting\\|minted\\)}" |
ed21c5c8 CD |
417 | "If this regexp matches in a frame, the frame is marked as fragile." |
418 | :group 'org-beamer | |
372d7b21 | 419 | :version "24.1" |
ed21c5c8 CD |
420 | :type 'regexp) |
421 | ||
422 | (defface org-beamer-tag '((t (:box (:line-width 1 :color grey40)))) | |
423 | "The special face for beamer tags." | |
424 | :group 'org-beamer) | |
425 | ||
426 | ||
427 | ;; Functions to initialize and post-process | |
27e428e7 | 428 | ;; These functions will be hooked into various places in the export process |
ed21c5c8 CD |
429 | |
430 | (defun org-beamer-initialize-open-trackers () | |
431 | "Reset variables that track if certain environments are open during export." | |
432 | (setq org-beamer-columns-open nil) | |
433 | (setq org-beamer-column-open nil) | |
434 | (setq org-beamer-inside-frame-at-level nil) | |
435 | (setq org-beamer-export-is-beamer-p nil)) | |
436 | ||
437 | (defun org-beamer-after-initial-vars () | |
86fbb8ca | 438 | "Find special settings for beamer and store them. |
ed21c5c8 CD |
439 | The effect is that these values will be accessible during export." |
440 | ;; First verify that we are exporting using the beamer class | |
441 | (setq org-beamer-export-is-beamer-p | |
442 | (string-match "\\\\documentclass\\(\\[[^][]*?\\]\\)?{beamer}" | |
443 | org-export-latex-header)) | |
444 | (when org-beamer-export-is-beamer-p | |
445 | ;; Find the frame level | |
446 | (setq org-beamer-frame-level-now | |
447 | (or (and (org-region-active-p) | |
448 | (save-excursion | |
449 | (goto-char (region-beginning)) | |
450 | (and (looking-at org-complex-heading-regexp) | |
451 | (org-entry-get nil "BEAMER_FRAME_LEVEL" 'selective)))) | |
452 | (save-excursion | |
453 | (save-restriction | |
454 | (widen) | |
455 | (goto-char (point-min)) | |
456 | (and (re-search-forward | |
457 | "^#\\+BEAMER_FRAME_LEVEL:[ \t]*\\(.*?\\)[ \t]*$" nil t) | |
458 | (match-string 1)))) | |
459 | (plist-get org-export-latex-options-plist :beamer-frame-level) | |
460 | org-beamer-frame-level)) | |
461 | ;; Normalize the value so that the functions can trust the value | |
462 | (cond | |
463 | ((not org-beamer-frame-level-now) | |
464 | (setq org-beamer-frame-level-now nil)) | |
465 | ((stringp org-beamer-frame-level-now) | |
466 | (setq org-beamer-frame-level-now | |
467 | (string-to-number org-beamer-frame-level-now)))) | |
27e428e7 | 468 | ;; Find the header additions, most likely theme commands |
ed21c5c8 CD |
469 | (setq org-beamer-header-extra |
470 | (or (and (org-region-active-p) | |
471 | (save-excursion | |
472 | (goto-char (region-beginning)) | |
473 | (and (looking-at org-complex-heading-regexp) | |
474 | (org-entry-get nil "BEAMER_HEADER_EXTRA" | |
475 | 'selective)))) | |
476 | (save-excursion | |
477 | (save-restriction | |
478 | (widen) | |
479 | (let ((txt "")) | |
480 | (goto-char (point-min)) | |
481 | (while (re-search-forward | |
482 | "^#\\+BEAMER_HEADER_EXTRA:[ \t]*\\(.*?\\)[ \t]*$" | |
483 | nil t) | |
484 | (setq txt (concat txt "\n" (match-string 1)))) | |
485 | (if (> (length txt) 0) (substring txt 1))))) | |
486 | (plist-get org-export-latex-options-plist | |
487 | :beamer-header-extra))) | |
488 | (let ((inhibit-read-only t) | |
489 | (case-fold-search nil) | |
490 | props) | |
491 | (org-unmodified | |
492 | (remove-text-properties (point-min) (point-max) '(org-props nil)) | |
493 | (org-map-entries | |
494 | '(progn | |
495 | (setq props (org-entry-properties nil 'standard)) | |
496 | (if (and (not (assoc "BEAMER_env" props)) | |
497 | (looking-at ".*?:B_\\(note\\(NH\\)?\\):")) | |
498 | (push (cons "BEAMER_env" (match-string 1)) props)) | |
8223b1d2 BG |
499 | (when (org-bound-and-true-p org-beamer-inherited-properties) |
500 | (mapc (lambda (p) | |
501 | (unless (assoc p props) | |
502 | (let ((v (org-entry-get nil p 'inherit))) | |
503 | (and v (push (cons p v) props))))) | |
504 | org-beamer-inherited-properties)) | |
ed21c5c8 CD |
505 | (put-text-property (point-at-bol) (point-at-eol) 'org-props props))) |
506 | (setq org-export-latex-options-plist | |
507 | (plist-put org-export-latex-options-plist :tags nil)))))) | |
508 | ||
509 | (defun org-beamer-auto-fragile-frames () | |
510 | "Mark any frames containing verbatim environments as fragile. | |
86fbb8ca | 511 | This function will run in the final LaTeX document." |
ed21c5c8 CD |
512 | (when org-beamer-export-is-beamer-p |
513 | (let (opts) | |
514 | (goto-char (point-min)) | |
515 | ;; Find something that might be fragile | |
516 | (while (re-search-forward org-beamer-fragile-re nil t) | |
517 | (save-excursion | |
518 | ;; Are we inside a frame here? | |
8223b1d2 | 519 | (when (and (re-search-backward "^[ \t]*\\\\\\(begin\\|end\\){frame}\\(<[^>]*>\\)?" |
ed21c5c8 CD |
520 | nil t) |
521 | (equal (match-string 1) "begin")) | |
522 | ;; yes, inside a frame, make sure "fragile" is one of the options | |
523 | (goto-char (match-end 0)) | |
524 | (if (not (looking-at "\\[.*?\\]")) | |
525 | (insert "[fragile]") | |
526 | (setq opts (substring (match-string 0) 1 -1)) | |
527 | (delete-region (match-beginning 0) (match-end 0)) | |
528 | (setq opts (org-split-string opts ",")) | |
529 | (add-to-list 'opts "fragile") | |
530 | (insert "[" (mapconcat 'identity opts ",") "]")))))))) | |
531 | ||
532 | (defcustom org-beamer-outline-frame-title "Outline" | |
533 | "Default title of a frame containing an outline." | |
534 | :group 'org-beamer | |
372d7b21 | 535 | :version "24.1" |
ed21c5c8 | 536 | :type '(string :tag "Outline frame title") |
8223b1d2 | 537 | ) |
ed21c5c8 CD |
538 | |
539 | (defcustom org-beamer-outline-frame-options nil | |
86fbb8ca CD |
540 | "Outline frame options appended after \\begin{frame}. |
541 | You might want to put e.g. [allowframebreaks=0.9] here. Remember to | |
542 | include square brackets." | |
ed21c5c8 | 543 | :group 'org-beamer |
372d7b21 | 544 | :version "24.1" |
ed21c5c8 | 545 | :type '(string :tag "Outline frame options") |
8223b1d2 | 546 | ) |
ed21c5c8 CD |
547 | |
548 | (defun org-beamer-fix-toc () | |
549 | "Fix the table of contents by removing the vspace line." | |
550 | (when org-beamer-export-is-beamer-p | |
551 | (save-excursion | |
552 | (goto-char (point-min)) | |
553 | (when (re-search-forward "\\(\\\\setcounter{tocdepth.*\n\\\\tableofcontents.*\n\\)\\(\\\\vspace\\*.*\\)" | |
554 | nil t) | |
555 | (replace-match | |
556 | (concat "\\\\begin{frame}" org-beamer-outline-frame-options | |
557 | "\n\\\\frametitle{" | |
558 | org-beamer-outline-frame-title | |
559 | "}\n\\1\\\\end{frame}") | |
560 | t nil))))) | |
561 | ||
562 | (defun org-beamer-property-changed (property value) | |
563 | "Track the BEAMER_env property with tags." | |
564 | (cond | |
565 | ((equal property "BEAMER_env") | |
566 | (save-excursion | |
567 | (org-back-to-heading t) | |
568 | (let ((tags (org-get-tags))) | |
569 | (setq tags (delq nil (mapcar (lambda (x) | |
570 | (if (string-match "^B_" x) nil x)) | |
571 | tags))) | |
572 | (org-set-tags-to tags)) | |
573 | (when (and value (stringp value) (string-match "\\S-" value)) | |
574 | (org-toggle-tag (concat "B_" value) 'on)))) | |
575 | ((equal property "BEAMER_col") | |
576 | (org-toggle-tag "BMCOL" (if (and value (string-match "\\S-" value)) | |
577 | 'on 'off))))) | |
578 | ||
579 | (defun org-beamer-select-beamer-code () | |
580 | "Take code marked for BEAMER and turn it into marked for LaTeX." | |
581 | (when org-beamer-export-is-beamer-p | |
582 | (goto-char (point-min)) | |
583 | (while (re-search-forward | |
584 | "^\\([ \]*#\\+\\(begin_\\|end_\\)?\\)\\(beamer\\)\\>" nil t) | |
585 | (replace-match "\\1latex")))) | |
586 | ||
587 | ;; OK, hook all these functions into appropriate places | |
588 | (add-hook 'org-export-first-hook | |
589 | 'org-beamer-initialize-open-trackers) | |
590 | (add-hook 'org-property-changed-functions | |
591 | 'org-beamer-property-changed) | |
592 | (add-hook 'org-export-latex-after-initial-vars-hook | |
593 | 'org-beamer-after-initial-vars) | |
594 | (add-hook 'org-export-latex-final-hook | |
595 | 'org-beamer-place-default-actions-for-lists) | |
596 | (add-hook 'org-export-latex-final-hook | |
597 | 'org-beamer-auto-fragile-frames) | |
598 | (add-hook 'org-export-latex-final-hook | |
599 | 'org-beamer-fix-toc) | |
600 | (add-hook 'org-export-latex-final-hook | |
601 | 'org-beamer-amend-header) | |
602 | (add-hook 'org-export-preprocess-before-selecting-backend-code-hook | |
603 | 'org-beamer-select-beamer-code) | |
604 | ||
153ae947 | 605 | (defun org-insert-beamer-options-template (&optional kind) |
ed21c5c8 CD |
606 | "Insert a settings template, to make sure users do this right." |
607 | (interactive (progn | |
608 | (message "Current [s]ubtree or [g]lobal?") | |
609 | (if (equal (read-char-exclusive) ?g) | |
610 | (list 'global) | |
611 | (list 'subtree)))) | |
612 | (if (eq kind 'subtree) | |
613 | (progn | |
614 | (org-back-to-heading t) | |
615 | (org-reveal) | |
616 | (org-entry-put nil "LaTeX_CLASS" "beamer") | |
617 | (org-entry-put nil "LaTeX_CLASS_OPTIONS" "[presentation]") | |
618 | (org-entry-put nil "EXPORT_FILE_NAME" "presentation.pdf") | |
619 | (org-entry-put nil "BEAMER_FRAME_LEVEL" (number-to-string | |
620 | org-beamer-frame-level)) | |
86fbb8ca CD |
621 | (when org-beamer-themes |
622 | (org-entry-put nil "BEAMER_HEADER_EXTRA" org-beamer-themes)) | |
623 | (when org-beamer-column-view-format | |
624 | (org-entry-put nil "COLUMNS" org-beamer-column-view-format)) | |
ed21c5c8 CD |
625 | (org-entry-put nil "BEAMER_col_ALL" "0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0 :ETC")) |
626 | (insert "#+LaTeX_CLASS: beamer\n") | |
627 | (insert "#+LaTeX_CLASS_OPTIONS: [presentation]\n") | |
628 | (insert (format "#+BEAMER_FRAME_LEVEL: %d\n" org-beamer-frame-level) "\n") | |
86fbb8ca CD |
629 | (when org-beamer-themes |
630 | (insert "#+BEAMER_HEADER_EXTRA: " org-beamer-themes "\n")) | |
631 | (when org-beamer-column-view-format | |
632 | (insert "#+COLUMNS: " org-beamer-column-view-format "\n")) | |
ed21c5c8 CD |
633 | (insert "#+PROPERTY: BEAMER_col_ALL 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0 :ETC\n"))) |
634 | ||
635 | ||
636 | (defun org-beamer-allowed-property-values (property) | |
637 | "Supply allowed values for BEAMER properties." | |
638 | (cond | |
639 | ((and (equal property "BEAMER_env") | |
640 | (not (org-entry-get nil (concat property "_ALL") 'inherit))) | |
641 | ;; If no allowed values for BEAMER_env have been defined, | |
642 | ;; supply all defined environments | |
643 | (mapcar 'car (append org-beamer-environments-extra | |
644 | org-beamer-environments-default))) | |
645 | ((and (equal property "BEAMER_col") | |
646 | (not (org-entry-get nil (concat property "_ALL") 'inherit))) | |
647 | ;; If no allowed values for BEAMER_col have been defined, | |
648 | ;; supply some | |
649 | '("0.1" "0.2" "0.3" "0.4" "0.5" "0.6" "0.7" "0.8" "0.9" "" ":ETC")) | |
650 | (t nil))) | |
651 | ||
652 | (add-hook 'org-property-allowed-value-functions | |
653 | 'org-beamer-allowed-property-values) | |
654 | ||
655 | (provide 'org-beamer) | |
656 | ||
ed21c5c8 | 657 | ;;; org-beamer.el ends here |