dotemacs

My Emacs configuration
git clone git://git.entf.net/dotemacs
Log | Files | Refs | LICENSE

ox-beamer.el (44459B)


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