1

I am trying to create a robust function to print the current buffer from Emacs on macOS (Sonoma+). My goal is to get a printout with:

  1. Syntax highlighting (color).
  2. Correct rendering for Japanese (CJK) characters.
  3. A pure white background (even though I use a dark theme).
  4. 2-in-1 page layout.

After many attempts, I've concluded that the most reliable approach is to temporarily switch to a minimal, white-background theme just before printing, and then switch back to my original dark theme after the print job is sent.

My Attempt

I wrote the following function to achieve this. The logic is:

  1. Define a minimal set of faces for a "print theme" with a white background.
  2. Save the user's currently enabled themes.
  3. Use unwind-protect to ensure the original theme is always restored.
  4. In the try block: disable the current theme, apply the temporary print faces using custom-theme-set-faces, and then run my printing pipeline (which uses htmlize and headless Chrome to generate and print a PDF).
  5. In the finally block: unload the temporary print faces and re-enable the user's original themes.

The Problematic Code

Here is the function I tried to implement:

(defun print-buffer-as-light-theme () "A command to print the buffer by temporarily applying a minimal light theme." (interactive) (let* ((print-theme-faces `((default ((t (:background "white" :foreground "black")))) (font-lock-comment-face ((t (:foreground "gray50")))) (font-lock-keyword-face ((t (:foreground "blue")))) (font-lock-string-face ((t (:foreground "purple")))) (font-lock-function-name-face ((t (:foreground "dark green")))) (font-lock-variable-name-face ((t (:foreground "saddle brown")))) (font-lock-type-face ((t (:foreground "teal")))) (font-lock-constant-face ((t (:foreground "dark violet")))))) (current-enabled-themes custom-enabled-themes)) (unwind-protect ;; --- TRY block: The main printing logic --- (progn (message "Applying temporary print theme...") (mapc #'disable-theme current-enabled-themes) (custom-theme-set-faces 'print-theme-temporary print-theme-faces) ;; The printing pipeline itself (which works fine on its own) (let* ((html-buffer (htmlize-buffer)) (html-content (with-current-buffer html-buffer (buffer-string))) (temp-html-file (make-temp-file "emacs-print-" nil ".html")) (temp-pdf-file (make-temp-file "emacs-print-" nil ".pdf")) (chrome-path "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome") (lpr-command (format "lpr -o number-up=2 '%s'" temp-pdf-file))) (kill-buffer html-buffer) (unwind-protect (progn (with-temp-file temp-html-file (insert html-content)) (shell-command (format "'%s' --headless --print-to-pdf='%s' --no-pdf-header-footer 'file://%s'" chrome-path temp-pdf-file temp-html-file)) (shell-command lpr-command)) (when (file-exists-p temp-html-file) (delete-file temp-html-file)) (when (file-exists-p temp-pdf-file) (delete-file temp-pdf-file))) (message "Print job sent."))) ;; --- FINALLY block: Restore the original theme --- (progn (message "Restoring original theme...") ;; Unload the temporary print faces (custom-theme-set-faces 'print-theme-temporary) ;; Re-enable the original themes (mapc #'enable-theme current-enabled-themes))))) 

The Error

When I run this function (M-x print-buffer-as-light-theme), it fails with the following error in the minibuffer:

Unknown theme 'print-theme-temporary'

This error seems to be triggered by the (custom-theme-set-faces 'print-theme-temporary) call in the cleanup (finally) block. It appears that applying faces with custom-theme-set-faces does not register a "theme" that can be unloaded by calling the same function with only the theme name.

My Question

What is the correct Emacs Lisp idiom to achieve this "temporary theme for printing" pattern? Specifically, how can I reliably apply a temporary set of faces, execute a command, and then guarantee that the original user theme is restored, without causing an "Unknown theme" error?

1 Answer 1

0

There are many posts about printing from Emacs. Start with:

Since you claim your goal is to have a .pdf file to print, an easier method is to make an .org file, and with the package engrave-faces from MELPA, you can get a light theme when exporting by adding only two lines in .org file:

#+LaTeX_HEADER: \usepackage{listings} #+latex_engraved_theme: modus-operandi 

You can use whatever light theme you like. Minimal configuration:

(use-package engrave-faces) ;; load/init org (with eval-after-load 'org (setq-default org-latex-src-block-backend 'engraved) (add-to-list 'org-latex-packages-alist '("" "listings")) (add-to-list 'org-latex-packages-alist '("" "color"))) 

The "2 in one" can be left to printer. enter image description here

1
  • Thank you so much for your detailed and insightful answer! The approach using Org mode and engrave-faces is a fantastic idea that I hadn't thought of. While I ran into some further issues on my local setup, your suggestion pointed me in a very promising direction. I really appreciate you taking the time to help. Commented Jun 26 at 10:11

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.