Maintainable Beamer-Markdown with Nix
Posted on 2019-11-30 by ubikiumUpdate
Please refer to the new post where nix flake
is used to make the process easier.
This post is only preserved for references.
Introduction
Nix is cool, Markdown is easy, and LaTeX-Beamer-Pandoc is powerful. How to combine the three together? Here I will introduce some configuration tricks I learned during the process. The main purpose of the post is to automate as much as possible and actually make the configuration maintainable.
Most of the contents of the post is from websites, with a little adaptation. The Nix part comes from kimagure’s wonderful post Easy Markdown to Beamer with Pandoc and Nix. The separation of configuration comes from Boilerplating Pandoc for Academic Writing. Plus some good documentations from TeXLive packages.
Installation
For this to work, you need to install Pandoc and some TeXLive packages. My configuration is as following:
let
pkgs = import <nixpkgs> {};
texlive = pkgs.texlive.combine {
inherit (pkgs.texlive)
scheme-full;
};
in {
slides = pkgs.stdenv.mkDerivation {
name = "slides";
src = ./.;
buildInputs = [
texlive
pkgs.pandoc
pkgs.watchexec
];
};
}
Notice that I’ve changed TeXLive schemes into the full one, meaning that you will get every package on TeXLive. This solves a lot of difficult dependency problems, and unless the disk storage is a problem, the full scheme is recommended. Of course, you can replace that with a basic one and add the packages you need. See the Nix manual’s TeXLive section.
Save this as a default.nix
file, which will be invoked whenever nix-shell
runs. You have to copy-paste this file to the directory where your source markdown file lives. I’ll introduce the automation technique later.
Makefile
Following the same Makefile from the original post,
default:
nix-shell --run 'make slides'
slides:
pandoc -t beamer slides.md -o slides.pdf
watch:
nix-shell --run 'watchexec -e md make'
repl:
nix repl '<nixpkgs>'
When you invoke make
command, the pandoc
command is run in the nix-shell
, which uses default.nix
to install the dependencies. As is the default.nix
file, you’ll have to put the Makefile wherever you write slides, and the slide source file’s name needs to be slides.md
.
Boilerplate the slide
You can try it now with the following slides.md
file,
---
title: Maintainable Markdown-Beamer
subtitle: a survey
author: Ubikium
date: 2019-11-29
---
# Introduction
## Motivation
Why *Markdown*?
- It's easy.
- It's simple.
Why `Beamer`?
- It's nice.
> - It has incremental bullets.
# Tests
## Mathematical symbols
Suppose $R$ is the radius of a sephere.
Then the volume can be calculated with the following formula:
$$V = \frac{4\pi}{3} R^3$$
## Code
```hs
data Maybe a = Just a | Nothing
```
## Inline LaTeX
\begin{center}
\emph{Hello, World!}
\end{center}
Copy the default.nix
and Makefile
to the directory where you put the markdown file, and run make
. You should see the slides.pdf
file in the same folder. The first time will take a while to actually install the dependencies, but consecutive calls are much faster. That’s the magic of Nix.
You can add a lot of things in the metadata part of the markdown file, including the usual filetype independent author
, keywords
, and abstract
. Also you can add some LaTeX command to add before the header, like installing a font and using some packages.
According to the Boilerplate post, it’s better to separate the useful metadata (e.g. title, author, date, abstract) and the formatting metadata (e.g. fontsize, theme). Leave the former in the header of the markdown source file, and put the latter into a separate file. Let’s call it default.yaml
. Here is my setting:
---
toc: true
toc-title: Table of Contents
fontsize: 12pt
---
Copy it to the source directory and the pandoc
command should be pandoc -t beamer default.yaml slides.md -o slides.pdf
.
For the LaTeX commands to be added before the document, why not seperate them as well? Because they tend to be many and they’re more or less the same each time.
My settings for the header is as following:
\usepackage{amsmath, amsfonts, amssymb}
\usetheme{metropolis}
\usepackage{FiraSans}
\usepackage{mathptmx}
\def\mathfamilydefault{ptm}
% Toggle text font between Sans Serif & Serif (math mode font unchanged)
% \renewcommand{\familydefault}{} # sans serif
% \renewcommand{\familydefault}{\sfdefault} # serif
\renewcommand{\familydefault}{\sfdefault}
% Dummy command to enable markdown inside raw latex
% example:
% \tex{
% \begin{center}
% }
%
% Markdown *here*.
%
% \tex{
% \end{center}
% }
\newcommand\tex[1]{#1}
% useful symbols
\newcommand{\heart}{\ensuremath\heartsuit}
\newcommand{\coheart}{\rotatebox[origin=c]{180}{\heart}}
\newcommand{\dialabel[1]}{\ensuremath\langle#1\rangle}
\newcommand{\boxlabel[1]}{\ensuremath[#1]}
\definecolor{DeepBlue}{RGB}{0, 0, 78}
\setbeamercolor{title}{fg=DeepBlue}
\setbeamercolor{frametitle}{bg=DeepBlue}
\setbeamercolor{structure}{bg=DeepBlue}
Note that if you need academic writing and want to use mathptmx
as your math mode font, the package must comes after the theme command.
You can keep the text font unchanged by setting \renewcommand{\familydefault}{\sfdefault}
. The other \tex{}
command is a workaround to write markdown inside inline LaTeX. I found that useful. See this issue.
Save it as header.tex
, and this concludes the final form of the pandoc
command. You can edit the Makefile to the following:
default:
nix-shell --run 'make slides'
slides:
pandoc -t beamer -H header.tex default.yaml slides.md -o slides.pdf
watch:
nix-shell --run 'watchexec -e md make'
repl:
nix repl '<nixpkgs>'``
Automating copying
For now, we have used files to boilerplate out most of the settings. But that’s a lot to copy each time, you need to have:
default.nix
default.yaml
header.tex
Makefile
slides.md
in your slides directory. Why not automate with some bash scripts.
Choose a directory that’s on your $PATH
environment variable. For example, ~/.local/bin
. Create a new script as following:
#!/run/current-system/sw/bin/bash
# Check if:
# default.nix
# default.yaml
# header.tex
# Makefile
# slides.md
# exists
# if not, copy from templates
BEAMERTEMP="/path/to/your/templates/beamer"
SLIDES="slides.md"
TODAY=$(date +%F)
check_and_copy () {
if test -f $1
then
echo "Using current $1"
else
echo "Creating $1"
cp "$BEAMERTEMP/$1" $1
# set slides date to today
if [ $1 == $SLIDES ]
then
sed -i "s/^date:.*$/date: $TODAY/" $SLIDES
fi
fi
}
check_and_copy "default.nix"
check_and_copy "default.yaml"
check_and_copy "header.tex"
check_and_copy "Makefile"
check_and_copy $SLIDES
This script will check if each file exists, if it already exists, just use them, otherwise, copy from the templates.
Don’t forget to change the path to your templates. It also changes the date:
into the creating day.
Also note that the shebang at the top of the script is for NixOS. If you’re not on NixOS, then it typically should be #!/bin/bash
. If you are not sure, just use which bash
.
Save it as beamer-init
, chmod u+x beamer-init
. By the way, you should also set the permission for other users.
If the directory is not already in your $PATH
variable, add it to your .bashrc
and source
it.
Conclusion
For a new slide show, just beamer-init
, then add the content, change some options maybe, and finally make
. That’s easy!
Hope this will help you, my friend.
Files
All files mentioned are available in the following URLs: