After edebug
-ing through org-export-to-file
and peeking at related posts, including Export to multiple files according to tags, I have come up with the solution below. It keeps the necessary decorations in the org file at a minimum and uses some elisp code to do the presentation/handout switch. Note the caveat about global latex class options at the end.
org file content
#+LaTeX_CLASS: beamer
#+BEAMER_THEME: default
#+AUTHOR: Niclas Börlin
#+LATEX_HEADER: \input{preamble.tex}
#+OPTIONS: email:t num:t toc:nil \n:nil ::t |:t ^:t -:t f:t *:t <:t
* L01 - Introduction :L01_intro:cur:
:PROPERTIES:
:EXPORT_DATE: 2017-10-31 Tue
:END:
** Lecture 1, Slide 1
- Items
** Lecture 1, Slide 2
- Items
* L02 - Fundamentals :L02_fundamentals:
:PROPERTIES:
:EXPORT_DATE: Fri 2017-11-03
:END:
** Lecture 2, Slide 1
- Items
Notes:
- The header contains stuff common for all lectures.
- It does not contain any
LATEX_CLASS_OPTIONS
. The handout
will be handled programatically (see .emacs
below).
- It contains one line that includes
preamble.tex
.
- Each lecture on its own top level. Slides within that lecture in sub-levels.
- Lecture-specific properties, e.g. the lecture date, in a property drawer.
- One unique tag per lecture. The tag also acts as a filename stub.
- One :cur: tag that denotes my currently active lecture (to enable keyboards shortcuts).
preamble.tex
content
\usepackage{lmodern}
\usepackage{tikz}
\usepackage{pgfplots}
\mode<handout>{
\usepackage{pgfpages}
\pgfpagesuselayout{4 on 1}[a4paper,border shrink=5mm,landscape]
}
Includes packages and settings common to all slides and lectures. The most important part is the conditional \mode<handout>
snippet (see e.g. https://tex.stackexchange.com/questions/266116/trying-to-hide-blocks-of-text-in-beamer/) that sets up the handout format.
If you prefer, you could of course include the lines in preamble.tex
as #+LaTeX_CLASS_OPTIONS:
lines in your org file instead.
.emacs
content
(defun export-slides-or-handouts (tagname handouts)
"Export org subtree with tag tagname as beamer slides or handouts. If handout
is non-nil, exports to a file named tagname-handouts.tex and uses \"[handout]\"
as the class option. Otherwise, export to a file named tagname-slides.tex with
empty class option. Any underscore in tagname is replaced by a dash in the file
name."
(save-excursion
(beginning-of-buffer)
; Search for tagname
(search-forward (concat ":" tagname ":"))
(let ((org-export-select-tags (list tagname))
(async nil)
(subtreep t)
(visible-only nil)
(body-only nil)
; Use [handout] option if exporting handouts, otherwise empty.
(ext-plist (if handouts '(:latex-class-options "[handout]")
'()))
; Export name is tagname (with underscores replaced by dashes)
; followed
(export-name (concat (subst-char-in-string ?_ ?- tagname)
(if handouts "-handouts" "-slides")
".tex")))
(org-export-to-file 'beamer export-name async subtreep
visible-only body-only ext-plist
(lambda (file) (org-latex-compile file))))
)
)
(defun get-current-lecture-tag()
"Return the first tag that appears together with the first :cur: tag in the file."
(save-excursion
(beginning-of-buffer)
; Search for first :cur: tag.
(if (search-forward ":cur:" nil t)
; Return first tag in list, excluding :cur:
(nth 0 (remove "cur" (org-get-tags)))
(error (message "No :cur: tag found.")))))
(defun export-current-slides()
"Export the subtree with the :cur: tag as beamer slides."
(interactive)
(let ((tag (get-current-lecture-tag)))
(if tag
(progn (message "Exporting %s slides" tag)
(export-slides-or-handouts tag nil))
(error (message "No tag on :cur: lecture")))))
(defun export-current-handouts()
"Export the subtree with the :cur: tag as beamer handouts."
(interactive)
(let ((tag (get-current-lecture-tag)))
(if tag
(progn (message "Exporting %s handouts" tag)
(export-slides-or-handouts tag t))
(error (message "No tag on :cur: lecture")))))
(defun set-my-beamer-export-keys()
(interactive)
(local-set-key (kbd "<f12>") 'export-current-slides)
(local-set-key (kbd "<S-f12>") 'export-current-handouts))
Notes
- The function
export-slides-or-handouts
does a subtree export for a specific tag.
- If handouts are requested,
'(:latex-class-options "[handout]")
is used for the ext-plist
argument in the call to org-export-to-file
. Otherwise, the property list is empty, i.e., no LaTeX class options. Without options, the default is to generate slides.
- The used file name is either tagname-slides.tex or tagname-handouts.tex. (For aesthetic reasons, the code also replaces underscores with hyphens in tagname.)
The export-slides-or-handouts
functions solves everything I need programmaticaly (see, e.g., EDIT2 of Export to multiple files according to tags). The other functions allow me easy access via function keys.
Usage:
- Start up emacs, open
your-lecture-notes.org
.
- Put necessary stuff in header.
- Do
M-x set-my-beamer-export-keys
to set up keys.
- Add a lecture with a title, give it a tag, add :cur: tag.
- Add slides, items, etc.
- Press F12 to export the current lecture notes as slide.
- Press S-F12 to export them as handouts.
- To shift focus to another lecture, move the :cur: tag.
Caveat
While the above solution is really nice to work with, there is room for improvement. For instance, as presented, my solution does not work with other beamer class options, e.g. 12pt
, as the file-local options override the programmatical ones in ext-plist
. (See, e.g., function comment for org-export-get-environment
. A workaround is to modify export-slides-or-handouts
to supply "[12pt,handout]" for handouts and "[12pt]" for slides. (Or supply the options as a parameter.)