Hi On Mon, 6 Apr 2026 at 19:03, Ihor Radchenko <[email protected]> wrote:
> Pedro Andres Aranda Gutierrez <[email protected]> writes: > > >> That's a bad idea to call ox-beamer functions from inside ox-latex. > >> This will lead to unmaintainable code if we mix different libraries. > > > > I was just trying to keep beamer code in ox-beamer.el > > But there is nothing that would break if we moved the function from > > ox-beamer.el to ox-latex.el. info will have the properties anyhow and > > independently > > of where the code is placed, or is there? > > 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... > Unfortunately, we already have bad > examples of such code style - org-agenda-prepare-buffers does > agenda-specific things in org.el, making the already complicated > org-agenda.el code even harder to parse. I do not want such code to > proliferate. > > >> If you want to modify how ox-latex generates the preamble, what about > >> modifying > >> > >> (unless (assoc "beamer" org-latex-classes) > >> (add-to-list 'org-latex-classes > >> '("beamer" > >> "\\documentclass[presentation]{beamer}" > >> ("\\section{%s}" . "\\section*{%s}") > >> ("\\subsection{%s}" . "\\subsection*{%s}") > >> ("\\subsubsection{%s}" . "\\subsubsection*{%s}")))) > >> > >> ? > >> > >> Or, alternatively, you can dynamically splice the theme into > >> :latex-classes in the INFO inside `org-beamer-template' before calling > >> `org-latex-make-preamble'. > >> > > > > Isn't that a bit of an overkill? Since the information is already > there.... > > This was just a way of keeping beamer stuff things together. But it > really > > doesn't have to. > > I feel that moving the function from ox-beamer to ox-latex makes the > trick > > cleaner. > > I hope I explained the reasons clearly in the above. > I am strongly against splitting code between libraries. We already have > too much of such practice. That is just creating headaches for future > contributors. > Maybe the current code is already a headache... Don't have time to to start an argument on that. 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 > But please do avoid putting ox-beamer code into > ox-latex directly. > > > >> > + (concat > >> > + pre-header > >> > + (mapconcat (lambda (args) (apply format-theme args)) > >> > >> I'd write (lambda (prop command) ...) explicitly. That's more readable > >> IMHO. > >> > > I was trying to just factor out the original code and not touch it. And > > that is how it was originally... > > Right. I did not notice that. I do not object keeping it then. Although > an improvement would be welcome (while we are at it). > > -- > 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> > -- 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 86a7d41007d3215caeac90de2ac88c0745acde69 Mon Sep 17 00:00:00 2001 From: "Pedro A. Aranda" <[email protected]> Date: Tue, 7 Apr 2026 08:57:33 +0200 Subject: [PATCH] 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 | 11 ++++++ lisp/ox-beamer.el | 66 +++++++++++++++++++++++----------- testing/lisp/test-ox-beamer.el | 14 ++++++++ 4 files changed, 83 insertions(+), 21 deletions(-) diff --git a/doc/org-manual.org b/doc/org-manual.org index 357487c70..28fb068e9 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 c5792cf58..ef0479d51 100644 --- a/etc/ORG-NEWS +++ b/etc/ORG-NEWS @@ -42,6 +42,12 @@ 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. + ** New features # We list the most important features, and the features that may @@ -149,6 +155,11 @@ header argument will be updated. This allows for the cache feature to still work when a block is evaluated indirectly to resolve a reference in another block. +*** 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..3e531db3f 100644 --- a/testing/lisp/test-ox-beamer.el +++ b/testing/lisp/test-ox-beamer.el @@ -109,5 +109,19 @@ 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}\n\\usepackage{geometry}\n\\usetheme{Boadilla}\n")))) + (provide 'test-ox-beamer) ;;; test-ox-beamer.el ends here -- 2.43.0
From 87702bdafc9486541c3f08401ec9b410b630f22d Mon Sep 17 00:00:00 2001 From: "Pedro A. Aranda" <[email protected]> Date: Wed, 8 Apr 2026 18:08:46 +0200 Subject: [PATCH] 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 | 41 +++++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/lisp/ox-latex.el b/lisp/ox-latex.el index f39240cd8..3f019386f 100644 --- a/lisp/ox-latex.el +++ b/lisp/ox-latex.el @@ -1,4 +1,4 @@ -;;; ox-latex.el --- LaTeX Backend for Org Export Engine -*- lexical-binding: t; -*- +;; ox-latex.el --- LaTeX Backend for Org Export Engine -*- lexical-binding: t; -*- ;; Copyright (C) 2011-2026 Free Software Foundation, Inc. @@ -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
