Miscellaneous Emacs configuration

6 minutes read

I’ve been spending a bit of time getting my Emacs configuration up-to-date, cutting down on bloat, and reducing package usage. Here’s how it went:

Setting up presentations

One of the things I wanted to streamline was setting up presentations directly from Emacs. I’ve tried a couple of methods, and here’s a quick rundown of what worked best for me.

Setting up a LaTeX environment

Org-mode continues to be one of Emacs’ most powerful tools. One thing I discovered recently is the Org-beamer export feature, which lets you create presentations directly from Org files. It’s pretty neat since you can structure your slides just like an outline. It’s like writing your slides in markdown but with the full power of Org-mode’s features. All you need to do is use a couple of #+ directives, and the export to LaTeX will handle the rest.

Note that this needs the following set up:

mkdir -p ~/.Texlive
cd ~/.Texlive
wget https://mirror.ctan.org/systems/texlive/tlnet/install-tl-unx.tar.gz
# this typically needs gunzip installed
unzip ~/.dotfiles/scripts/ex install-tl-unx.tar.gz
./install-tl --texdir ~/.Texlive

I added the Texlive installation to the Emacs path because I do not like these scripts “polluting” my fish suggestions 🙄. Anyways, a simple

(setenv "PATH" (concat (getenv "HOME") "/.Texlive/bin/x86_64-linux:" (getenv "PATH")))

did the job for me.

I ended up using this setup for a few talks, and honestly, it’s super handy. The presentation is completely text-based, so you can tweak content as easily as changing a heading. I also love that you can embed code blocks with results in your slides if you’re doing a technical talk, which looks great.

Org-beamer

The LaTeX backend for Org-beamer is solid and works wonders with the LaTeX environment mentioned above. YMMV.

Here’s a minimal setup for using Org-beamer:

#+LATEX_CLASS: beamer
#+LATEX_CLASS_OPTIONS: [presentation]
#+BEAMER_THEME: Madrid

You can specify themes, colors, and the layout you want. A couple of tweaks like this can go a long way to make your presentation look clean without needing to dive into too many customization details.

Here’s what my setup looks like. Note that I’ve set this in my Emacs configuration because I’ll mostly follow similar settings across presentations.

(setq org-latex-default-class "beamer"
	org-latex-class-options "[smaller]"
	org-beamer-theme "Malmoe"
	org-latex-with-hyperref nil)

To get Org-Beamer to work, all you need to do is add a #+STARTUP: beamer to the (top of) the file you want to export.

You can then export your slides to Beamer PDF and open it in any PDF viewer (or even your browser). Sweet. Who needs PowerPoint office suites?!

Via Org-reveal and RevealJS

On the other hand, if you’re more into web-based presentations, Org-reveal comes to the rescue. It exports your Org-mode files to HTML and integrates seamlessly with Reveal.js, giving you smooth transitions and interactive slides.

The process is pretty straightforward: just make sure you’ve got the necessary tools installed (like the ox-reveal package). Once you’ve set up Org-reveal, your Org files can become fully interactive web presentations.

The best part? You can embed JavaScript, custom themes, and even interactive elements like quizzes and polls. I prefer this setup for non-technical presentations, where I want some snazzy effects and a more polished, web-based result.

Call me biased, but I prefer this over the previously mentioned Beamer solution. Who doesn’t like some pizzazz??

Add something like this to the Org file that you want to export:

#+REVEAL_JS: t
#+REVEAL_THEME: solarized
#+REVEAL_TRANSITIONS: zoom

And here are my settings:

(setq
	;; org-reveal-root "https://cdn.jsdelivr.net/npm/reveal.js"
	org-reveal-root "/home/stig/Git/reveal.js"
	org-reveal-theme "league"
	org-reveal-width 1920 ;; 1200 too small
	org-reveal-height 1080 ;;800 too broad
	org-reveal-margin 0.001
	org-reveal-min-scale 0.01
	org-reveal-max-scale 1.0
	org-reveal-transition "cube" ;; Wayfire vibes
	;; org-reveal-head-preamble "<meta name=\"description\" content=\"Org-Reveal Introduction.\">"
	;; org-reveal-postamble "<p> Created by ZeStig. </p>"
	org-reveal-hlevel 1)

There are lots of themes and transitions available out of the box, and you can always tweak them as needed.

Switching to Elpaca from Straight

I’ve also been taking a closer look at package management in Emacs. After spending a long time using Straight.el, I decided to give Elpaca a try, mostly due to its simplicity and speed. Straight.el has been great, but it can sometimes feel like overkill, especially if you’re just looking for a lightweight, fast way to manage packages.

Elpaca is built to be much leaner, and it doesn’t try to do too much. It’s focused on performance, which, for me, is a huge deal. I noticed a slight performance boost after switching, and the configuration is super simple compared to what I had with Straight.el.

Here’s how you set it up:

(I’ve plagiarised this from the elpaca README).

(defvar elpaca-installer-version 0.8)
(defvar elpaca-directory (expand-file-name "elpaca/" user-emacs-directory))
(defvar elpaca-builds-directory (expand-file-name "builds/" elpaca-directory))
(defvar elpaca-repos-directory (expand-file-name "repos/" elpaca-directory))
(defvar elpaca-order '(elpaca :repo "https://github.com/progfolio/elpaca.git"
                              :ref nil :depth 1
                              :files (:defaults "elpaca-test.el" (:exclude "extensions"))
                              :build (:not elpaca--activate-package)))
(let* ((repo  (expand-file-name "elpaca/" elpaca-repos-directory))
       (build (expand-file-name "elpaca/" elpaca-builds-directory))
       (order (cdr elpaca-order))
       (default-directory repo))
  (add-to-list 'load-path (if (file-exists-p build) build repo))
  (unless (file-exists-p repo)
    (make-directory repo t)
    (when (< emacs-major-version 28) (require 'subr-x))
    (condition-case-unless-debug err
        (if-let* ((buffer (pop-to-buffer-same-window "*elpaca-bootstrap*"))
                  ((zerop (apply #'call-process `("git" nil ,buffer t "clone"
                                                  ,@(when-let* ((depth (plist-get order :depth)))
                                                      (list (format "--depth=%d" depth) "--no-single-branch"))
                                                  ,(plist-get order :repo) ,repo))))
                  ((zerop (call-process "git" nil buffer t "checkout"
                                        (or (plist-get order :ref) "--"))))
                  (emacs (concat invocation-directory invocation-name))
                  ((zerop (call-process emacs nil buffer nil "-Q" "-L" "." "--batch"
                                        "--eval" "(byte-recompile-directory \".\" 0 'force)")))
                  ((require 'elpaca))
                  ((elpaca-generate-autoloads "elpaca" repo)))
            (progn (message "%s" (buffer-string)) (kill-buffer buffer))
          (error "%s" (with-current-buffer buffer (buffer-string))))
      ((error) (warn "%s" err) (delete-directory repo 'recursive))))
  (unless (require 'elpaca-autoloads nil t)
    (require 'elpaca)
    (elpaca-generate-autoloads "elpaca" repo)
    (load "./elpaca-autoloads")))
(add-hook 'after-init-hook #'elpaca-process-queues)
(elpaca `(,@elpaca-order))

  ;; Install use-package support
(elpaca elpaca-use-package
  ;; Enable :elpaca use-package keyword.
  (elpaca-use-package-mode)
  ;; Assume :elpaca t unless otherwise specified.
  ;; (setq elpaca-use-package-by-default t)) -> replace https://github.com/progfolio/elpaca/issues/255
  (setq use-package-always-ensure t))
(elpaca-wait)

Then, I just migrated my existing packages over to Elpaca. The process was smooth and didn’t require a complete rework of my setup. So far, everything’s been fast, and the management overhead is much lower.

For migrating packages available on GitHub from Straight to Elpaca:

- (use-package emacs-everywhere
-      :straight (:type git :host github :repo "tecosaur/emacs-everywhere")
+ (use-package emacs-everywhere
+  :ensure '(emacs-everywhere :host github :repo "tecosaur/emacs-everywhere")

If you’re looking to simplify your package management and reduce some of the complexity that comes with more feature-rich solutions like Straight, Elpaca is definitely worth checking out.

Mail

This is where the fun begins.

Anakin, Ep 3, Revenge of the Sith (2005)

You need a mail indexer such as mu installed. You also need a mailbox synchroniser such as mbsync:

yay -S mu
sudo pacman -S isync gnutls

gnutls is likely installed by default on your GNU+Linux distribution. Then you need an Application Password for authenticating to GMail. You can obtain one from the Google Accounts page. Simply search for “App Password” in the search field and create an app password. Store the App password securely for we’ll need it later.

We now need to configure Emacs and mbsync.

Emacs

Add this to your configuration:

(add-to-list 'load-path "/usr/share/emacs/site-lisp/mu4e")(require 'mu4e)(use-package mu4e  :ensure nil  :config
  (setq mail-user-agent 'mu4e-user-agent)

  (setq mu4e-drafts-folder "/[Gmail].Drafts")
  (setq mu4e-sent-folder   "/[Gmail].Sent Mail")
  (setq mu4e-trash-folder  "/[Gmail].Trash")

  ;; don't save message to Sent Messages, Gmail/IMAP takes care of this
  (setq mu4e-sent-messages-behavior 'delete)

    ;; setup some handy shortcuts
  ;; you can quickly switch to your Inbox -- press ``ji''
  ;; then, when you want archive some messages, move them to
  ;; the 'All Mail' folder by pressing ``ma''.
  
   (setq mu4e-maildir-shortcuts
    '( (:maildir "/INBOX"              :key ?i)
       (:maildir "/[Gmail].Sent Mail"  :key ?s)
       (:maildir "/[Gmail].Trash"      :key ?t)
       (:maildir "/[Gmail].All Mail"   :key ?a)))

  (add-to-list 'mu4e-bookmarks
           ;; ':favorite t' i.e, use this one for the modeline
           '(:query "maildir:/inbox" :name "Inbox" :key ?i :favorite t))

  ;; allow for updating mail using 'U' in the main view:
  (setq mu4e-get-mail-command "mbsync -a")

  ;; something about ourselves
  (setq user-mail-address "<USERNAME>@gmail.com"
    user-full-name  "<NAME>")
  ;; ( setq message-signature (concat "\n" "\n"))

  (setq mu4e-compose-signature (concat "Sent with <U+E7CF>\n" "https://zstg.is-a.dev\n"))
   (require 'smtpmail)
  (setq message-send-mail-function 'smtpmail-send-it
    send-mail-function 'smtpmail-send-it
    smtpmail-default-smtp-server "smtp.gmail.com"
    smtpmail-smtp-server "smtp.gmail.com"
    smtpmail-smtp-service 587
    smtpmail-stream-type 'starttls
    smtpmail-smtp-user "<USERNAME>@gmail.com"
    starttls-use-gnutls t
    starttls-gnutls-program "gnutls-cli"
    starttls-extra-arguments nil)
  ;; this is not the right place to configure auth details...
  (setq auth-source-debug t
    auth-sources '((:source "~/.authinfo.gpg"))
        ;; don't keep message buffers around
        message-kill-buffer-on-exit t))

Replace USERNAME and NAME appropriately.

But wait? Where are the actual Gmail credentials? Surely they must be stored somewhere?

To answer that question, add this to the ~/.authinfo file: Create the file if it doesn’t exist.

machine "smtp.gmail.com" login "username@gmail.com" password "abcd bcde cdef defg"

Obviously replace abcd bcde cdef defg with the Application Password that you set previously.

Now encrypt this file:

gpg -c ~/.authinfo

This will create a ~/.authinfo.gpg file that stores the App Password.

Do the same thing for your Gmail password.

echo <password> > .passwd
gpg -c .passwd
rm .passwd

Create the directory where you want to store your mail. I’ve stored mine in ~/.mail.

We’re almost there. Now all that’s left is to configure mbsync (aka isync) and fetch the mail…

Create ~/.mbsyncrc with the following content:

IMAPStore gmail-remote
Host imap.gmail.com
SSLType IMAPS
AuthMechs LOGIN
User <USERNAME>@gmail.com
PassCmd "gpg -dq --for-your-eyes-only ~/.passwd.gpg"

MaildirStore gmail-local
Path ~/.mail/
Inbox ~/.mail/INBOX
Subfolders Verbatim

Channel gmail
Master :gmail-remote:
Slave :gmail-local:
Create Both
Expunge Both
Patterns * !"[Gmail]/All Mail" !"[Gmail]/Important" !"[Gmail]/Starred" !"[Gmail]/Bin"
SyncState *

Obviously replace <USERNAME>@gmail.com with your email address.

Finally, let’s create initialise the mail index and fetch the mail:

mu init --maildir=$HOME/.mail --my-address='<USERNAME>@gmail.com'
mu index

When you open Emacs the next time, a simple mu4e-update-index will display all the email you have received.

RSS

I’m not quite sure how often (or even if) I’ll use this functionality, but I’ve set up an RSS reader inside Emacs. This was simple to do, and I’ve just plagarised DT’s configuration.

(use-package elfeed
  :config
  (setq elfeed-search-feed-face ":foreground #ffffff :weight bold"
        elfeed-feeds (quote
	(("https://www.reddit.com/r/linux.rss" reddit linux)
	("https://www.reddit.com/r/archlinux.rss" reddit archlinux)
	("https://www.reddit.com/r/linuxfornoobs.rss" reddit linuxfornoobs)
	("https://www.reddit.com/r/linuxquestions.rss" reddit linuxquestions)
	("https://www.reddit.com/r/commandline.rss" reddit commandline)
	("https://www.reddit.com/r/distrotube.rss" reddit distrotube)
	("https://www.reddit.com/r/emacs.rss" reddit emacs)
	("https://www.gamingonlinux.com/article_rss.php" gaming linux)
	("https://hackaday.com/blog/feed/" hackaday linux)
	("https://opensource.com/feed" opensource linux)
	("https://linux.softpedia.com/backend.xml" softpedia linux)
	("https://itsfoss.com/feed/" itsfoss linux)
	("https://www.zdnet.com/topic/linux/rss.xml" zdnet linux)
	("https://www.phoronix.com/rss.php" phoronix linux)
	("http://feeds.feedburner.com/d0od" omgubuntu linux)
	("https://www.computerworld.com/index.rss" computerworld linux)
	("https://www.networkworld.com/category/linux/index.rss" networkworld linux)
	("https://www.techrepublic.com/rssfeeds/topic/open-source/" techrepublic linux)
	("https://betanews.com/feed" betanews linux)
	("http://lxer.com/module/newswire/headlines.rss" lxer linux)
	("https://distrowatch.com/news/dwd.xml" distrowatch linux)))))

Fin

All in all, this update to my Emacs setup has been pretty satisfying. I’ve cut down on unnecessary packages, streamlined my workflow for creating presentations, and improved performance. The best part is that it’s still flexible enough for me to jump into new tools or adjust things as I need them.

If you’re looking to clean up your own configuration or try out some of the things I mentioned, I’d say go for it. Emacs is an ongoing adventure, and it’s always fun to explore new ways of improving the experience. Happy hacking!