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