Hi... On Sun, 5 Jul 2026 at 12:02, Ihor Radchenko <[email protected]> wrote:
> Pedro Andres Aranda Gutierrez <[email protected]> writes: > > >> Also, I have no clue "please test this stuff!" is asking to do. > >> > > Then, you should have the same problem with the Beamer example I didn't > > write ;| > > Hmm. Yeah. Ok then. (I still do not like it, but let it be) > ACK > >> > \texttt should not make a frame fragile, while \verb@@ should. So why > >> use > >> > frame* instead of frame in ltx-talk. > >> > Side effect, we don't mark Beamer frames as fragile if they really > aren't > >> > >> Ok, but can you make it a separate commit? > > > > Keep it here. If someone knowing ltx-talk sees a frame* that has nothing > > fragile in it, that *will* raise questions. > > My point is that it changes beamer export as well, not just ltx-talk. > If this change turns out to be a problem later, it will be very > confusing that adding ltx-talk breaks beamer. > > My suggestion is simple: (1) change the beamer first; (2) apply ltx-talk > support /after/ that change. > Since ltx-talk doesn't break with frame* not really needing *, I have removed this. Keep it for the future... > >> > + (list > >> > + (and (not (member "allowframebreaks" options)) > >> > + (not (cl-some (lambda (s) (string-match-p > >> "^label=" s)) > >> > + options)) > >> > >> You did not address my comment here. > >> We do not auto-generate label when it is provided in options, but what > >> if name=... is given? > >> > > allowframebreaks is never mentioned in the ltx-talk manual. So this case > > just doesn't apply. > > Consider a frame like > > ** Frame > :PROPERTIES: > :BEAMER_OPT: label=mylabel > :END: > > This has nothing to do with allowframebreaks, I only meant > >> > + (not (cl-some (lambda (s) (string-match-p > >>> "^label=" s)) > Sigh... I didn't get what you were after. I have changed this to search for label or name depending on the class... > > > >> +popular display formats. Additionally, the Beamer exporter also > supports > > > > "Additionally, ... also" sounds strange. Again, this is minor. > > You did not address this comment. > You said is was minor, so I ignored it... Anyhow, I've rewritten the sentence... > > > +Added to check that the ltx-talk adaptation doesn't break anything in > Beamaer." > > *Beamer > Done > > -- > 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 This was produced by a human (implied virtues and weaknesses acknowledged) I'd hate this being fed to any form of AS (sorry AI)...
From 969d8f99729e8258410b5a005c2de7f74c78b20a Mon Sep 17 00:00:00 2001 From: "Pedro A. Aranda" <[email protected]> Date: Sun, 05 Jul 2026 14:07:18 +0200 Subject: ox-beamer.el: add ltx-talk support * etc/ORG-NEWS: Announce ltx-talk support in Beamer * doc/org-manual.org: Beamer exporter section: explain what accesibility means; add a link to the ltx-talk documentation in CTAN. Beamer export commands: mention that theme-related Beamer keywords don't apply for ltx-talk and will be ignored. Add explicitly LATEX_CLASS: ltx-talk as an example ltx-talk example: derive it from the Beamer example to highlight differences. Add obervations and a table with blocks and if they are supported or not. * lisp/ox-beamer.el top level: add ltx-class to org-latex-classes. (org-beamer--format-frame): Fragile frames use the frame* environment with ltx-talk. Labels in ltx-talk are passed as 'name=xxx'. Frame title needs an explicit \frametitle{} for ltx-talk (could also be used for beamer and __greatly__ simplify the code!!) (org-beamer-template): bail out with error if ltx-talk doesn't see lualatex as the compiler. Suppress beamer theme for ltx-talk. * testing/lisp/test-ox-beamer.el (test-ox-beamer/ltx-talk-class): Basic test for ltx-talk code. (test-ox-beamer/ltx-talk-multi-line-metadata): Document metadata can be multiline. (test-ox-beamer/ltx-talk-multi-verb-frame): Frame with example is frame*. (test-ox-beamer/beamer-verb-frame): Make sure fragile frames continue to work as expected -fragile in the options- with the Beamer class. --- doc/org-manual.org | 87 ++++++++++++++++++++- etc/ORG-NEWS | 10 +++ lisp/ox-beamer.el | 69 ++++++++++------- testing/lisp/test-ox-beamer.el | 169 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 305 insertions(+), 30 deletions(-) diff --git a/doc/org-manual.org b/doc/org-manual.org index 96de73975..63eba83f8 100644 --- a/doc/org-manual.org +++ b/doc/org-manual.org @@ -13104,11 +13104,20 @@ It's just a jump to the left... Org uses Beamer export to convert an Org file tree structure into high-quality interactive slides for presentations. Beamer is a LaTeX document class for creating presentations in PDF, HTML, and other -popular display formats. +popular display formats. In addition to the =beamer= class, the +exporter can also handle documents using the =ltx-talk= class to +produce accessible presentations that can be handled, for example, by +screen readers for people with visual impairments. [fn:: The +=ltx-class= needs a recent *LuaLaTeX* compiler.] Section [[*An example +of a presentation using =ltx-talk=]] discusses the main differences +between both classes. We strongly recommend familiarizing yourself with Beamer terminology before reading the rest of this chapter. See <https://en.wikipedia.org/wiki/Beamer_(LaTeX)> and references therein. +If you plan to use =ltx-talk=, consult the +[[https://mirrors.ctan.org//macros/latex/contrib/ltx-talk.tds.zip/ltx-talk.pdf][=ltx-talk= +documentation]]. *** Beamer export commands :PROPERTIES: @@ -13147,7 +13156,8 @@ before reading the rest of this chapter. See Beamer export backend has several additional keywords for customizing Beamer output. These keywords work similar to the general options -settings (see [[*Export Settings]]). +settings (see [[*Export Settings]]). *Note:* =BEAMER_..._THEME= +keywords do not apply to =ltx-talk= and will be ignored. - =BEAMER_THEME= :: @@ -13206,6 +13216,16 @@ settings (see [[*Export Settings]]). ~org-latex-title-command~ to configure typesetting of subtitle as part of front matter. +- =LATEX_CLASS= :: + + #+cindex: @samp{SUBTITLE}, keyword + The LaTeX class to use. Implicitly set to =beamer=. Set it + explicitly to =ltx-talk= to use this class: + + #+BEGIN_SRC org +,#+LATEX_CLASS: ltx-talk + #+END_SRC + *** Frames and Blocks in Beamer :PROPERTIES: :DESCRIPTION: For composing Beamer slides. @@ -13280,6 +13300,7 @@ should in principle be exportable as a Beamer presentation. headlines. To manually adjust them for any unique configurations needs, use the =BEAMER_ENV= property. + *** Beamer specific syntax :PROPERTIES: :DESCRIPTION: For using in Org documents. @@ -13403,6 +13424,68 @@ Here is an example of an Org document ready for Beamer export. Please test this stuff! #+end_example +*** An example of a presentation using =ltx-talk= + +=ltx-talk= is an alternative to the =beamer= class. It depends on +LuaLaTeX and produces tagged PDF files with enhanced accessibility +features for screen readers and similar applications. The Beamer +exporter can produce presentations for this class, too. The following +is the version of the Beamer example above adapted to ~ltx-talk:~ + +#+BEGIN_SRC org +,#+STARTUP: beamer +,#+OPTIONS: toc:nil H:2 title:t +,#+LATEX_COMPILER: lualatex +,#+LATEX_CLASS: ltx-talk +,#+LATEX_DOC_METADATA: tagging=on + +,#+COLUMNS: %45ITEM %10BEAMER_ENV(Env) %10BEAMER_ACT(Act) %4BEAMER_COL(Col) +,* This is the first structural section + +,** Frame 1 +,*** Thanks to Eric Fraga :B_block: + :PROPERTIES: + :BEAMER_COL: 0.48 + :BEAMER_ENV: block + :END: + for the first viable Beamer setup in Org, which also works for =ltx-class= +,*** Thanks to everyone else :B_block: + :PROPERTIES: + :BEAMER_COL: 0.48 + :BEAMER_ACT: <2-> + :BEAMER_ENV: block + :END: + for contributing to the discussion. + +,** Frame 2 (where we will not use columns) +,*** Request + +1. Please read the notes, because not all Beamer environments are supported. +2. Please test this stuff! + +#+END_SRC + +**** Differences between Beamer and =ltx-talk= + :PROPERTIES: + :UNNUMBERED: notoc + :END: + +1. You need to add document metadata to your document. ~tagging=on~ is + the minimum to produce a usable presentation. +2. ~#+BEAMER_..._THEME~ keywords will be silently ignored. +3. Beamer environments not supported in =ltx-talk= are: + + | Beamer environment | Support | Comment | + |--------------------+---------+-----------------| + | =alertblock= | Partial | Only =alertenv= | + | =theorem= | No | | + | =definition= | No | | + | =proof= | No | | + | =beamercolorbox= | No | | + | =exampleblock= | No | | + | =note= | No | | + |--------------------+---------+-----------------| + ** HTML Export :PROPERTIES: :DESCRIPTION: Exporting to HTML. diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS index 22cc760d8..f5bc3a908 100644 --- a/etc/ORG-NEWS +++ b/etc/ORG-NEWS @@ -144,6 +144,16 @@ A current limitation is that export blocks and keywords are only implemented for events and todos, and not yet for calendar-wide properties. +*** ox-beamer.el now supports the ltx-talk class + +ltx-talk is an alternative document class for presentations that can +produce PDFs with extra information for on-screen reader +applications. It will only work with LuaLaTeX. + +Presentations written with Beamer and ltx-talk are mostly portable, +except that Beamer theme information is ignored when using ltx-talk +and some environments listed in the manual are not supported. + ** New and changed options # Changes dealing with changing default values of customizations, diff --git a/lisp/ox-beamer.el b/lisp/ox-beamer.el index 4ebfca1f9..b7b5aacb5 100644 --- a/lisp/ox-beamer.el +++ b/lisp/ox-beamer.el @@ -44,7 +44,11 @@ (unless (assoc "beamer" org-latex-classes) ("\\section{%s}" . "\\section*{%s}") ("\\subsection{%s}" . "\\subsection*{%s}") ("\\subsubsection{%s}" . "\\subsubsection*{%s}")))) - +(unless (assoc "ltx-talk" org-latex-classes) + (add-to-list 'org-latex-classes + '("ltx-talk" + "\\documentclass{ltx-talk}" + ("\\section{%s}" . "\\section*{%s}")))) ;;; User-Configurable Variables @@ -77,7 +81,7 @@ (defcustom org-beamer-frame-level 1 (defcustom org-beamer-frame-default-options "" "Default options string to use for frames. -For example, it could be set to \"allowframebreaks\"." +For example, it could be set to \"allowframebreaks\" for Beamer." :group 'org-export-beamer :type '(string :tag "[options]")) @@ -136,7 +140,7 @@ (defcustom org-beamer-outline-frame-title "Outline" (defcustom org-beamer-outline-frame-options "" "Outline frame options appended after \\begin{frame}. -You might want to put e.g. \"allowframebreaks=0.9\" here." +You might want to put e.g. \"allowframebreaks=0.9\" for Beamer here." :group 'org-export-beamer :safe #'stringp :type '(string :tag "Outline frame options")) @@ -476,26 +480,30 @@ (defun org-beamer--format-frame (headline contents info) (match-string 1 beamer-opt)) ","))))) (fragile - ;; Add "fragile" option if necessary. - (and fragilep + ;; Add "fragile" option if necessary for beamer. + (and (equal latex-class "beamer") + fragilep (not (member "fragile" options)) (list "fragile"))) + ;; ltx-talk uses name instead of label + (label-str (or (and (equal latex-class "beamer") "label") + "name")) (label ;; Provide an automatic label for the frame unless ;; the user specified one. Also refrain from ;; labeling `allowframebreaks' frames; this is not ;; allowed by Beamer. (and (not (member "allowframebreaks" options)) - (not (cl-some (lambda (s) (string-match-p "^label=" s)) + (not (cl-some (lambda (s) (string-match-p (concat "^" label-str "=" s))) options)) (list (let ((label (org-beamer--get-label headline info))) ;; Labels containing colons need to be ;; wrapped within braces. (format (if (string-match-p ":" label) - "label={%s}" - "label=%s") - label)))))) + "%s={%s}" + "%s=%s") + label-str label)))))) ;; Change options list into a string. (org-beamer--normalize-argument (mapconcat #'identity (append label fragile options) ",") @@ -869,7 +877,11 @@ (defun org-beamer-template (contents info) CONTENTS is the transcoded contents string. INFO is a plist holding export options." (let ((title (org-export-data (plist-get info :title) info)) - (subtitle (org-export-data (plist-get info :subtitle) info))) + (subtitle (org-export-data (plist-get info :subtitle) info)) + (beamer-class (plist-get info :latex-class))) + (when (equal beamer-class "ltx-talk") + (unless (equal "lualatex" (plist-get info :latex-compiler)) + (error "ox-beamer: `ltx-talk' needs LuaLaTeX!"))) (concat ;; Timestamp. (and (plist-get info :time-stamp-file) @@ -883,24 +895,25 @@ (defun org-beamer-template (contents info) (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")) - "")) + (unless (equal beamer-class "ltx-talk") + (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 482f22c8f..fc775dfc7 100644 --- a/testing/lisp/test-ox-beamer.el +++ b/testing/lisp/test-ox-beamer.el @@ -111,5 +111,174 @@ (ert-deftest test-ox-beamer/orgframe-in-one-example () (should (search-forward (concat "\\end{frame}") nil t)) (should (search-forward (concat "\\end{" org-beamer-frame-environment "}")))))) +(ert-deftest test-ox-beamer/ltx-talk-class () + "Initial test for a simple ltx-talk example. +1. Default Metadata is inserted +2. Sectioning is supported +3. Labels and Beamer theme stuff are ignored" + + (let ((org-latex-compiler "lualatex") + (org-latex-hyperref-template nil) + (org-latex-packages-alist nil) + (org-latex-default-packages-alist nil)) + (org-test-with-exported-text + 'beamer + "#+STARTUP: beamer +#+OPTIONS: toc:nil H:2 +#+LATEX_CLASS: ltx-talk +#+LATEX_CLASS_OPTIONS: +#+LATEX_CLASS_PRE: \\DocumentMetadata{tagging = on} +#+TITLE: Testing =ltx-talk= +#+BEAMER_THEME: Boadilla + +* A section +** A frame +- First +- Second +- Third +" + ;; (message "--> \n%s" (buffer-string)) + (goto-char (point-min)) + ;; ltx-talk ignores theme info + (save-excursion (should-not (search-forward "\\usetheme{" nil t))) + ;; ltx-talk doesn't generate labels + (save-excursion (should-not (search-forward "[label=]" nil t))) + (save-excursion + (should (search-forward "\\DocumentMetadata{tagging = on}\n" nil t)) + (should (search-forward "\\documentclass{ltx-talk}\n" nil t)) + (should (search-forward "\\section{A section}" nil t)) + (should (search-forward "\\frametitle{A frame}" nil t)))))) + +(ert-deftest test-ox-beamer/ltx-talk-multi-line-metadata () + "Initial test for a simple ltx-talk example. +1. Default Metadata is inserted +2. Sectioning is supported +3. Labels are supppressed." + (let ((org-latex-compiler "lualatex") + (org-latex-hyperref-template nil) + (org-latex-packages-alist nil) + (org-latex-default-packages-alist nil)) + (org-test-with-exported-text + 'beamer + "#+STARTUP: beamer +#+OPTIONS: toc:nil H:2 +#+LATEX_CLASS: ltx-talk +#+LATEX_CLASS_OPTIONS: +#+LATEX_CLASS_PRE: \\DocumentMetadata{lang=en, +#+LATEX_CLASS_PRE: pdfstandard = ua-2, +#+LATEX_CLASS_PRE: pdfstandard = a-4f, +#+LATEX_CLASS_PRE: pdfversion = 2.0, +#+LATEX_CLASS_PRE: tagging=on} +#+LATEX_CLASS_PRE: \\tagpdfsetup{table/header-rows={1},role / new-tag = frametitle / H2} +#+TITLE: Testing =ltx-talk= +#+BEAMER_THEME: + +* A section +** A frame +- First +- Second +- Third +" + ;; (message "--> \n%s" (buffer-string)) + (goto-char (point-min)) + (save-excursion (should-not (search-forward "\\usetheme{" nil t))) + (save-excursion (should-not (search-forward "[label=]" nil t))) + (save-excursion + (should (search-forward "\\DocumentMetadata{lang=en," nil t)) + (should (search-forward "pdfversion = 2.0," nil t)) + (should (search-forward "tagging=on}" nil t)) + (should (search-forward "\\tagpdfsetup{table" nil t)) + (should (search-forward "\\section{A section}" nil t)) + (should (search-forward "\\frametitle{A frame}" nil t)))))) + +(ert-deftest test-ox-beamer/ltx-talk-frame-subtitle () + "Test that a frame with verbatim elements uses \"frame*\"." + (let ((org-latex-compiler "lualatex") + (org-latex-hyperref-template nil) + (org-latex-packages-alist nil) + (org-latex-default-packages-alist nil)) + (org-test-with-exported-text + 'beamer + "#+STARTUP: beamer +#+OPTIONS: toc:nil H:2 title:t +#+LATEX_CLASS: ltx-talk +#+LATEX_DOC_METADATA: tagging=on +#+LATEX_CLASS_OPTIONS: handout +#+TITLE: Testing =ltx-talk= verbatims +#+BEAMER_THEME: + +* A section +** A frame +- First +- Second +- Third +** A second frame with a subtitle + :properties: + :beamer_subtitle: Testing listings + :end: +- This is a listing: + #+BEGIN_SRC python +import sys + +print(\"Hello, ltx-talk!\", file=sys.stderr) + #+END_SRC +" + ;; (message "--> \n%s" (buffer-string)) + (goto-char (point-min)) + (save-excursion (should-not (search-forward "\\usetheme{" nil t))) + (save-excursion (should-not (search-forward "[label=]" nil t))) + (save-excursion + (should (search-forward "\\DocumentMetadata{tagging=on}" nil t)) + (should (search-forward "\\documentclass[handout]{ltx-talk}" nil t)) + (should (search-forward "\\section{A section}\n" nil t)) + (should (search-forward "\\begin{frame}" nil t)) + (should (search-forward "\\frametitle{A frame}\n" nil t)) + (should (search-forward "\\end{frame}" nil t)) + (should (search-forward "\\begin{frame*}" nil t)) + (should (search-forward "\\frametitle{A second frame with a subtitle}\n" nil t)) + (should (search-forward "\\framesubtitle{Testing listings}\n" nil t)) + (should (search-forward "\\end{frame*}" nil t)))))) + +(ert-deftest test-ox-beamer/beamer-verb-frame () + "Test that a frame with verbatim elements sets fragile in beamer. +Added to check that the ltx-talk adaptation doesn't break anything in Beamer." + (let ((org-latex-compiler "lualatex") + (org-latex-hyperref-template nil) + (org-latex-packages-alist nil) + (org-latex-default-packages-alist nil)) + (org-test-with-exported-text + 'beamer + "#+STARTUP: beamer +#+OPTIONS: toc:nil H:2 title:t +#+LATEX_CLASS_OPTIONS: [presentation,11pt,t] +#+TITLE: Testing =beamer= verbatims +#+BEAMER_THEME: Boadilla + +* A section +** A frame +- First +- Second +- Third +** A frame with a listing +- This is a listing: + #+BEGIN_SRC python +import sys + +print(\"Hello, beamer!\", file=sys.stderr) + #+END_SRC +" + ;; (message "--> \n%s" (buffer-string)) + (goto-char (point-min)) + (save-excursion + (should-not (search-forward "\\DocumentMetadata{tagging=on}" nil t))) + (save-excursion + (should (search-forward "\\documentclass[presentation,11pt,t]{beamer}" nil t)) + (should (search-forward "\\usetheme{" nil t))) + (should (search-forward "\\section{A section}\n" nil t)) + (should (search-forward-regexp "^\\\\begin{frame}\\[.+?]{A frame}$" nil t)) + (should (search-forward "\\end{frame}\n" nil t)) + (should (search-forward-regexp "^\\\\begin{frame}\\[.+?\\,fragile]{A frame with a listing}$" nil t)) + (should (search-forward "\\end{frame}\n" nil t))))) + (provide 'test-ox-beamer) ;;; test-ox-beamer.el ends here
