Commit | Line | Data |
---|---|---|
ed21c5c8 CD |
1 | ;;; org-beamer.el --- Beamer-specific LaTeX export for org-mode |
2 | ;; | |
cbd20947 | 3 | ;; Copyright (C) 2007-2011 Free Software Foundation, Inc. |
ed21c5c8 | 4 | ;; |
3ab2c837 | 5 | ;; Version: 7.7 |
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 | |
3ab2c837 | 142 | %x the content of the BEAMER_extra property |
ed21c5c8 CD |
143 | close The closing string of the environment." |
144 | ||
145 | :group 'org-beamer | |
146 | :type '(repeat | |
147 | (list | |
148 | (string :tag "Environment") | |
149 | (string :tag "Selection key") | |
150 | (string :tag "Begin") | |
151 | (string :tag "End")))) | |
152 | ||
153 | (defvar org-beamer-frame-level-now nil) | |
154 | (defvar org-beamer-header-extra nil) | |
155 | (defvar org-beamer-export-is-beamer-p nil) | |
156 | (defvar org-beamer-inside-frame-at-level nil) | |
157 | (defvar org-beamer-columns-open nil) | |
158 | (defvar org-beamer-column-open nil) | |
159 | ||
160 | (defun org-beamer-cleanup-column-width (width) | |
161 | "Make sure the width is not empty, and that it has a unit." | |
162 | (setq width (org-trim (or width ""))) | |
163 | (unless (string-match "\\S-" width) (setq width "0.5")) | |
164 | (if (string-match "\\`[.0-9]+\\'" width) | |
165 | (setq width (concat width "\\textwidth"))) | |
166 | width) | |
167 | ||
168 | (defun org-beamer-open-column (&optional width opt) | |
169 | (org-beamer-close-column-maybe) | |
170 | (setq org-beamer-column-open t) | |
171 | (setq width (org-beamer-cleanup-column-width width)) | |
172 | (insert (format "\\begin{column}%s{%s}\n" (or opt "") width))) | |
173 | (defun org-beamer-close-column-maybe () | |
174 | (when org-beamer-column-open | |
175 | (setq org-beamer-column-open nil) | |
176 | (insert "\\end{column}\n"))) | |
177 | (defun org-beamer-open-columns-maybe (&optional opts) | |
178 | (unless org-beamer-columns-open | |
179 | (setq org-beamer-columns-open t) | |
180 | (insert (format "\\begin{columns}%s\n" (or opts ""))))) | |
181 | (defun org-beamer-close-columns-maybe () | |
182 | (org-beamer-close-column-maybe) | |
183 | (when org-beamer-columns-open | |
184 | (setq org-beamer-columns-open nil) | |
185 | (insert "\\end{columns}\n"))) | |
186 | ||
187 | (defun org-beamer-select-environment () | |
188 | "Select the environment to be used by beamer for this entry. | |
86fbb8ca | 189 | While this uses (for convenience) a tag selection interface, the result |
ed21c5c8 CD |
190 | of this command will be that the BEAMER_env *property* of the entry is set. |
191 | ||
192 | In addition to this, the command will also set a tag as a visual aid, but | |
193 | the tag does not have any semantic meaning." | |
194 | (interactive) | |
195 | (let* ((envs (append org-beamer-environments-extra | |
196 | org-beamer-environments-default)) | |
197 | (org-tag-alist | |
198 | (append '((:startgroup)) | |
199 | (mapcar (lambda (e) (cons (concat "B_" (car e)) | |
200 | (string-to-char (nth 1 e)))) | |
201 | envs) | |
202 | '((:endgroup)) | |
203 | '(("BMCOL" . ?|)))) | |
204 | (org-fast-tag-selection-single-key t)) | |
205 | (org-set-tags) | |
206 | (let ((tags (or (ignore-errors (org-get-tags-string)) ""))) | |
207 | (cond | |
208 | ((equal org-last-tag-selection-key ?|) | |
209 | (if (string-match ":BMCOL:" tags) | |
210 | (org-set-property "BEAMER_col" (read-string "Column width: ")) | |
211 | (org-delete-property "BEAMER_col"))) | |
212 | ((string-match (concat ":B_\\(" | |
213 | (mapconcat 'car envs "\\|") | |
214 | "\\):") | |
215 | tags) | |
216 | (org-entry-put nil "BEAMER_env" (match-string 1 tags))) | |
217 | (t (org-entry-delete nil "BEAMER_env")))))) | |
218 | ||
219 | ||
220 | (defun org-beamer-sectioning (level text) | |
221 | "Return the sectioning entry for the current headline. | |
222 | LEVEL is the reduced level of the headline. | |
223 | TEXT is the text of the headline, everything except the leading stars. | |
224 | The return value is a cons cell. The car is the headline text, usually | |
225 | just TEXT, but possibly modified if options have been extracted from the | |
226 | text. The cdr is the sectioning entry, similar to what is given | |
227 | in org-export-latex-classes." | |
228 | (let* ((frame-level (or org-beamer-frame-level-now org-beamer-frame-level)) | |
229 | (default | |
230 | (if org-beamer-use-parts | |
231 | '((1 . ("\\part{%s}" . "\\part*{%s}")) | |
232 | (2 . ("\\section{%s}" . "\\section*{%s}")) | |
233 | (3 . ("\\subsection{%s}" . "\\subsection*{%s}"))) | |
234 | '((1 . ("\\section{%s}" . "\\section*{%s}")) | |
235 | (2 . ("\\subsection{%s}" . "\\subsection*{%s}"))))) | |
236 | (envs (append org-beamer-environments-extra | |
237 | org-beamer-environments-default)) | |
238 | (props (org-get-text-property-any 0 'org-props text)) | |
239 | (in "") (out "") option action defaction environment extra | |
240 | columns-option column-option | |
241 | env have-text ass tmp) | |
242 | (if (= frame-level 0) (setq frame-level nil)) | |
243 | (when (and org-beamer-inside-frame-at-level | |
244 | (<= level org-beamer-inside-frame-at-level)) | |
245 | (setq org-beamer-inside-frame-at-level nil)) | |
246 | (when (setq tmp (org-beamer-assoc-not-empty "BEAMER_col" props)) | |
247 | (if (and (string-match "\\`[0-9.]+\\'" tmp) | |
248 | (or (= (string-to-number tmp) 1.0) | |
249 | (= (string-to-number tmp) 0.0))) | |
acedf35c | 250 | ;; column width 1 means close columns, go back to full width |
ed21c5c8 CD |
251 | (org-beamer-close-columns-maybe) |
252 | (when (setq ass (assoc "BEAMER_envargs" props)) | |
253 | (let (case-fold-search) | |
acedf35c | 254 | (while (string-match "C\\(\\[[^][]*\\]\\|<[^<>]*>\\)" (cdr ass)) |
ed21c5c8 CD |
255 | (setq columns-option (match-string 1 (cdr ass))) |
256 | (setcdr ass (replace-match "" t t (cdr ass)))) | |
acedf35c | 257 | (while (string-match "c\\(\\[[^][]*\\]\\|<[^<>]*>\\)" (cdr ass)) |
ed21c5c8 CD |
258 | (setq column-option (match-string 1 (cdr ass))) |
259 | (setcdr ass (replace-match "" t t (cdr ass)))))) | |
260 | (org-beamer-open-columns-maybe columns-option) | |
261 | (org-beamer-open-column tmp column-option))) | |
262 | (cond | |
263 | ((or (equal (cdr (assoc "BEAMER_env" props)) "frame") | |
264 | (and frame-level (= level frame-level))) | |
265 | ;; A frame | |
266 | (org-beamer-get-special props) | |
267 | ||
268 | (setq in (org-fill-template | |
269 | "\\begin{frame}%a%A%o%T%S%x" | |
270 | (list (cons "a" (or action "")) | |
271 | (cons "A" (or defaction "")) | |
272 | (cons "o" (or option org-beamer-frame-default-options "")) | |
273 | (cons "x" (if extra (concat "\n" extra) "")) | |
274 | (cons "h" "%s") | |
275 | (cons "T" (if (string-match "\\S-" text) | |
276 | "\n\\frametitle{%s}" "")) | |
277 | (cons "S" (if (string-match "\\\\\\\\" text) | |
278 | "\n\\framesubtitle{%s}" "")))) | |
279 | out (copy-sequence "\\end{frame}")) | |
280 | (org-add-props out | |
281 | '(org-insert-hook org-beamer-close-columns-maybe)) | |
282 | (setq org-beamer-inside-frame-at-level level) | |
283 | (cons text (list in out in out))) | |
284 | ((and (setq env (cdr (assoc "BEAMER_env" props))) | |
285 | (setq ass (assoc env envs))) | |
286 | ;; A beamer environment selected by the BEAMER_env property | |
287 | (if (string-match "[ \t]+:[ \t]*$" text) | |
288 | (setq text (replace-match "" t t text))) | |
289 | (if (member env '("note" "noteNH")) | |
290 | ;; There should be no labels in a note, so we remove the targets | |
291 | ;; FIXME??? | |
292 | (remove-text-properties 0 (length text) '(target nil) text)) | |
293 | (org-beamer-get-special props) | |
294 | (setq text (org-trim text)) | |
295 | (setq have-text (string-match "\\S-" text)) | |
296 | (setq in (org-fill-template | |
297 | (nth 2 ass) | |
298 | (list (cons "a" (or action "")) | |
299 | (cons "A" (or defaction "")) | |
300 | (cons "o" (or option "")) | |
301 | (cons "x" (if extra (concat "\n" extra) "")) | |
302 | (cons "h" "%s") | |
303 | (cons "H" (if have-text (concat "{" text "}") "")) | |
304 | (cons "U" (if have-text (concat "[" text "]") "")))) | |
305 | out (nth 3 ass)) | |
306 | (cond | |
307 | ((equal out "\\end{columns}") | |
308 | (setq org-beamer-columns-open t) | |
309 | (setq out (org-add-props (copy-sequence out) | |
310 | '(org-insert-hook | |
311 | (lambda () | |
312 | (org-beamer-close-column-maybe) | |
313 | (setq org-beamer-columns-open nil)))))) | |
314 | ((equal out "\\end{column}") | |
315 | (org-beamer-open-columns-maybe))) | |
316 | (cons text (list in out in out))) | |
317 | ((and (not org-beamer-inside-frame-at-level) | |
318 | (or (not frame-level) | |
319 | (< level frame-level)) | |
320 | (assoc level default)) | |
321 | ;; Normal sectioning | |
322 | (cons text (cdr (assoc level default)))) | |
323 | (t nil)))) | |
324 | ||
325 | (defvar extra) | |
326 | (defvar option) | |
327 | (defvar action) | |
328 | (defvar defaction) | |
329 | (defvar environment) | |
330 | (defun org-beamer-get-special (props) | |
331 | "Extract an option, action, and default action string from text. | |
332 | The variables option, action, defaction, extra are all scoped into | |
333 | this function dynamically." | |
334 | (let (tmp) | |
335 | (setq environment (org-beamer-assoc-not-empty "BEAMER_env" props)) | |
336 | (setq extra (org-beamer-assoc-not-empty "BEAMER_extra" props)) | |
337 | (when extra | |
338 | (setq extra (replace-regexp-in-string "\\\\n" "\n" extra))) | |
339 | (setq tmp (org-beamer-assoc-not-empty "BEAMER_envargs" props)) | |
340 | (when tmp | |
341 | (setq tmp (copy-sequence tmp)) | |
342 | (if (string-match "\\[<[^][<>]*>\\]" tmp) | |
343 | (setq defaction (match-string 0 tmp) | |
344 | tmp (replace-match "" t t tmp))) | |
345 | (if (string-match "\\[[^][]*\\]" tmp) | |
346 | (setq option (match-string 0 tmp) | |
347 | tmp (replace-match "" t t tmp))) | |
348 | (if (string-match "<[^<>]*>" tmp) | |
349 | (setq action (match-string 0 tmp) | |
350 | tmp (replace-match "" t t tmp)))))) | |
351 | ||
352 | (defun org-beamer-assoc-not-empty (elt list) | |
353 | (let ((tmp (cdr (assoc elt list)))) | |
354 | (and tmp (string-match "\\S-" tmp) tmp))) | |
355 | ||
356 | ||
357 | (defvar org-beamer-mode-map (make-sparse-keymap) | |
358 | "The keymap for `org-beamer-mode'.") | |
359 | (define-key org-beamer-mode-map "\C-c\C-b" 'org-beamer-select-environment) | |
360 | ||
361 | (define-minor-mode org-beamer-mode | |
362 | "Special support for editing Org-mode files made to export to beamer." | |
363 | nil " Bm" nil) | |
364 | (when (fboundp 'font-lock-add-keywords) | |
365 | (font-lock-add-keywords | |
366 | 'org-mode | |
367 | '((":\\(B_[a-z]+\\|BMCOL\\):" 1 'org-beamer-tag prepend)) | |
368 | 'prepent)) | |
369 | ||
370 | (defun org-beamer-place-default-actions-for-lists () | |
371 | "Find default overlay specifications in items, and move them. | |
372 | The need to be after the begin statement of the environment." | |
373 | (when org-beamer-export-is-beamer-p | |
374 | (let (dovl) | |
375 | (goto-char (point-min)) | |
376 | (while (re-search-forward | |
afe98dfa | 377 | "^[ \t]*\\\\begin{\\(itemize\\|enumerate\\|description\\)}[ \t\n]*\\\\item\\>\\( ?\\(<[^<>\n]*>\\|\\[[^][\n*]\\]\\)\\)?[ \t]*\\S-" nil t) |
ed21c5c8 CD |
378 | (if (setq dovl (cdr (assoc "BEAMER_dovl" |
379 | (get-text-property (match-end 0) | |
380 | 'org-props)))) | |
381 | (save-excursion | |
382 | (goto-char (1+ (match-end 1))) | |
383 | (insert dovl))))))) | |
384 | ||
385 | (defun org-beamer-amend-header () | |
afe98dfa | 386 | "Add `org-beamer-header-extra' to the LaTeX header. |
ed21c5c8 CD |
387 | If the file contains the string BEAMER-HEADER-EXTRA-HERE on a line |
388 | by itself, it will be replaced with `org-beamer-header-extra'. If not, | |
389 | the value will be inserted right after the documentclass statement." | |
390 | (when (and org-beamer-export-is-beamer-p | |
391 | org-beamer-header-extra) | |
392 | (goto-char (point-min)) | |
393 | (cond | |
86fbb8ca CD |
394 | ((re-search-forward |
395 | "^[ \t]*\\[?BEAMER-HEADER-EXTRA\\(-HERE\\)?\\]?[ \t]*$" nil t) | |
ed21c5c8 CD |
396 | (replace-match org-beamer-header-extra t t) |
397 | (or (bolp) (insert "\n"))) | |
86fbb8ca CD |
398 | ((re-search-forward "^[ \t]*\\\\begin{document}" nil t) |
399 | (beginning-of-line 1) | |
ed21c5c8 CD |
400 | (insert org-beamer-header-extra) |
401 | (or (bolp) (insert "\n")))))) | |
402 | ||
3ab2c837 | 403 | (defcustom org-beamer-fragile-re "^[ \t]*\\\\begin{\\(verbatim\\|lstlisting\\|minted\\)}" |
ed21c5c8 CD |
404 | "If this regexp matches in a frame, the frame is marked as fragile." |
405 | :group 'org-beamer | |
406 | :type 'regexp) | |
407 | ||
408 | (defface org-beamer-tag '((t (:box (:line-width 1 :color grey40)))) | |
409 | "The special face for beamer tags." | |
410 | :group 'org-beamer) | |
411 | ||
412 | ||
413 | ;; Functions to initialize and post-process | |
414 | ;; These fuctions will be hooked into various places in the export process | |
415 | ||
416 | (defun org-beamer-initialize-open-trackers () | |
417 | "Reset variables that track if certain environments are open during export." | |
418 | (setq org-beamer-columns-open nil) | |
419 | (setq org-beamer-column-open nil) | |
420 | (setq org-beamer-inside-frame-at-level nil) | |
421 | (setq org-beamer-export-is-beamer-p nil)) | |
422 | ||
423 | (defun org-beamer-after-initial-vars () | |
86fbb8ca | 424 | "Find special settings for beamer and store them. |
ed21c5c8 CD |
425 | The effect is that these values will be accessible during export." |
426 | ;; First verify that we are exporting using the beamer class | |
427 | (setq org-beamer-export-is-beamer-p | |
428 | (string-match "\\\\documentclass\\(\\[[^][]*?\\]\\)?{beamer}" | |
429 | org-export-latex-header)) | |
430 | (when org-beamer-export-is-beamer-p | |
431 | ;; Find the frame level | |
432 | (setq org-beamer-frame-level-now | |
433 | (or (and (org-region-active-p) | |
434 | (save-excursion | |
435 | (goto-char (region-beginning)) | |
436 | (and (looking-at org-complex-heading-regexp) | |
437 | (org-entry-get nil "BEAMER_FRAME_LEVEL" 'selective)))) | |
438 | (save-excursion | |
439 | (save-restriction | |
440 | (widen) | |
441 | (goto-char (point-min)) | |
442 | (and (re-search-forward | |
443 | "^#\\+BEAMER_FRAME_LEVEL:[ \t]*\\(.*?\\)[ \t]*$" nil t) | |
444 | (match-string 1)))) | |
445 | (plist-get org-export-latex-options-plist :beamer-frame-level) | |
446 | org-beamer-frame-level)) | |
447 | ;; Normalize the value so that the functions can trust the value | |
448 | (cond | |
449 | ((not org-beamer-frame-level-now) | |
450 | (setq org-beamer-frame-level-now nil)) | |
451 | ((stringp org-beamer-frame-level-now) | |
452 | (setq org-beamer-frame-level-now | |
453 | (string-to-number org-beamer-frame-level-now)))) | |
91af3942 | 454 | ;; Find the header additions, most likely theme commands |
ed21c5c8 CD |
455 | (setq org-beamer-header-extra |
456 | (or (and (org-region-active-p) | |
457 | (save-excursion | |
458 | (goto-char (region-beginning)) | |
459 | (and (looking-at org-complex-heading-regexp) | |
460 | (org-entry-get nil "BEAMER_HEADER_EXTRA" | |
461 | 'selective)))) | |
462 | (save-excursion | |
463 | (save-restriction | |
464 | (widen) | |
465 | (let ((txt "")) | |
466 | (goto-char (point-min)) | |
467 | (while (re-search-forward | |
468 | "^#\\+BEAMER_HEADER_EXTRA:[ \t]*\\(.*?\\)[ \t]*$" | |
469 | nil t) | |
470 | (setq txt (concat txt "\n" (match-string 1)))) | |
471 | (if (> (length txt) 0) (substring txt 1))))) | |
472 | (plist-get org-export-latex-options-plist | |
473 | :beamer-header-extra))) | |
474 | (let ((inhibit-read-only t) | |
475 | (case-fold-search nil) | |
476 | props) | |
477 | (org-unmodified | |
478 | (remove-text-properties (point-min) (point-max) '(org-props nil)) | |
479 | (org-map-entries | |
480 | '(progn | |
481 | (setq props (org-entry-properties nil 'standard)) | |
482 | (if (and (not (assoc "BEAMER_env" props)) | |
483 | (looking-at ".*?:B_\\(note\\(NH\\)?\\):")) | |
484 | (push (cons "BEAMER_env" (match-string 1)) props)) | |
485 | (put-text-property (point-at-bol) (point-at-eol) 'org-props props))) | |
486 | (setq org-export-latex-options-plist | |
487 | (plist-put org-export-latex-options-plist :tags nil)))))) | |
488 | ||
489 | (defun org-beamer-auto-fragile-frames () | |
490 | "Mark any frames containing verbatim environments as fragile. | |
86fbb8ca | 491 | This function will run in the final LaTeX document." |
ed21c5c8 CD |
492 | (when org-beamer-export-is-beamer-p |
493 | (let (opts) | |
494 | (goto-char (point-min)) | |
495 | ;; Find something that might be fragile | |
496 | (while (re-search-forward org-beamer-fragile-re nil t) | |
497 | (save-excursion | |
498 | ;; Are we inside a frame here? | |
499 | (when (and (re-search-backward "^[ \t]*\\\\\\(begin\\|end\\){frame}" | |
500 | nil t) | |
501 | (equal (match-string 1) "begin")) | |
502 | ;; yes, inside a frame, make sure "fragile" is one of the options | |
503 | (goto-char (match-end 0)) | |
504 | (if (not (looking-at "\\[.*?\\]")) | |
505 | (insert "[fragile]") | |
506 | (setq opts (substring (match-string 0) 1 -1)) | |
507 | (delete-region (match-beginning 0) (match-end 0)) | |
508 | (setq opts (org-split-string opts ",")) | |
509 | (add-to-list 'opts "fragile") | |
510 | (insert "[" (mapconcat 'identity opts ",") "]")))))))) | |
511 | ||
512 | (defcustom org-beamer-outline-frame-title "Outline" | |
513 | "Default title of a frame containing an outline." | |
514 | :group 'org-beamer | |
515 | :type '(string :tag "Outline frame title") | |
516 | ) | |
517 | ||
518 | (defcustom org-beamer-outline-frame-options nil | |
86fbb8ca CD |
519 | "Outline frame options appended after \\begin{frame}. |
520 | You might want to put e.g. [allowframebreaks=0.9] here. Remember to | |
521 | include square brackets." | |
ed21c5c8 CD |
522 | :group 'org-beamer |
523 | :type '(string :tag "Outline frame options") | |
524 | ) | |
525 | ||
526 | (defun org-beamer-fix-toc () | |
527 | "Fix the table of contents by removing the vspace line." | |
528 | (when org-beamer-export-is-beamer-p | |
529 | (save-excursion | |
530 | (goto-char (point-min)) | |
531 | (when (re-search-forward "\\(\\\\setcounter{tocdepth.*\n\\\\tableofcontents.*\n\\)\\(\\\\vspace\\*.*\\)" | |
532 | nil t) | |
533 | (replace-match | |
534 | (concat "\\\\begin{frame}" org-beamer-outline-frame-options | |
535 | "\n\\\\frametitle{" | |
536 | org-beamer-outline-frame-title | |
537 | "}\n\\1\\\\end{frame}") | |
538 | t nil))))) | |
539 | ||
540 | (defun org-beamer-property-changed (property value) | |
541 | "Track the BEAMER_env property with tags." | |
542 | (cond | |
543 | ((equal property "BEAMER_env") | |
544 | (save-excursion | |
545 | (org-back-to-heading t) | |
546 | (let ((tags (org-get-tags))) | |
547 | (setq tags (delq nil (mapcar (lambda (x) | |
548 | (if (string-match "^B_" x) nil x)) | |
549 | tags))) | |
550 | (org-set-tags-to tags)) | |
551 | (when (and value (stringp value) (string-match "\\S-" value)) | |
552 | (org-toggle-tag (concat "B_" value) 'on)))) | |
553 | ((equal property "BEAMER_col") | |
554 | (org-toggle-tag "BMCOL" (if (and value (string-match "\\S-" value)) | |
555 | 'on 'off))))) | |
556 | ||
557 | (defun org-beamer-select-beamer-code () | |
558 | "Take code marked for BEAMER and turn it into marked for LaTeX." | |
559 | (when org-beamer-export-is-beamer-p | |
560 | (goto-char (point-min)) | |
561 | (while (re-search-forward | |
562 | "^\\([ \]*#\\+\\(begin_\\|end_\\)?\\)\\(beamer\\)\\>" nil t) | |
563 | (replace-match "\\1latex")))) | |
564 | ||
565 | ;; OK, hook all these functions into appropriate places | |
566 | (add-hook 'org-export-first-hook | |
567 | 'org-beamer-initialize-open-trackers) | |
568 | (add-hook 'org-property-changed-functions | |
569 | 'org-beamer-property-changed) | |
570 | (add-hook 'org-export-latex-after-initial-vars-hook | |
571 | 'org-beamer-after-initial-vars) | |
572 | (add-hook 'org-export-latex-final-hook | |
573 | 'org-beamer-place-default-actions-for-lists) | |
574 | (add-hook 'org-export-latex-final-hook | |
575 | 'org-beamer-auto-fragile-frames) | |
576 | (add-hook 'org-export-latex-final-hook | |
577 | 'org-beamer-fix-toc) | |
578 | (add-hook 'org-export-latex-final-hook | |
579 | 'org-beamer-amend-header) | |
580 | (add-hook 'org-export-preprocess-before-selecting-backend-code-hook | |
581 | 'org-beamer-select-beamer-code) | |
582 | ||
86fbb8ca | 583 | (defun org-insert-beamer-options-template (kind) |
ed21c5c8 CD |
584 | "Insert a settings template, to make sure users do this right." |
585 | (interactive (progn | |
586 | (message "Current [s]ubtree or [g]lobal?") | |
587 | (if (equal (read-char-exclusive) ?g) | |
588 | (list 'global) | |
589 | (list 'subtree)))) | |
590 | (if (eq kind 'subtree) | |
591 | (progn | |
592 | (org-back-to-heading t) | |
593 | (org-reveal) | |
594 | (org-entry-put nil "LaTeX_CLASS" "beamer") | |
595 | (org-entry-put nil "LaTeX_CLASS_OPTIONS" "[presentation]") | |
596 | (org-entry-put nil "EXPORT_FILE_NAME" "presentation.pdf") | |
597 | (org-entry-put nil "BEAMER_FRAME_LEVEL" (number-to-string | |
598 | org-beamer-frame-level)) | |
86fbb8ca CD |
599 | (when org-beamer-themes |
600 | (org-entry-put nil "BEAMER_HEADER_EXTRA" org-beamer-themes)) | |
601 | (when org-beamer-column-view-format | |
602 | (org-entry-put nil "COLUMNS" org-beamer-column-view-format)) | |
ed21c5c8 CD |
603 | (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")) |
604 | (insert "#+LaTeX_CLASS: beamer\n") | |
605 | (insert "#+LaTeX_CLASS_OPTIONS: [presentation]\n") | |
606 | (insert (format "#+BEAMER_FRAME_LEVEL: %d\n" org-beamer-frame-level) "\n") | |
86fbb8ca CD |
607 | (when org-beamer-themes |
608 | (insert "#+BEAMER_HEADER_EXTRA: " org-beamer-themes "\n")) | |
609 | (when org-beamer-column-view-format | |
610 | (insert "#+COLUMNS: " org-beamer-column-view-format "\n")) | |
ed21c5c8 CD |
611 | (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"))) |
612 | ||
613 | ||
614 | (defun org-beamer-allowed-property-values (property) | |
615 | "Supply allowed values for BEAMER properties." | |
616 | (cond | |
617 | ((and (equal property "BEAMER_env") | |
618 | (not (org-entry-get nil (concat property "_ALL") 'inherit))) | |
619 | ;; If no allowed values for BEAMER_env have been defined, | |
620 | ;; supply all defined environments | |
621 | (mapcar 'car (append org-beamer-environments-extra | |
622 | org-beamer-environments-default))) | |
623 | ((and (equal property "BEAMER_col") | |
624 | (not (org-entry-get nil (concat property "_ALL") 'inherit))) | |
625 | ;; If no allowed values for BEAMER_col have been defined, | |
626 | ;; supply some | |
627 | '("0.1" "0.2" "0.3" "0.4" "0.5" "0.6" "0.7" "0.8" "0.9" "" ":ETC")) | |
628 | (t nil))) | |
629 | ||
630 | (add-hook 'org-property-allowed-value-functions | |
631 | 'org-beamer-allowed-property-values) | |
632 | ||
633 | (provide 'org-beamer) | |
634 | ||
5b409b39 | 635 | |
ed21c5c8 CD |
636 | |
637 | ;;; org-beamer.el ends here |