Hi again On Sat, 11 Apr 2026 at 17:34, Ihor Radchenko <[email protected]> wrote:
> Pedro Andres Aranda Gutierrez <[email protected]> writes: > > >> Nothing will break, yes. > >> But having beamer-related code in other files is simply a bad coding > >> practice, especially if that's such a core functionality as defining > >> themes. This is not about correctness, but about code quality. > > > >> If you have library functionality split across multiple other libraries, > >> it makes it difficult to understand how the code works. It also makes it > >> potentially difficult to change ox-latex -- it will effectively gain an > >> extra dependency to account for. > > > > IMHO trying to compact code too much makes things worse. > > There are ways to move code around when you understand what the code > does... > > Sure. But keeping code in a single library is not too much in my book. Different schools of thought then... > > Just look at the attached 0001-ox-latex-... patch. Came after I broke my > > head over the "real" patch. > > > > My suggestion may be an overkill, yes. I will be happy if you find > >> something simpler. > > > > > > Apparently there was... if the code had only been easier to read. See > > 0001-ox-beamer... patch > > I am trying to not make it harder to read at least :) > > > lisp/ox-beamer.el: New option BEAMER_THEME_PRE. > > (org-beamer-theme-settings): new function to manage theme-related > > settings. > > *New (capitalized). Similar in other places. > These are small things, but let's keep the commit message format > consistent. Also, all sentences should end with ".". > OK > > @@ -13162,6 +13162,19 @@ settings (see [[*Export Settings]]). > > #+cindex: @samp{BEAMER_OUTER_THEME}, keyword > > The Beamer outer theme. > > > > + - =BEAMER_THEME_PRE= :: > > It is a sublist under previous item. Is it intentional? > Space that slipped in... > > +*** ox-beamer: New LaTeX preamble sequence > > + > > +When exporting to Beamer, all theme-related configuration will be > > +generated right after the document class declaration in concordance > > +with the examples shipped with the Beamer class. > > It is worth mentioning what was the previous default. > Done > > +;; Generate the preamble up to the theme > > +(defun org-beamer-class-template(info) > > + "Generate the class template from INFO. > > +This will include class-pre, class and theme definitions." > > + (let* ((class-pre (plist-get info :latex-class-pre)) > > + (class-options (concat "[" (plist-get info > :latex-class-options) "]"))) > > + ;; See org-latex--mk-options: > > + ;; Accept class options with and without square brackets > > + (setq class-options (replace-regexp-in-string "\\`\\[+" "[" > class-options)) > > + (setq class-options (replace-regexp-in-string "\\]+\\'" "]" > class-options)) > > + (concat class-pre (and class-pre "\n") > > + "\\documentclass" class-options "{beamer}\n" > > + (org-beamer-theme-settings info)))) > > Now, we are copying the logic from ox-latex. If we ever change how > ox-latex handles things, and forget this place, it will be a bug we > could have avoided. > I don't get this. 1. We don't want to have this ox-latex related code in ox-latex, OK 2. I'm generating foundational Beamer (and LaTeX) code here. Nothing exotic that will change in the way LaTeX expects files. What about very dumb approach - call `org-latex-make-preamble', find > \documentclass... inside, and then insert the theme definition right > after \documentclass, in the already-expanded preamble? > IMHO, that, exactly that, is what makes the code so hard to understand. > +(ert-deftest ox-beamer/org-beamer-pre-theme () > > + "Test that the theme is in its new place and beamer-pre is included." > > + (org-test-with-exported-text > > + 'beamer > > + "#+OPTIONS: toc:nil > > +#+LATEX_CLASS_OPTIONS: presentation,t > > +#+BEAMER_THEME_PRE: \\usepackage{geometry} > > +#+BEAMER_THEME: Boadilla > > +* A frame > > +Here is an example. > > +" > > + (goto-char (point-min)) > > + (should (search-forward > "\\documentclass[presentation,t]{beamer}\n\\usepackage{geometry}\n\\usetheme{Boadilla}\n")))) > > Nitpick: You do not have to use \n in the search forward. Can keep the > actual newlines as in the org-test-with-exported-text argument. It will > be easier to read. > Nice ... done > -;;; ox-latex.el --- LaTeX Backend for Org Export Engine -*- > lexical-binding: t; -*- > > +;; ox-latex.el --- LaTeX Backend for Org Export Engine -*- > lexical-binding: t; -*- > > Why this change? > Maybe a Ctrl-S turned inadvertedly in a Ctrl-D > The number of ;'s is not meaningless. It defines outline level in > outline-minor-mode. > > -- > Ihor Radchenko // yantar92, > Org mode maintainer, > Learn more about Org mode at <https://orgmode.org/>. > Support Org development at <https://liberapay.com/org-mode>, > or support my work at <https://liberapay.com/yantar92> > Give the patches a chance... -- Fragen sind nicht da, um beantwortet zu werden, Fragen sind da um gestellt zu werden Georg Kreisler "Sagen's Paradeiser" (ORF: Als Radiohören gefährlich war) => write BE! Year 2 of the New Koprocracy
From 3f939b5ef4776a136c107f6bad439ee1f0a0fe50 Mon Sep 17 00:00:00 2001 From: "Pedro A. Aranda" <[email protected]> Date: Sun, 12 Apr 2026 07:06:44 +0200 Subject: [PATCH 1/2] ox-beamer: New LaTeX preamble sequence and new BEAMER_THEME_PRE lisp/ox-beamer.el: New option BEAMER_THEME_PRE. (org-beamer-theme-settings): New function to manage theme-related settings. (org-beamer-class-template): New function to generate the Beamer class template. (org-beamer-template): Pass the generated Beamer class template to (org-latex-make-preamble). testing/lisp/test-ox-beamer.el: New test for BEAMER_CLASS_PRE and the new Latex class template. doc/org-manual.org: Document BEAMER_THEME_PRE etc/ORG-NEWS: Announce new LaTeX preamble sequence in Beamer header and BEAMER_THEME_PRE. --- doc/org-manual.org | 13 +++++++ etc/ORG-NEWS | 13 +++++++ lisp/ox-beamer.el | 66 +++++++++++++++++++++++----------- testing/lisp/test-ox-beamer.el | 16 +++++++++ 4 files changed, 87 insertions(+), 21 deletions(-) diff --git a/doc/org-manual.org b/doc/org-manual.org index baa1127a0..6658a7e51 100644 --- a/doc/org-manual.org +++ b/doc/org-manual.org @@ -13162,6 +13162,19 @@ settings (see [[*Export Settings]]). #+cindex: @samp{BEAMER_OUTER_THEME}, keyword The Beamer outer theme. +- =BEAMER_THEME_PRE= :: + + #+cindex: @samp{BEAMER_THEME_PRE}, keyword + Arbitrary lines inserted in the preamble, just before + =\usetheme{}=. For example: + + : #+BEAMER_THEME_PRE: \usepackage{geometry} + : #+BEAMER_THEME_PRE: \geometry{paperwidth=160mm, paperheight=90mm} + : #+BEAMER_THEME: Madrid + + Use the ~Madrid~ theme, setting the page size to 160mm by 90mm. This + can be used to help creating figures with TiKZ. + - =BEAMER_HEADER= :: #+cindex: @samp{BEAMER_HEADER}, keyword diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS index c6063470b..3ff6260c3 100644 --- a/etc/ORG-NEWS +++ b/etc/ORG-NEWS @@ -42,6 +42,14 @@ assume that the outer list has length one, which means ~(car (org-babel-tangle-single-block ...))~ is not guaranteed to return the correct ~(FILE . ...)~ cons. +*** ox-beamer: New LaTeX preamble sequence + +When exporting to Beamer, all theme-related configuration will be +generated right after the document class declaration in concordance +with the examples shipped with the Beamer class. Previously, the +theme configuration went after the whole LaTeX preamble and the beamer +frame definition, if it was needed. + ** New features # We list the most important features, and the features that may @@ -163,6 +171,11 @@ addition to being added to a data attribute, ~data-linenr~, on that highlight and copy/paste multiple lines from a code block without having the line numbers included. +*** New option BEAMER_THEME_PRE + +The new option BEAMER_THEME_PRE is used to add arbitrary LaTeX lines +that must be processed before the Beamer theme is loaded. + ** New functions and changes in function arguments # This also includes changes in function behavior from Elisp perspective. diff --git a/lisp/ox-beamer.el b/lisp/ox-beamer.el index 72fe18acd..0e7dc5c6d 100644 --- a/lisp/ox-beamer.el +++ b/lisp/ox-beamer.el @@ -261,6 +261,7 @@ Return overlay specification, as a string, or nil." (:latex-class "LATEX_CLASS" nil "beamer" t) (:beamer-subtitle-format nil nil org-beamer-subtitle-format) (:beamer-column-view-format "COLUMNS" nil org-beamer-column-view-format) + (:beamer-theme-pre "BEAMER_THEME_PRE" nil nil newline) (:beamer-theme "BEAMER_THEME" nil org-beamer-theme) (:beamer-color-theme "BEAMER_COLOR_THEME" nil nil t) (:beamer-font-theme "BEAMER_FONT_THEME" nil nil t) @@ -856,6 +857,48 @@ contextual information." ;;;; Template ;; +;; Extract theme related information +;; +(defun org-beamer-theme-settings (info) + "Return the code related to the Beamer theme for the latex preamble. +Will be called with the latex class is \"beamer\". +INFO is a plist holding the export options." + (let ((pre-header (plist-get info :beamer-theme-pre)) + (format-theme + (lambda (prop command) + (let ((theme (plist-get info prop))) + (when theme + (concat command + (if (not (string-match "\\[.*\\]" theme)) + (format "{%s}\n" theme) + (format "%s{%s}\n" + (match-string 0 theme) + (org-trim + (replace-match "" nil nil theme)))))))))) + (concat + pre-header (and pre-header "\n") + (mapconcat (lambda (args) (apply format-theme args)) + '((:beamer-theme "\\usetheme") + (:beamer-color-theme "\\usecolortheme") + (:beamer-font-theme "\\usefonttheme") + (:beamer-inner-theme "\\useinnertheme") + (:beamer-outer-theme "\\useoutertheme")) + "")))) +;; +;; Generate the preamble up to the theme +(defun org-beamer-class-template(info) + "Generate the class template from INFO. +This will include class-pre, class and theme definitions." + (let* ((class-pre (plist-get info :latex-class-pre)) + (class-options (concat "[" (plist-get info :latex-class-options) "]"))) + ;; See org-latex--mk-options: + ;; Accept class options with and without square brackets + (setq class-options (replace-regexp-in-string "\\`\\[+" "[" class-options)) + (setq class-options (replace-regexp-in-string "\\]+\\'" "]" class-options)) + (concat class-pre (and class-pre "\n") + "\\documentclass" class-options "{beamer}\n" + (org-beamer-theme-settings info)))) +;; ;; Template used is similar to the one used in `latex' backend, ;; excepted for the table of contents and Beamer themes. @@ -871,31 +914,12 @@ holding export options." (format-time-string "%% Created %Y-%m-%d %a %H:%M\n")) ;; LaTeX compiler (org-latex--insert-compiler info) - ;; Document class and packages. - (org-latex-make-preamble info) + ;; Document class, theme and packages. + (org-latex-make-preamble info (org-beamer-class-template info)) ;; Define the alternative frame environment, if needed. (when (plist-get info :beamer-define-frame) (format "\\newenvironment<>{%s}[1][]{\\begin{frame}#2[environment=%1$s,#1]}{\\end{frame}}\n" org-beamer-frame-environment)) - ;; Insert themes. - (let ((format-theme - (lambda (prop command) - (let ((theme (plist-get info prop))) - (when theme - (concat command - (if (not (string-match "\\[.*\\]" theme)) - (format "{%s}\n" theme) - (format "%s{%s}\n" - (match-string 0 theme) - (org-trim - (replace-match "" nil nil theme)))))))))) - (mapconcat (lambda (args) (apply format-theme args)) - '((:beamer-theme "\\usetheme") - (:beamer-color-theme "\\usecolortheme") - (:beamer-font-theme "\\usefonttheme") - (:beamer-inner-theme "\\useinnertheme") - (:beamer-outer-theme "\\useoutertheme")) - "")) ;; Possibly limit depth for headline numbering. (let ((sec-num (plist-get info :section-numbers))) (when (integerp sec-num) diff --git a/testing/lisp/test-ox-beamer.el b/testing/lisp/test-ox-beamer.el index 24550ec62..4c68fa33a 100644 --- a/testing/lisp/test-ox-beamer.el +++ b/testing/lisp/test-ox-beamer.el @@ -109,5 +109,21 @@ Here is a second example: (should (search-forward (concat "\\end{frame}") nil t)) (should (search-forward (concat "\\end{" org-beamer-frame-environment "}")))))) +(ert-deftest ox-beamer/org-beamer-pre-theme () + "Test that the theme is in its new place and beamer-pre is included." + (org-test-with-exported-text + 'beamer + "#+OPTIONS: toc:nil +#+LATEX_CLASS_OPTIONS: presentation,t +#+BEAMER_THEME_PRE: \\usepackage{geometry} +#+BEAMER_THEME: Boadilla +* A frame +Here is an example. +" + (goto-char (point-min)) + (should (search-forward "\\documentclass[presentation,t]{beamer} +\\usepackage{geometry} +\\usetheme{Boadilla}\n")))) + (provide 'test-ox-beamer) ;;; test-ox-beamer.el ends here -- 2.43.0
From 6a13ddec9863207e4b0ba96724d8760e0049b7cf Mon Sep 17 00:00:00 2001 From: "Pedro A. Aranda" <[email protected]> Date: Sun, 12 Apr 2026 07:11:36 +0200 Subject: [PATCH 2/2] ox-latex.el: Improve readibility of org-latex-make-preamble ox-latex.el: Factor out the class template generation to (org-latex--make-class-template). Clean up and simplify the code. (org-latex-make-preamble): use new function and remove empty line. --- lisp/ox-latex.el | 39 ++++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/lisp/ox-latex.el b/lisp/ox-latex.el index f39240cd8..8c5b67463 100644 --- a/lisp/ox-latex.el +++ b/lisp/ox-latex.el @@ -2032,6 +2032,26 @@ If the square brackets are missing, return STR enclosed in square brackets." (replace-regexp-in-string ; remove excess ] at the end "]+\\'" "]" str)))))) +;;; LaTeX class declaration +(defun org-latex--make-class-template (info snippet?) + "Return the class template from INFO. +Factored out from `org-latex-make-preamble' to improve readibility" + (let* ((class (plist-get info :latex-class)) + (class-options (org-latex--mk-options (plist-get info :latex-class-options))) + (header (nth 1 (assoc class (plist-get info :latex-classes))))) + (if (stringp header) ;; when the class is defined in org-latex-classes + (mapconcat #'org-element-normalize-string + (list + (and (not snippet?) + (plist-get info :latex-class-pre)) + (if (not class-options) header + (replace-regexp-in-string + "^[ \t]*\\\\documentclass\\(\\(\\[[^]]*\\]\\)?\\)" + class-options header t nil 1))) + nil) + (user-error "Unknown LaTeX class `%s'" class)))) + + ;;;###autoload (defun org-latex-make-preamble (info &optional template snippet?) "Return a formatted LaTeX preamble. @@ -2041,22 +2061,8 @@ as expected by `org-splice-latex-header'. When SNIPPET? is non-nil, only includes packages relevant to image generation, as specified in `org-latex-default-packages-alist' or `org-latex-packages-alist'." - (let* ((class (plist-get info :latex-class)) - (class-template - (or template - (let* ((class-options (org-latex--mk-options (plist-get info :latex-class-options))) - (header (nth 1 (assoc class (plist-get info :latex-classes))))) - (and (stringp header) - (mapconcat #'org-element-normalize-string - (list - (and (not snippet?) - (plist-get info :latex-class-pre)) - (if (not class-options) header - (replace-regexp-in-string - "^[ \t]*\\\\documentclass\\(\\(\\[[^]]*\\]\\)?\\)" - class-options header t nil 1))) - nil))) - (user-error "Unknown LaTeX class `%s'" class)))) + (let ((class-template + (or template (org-latex--make-class-template info snippet?))) (org-latex-guess-polyglossia-language (org-latex-guess-babel-language (org-latex-guess-inputenc @@ -2073,7 +2079,6 @@ specified in `org-latex-default-packages-alist' or (and (not snippet?) (plist-get info :latex-use-sans) "\\renewcommand*\\familydefault{\\sfdefault}")) - "")))) info) info))) -- 2.43.0
