Commit | Line | Data |
---|---|---|
271672fa BG |
1 | ;;; ox-beamer.el --- Beamer Back-End for Org Export Engine |
2 | ||
ba318903 | 3 | ;; Copyright (C) 2007-2014 Free Software Foundation, Inc. |
271672fa BG |
4 | |
5 | ;; Author: Carsten Dominik <carsten.dominik AT gmail DOT com> | |
6 | ;; Nicolas Goaziou <n.goaziou AT gmail DOT com> | |
7 | ;; Keywords: org, wp, tex | |
8 | ||
439d6b1c GM |
9 | ;; This file is part of GNU Emacs. |
10 | ||
271672fa BG |
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 implements both a Beamer back-end, derived from the | |
27 | ;; LaTeX one and a minor mode easing structure edition of the | |
28 | ;; document. See Org manual for more information. | |
29 | ||
30 | ;;; Code: | |
31 | ||
32 | (eval-when-compile (require 'cl)) | |
33 | (require 'ox-latex) | |
34 | ||
35 | ;; Install a default set-up for Beamer export. | |
36 | (unless (assoc "beamer" org-latex-classes) | |
37 | (add-to-list 'org-latex-classes | |
38 | '("beamer" | |
30cb51f1 | 39 | "\\documentclass[presentation]{beamer}" |
271672fa BG |
40 | ("\\section{%s}" . "\\section*{%s}") |
41 | ("\\subsection{%s}" . "\\subsection*{%s}") | |
42 | ("\\subsubsection{%s}" . "\\subsubsection*{%s}")))) | |
43 | ||
44 | ||
45 | \f | |
46 | ;;; User-Configurable Variables | |
47 | ||
48 | (defgroup org-export-beamer nil | |
49 | "Options specific for using the beamer class in LaTeX export." | |
50 | :tag "Org Beamer" | |
51 | :group 'org-export | |
52 | :version "24.2") | |
53 | ||
54 | (defcustom org-beamer-frame-level 1 | |
55 | "The level at which headlines become frames. | |
56 | ||
57 | Headlines at a lower level will be translated into a sectioning | |
58 | structure. At a higher level, they will be translated into | |
59 | blocks. | |
60 | ||
61 | If a headline with a \"BEAMER_env\" property set to \"frame\" is | |
62 | found within a tree, its level locally overrides this number. | |
63 | ||
64 | This variable has no effect on headlines with the \"BEAMER_env\" | |
65 | property set to either \"ignoreheading\", \"appendix\", or | |
66 | \"note\", which will respectively, be invisible, become an | |
67 | appendix or a note. | |
68 | ||
69 | This integer is relative to the minimal level of a headline | |
70 | within the parse tree, defined as 1." | |
71 | :group 'org-export-beamer | |
72 | :type 'integer) | |
73 | ||
74 | (defcustom org-beamer-frame-default-options "" | |
75 | "Default options string to use for frames. | |
76 | For example, it could be set to \"allowframebreaks\"." | |
77 | :group 'org-export-beamer | |
78 | :type '(string :tag "[options]")) | |
79 | ||
80 | (defcustom org-beamer-column-view-format | |
81 | "%45ITEM %10BEAMER_env(Env) %10BEAMER_act(Act) %4BEAMER_col(Col) %8BEAMER_opt(Opt)" | |
82 | "Column view format that should be used to fill the template." | |
83 | :group 'org-export-beamer | |
84 | :version "24.4" | |
85 | :package-version '(Org . "8.0") | |
86 | :type '(choice | |
87 | (const :tag "Do not insert Beamer column view format" nil) | |
88 | (string :tag "Beamer column view format"))) | |
89 | ||
90 | (defcustom org-beamer-theme "default" | |
91 | "Default theme used in Beamer presentations." | |
92 | :group 'org-export-beamer | |
93 | :version "24.4" | |
94 | :package-version '(Org . "8.0") | |
95 | :type '(choice | |
96 | (const :tag "Do not insert a Beamer theme" nil) | |
97 | (string :tag "Beamer theme"))) | |
98 | ||
99 | (defcustom org-beamer-environments-extra nil | |
100 | "Environments triggered by tags in Beamer export. | |
101 | Each entry has 4 elements: | |
102 | ||
103 | name Name of the environment | |
104 | key Selection key for `org-beamer-select-environment' | |
105 | open The opening template for the environment, with the following escapes | |
106 | %a the action/overlay specification | |
107 | %A the default action/overlay specification | |
108 | %o the options argument of the template | |
109 | %h the headline text | |
110 | %r the raw headline text (i.e. without any processing) | |
111 | %H if there is headline text, that raw text in {} braces | |
112 | %U if there is headline text, that raw text in [] brackets | |
113 | close The closing string of the environment." | |
114 | :group 'org-export-beamer | |
115 | :version "24.4" | |
116 | :package-version '(Org . "8.1") | |
117 | :type '(repeat | |
118 | (list | |
119 | (string :tag "Environment") | |
120 | (string :tag "Selection key") | |
121 | (string :tag "Begin") | |
122 | (string :tag "End")))) | |
123 | ||
124 | (defcustom org-beamer-outline-frame-title "Outline" | |
125 | "Default title of a frame containing an outline." | |
126 | :group 'org-export-beamer | |
127 | :type '(string :tag "Outline frame title")) | |
128 | ||
129 | (defcustom org-beamer-outline-frame-options "" | |
130 | "Outline frame options appended after \\begin{frame}. | |
131 | You might want to put e.g. \"allowframebreaks=0.9\" here." | |
132 | :group 'org-export-beamer | |
133 | :type '(string :tag "Outline frame options")) | |
134 | ||
135 | ||
136 | \f | |
137 | ;;; Internal Variables | |
138 | ||
139 | (defconst org-beamer-column-widths | |
140 | "0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 0.0 :ETC" | |
141 | "The column widths that should be installed as allowed property values.") | |
142 | ||
143 | (defconst org-beamer-environments-special | |
144 | '(("againframe" "A") | |
145 | ("appendix" "x") | |
146 | ("column" "c") | |
147 | ("columns" "C") | |
148 | ("frame" "f") | |
149 | ("fullframe" "F") | |
150 | ("ignoreheading" "i") | |
151 | ("note" "n") | |
152 | ("noteNH" "N")) | |
153 | "Alist of environments treated in a special way by the back-end. | |
154 | Keys are environment names, as strings, values are bindings used | |
155 | in `org-beamer-select-environment'. Environments listed here, | |
156 | along with their binding, are hard coded and cannot be modified | |
157 | through `org-beamer-environments-extra' variable.") | |
158 | ||
159 | (defconst org-beamer-environments-default | |
160 | '(("block" "b" "\\begin{block}%a{%h}" "\\end{block}") | |
161 | ("alertblock" "a" "\\begin{alertblock}%a{%h}" "\\end{alertblock}") | |
162 | ("verse" "v" "\\begin{verse}%a %% %h" "\\end{verse}") | |
163 | ("quotation" "q" "\\begin{quotation}%a %% %h" "\\end{quotation}") | |
164 | ("quote" "Q" "\\begin{quote}%a %% %h" "\\end{quote}") | |
165 | ("structureenv" "s" "\\begin{structureenv}%a %% %h" "\\end{structureenv}") | |
166 | ("theorem" "t" "\\begin{theorem}%a%U" "\\end{theorem}") | |
167 | ("definition" "d" "\\begin{definition}%a%U" "\\end{definition}") | |
168 | ("example" "e" "\\begin{example}%a%U" "\\end{example}") | |
169 | ("exampleblock" "E" "\\begin{exampleblock}%a{%h}" "\\end{exampleblock}") | |
170 | ("proof" "p" "\\begin{proof}%a%U" "\\end{proof}") | |
171 | ("beamercolorbox" "o" "\\begin{beamercolorbox}%o{%h}" "\\end{beamercolorbox}")) | |
172 | "Environments triggered by properties in Beamer export. | |
173 | These are the defaults - for user definitions, see | |
174 | `org-beamer-environments-extra'.") | |
175 | ||
176 | (defconst org-beamer-verbatim-elements | |
177 | '(code example-block fixed-width inline-src-block src-block verbatim) | |
178 | "List of element or object types producing verbatim text. | |
179 | This is used internally to determine when a frame should have the | |
180 | \"fragile\" option.") | |
181 | ||
182 | ||
183 | \f | |
184 | ;;; Internal functions | |
185 | ||
186 | (defun org-beamer--normalize-argument (argument type) | |
187 | "Return ARGUMENT string with proper boundaries. | |
188 | ||
189 | TYPE is a symbol among the following: | |
190 | `action' Return ARGUMENT within angular brackets. | |
191 | `defaction' Return ARGUMENT within both square and angular brackets. | |
192 | `option' Return ARGUMENT within square brackets." | |
193 | (if (not (string-match "\\S-" argument)) "" | |
194 | (case type | |
195 | (action (if (string-match "\\`<.*>\\'" argument) argument | |
196 | (format "<%s>" argument))) | |
197 | (defaction (cond | |
198 | ((string-match "\\`\\[<.*>\\]\\'" argument) argument) | |
199 | ((string-match "\\`<.*>\\'" argument) | |
200 | (format "[%s]" argument)) | |
201 | ((string-match "\\`\\[\\(.*\\)\\]\\'" argument) | |
202 | (format "[<%s>]" (match-string 1 argument))) | |
203 | (t (format "[<%s>]" argument)))) | |
204 | (option (if (string-match "\\`\\[.*\\]\\'" argument) argument | |
205 | (format "[%s]" argument))) | |
206 | (otherwise argument)))) | |
207 | ||
208 | (defun org-beamer--element-has-overlay-p (element) | |
209 | "Non-nil when ELEMENT has an overlay specified. | |
210 | An element has an overlay specification when it starts with an | |
211 | `beamer' export-snippet whose value is between angular brackets. | |
212 | Return overlay specification, as a string, or nil." | |
213 | (let ((first-object (car (org-element-contents element)))) | |
214 | (when (eq (org-element-type first-object) 'export-snippet) | |
215 | (let ((value (org-element-property :value first-object))) | |
216 | (and (string-match "\\`<.*>\\'" value) value))))) | |
217 | ||
218 | ||
219 | \f | |
220 | ;;; Define Back-End | |
221 | ||
222 | (org-export-define-derived-backend 'beamer 'latex | |
223 | :export-block "BEAMER" | |
224 | :menu-entry | |
225 | '(?l 1 | |
226 | ((?B "As LaTeX buffer (Beamer)" org-beamer-export-as-latex) | |
227 | (?b "As LaTeX file (Beamer)" org-beamer-export-to-latex) | |
228 | (?P "As PDF file (Beamer)" org-beamer-export-to-pdf) | |
229 | (?O "As PDF file and open (Beamer)" | |
230 | (lambda (a s v b) | |
231 | (if a (org-beamer-export-to-pdf t s v b) | |
232 | (org-open-file (org-beamer-export-to-pdf nil s v b))))))) | |
233 | :options-alist | |
234 | '((:beamer-theme "BEAMER_THEME" nil org-beamer-theme) | |
235 | (:beamer-color-theme "BEAMER_COLOR_THEME" nil nil t) | |
236 | (:beamer-font-theme "BEAMER_FONT_THEME" nil nil t) | |
237 | (:beamer-inner-theme "BEAMER_INNER_THEME" nil nil t) | |
238 | (:beamer-outer-theme "BEAMER_OUTER_THEME" nil nil t) | |
239 | (:beamer-header-extra "BEAMER_HEADER" nil nil newline) | |
240 | ;; Modify existing properties. | |
241 | (:headline-levels nil "H" org-beamer-frame-level) | |
242 | (:latex-class "LATEX_CLASS" nil "beamer" t)) | |
243 | :translate-alist '((bold . org-beamer-bold) | |
244 | (export-block . org-beamer-export-block) | |
245 | (export-snippet . org-beamer-export-snippet) | |
246 | (headline . org-beamer-headline) | |
247 | (item . org-beamer-item) | |
248 | (keyword . org-beamer-keyword) | |
249 | (link . org-beamer-link) | |
250 | (plain-list . org-beamer-plain-list) | |
251 | (radio-target . org-beamer-radio-target) | |
252 | (target . org-beamer-target) | |
253 | (template . org-beamer-template))) | |
254 | ||
255 | ||
256 | \f | |
257 | ;;; Transcode Functions | |
258 | ||
259 | ;;;; Bold | |
260 | ||
261 | (defun org-beamer-bold (bold contents info) | |
262 | "Transcode BLOCK object into Beamer code. | |
263 | CONTENTS is the text being bold. INFO is a plist used as | |
264 | a communication channel." | |
265 | (format "\\alert%s{%s}" | |
266 | (or (org-beamer--element-has-overlay-p bold) "") | |
267 | contents)) | |
268 | ||
269 | ||
270 | ;;;; Export Block | |
271 | ||
272 | (defun org-beamer-export-block (export-block contents info) | |
273 | "Transcode an EXPORT-BLOCK element into Beamer code. | |
274 | CONTENTS is nil. INFO is a plist used as a communication | |
275 | channel." | |
276 | (when (member (org-element-property :type export-block) '("BEAMER" "LATEX")) | |
277 | (org-remove-indentation (org-element-property :value export-block)))) | |
278 | ||
279 | ||
280 | ;;;; Export Snippet | |
281 | ||
282 | (defun org-beamer-export-snippet (export-snippet contents info) | |
283 | "Transcode an EXPORT-SNIPPET object into Beamer code. | |
284 | CONTENTS is nil. INFO is a plist used as a communication | |
285 | channel." | |
286 | (let ((backend (org-export-snippet-backend export-snippet)) | |
287 | (value (org-element-property :value export-snippet))) | |
288 | ;; Only "latex" and "beamer" snippets are retained. | |
289 | (cond ((eq backend 'latex) value) | |
290 | ;; Ignore "beamer" snippets specifying overlays. | |
291 | ((and (eq backend 'beamer) | |
292 | (or (org-export-get-previous-element export-snippet info) | |
293 | (not (string-match "\\`<.*>\\'" value)))) | |
294 | value)))) | |
295 | ||
296 | ||
297 | ;;;; Headline | |
298 | ;; | |
299 | ;; The main function to translate a headline is | |
300 | ;; `org-beamer-headline'. | |
301 | ;; | |
302 | ;; Depending on the level at which a headline is considered as | |
303 | ;; a frame (given by `org-beamer--frame-level'), the headline is | |
304 | ;; either a section (`org-beamer--format-section'), a frame | |
305 | ;; (`org-beamer--format-frame') or a block | |
306 | ;; (`org-beamer--format-block'). | |
307 | ;; | |
308 | ;; `org-beamer-headline' also takes care of special environments | |
309 | ;; like "ignoreheading", "note", "noteNH", "appendix" and | |
310 | ;; "againframe". | |
311 | ||
312 | (defun org-beamer--get-label (headline info) | |
313 | "Return label for HEADLINE, as a string. | |
314 | ||
315 | INFO is a plist used as a communication channel. | |
316 | ||
317 | The value is either the label specified in \"BEAMER_opt\" | |
318 | property, or a fallback value built from headline's number. This | |
319 | function assumes HEADLINE will be treated as a frame." | |
320 | (let ((opt (org-element-property :BEAMER_OPT headline))) | |
321 | (if (and (org-string-nw-p opt) | |
322 | (string-match "\\(?:^\\|,\\)label=\\(.*?\\)\\(?:$\\|,\\)" opt)) | |
323 | (match-string 1 opt) | |
324 | (format "sec-%s" | |
325 | (mapconcat 'number-to-string | |
326 | (org-export-get-headline-number headline info) | |
327 | "-"))))) | |
328 | ||
329 | (defun org-beamer--frame-level (headline info) | |
330 | "Return frame level in subtree containing HEADLINE. | |
331 | INFO is a plist used as a communication channel." | |
332 | (or | |
333 | ;; 1. Look for "frame" environment in parents, starting from the | |
334 | ;; farthest. | |
335 | (catch 'exit | |
336 | (mapc (lambda (parent) | |
337 | (let ((env (org-element-property :BEAMER_ENV parent))) | |
338 | (when (and env (member-ignore-case env '("frame" "fullframe"))) | |
339 | (throw 'exit (org-export-get-relative-level parent info))))) | |
340 | (nreverse (org-export-get-genealogy headline))) | |
341 | nil) | |
342 | ;; 2. Look for "frame" environment in HEADLINE. | |
343 | (let ((env (org-element-property :BEAMER_ENV headline))) | |
344 | (and env (member-ignore-case env '("frame" "fullframe")) | |
345 | (org-export-get-relative-level headline info))) | |
346 | ;; 3. Look for "frame" environment in sub-tree. | |
347 | (org-element-map headline 'headline | |
348 | (lambda (hl) | |
349 | (let ((env (org-element-property :BEAMER_ENV hl))) | |
350 | (when (and env (member-ignore-case env '("frame" "fullframe"))) | |
351 | (org-export-get-relative-level hl info)))) | |
352 | info 'first-match) | |
353 | ;; 4. No "frame" environment in tree: use default value. | |
354 | (plist-get info :headline-levels))) | |
355 | ||
356 | (defun org-beamer--format-section (headline contents info) | |
357 | "Format HEADLINE as a sectioning part. | |
358 | CONTENTS holds the contents of the headline. INFO is a plist | |
359 | used as a communication channel." | |
360 | (let ((latex-headline | |
361 | (org-export-with-backend | |
362 | ;; We create a temporary export back-end which behaves the | |
363 | ;; same as current one, but adds "\protect" in front of the | |
364 | ;; output of some objects. | |
365 | (org-export-create-backend | |
366 | :parent 'latex | |
367 | :transcoders | |
368 | (let ((protected-output | |
369 | (function | |
370 | (lambda (object contents info) | |
371 | (let ((code (org-export-with-backend | |
372 | 'beamer object contents info))) | |
373 | (if (org-string-nw-p code) (concat "\\protect" code) | |
374 | code)))))) | |
375 | (mapcar #'(lambda (type) (cons type protected-output)) | |
376 | '(bold footnote-reference italic strike-through timestamp | |
377 | underline)))) | |
378 | headline | |
379 | contents | |
380 | info)) | |
381 | (mode-specs (org-element-property :BEAMER_ACT headline))) | |
382 | (if (and mode-specs | |
383 | (string-match "\\`\\\\\\(.*?\\)\\(?:\\*\\|\\[.*\\]\\)?{" | |
384 | latex-headline)) | |
385 | ;; Insert overlay specifications. | |
386 | (replace-match (concat (match-string 1 latex-headline) | |
387 | (format "<%s>" mode-specs)) | |
388 | nil nil latex-headline 1) | |
389 | latex-headline))) | |
390 | ||
391 | (defun org-beamer--format-frame (headline contents info) | |
392 | "Format HEADLINE as a frame. | |
393 | CONTENTS holds the contents of the headline. INFO is a plist | |
394 | used as a communication channel." | |
395 | (let ((fragilep | |
396 | ;; FRAGILEP is non-nil when HEADLINE contains an element | |
397 | ;; among `org-beamer-verbatim-elements'. | |
398 | (org-element-map headline org-beamer-verbatim-elements 'identity | |
399 | info 'first-match))) | |
400 | (concat "\\begin{frame}" | |
401 | ;; Overlay specification, if any. When surrounded by | |
402 | ;; square brackets, consider it as a default | |
403 | ;; specification. | |
404 | (let ((action (org-element-property :BEAMER_ACT headline))) | |
405 | (cond | |
406 | ((not action) "") | |
407 | ((string-match "\\`\\[.*\\]\\'" action ) | |
408 | (org-beamer--normalize-argument action 'defaction)) | |
409 | (t (org-beamer--normalize-argument action 'action)))) | |
410 | ;; Options, if any. | |
411 | (let* ((beamer-opt (org-element-property :BEAMER_OPT headline)) | |
412 | (options | |
413 | ;; Collect options from default value and headline's | |
414 | ;; properties. Also add a label for links. | |
415 | (append | |
416 | (org-split-string org-beamer-frame-default-options ",") | |
417 | (and beamer-opt | |
418 | (org-split-string | |
419 | ;; Remove square brackets if user provided | |
420 | ;; them. | |
421 | (and (string-match "^\\[?\\(.*\\)\\]?$" beamer-opt) | |
422 | (match-string 1 beamer-opt)) | |
423 | ",")) | |
424 | ;; Provide an automatic label for the frame | |
425 | ;; unless the user specified one. | |
426 | (unless (and beamer-opt | |
427 | (string-match "\\(^\\|,\\)label=" beamer-opt)) | |
428 | (list | |
429 | (format "label=%s" | |
430 | (org-beamer--get-label headline info))))))) | |
431 | ;; Change options list into a string. | |
432 | (org-beamer--normalize-argument | |
433 | (mapconcat | |
434 | 'identity | |
435 | (if (or (not fragilep) (member "fragile" options)) options | |
436 | (cons "fragile" options)) | |
437 | ",") | |
438 | 'option)) | |
439 | ;; Title. | |
440 | (let ((env (org-element-property :BEAMER_ENV headline))) | |
441 | (format "{%s}" | |
442 | (if (and env (equal (downcase env) "fullframe")) "" | |
443 | (org-export-data | |
444 | (org-element-property :title headline) info)))) | |
445 | "\n" | |
446 | ;; The following workaround is required in fragile frames | |
447 | ;; as Beamer will append "\par" to the beginning of the | |
448 | ;; contents. So we need to make sure the command is | |
449 | ;; separated from the contents by at least one space. If | |
450 | ;; it isn't, it will create "\parfirst-word" command and | |
451 | ;; remove the first word from the contents in the PDF | |
452 | ;; output. | |
453 | (if (not fragilep) contents | |
454 | (replace-regexp-in-string "\\`\n*" "\\& " (or contents ""))) | |
455 | "\\end{frame}"))) | |
456 | ||
457 | (defun org-beamer--format-block (headline contents info) | |
458 | "Format HEADLINE as a block. | |
459 | CONTENTS holds the contents of the headline. INFO is a plist | |
460 | used as a communication channel." | |
461 | (let* ((column-width (org-element-property :BEAMER_COL headline)) | |
462 | ;; ENVIRONMENT defaults to "block" if none is specified and | |
463 | ;; there is no column specification. If there is a column | |
464 | ;; specified but still no explicit environment, ENVIRONMENT | |
465 | ;; is "column". | |
466 | (environment (let ((env (org-element-property :BEAMER_ENV headline))) | |
467 | (cond | |
468 | ;; "block" is the fallback environment. | |
469 | ((and (not env) (not column-width)) "block") | |
470 | ;; "column" only. | |
471 | ((not env) "column") | |
472 | ;; Use specified environment. | |
473 | (t env)))) | |
474 | (raw-title (org-element-property :raw-value headline)) | |
475 | (env-format | |
476 | (cond ((member environment '("column" "columns")) nil) | |
477 | ((assoc environment | |
478 | (append org-beamer-environments-extra | |
479 | org-beamer-environments-default))) | |
480 | (t (user-error "Wrong block type at a headline named \"%s\"" | |
481 | raw-title)))) | |
482 | (title (org-export-data (org-element-property :title headline) info)) | |
483 | (options (let ((options (org-element-property :BEAMER_OPT headline))) | |
484 | (if (not options) "" | |
485 | (org-beamer--normalize-argument options 'option)))) | |
486 | ;; Start a "columns" environment when explicitly requested or | |
487 | ;; when there is no previous headline or the previous | |
488 | ;; headline do not have a BEAMER_column property. | |
489 | (parent-env (org-element-property | |
490 | :BEAMER_ENV (org-export-get-parent-headline headline))) | |
491 | (start-columns-p | |
492 | (or (equal environment "columns") | |
493 | (and column-width | |
494 | (not (and parent-env | |
495 | (equal (downcase parent-env) "columns"))) | |
496 | (or (org-export-first-sibling-p headline info) | |
497 | (not (org-element-property | |
498 | :BEAMER_COL | |
499 | (org-export-get-previous-element | |
500 | headline info))))))) | |
501 | ;; End the "columns" environment when explicitly requested or | |
502 | ;; when there is no next headline or the next headline do not | |
503 | ;; have a BEAMER_column property. | |
504 | (end-columns-p | |
505 | (or (equal environment "columns") | |
506 | (and column-width | |
507 | (not (and parent-env | |
508 | (equal (downcase parent-env) "columns"))) | |
509 | (or (org-export-last-sibling-p headline info) | |
510 | (not (org-element-property | |
511 | :BEAMER_COL | |
512 | (org-export-get-next-element headline info)))))))) | |
513 | (concat | |
514 | (when start-columns-p | |
515 | ;; Column can accept options only when the environment is | |
516 | ;; explicitly defined. | |
517 | (if (not (equal environment "columns")) "\\begin{columns}\n" | |
518 | (format "\\begin{columns}%s\n" options))) | |
519 | (when column-width | |
520 | (format "\\begin{column}%s{%s}\n" | |
521 | ;; One can specify placement for column only when | |
522 | ;; HEADLINE stands for a column on its own. | |
523 | (if (equal environment "column") options "") | |
524 | (format "%s\\textwidth" column-width))) | |
525 | ;; Block's opening string. | |
526 | (when (nth 2 env-format) | |
527 | (concat | |
528 | (org-fill-template | |
529 | (nth 2 env-format) | |
530 | (nconc | |
531 | ;; If BEAMER_act property has its value enclosed in square | |
532 | ;; brackets, it is a default overlay specification and | |
533 | ;; overlay specification is empty. Otherwise, it is an | |
534 | ;; overlay specification and the default one is nil. | |
535 | (let ((action (org-element-property :BEAMER_ACT headline))) | |
536 | (cond | |
537 | ((not action) (list (cons "a" "") (cons "A" ""))) | |
538 | ((string-match "\\`\\[.*\\]\\'" action) | |
539 | (list | |
540 | (cons "A" (org-beamer--normalize-argument action 'defaction)) | |
541 | (cons "a" ""))) | |
542 | (t | |
543 | (list (cons "a" (org-beamer--normalize-argument action 'action)) | |
544 | (cons "A" ""))))) | |
545 | (list (cons "o" options) | |
546 | (cons "h" title) | |
547 | (cons "r" raw-title) | |
548 | (cons "H" (if (equal raw-title "") "" | |
549 | (format "{%s}" raw-title))) | |
550 | (cons "U" (if (equal raw-title "") "" | |
551 | (format "[%s]" raw-title)))))) | |
552 | "\n")) | |
553 | contents | |
554 | ;; Block's closing string, if any. | |
555 | (and (nth 3 env-format) (concat (nth 3 env-format) "\n")) | |
556 | (when column-width "\\end{column}\n") | |
557 | (when end-columns-p "\\end{columns}")))) | |
558 | ||
559 | (defun org-beamer-headline (headline contents info) | |
560 | "Transcode HEADLINE element into Beamer code. | |
561 | CONTENTS is the contents of the headline. INFO is a plist used | |
562 | as a communication channel." | |
563 | (unless (org-element-property :footnote-section-p headline) | |
564 | (let ((level (org-export-get-relative-level headline info)) | |
565 | (frame-level (org-beamer--frame-level headline info)) | |
566 | (environment (let ((env (org-element-property :BEAMER_ENV headline))) | |
567 | (or (org-string-nw-p env) "block")))) | |
568 | (cond | |
569 | ;; Case 1: Resume frame specified by "BEAMER_ref" property. | |
570 | ((equal environment "againframe") | |
571 | (let ((ref (org-element-property :BEAMER_REF headline))) | |
572 | ;; Reference to frame being resumed is mandatory. Ignore | |
573 | ;; the whole headline if it isn't provided. | |
574 | (when (org-string-nw-p ref) | |
575 | (concat "\\againframe" | |
576 | ;; Overlay specification. | |
577 | (let ((overlay (org-element-property :BEAMER_ACT headline))) | |
578 | (when overlay | |
579 | (org-beamer--normalize-argument | |
580 | overlay | |
581 | (if (string-match "^\\[.*\\]$" overlay) 'defaction | |
582 | 'action)))) | |
583 | ;; Options. | |
584 | (let ((options (org-element-property :BEAMER_OPT headline))) | |
585 | (when options | |
586 | (org-beamer--normalize-argument options 'option))) | |
587 | ;; Resolve reference provided by "BEAMER_ref" | |
588 | ;; property. This is done by building a minimal fake | |
589 | ;; link and calling the appropriate resolve function, | |
590 | ;; depending on the reference syntax. | |
591 | (let* ((type | |
592 | (progn | |
593 | (string-match "^\\(id:\\|#\\|\\*\\)?\\(.*\\)" ref) | |
594 | (cond | |
595 | ((or (not (match-string 1 ref)) | |
596 | (equal (match-string 1 ref) "*")) 'fuzzy) | |
597 | ((equal (match-string 1 ref) "id:") 'id) | |
598 | (t 'custom-id)))) | |
599 | (link (list 'link (list :path (match-string 2 ref)))) | |
600 | (target (if (eq type 'fuzzy) | |
601 | (org-export-resolve-fuzzy-link link info) | |
602 | (org-export-resolve-id-link link info)))) | |
603 | ;; Now use user-defined label provided in TARGET | |
604 | ;; headline, or fallback to standard one. | |
605 | (format "{%s}" (org-beamer--get-label target info))))))) | |
606 | ;; Case 2: Creation of an appendix is requested. | |
607 | ((equal environment "appendix") | |
608 | (concat "\\appendix" | |
609 | (org-element-property :BEAMER_ACT headline) | |
610 | "\n" | |
611 | (make-string (org-element-property :pre-blank headline) ?\n) | |
612 | contents)) | |
613 | ;; Case 3: Ignore heading. | |
614 | ((equal environment "ignoreheading") | |
615 | (concat (make-string (org-element-property :pre-blank headline) ?\n) | |
616 | contents)) | |
617 | ;; Case 4: HEADLINE is a note. | |
618 | ((member environment '("note" "noteNH")) | |
619 | (format "\\note{%s}" | |
620 | (concat (and (equal environment "note") | |
621 | (concat | |
622 | (org-export-data | |
623 | (org-element-property :title headline) info) | |
624 | "\n")) | |
625 | (org-trim contents)))) | |
626 | ;; Case 5: HEADLINE is a frame. | |
627 | ((= level frame-level) | |
628 | (org-beamer--format-frame headline contents info)) | |
629 | ;; Case 6: Regular section, extracted from | |
630 | ;; `org-latex-classes'. | |
631 | ((< level frame-level) | |
632 | (org-beamer--format-section headline contents info)) | |
633 | ;; Case 7: Otherwise, HEADLINE is a block. | |
634 | (t (org-beamer--format-block headline contents info)))))) | |
635 | ||
636 | ||
637 | ;;;; Item | |
638 | ||
639 | (defun org-beamer-item (item contents info) | |
640 | "Transcode an ITEM element into Beamer code. | |
641 | CONTENTS holds the contents of the item. INFO is a plist holding | |
642 | contextual information." | |
643 | (let ((action (let ((first-element (car (org-element-contents item)))) | |
644 | (and (eq (org-element-type first-element) 'paragraph) | |
645 | (org-beamer--element-has-overlay-p first-element)))) | |
646 | (output (org-export-with-backend 'latex item contents info))) | |
30cb51f1 | 647 | (if (or (not action) (not (string-match "\\\\item" output))) output |
271672fa BG |
648 | ;; If the item starts with a paragraph and that paragraph starts |
649 | ;; with an export snippet specifying an overlay, insert it after | |
650 | ;; \item command. | |
30cb51f1 | 651 | (replace-match (concat "\\\\item" action) nil nil output)))) |
271672fa BG |
652 | |
653 | ||
654 | ;;;; Keyword | |
655 | ||
656 | (defun org-beamer-keyword (keyword contents info) | |
657 | "Transcode a KEYWORD element into Beamer code. | |
658 | CONTENTS is nil. INFO is a plist used as a communication | |
659 | channel." | |
660 | (let ((key (org-element-property :key keyword)) | |
661 | (value (org-element-property :value keyword))) | |
662 | ;; Handle specifically BEAMER and TOC (headlines only) keywords. | |
663 | ;; Otherwise, fallback to `latex' back-end. | |
664 | (cond | |
665 | ((equal key "BEAMER") value) | |
666 | ((and (equal key "TOC") (string-match "\\<headlines\\>" value)) | |
667 | (let ((depth (or (and (string-match "[0-9]+" value) | |
668 | (string-to-number (match-string 0 value))) | |
669 | (plist-get info :with-toc))) | |
670 | (options (and (string-match "\\[.*?\\]" value) | |
671 | (match-string 0 value)))) | |
672 | (concat | |
673 | (when (wholenump depth) (format "\\setcounter{tocdepth}{%s}\n" depth)) | |
674 | "\\tableofcontents" options))) | |
675 | (t (org-export-with-backend 'latex keyword contents info))))) | |
676 | ||
677 | ||
678 | ;;;; Link | |
679 | ||
680 | (defun org-beamer-link (link contents info) | |
681 | "Transcode a LINK object into Beamer code. | |
682 | CONTENTS is the description part of the link. INFO is a plist | |
683 | used as a communication channel." | |
684 | (let ((type (org-element-property :type link)) | |
685 | (path (org-element-property :path link))) | |
686 | ;; Use \hyperlink command for all internal links. | |
687 | (cond | |
688 | ((equal type "radio") | |
689 | (let ((destination (org-export-resolve-radio-link link info))) | |
690 | (when destination | |
691 | (format "\\hyperlink%s{%s}{%s}" | |
692 | (or (org-beamer--element-has-overlay-p link) "") | |
30cb51f1 BG |
693 | (org-export-solidify-link-text |
694 | (org-element-property :value destination)) | |
695 | contents)))) | |
271672fa BG |
696 | ((and (member type '("custom-id" "fuzzy" "id")) |
697 | (let ((destination (if (string= type "fuzzy") | |
698 | (org-export-resolve-fuzzy-link link info) | |
699 | (org-export-resolve-id-link link info)))) | |
700 | (case (org-element-type destination) | |
701 | (headline | |
702 | (let ((label | |
703 | (format "sec-%s" | |
704 | (mapconcat | |
705 | 'number-to-string | |
706 | (org-export-get-headline-number | |
707 | destination info) | |
708 | "-")))) | |
709 | (if (and (plist-get info :section-numbers) (not contents)) | |
710 | (format "\\ref{%s}" label) | |
711 | (format "\\hyperlink%s{%s}{%s}" | |
712 | (or (org-beamer--element-has-overlay-p link) "") | |
713 | label | |
714 | contents)))) | |
715 | (target | |
716 | (let ((path (org-export-solidify-link-text path))) | |
717 | (if (not contents) (format "\\ref{%s}" path) | |
718 | (format "\\hyperlink%s{%s}{%s}" | |
719 | (or (org-beamer--element-has-overlay-p link) "") | |
720 | path | |
721 | contents)))))))) | |
722 | ;; Otherwise, use `latex' back-end. | |
723 | (t (org-export-with-backend 'latex link contents info))))) | |
724 | ||
725 | ||
726 | ;;;; Plain List | |
727 | ;; | |
728 | ;; Plain lists support `:environment', `:overlay' and `:options' | |
729 | ;; attributes. | |
730 | ||
731 | (defun org-beamer-plain-list (plain-list contents info) | |
732 | "Transcode a PLAIN-LIST element into Beamer code. | |
733 | CONTENTS is the contents of the list. INFO is a plist holding | |
734 | contextual information." | |
735 | (let* ((type (org-element-property :type plain-list)) | |
736 | (attributes (org-combine-plists | |
737 | (org-export-read-attribute :attr_latex plain-list) | |
738 | (org-export-read-attribute :attr_beamer plain-list))) | |
739 | (latex-type (let ((env (plist-get attributes :environment))) | |
740 | (cond (env) | |
741 | ((eq type 'ordered) "enumerate") | |
742 | ((eq type 'descriptive) "description") | |
743 | (t "itemize"))))) | |
744 | (org-latex--wrap-label | |
745 | plain-list | |
746 | (format "\\begin{%s}%s%s\n%s\\end{%s}" | |
747 | latex-type | |
748 | ;; Default overlay specification, if any. | |
749 | (org-beamer--normalize-argument | |
750 | (or (plist-get attributes :overlay) "") | |
751 | 'defaction) | |
752 | ;; Second optional argument depends on the list type. | |
753 | (org-beamer--normalize-argument | |
754 | (or (plist-get attributes :options) "") | |
755 | 'option) | |
756 | ;; Eventually insert contents and close environment. | |
757 | contents | |
758 | latex-type)))) | |
759 | ||
760 | ||
761 | ;;;; Radio Target | |
762 | ||
763 | (defun org-beamer-radio-target (radio-target text info) | |
764 | "Transcode a RADIO-TARGET object into Beamer code. | |
765 | TEXT is the text of the target. INFO is a plist holding | |
766 | contextual information." | |
767 | (format "\\hypertarget%s{%s}{%s}" | |
768 | (or (org-beamer--element-has-overlay-p radio-target) "") | |
769 | (org-export-solidify-link-text | |
770 | (org-element-property :value radio-target)) | |
771 | text)) | |
772 | ||
773 | ||
774 | ;;;; Target | |
775 | ||
776 | (defun org-beamer-target (target contents info) | |
777 | "Transcode a TARGET object into Beamer code. | |
778 | CONTENTS is nil. INFO is a plist holding contextual | |
779 | information." | |
780 | (format "\\hypertarget{%s}{}" | |
781 | (org-export-solidify-link-text (org-element-property :value target)))) | |
782 | ||
783 | ||
784 | ;;;; Template | |
785 | ;; | |
786 | ;; Template used is similar to the one used in `latex' back-end, | |
787 | ;; excepted for the table of contents and Beamer themes. | |
788 | ||
789 | (defun org-beamer-template (contents info) | |
790 | "Return complete document string after Beamer conversion. | |
791 | CONTENTS is the transcoded contents string. INFO is a plist | |
792 | holding export options." | |
793 | (let ((title (org-export-data (plist-get info :title) info))) | |
794 | (concat | |
795 | ;; 1. Time-stamp. | |
796 | (and (plist-get info :time-stamp-file) | |
797 | (format-time-string "%% Created %Y-%m-%d %a %H:%M\n")) | |
798 | ;; 2. Document class and packages. | |
799 | (let* ((class (plist-get info :latex-class)) | |
800 | (class-options (plist-get info :latex-class-options)) | |
801 | (header (nth 1 (assoc class org-latex-classes))) | |
802 | (document-class-string | |
803 | (and (stringp header) | |
804 | (if (not class-options) header | |
805 | (replace-regexp-in-string | |
806 | "^[ \t]*\\\\documentclass\\(\\(\\[[^]]*\\]\\)?\\)" | |
807 | class-options header t nil 1))))) | |
808 | (if (not document-class-string) | |
809 | (user-error "Unknown LaTeX class `%s'" class) | |
810 | (org-latex-guess-babel-language | |
811 | (org-latex-guess-inputenc | |
812 | (org-element-normalize-string | |
813 | (org-splice-latex-header | |
814 | document-class-string | |
815 | org-latex-default-packages-alist | |
816 | org-latex-packages-alist nil | |
817 | (concat (org-element-normalize-string | |
818 | (plist-get info :latex-header)) | |
819 | (org-element-normalize-string | |
820 | (plist-get info :latex-header-extra)) | |
821 | (plist-get info :beamer-header-extra))))) | |
822 | info))) | |
823 | ;; 3. Insert themes. | |
824 | (let ((format-theme | |
825 | (function | |
826 | (lambda (prop command) | |
827 | (let ((theme (plist-get info prop))) | |
828 | (when theme | |
829 | (concat command | |
830 | (if (not (string-match "\\[.*\\]" theme)) | |
831 | (format "{%s}\n" theme) | |
832 | (format "%s{%s}\n" | |
833 | (match-string 0 theme) | |
834 | (org-trim | |
835 | (replace-match "" nil nil theme))))))))))) | |
836 | (mapconcat (lambda (args) (apply format-theme args)) | |
837 | '((:beamer-theme "\\usetheme") | |
838 | (:beamer-color-theme "\\usecolortheme") | |
839 | (:beamer-font-theme "\\usefonttheme") | |
840 | (:beamer-inner-theme "\\useinnertheme") | |
841 | (:beamer-outer-theme "\\useoutertheme")) | |
842 | "")) | |
843 | ;; 4. Possibly limit depth for headline numbering. | |
844 | (let ((sec-num (plist-get info :section-numbers))) | |
845 | (when (integerp sec-num) | |
846 | (format "\\setcounter{secnumdepth}{%d}\n" sec-num))) | |
847 | ;; 5. Author. | |
848 | (let ((author (and (plist-get info :with-author) | |
849 | (let ((auth (plist-get info :author))) | |
850 | (and auth (org-export-data auth info))))) | |
851 | (email (and (plist-get info :with-email) | |
852 | (org-export-data (plist-get info :email) info)))) | |
853 | (cond ((and author email (not (string= "" email))) | |
854 | (format "\\author{%s\\thanks{%s}}\n" author email)) | |
855 | (author (format "\\author{%s}\n" author)) | |
856 | (t "\\author{}\n"))) | |
857 | ;; 6. Date. | |
858 | (let ((date (and (plist-get info :with-date) (org-export-get-date info)))) | |
859 | (format "\\date{%s}\n" (org-export-data date info))) | |
860 | ;; 7. Title | |
861 | (format "\\title{%s}\n" title) | |
862 | ;; 8. Hyperref options. | |
863 | (when (plist-get info :latex-hyperref-p) | |
864 | (format "\\hypersetup{\n pdfkeywords={%s},\n pdfsubject={%s},\n pdfcreator={%s}}\n" | |
865 | (or (plist-get info :keywords) "") | |
866 | (or (plist-get info :description) "") | |
867 | (if (not (plist-get info :with-creator)) "" | |
868 | (plist-get info :creator)))) | |
869 | ;; 9. Document start. | |
870 | "\\begin{document}\n\n" | |
871 | ;; 10. Title command. | |
872 | (org-element-normalize-string | |
873 | (cond ((string= "" title) nil) | |
874 | ((not (stringp org-latex-title-command)) nil) | |
875 | ((string-match "\\(?:[^%]\\|^\\)%s" | |
876 | org-latex-title-command) | |
877 | (format org-latex-title-command title)) | |
878 | (t org-latex-title-command))) | |
879 | ;; 11. Table of contents. | |
880 | (let ((depth (plist-get info :with-toc))) | |
881 | (when depth | |
882 | (concat | |
883 | (format "\\begin{frame}%s{%s}\n" | |
884 | (org-beamer--normalize-argument | |
885 | org-beamer-outline-frame-options 'option) | |
886 | org-beamer-outline-frame-title) | |
887 | (when (wholenump depth) | |
888 | (format "\\setcounter{tocdepth}{%d}\n" depth)) | |
889 | "\\tableofcontents\n" | |
890 | "\\end{frame}\n\n"))) | |
891 | ;; 12. Document's body. | |
892 | contents | |
893 | ;; 13. Creator. | |
894 | (let ((creator-info (plist-get info :with-creator))) | |
895 | (cond | |
896 | ((not creator-info) "") | |
897 | ((eq creator-info 'comment) | |
898 | (format "%% %s\n" (plist-get info :creator))) | |
899 | (t (concat (plist-get info :creator) "\n")))) | |
900 | ;; 14. Document end. | |
901 | "\\end{document}"))) | |
902 | ||
903 | ||
904 | \f | |
905 | ;;; Minor Mode | |
906 | ||
907 | ||
908 | (defvar org-beamer-mode-map (make-sparse-keymap) | |
909 | "The keymap for `org-beamer-mode'.") | |
910 | (define-key org-beamer-mode-map "\C-c\C-b" 'org-beamer-select-environment) | |
911 | ||
912 | ;;;###autoload | |
913 | (define-minor-mode org-beamer-mode | |
914 | "Support for editing Beamer oriented Org mode files." | |
915 | nil " Bm" 'org-beamer-mode-map) | |
916 | ||
917 | (when (fboundp 'font-lock-add-keywords) | |
918 | (font-lock-add-keywords | |
919 | 'org-mode | |
920 | '((":\\(B_[a-z]+\\|BMCOL\\):" 1 'org-beamer-tag prepend)) | |
921 | 'prepend)) | |
922 | ||
923 | (defface org-beamer-tag '((t (:box (:line-width 1 :color grey40)))) | |
924 | "The special face for beamer tags." | |
925 | :group 'org-export-beamer) | |
926 | ||
927 | (defun org-beamer-property-changed (property value) | |
928 | "Track the BEAMER_env property with tags. | |
929 | PROPERTY is the name of the modified property. VALUE is its new | |
930 | value." | |
931 | (cond | |
932 | ((equal property "BEAMER_env") | |
933 | (save-excursion | |
934 | (org-back-to-heading t) | |
935 | ;; Filter out Beamer-related tags and install environment tag. | |
936 | (let ((tags (org-remove-if (lambda (x) (string-match "^B_" x)) | |
937 | (org-get-tags))) | |
938 | (env-tag (and (org-string-nw-p value) (concat "B_" value)))) | |
939 | (org-set-tags-to (if env-tag (cons env-tag tags) tags)) | |
940 | (when env-tag (org-toggle-tag env-tag 'on))))) | |
941 | ((equal property "BEAMER_col") | |
942 | (org-toggle-tag "BMCOL" (if (org-string-nw-p value) 'on 'off))))) | |
943 | ||
944 | (add-hook 'org-property-changed-functions 'org-beamer-property-changed) | |
945 | ||
946 | (defun org-beamer-allowed-property-values (property) | |
947 | "Supply allowed values for PROPERTY." | |
948 | (cond | |
949 | ((and (equal property "BEAMER_env") | |
950 | (not (org-entry-get nil (concat property "_ALL") 'inherit))) | |
951 | ;; If no allowed values for BEAMER_env have been defined, | |
952 | ;; supply all defined environments | |
953 | (mapcar 'car (append org-beamer-environments-special | |
954 | org-beamer-environments-extra | |
955 | org-beamer-environments-default))) | |
956 | ((and (equal property "BEAMER_col") | |
957 | (not (org-entry-get nil (concat property "_ALL") 'inherit))) | |
958 | ;; If no allowed values for BEAMER_col have been defined, | |
959 | ;; supply some | |
960 | (org-split-string org-beamer-column-widths " ")))) | |
961 | ||
962 | (add-hook 'org-property-allowed-value-functions | |
963 | 'org-beamer-allowed-property-values) | |
964 | ||
965 | ||
966 | \f | |
967 | ;;; Commands | |
968 | ||
969 | ;;;###autoload | |
970 | (defun org-beamer-export-as-latex | |
971 | (&optional async subtreep visible-only body-only ext-plist) | |
972 | "Export current buffer as a Beamer buffer. | |
973 | ||
974 | If narrowing is active in the current buffer, only export its | |
975 | narrowed part. | |
976 | ||
977 | If a region is active, export that region. | |
978 | ||
979 | A non-nil optional argument ASYNC means the process should happen | |
980 | asynchronously. The resulting buffer should be accessible | |
981 | through the `org-export-stack' interface. | |
982 | ||
983 | When optional argument SUBTREEP is non-nil, export the sub-tree | |
984 | at point, extracting information from the headline properties | |
985 | first. | |
986 | ||
987 | When optional argument VISIBLE-ONLY is non-nil, don't export | |
988 | contents of hidden elements. | |
989 | ||
990 | When optional argument BODY-ONLY is non-nil, only write code | |
991 | between \"\\begin{document}\" and \"\\end{document}\". | |
992 | ||
993 | EXT-PLIST, when provided, is a property list with external | |
994 | parameters overriding Org default settings, but still inferior to | |
995 | file-local settings. | |
996 | ||
997 | Export is done in a buffer named \"*Org BEAMER Export*\", which | |
998 | will be displayed when `org-export-show-temporary-export-buffer' | |
999 | is non-nil." | |
1000 | (interactive) | |
1001 | (org-export-to-buffer 'beamer "*Org BEAMER Export*" | |
1002 | async subtreep visible-only body-only ext-plist (lambda () (LaTeX-mode)))) | |
1003 | ||
1004 | ;;;###autoload | |
1005 | (defun org-beamer-export-to-latex | |
1006 | (&optional async subtreep visible-only body-only ext-plist) | |
1007 | "Export current buffer as a Beamer presentation (tex). | |
1008 | ||
1009 | If narrowing is active in the current buffer, only export its | |
1010 | narrowed part. | |
1011 | ||
1012 | If a region is active, export that region. | |
1013 | ||
1014 | A non-nil optional argument ASYNC means the process should happen | |
1015 | asynchronously. The resulting file should be accessible through | |
1016 | the `org-export-stack' interface. | |
1017 | ||
1018 | When optional argument SUBTREEP is non-nil, export the sub-tree | |
1019 | at point, extracting information from the headline properties | |
1020 | first. | |
1021 | ||
1022 | When optional argument VISIBLE-ONLY is non-nil, don't export | |
1023 | contents of hidden elements. | |
1024 | ||
1025 | When optional argument BODY-ONLY is non-nil, only write code | |
1026 | between \"\\begin{document}\" and \"\\end{document}\". | |
1027 | ||
1028 | EXT-PLIST, when provided, is a property list with external | |
1029 | parameters overriding Org default settings, but still inferior to | |
1030 | file-local settings. | |
1031 | ||
1032 | Return output file's name." | |
1033 | (interactive) | |
1034 | (let ((file (org-export-output-file-name ".tex" subtreep))) | |
1035 | (org-export-to-file 'beamer file | |
1036 | async subtreep visible-only body-only ext-plist))) | |
1037 | ||
1038 | ;;;###autoload | |
1039 | (defun org-beamer-export-to-pdf | |
1040 | (&optional async subtreep visible-only body-only ext-plist) | |
1041 | "Export current buffer as a Beamer presentation (PDF). | |
1042 | ||
1043 | If narrowing is active in the current buffer, only export its | |
1044 | narrowed part. | |
1045 | ||
1046 | If a region is active, export that region. | |
1047 | ||
1048 | A non-nil optional argument ASYNC means the process should happen | |
1049 | asynchronously. The resulting file should be accessible through | |
1050 | the `org-export-stack' interface. | |
1051 | ||
1052 | When optional argument SUBTREEP is non-nil, export the sub-tree | |
1053 | at point, extracting information from the headline properties | |
1054 | first. | |
1055 | ||
1056 | When optional argument VISIBLE-ONLY is non-nil, don't export | |
1057 | contents of hidden elements. | |
1058 | ||
1059 | When optional argument BODY-ONLY is non-nil, only write code | |
1060 | between \"\\begin{document}\" and \"\\end{document}\". | |
1061 | ||
1062 | EXT-PLIST, when provided, is a property list with external | |
1063 | parameters overriding Org default settings, but still inferior to | |
1064 | file-local settings. | |
1065 | ||
1066 | Return PDF file's name." | |
1067 | (interactive) | |
1068 | (let ((file (org-export-output-file-name ".tex" subtreep))) | |
1069 | (org-export-to-file 'beamer file | |
1070 | async subtreep visible-only body-only ext-plist | |
1071 | (lambda (file) (org-latex-compile file))))) | |
1072 | ||
1073 | ;;;###autoload | |
1074 | (defun org-beamer-select-environment () | |
1075 | "Select the environment to be used by beamer for this entry. | |
1076 | While this uses (for convenience) a tag selection interface, the | |
1077 | result of this command will be that the BEAMER_env *property* of | |
1078 | the entry is set. | |
1079 | ||
1080 | In addition to this, the command will also set a tag as a visual | |
1081 | aid, but the tag does not have any semantic meaning." | |
1082 | (interactive) | |
1083 | ;; Make sure `org-beamer-environments-special' has a higher | |
1084 | ;; priority than `org-beamer-environments-extra'. | |
1085 | (let* ((envs (append org-beamer-environments-special | |
1086 | org-beamer-environments-extra | |
1087 | org-beamer-environments-default)) | |
1088 | (org-tag-alist | |
1089 | (append '((:startgroup)) | |
1090 | (mapcar (lambda (e) (cons (concat "B_" (car e)) | |
1091 | (string-to-char (nth 1 e)))) | |
1092 | envs) | |
1093 | '((:endgroup)) | |
1094 | '(("BMCOL" . ?|)))) | |
30cb51f1 | 1095 | (org-use-fast-tag-selection t) |
271672fa BG |
1096 | (org-fast-tag-selection-single-key t)) |
1097 | (org-set-tags) | |
1098 | (let ((tags (or (ignore-errors (org-get-tags-string)) ""))) | |
1099 | (cond | |
1100 | ;; For a column, automatically ask for its width. | |
1101 | ((eq org-last-tag-selection-key ?|) | |
1102 | (if (string-match ":BMCOL:" tags) | |
1103 | (org-set-property "BEAMER_col" (read-string "Column width: ")) | |
1104 | (org-delete-property "BEAMER_col"))) | |
1105 | ;; For an "againframe" section, automatically ask for reference | |
1106 | ;; to resumed frame and overlay specifications. | |
1107 | ((eq org-last-tag-selection-key ?A) | |
1108 | (if (equal (org-entry-get nil "BEAMER_env") "againframe") | |
1109 | (progn (org-entry-delete nil "BEAMER_env") | |
1110 | (org-entry-delete nil "BEAMER_ref") | |
1111 | (org-entry-delete nil "BEAMER_act")) | |
1112 | (org-entry-put nil "BEAMER_env" "againframe") | |
1113 | (org-set-property | |
1114 | "BEAMER_ref" | |
1115 | (read-string "Frame reference (*Title, #custom-id, id:...): ")) | |
1116 | (org-set-property "BEAMER_act" | |
1117 | (read-string "Overlay specification: ")))) | |
1118 | ((string-match (concat ":B_\\(" (mapconcat 'car envs "\\|") "\\):") tags) | |
1119 | (org-entry-put nil "BEAMER_env" (match-string 1 tags))) | |
1120 | (t (org-entry-delete nil "BEAMER_env")))))) | |
1121 | ||
1122 | ;;;###autoload | |
1123 | (defun org-beamer-insert-options-template (&optional kind) | |
1124 | "Insert a settings template, to make sure users do this right." | |
1125 | (interactive (progn | |
1126 | (message "Current [s]ubtree or [g]lobal?") | |
1127 | (if (eq (read-char-exclusive) ?g) (list 'global) | |
1128 | (list 'subtree)))) | |
1129 | (if (eq kind 'subtree) | |
1130 | (progn | |
1131 | (org-back-to-heading t) | |
1132 | (org-reveal) | |
1133 | (org-entry-put nil "EXPORT_LaTeX_CLASS" "beamer") | |
1134 | (org-entry-put nil "EXPORT_LaTeX_CLASS_OPTIONS" "[presentation]") | |
1135 | (org-entry-put nil "EXPORT_FILE_NAME" "presentation.pdf") | |
1136 | (when org-beamer-column-view-format | |
1137 | (org-entry-put nil "COLUMNS" org-beamer-column-view-format)) | |
1138 | (org-entry-put nil "BEAMER_col_ALL" org-beamer-column-widths)) | |
1139 | (insert "#+LaTeX_CLASS: beamer\n") | |
1140 | (insert "#+LaTeX_CLASS_OPTIONS: [presentation]\n") | |
1141 | (when org-beamer-theme (insert "#+BEAMER_THEME: " org-beamer-theme "\n")) | |
1142 | (when org-beamer-column-view-format | |
1143 | (insert "#+COLUMNS: " org-beamer-column-view-format "\n")) | |
1144 | (insert "#+PROPERTY: BEAMER_col_ALL " org-beamer-column-widths "\n"))) | |
1145 | ||
1146 | ;;;###autoload | |
1147 | (defun org-beamer-publish-to-latex (plist filename pub-dir) | |
1148 | "Publish an Org file to a Beamer presentation (LaTeX). | |
1149 | ||
1150 | FILENAME is the filename of the Org file to be published. PLIST | |
1151 | is the property list for the given project. PUB-DIR is the | |
1152 | publishing directory. | |
1153 | ||
1154 | Return output file name." | |
1155 | (org-publish-org-to 'beamer filename ".tex" plist pub-dir)) | |
1156 | ||
1157 | ;;;###autoload | |
1158 | (defun org-beamer-publish-to-pdf (plist filename pub-dir) | |
1159 | "Publish an Org file to a Beamer presentation (PDF, via LaTeX). | |
1160 | ||
1161 | FILENAME is the filename of the Org file to be published. PLIST | |
1162 | is the property list for the given project. PUB-DIR is the | |
1163 | publishing directory. | |
1164 | ||
1165 | Return output file name." | |
1166 | ;; Unlike to `org-beamer-publish-to-latex', PDF file is generated in | |
1167 | ;; working directory and then moved to publishing directory. | |
1168 | (org-publish-attachment | |
1169 | plist | |
30cb51f1 BG |
1170 | (org-latex-compile |
1171 | (org-publish-org-to | |
1172 | 'beamer filename ".tex" plist (file-name-directory filename))) | |
271672fa BG |
1173 | pub-dir)) |
1174 | ||
1175 | ||
1176 | (provide 'ox-beamer) | |
1177 | ||
1178 | ;; Local variables: | |
1179 | ;; generated-autoload-file: "org-loaddefs.el" | |
1180 | ;; End: | |
1181 | ||
1182 | ;;; ox-beamer.el ends here |