If you're here to copy and paste the full config file, use this link. Otherwise enjoy reading!
Introduction
Welcome back to another iteration of the Emacs from Scratch series. This time I'm going to be setting up Emacs for writing documents in LaTeX, which I think is one of the best uses for Emacs, especially for beginners. Today I'll be setting this up on a fresh Debian 11 instance on Vultr, but hopefully the same steps will work on other mainstream distributions like Ubuntu and Arch.
As in the last installment, the first command I'll run is
sudo apt update && apt upgrade
to make sure my installed packages are up to date and to refresh the package repositories for installing Emacs. After that, I will actually install Emacs with the command
sudo apt install emacs
That should finish pretty quickly, and in my case it looks like
it installed Emacs 27.1, which is a pretty recent version. Now
I'll start the long installation of LaTeX. There are several
packages available that provide LaTeX with varying levels of
accompanying packages. I think texlive-base
is the bare
essentials, texlive
offers "a decent selection" of packages,
and texlive-full
comes with basically everything you can
imagine and requires about 5-6 Gb to fully install. Since I use
LaTeX for science and math, I'll give texlive-science
a try. I
think on Arch I install texlive-most
, which, as the name
indicates, comes with most of the packages, but excludes most of
the language packages that make up most of the size of
texlive-full
.
apt install texlive-science
Finally, I'll install my favorite PDF viewer, zathura.
apt install zathura
Of course, all of these could be combined into a single command:
apt install emacs zathura texlive-science
At this point, my YouTube video begins, so you can also watch that to follow along.
As a quick aside, Emacs users typically abbreviate the Control
key as C- and the Meta or Alt key as M- in a key chord. So when I
say type "M-x" that means hold down your Alt key and press the x
key at the same time. Space in key chords mean they are separate
commands. For example C-x C-f
, the chord for find-file
, is
produced by holding Control, pressing x, releasing x, and
pressing f. Of course you can release Control at the same time
you release x, but since you're about to press C-f
you probably
won't.
Basic Emacs Configuration
Just like last time, the first bit to add to the fresh Emacs config initializes the package repositories so we can actually install stuff.
(require 'package) (add-to-list 'package-archives '("melpa" . "http://melpa.org/packages/")) (package-initialize)
After evaluating this code (probably by placing your cursor after
each closing parenthesis and typing C-x C-e
or by running M-x
eval-buffer
), you should run M-x package-refresh-contents
to
ensure your package repositories are up to date. This should head
off any issues with installing packages. One other thing I
remembered in making the video is that some of the later package
operations will write out Custom variables to your config file. If
you want to hide that, just add the following snippet:
(setq custom-file "~/.custom.el") (load custom-file)
For the sake of this post, I just use the .emacs
file in my home
directory, but if you are using a more normal path inside
~/.emacs.d
, just update the path to be in there, or really
anywhere you prefer.
With that out of the way, we'll use use-package
to install the
rest of our packages since that's the easiest technique I've
found. This snippet will set that up:
(unless (package-installed-p 'use-package) (package-install 'use-package)) (require 'use-package)
Assuming you're a Vim user, the next thing to set up is
evil-mode
, the major Vim emulation package for Emacs. Now that
we have use-package
, we can do that with
(use-package evil :ensure t :config (evil-mode))
One "issue" with evil-mode
now is that it doesn't come with an
undo/redo facility by default. Really this is an issue with
Emacs, which is supposed to be fixed, I think in Emacs 28. I call
it an "issue" with evil-mode
because evil used to come with
undo-tree
, but several months ago it dropped that as a
dependency, instead opting to let (make) you choose your
own. We'll just install undo-tree
, which is actually pretty
nice on its own as well. We'll also enable it globally.
(use-package undo-tree :ensure t :config (global-undo-tree-mode 1))
Now that we have undo-tree
, we need to make some tweaks to our
evil config. The main thing here is telling evil to use
undo-tree
as the undo system, but I also added
evil-search-module
since the new default is to use the built-in
Emacs search functionality instead of Vim-style searches. If
you're not a Vim user, you may want to try the default as well.
(use-package evil :ensure t :config (evil-set-undo-system 'undo-tree) (setq evil-search-module 'evil-search) (evil-mode))
One other piece of basic setup I like to do is installing ivy
,
which offers nicer completion menus than the Emacs defaults. This
part is totally optional but may smooth your experience with
switching buffers and completing LaTeX commands later on.
(use-package ivy :ensure t :config (ivy-mode 1))
AUCTeX
With that basic functionality established, all we really have left
is to install AUCTeX, which helps to smoothly integrate Emacs and
LaTeX. As usual, the basic configuration is just to ensure the
package is installed with use-package
. However, we also need to
make sure to defer
the package to avoid an error about auctex
not providing the auctex
feature, which I ran into in the video. I
think this is because auctex
doesn't provide its own package, it
just adds features to the built-in TeX package or something like
that. Regardless, :defer t
will prevent that.
(use-package auctex :ensure t :defer t)
Assuming you want to view the PDFs produced by LaTeX in an external
program, you'll also need to set the TeX-view-program-selection
variable to your external PDF viewer. Since we installed zathura
and since it automatically refreshes when you recompile your
document, update your configuration as shown below.
(use-package auctex :ensure t :defer t :hook (LaTeX-mode . (lambda () (push (list 'output-pdf "Zathura") TeX-view-program-selection))))
I don't really think this should need to be a hook, but this is the best way I've found to ensure you don't run into a weird error message on startup. If you try setting the variable directly, you will likely receive an error about it being an unbound variable before you load AUCTeX the first time.
Now that we have auctex
installed and set up, let me show you
around a bit. To do that, you'll need a minimal example of a LaTeX
file such as the one shown below:
\documentclass{article} \begin{document} Hello world \end{document}
The first thing to do is press C-c C-c
, which will let you select
a LaTeX command to run. The default should fittingly be
LaTeX
. Pressing RET
will compile the document. After that,
pressing C-c C-c
again should default to View
since the document
is already up to date. Since we have set up Zathura as our PDF
viewer, pressing RET
on View
should prompt you for a Zathura
command. Pressing RET
again should open Zathura.
One of the most useful features of AUCTeX, beyond the ease of
compilation and viewing, is its insertion of various LaTeX
environments through the C-c C-e
binding. This part is probably
easier to see in the video or just by trying it yourself, but
inserting a table
, for example, will walk you through the parts of
a table environment, including the caption, the label, and the
alignment of the columns. This is very helpful especially if you are
new to LaTeX. You can similarly insert environments like figures,
itemized lists, enumerated lists, equations, and so on. That
basically exhausts what I typically use inside of AUCTeX, but if you
press C-h b
to list the bindings available and search for
latex-mode
, there are actually many more useful bindings. I
already see some that I will try to integrate into my workflow in
the future.
One last feature that is pretty nice, and will become apparent as soon as you start typing a real document, is the in-line preview. Assuming you're running a graphical Emacs instance, AUCTeX will preview font features like sub- and superscripts, italics, and boldface. I don't find this that helpful personally, but some people who have seen me editing LaTeX files have been very impressed, so I hope people reading this will be too.
Snippets
If the existing AUCTeX commands don't do enough for you, another nice thing to include when editing LaTeX is a way to insert snippets. These allow you to type a small prefix, which expands into a full piece of code when you press Tab. The package I use for snippets in Emacs is called yasnippet. Install it using the code below.
(use-package yasnippet :ensure t :config (yas-global-mode 1))
Once you have this installed, you can add a new LaTeX snippet from a
TeX buffer with the command M-x yas-new-snippet
. This will open a
new buffer that looks like
# -*- mode: snippet -*- # name: # key: # --
You can put whatever you want in the name
spot, but the key
is
what you will type to trigger the snippet. I usually make them both
the same thing. Since I write about fundamental vibrational
frequencies often and these are typically referred to with the Greek
letter "nu", I have a snippet like the one below set up:
# -*- mode: snippet -*- # name: nu # key: nu # -- \$\nu_{$1}\$$0
After I type nu
in a LaTeX file, I can now hit Tab and this text
is inserted, then my cursor is placed in the $1
location. There I
can type the appropriate subscript. Then when I hit Tab again, my
cursor moves to the $0
location and the snippet is finished. One
problem I ran into on the video, though, is that saving the snippet
did not work as usual. Normally I can just press C-c C-c
to finish
editing the snippet. If you run into the same problem, this
keybinding is supposed to be bound to
yas-load-snippet-buffer-and-close
, so you can at least call this
directly. I got out of it by saving the snippet buffer, but that's
not as easy as it should be.
If it's not clear, yasnippet
is useful in other modes as well. For
example, when working on a very repetitive programming project, I
wrote a Golang snippet for inserting the template of a for
loop. I've also written some for org-mode that I can't think of
right now. But the point is that snippets are very handy anywhere
there is a lot of repetitive text to be inserted, potentially with
components that need to be modified each time.
Viewing PDFs in Emacs
If you aren't satisfied with opening your PDFs in an external
viewer, you can also use Emacs to view the PDFs directly. As I
showed (with some difficulty) in the video, you can use the built-in
doc-view-mode
to view PDFs by finding them with C-x
C-f
, but this is pretty plain. Another issue
with doc-view-mode
is that it doesn't update
automatically upon recompiling LaTeX, but you can add a hook to fix
that:
(add-hook 'doc-view-mode-hook 'auto-revert-mode)
The issue I ran into in the video was actually that I didn't have
ghostscript
installed, so make sure to run
sudo apt install ghostscript
if you do want to use doc-view-mode
. With ghostscript
installed,
I think it should be triggered automatically for files with a .pdf
extension.
Another option is to use the pdf-tools package. I've had some trouble with this package in the past, but that was several years ago. Just in the past week I have heard that one of my friends is using it to great effect, so I expect it is much improved. It looks like they have good documentation for installing it, so I will defer to them for now, but I may make another post or video about setting it up if I give it a try myself or if enough people request it.
Full Config
Here is the full configuration file I put together in the video and modified slightly while writing the post itself. As always, let me know if you have any suggestions or run into problems!
(require 'package) (add-to-list 'package-archives '("melpa" . "http://melpa.org/packages/")) (package-initialize) (setq custom-file "~/.custom.el") (load custom-file) (unless (package-installed-p 'use-package) (package-install 'use-package)) (require 'use-package) (use-package evil :ensure t :config (evil-mode) (evil-set-undo-system 'undo-tree)) (use-package undo-tree :ensure t :config (global-undo-tree-mode 1)) (use-package ivy :ensure t :config (ivy-mode 1)) (use-package auctex :ensure t :defer t :hook (LaTeX-mode . (lambda () (push (list 'output-pdf "Zathura") TeX-view-program-selection)))) (use-package yasnippet :ensure t :config (yas-global-mode 1)) (add-hook 'doc-view-mode-hook 'auto-revert-mode)