Hi,

just a bit of editing comfort. Current behaviour is preserved.
100% backward compatible.

/PA
-- 
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 2fbfd6dfc65545a6b7b3dd2064eb26d03f7b65fd Mon Sep 17 00:00:00 2001
From: "Pedro A. Aranda" <[email protected]>
Date: Thu, 19 Mar 2026 18:00:36 +0000
Subject: [PATCH] ox-latex: Make brackets around LATEX_CLASS_OPTIONS optional

* doc/org-manual.org:
Document that square brackets around the LATEX_CLASS_OPTIONS is
optional.
* etc/ORG-NEWS:
Announce the new behaviour.
* lisp/ox-latex.el: (org-latex--mk-options, org-latex-make-preamble)
(org-latex--mk-options): New function to add square brackets around a
string if needed.
(org-latex-make-preamble): use (org-latex--mk-options)
* testing/lisp/test-ox-latex.el: (test-ox-latex/simpler-class-options,
test-ox-latex/simpler-class-options-old)
(test-ox-latex/simpler-class-options): test new way of setting the
document class options.
(test-ox-latex/simpler-class-options-old): test that the old way works
correctly.
---
 doc/org-manual.org            | 11 ++++++++---
 etc/ORG-NEWS                  |  4 ++++
 lisp/ox-latex.el              | 14 +++++++++++++-
 testing/lisp/test-ox-latex.el | 35 +++++++++++++++++++++++++++++++++++
 4 files changed, 60 insertions(+), 4 deletions(-)

diff --git a/doc/org-manual.org b/doc/org-manual.org
index 904e1270d..ee6a68fd7 100644
--- a/doc/org-manual.org
+++ b/doc/org-manual.org
@@ -14337,12 +14337,17 @@ custom sectioning or custom classes.
 #+cindex: @samp{EXPORT_LATEX_CLASS_OPTIONS}, property
 The LaTeX export backend sends the =LATEX_CLASS_OPTIONS= keyword and
 =EXPORT_LATEX_CLASS_OPTIONS= property as options to the LaTeX
-~\documentclass~ macro.  The options and the syntax for specifying
-them, including enclosing them in square brackets, follow LaTeX
-conventions.
+~\documentclass~ macro.  The options follow LaTeX conventions.
+Enclosing them in square brackets is optional:
 
 : #+LATEX_CLASS_OPTIONS: [a4paper,11pt,twoside,twocolumn]
 
+and
+
+: #+LATEX_CLASS_OPTIONS: a4paper,11pt,twoside,twocolumn
+
+are equivalent.
+
 #+cindex: @samp{LATEX_HEADER}, keyword
 #+cindex: @samp{LATEX_HEADER_EXTRA}, keyword
 The LaTeX export backend appends values from =LATEX_HEADER= and
diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS
index 2dcd86aee..94bcd058a 100644
--- a/etc/ORG-NEWS
+++ b/etc/ORG-NEWS
@@ -97,6 +97,10 @@ This tangles the block to four files:
 You can set the LaTeX environment used in ~example~ blocks with this
 variable.
 
+*** Square brackets around LATEX_CLASS_OPTIONS are now optional.
+
+Square brackets around the LATEX_CLASS_OPTIONS may be ommited.
+
 ** New functions and changes in function arguments
 
 # This also includes changes in function behavior from Elisp perspective.
diff --git a/lisp/ox-latex.el b/lisp/ox-latex.el
index 4607be2d5..18a4ae91a 100644
--- a/lisp/ox-latex.el
+++ b/lisp/ox-latex.el
@@ -2018,6 +2018,18 @@ The default behaviour is to typeset with the Roman font family."
 
 ;;; Template
 
+(defun org-latex--mk-options (str)
+  "Make STR be enclosed in [ ] or return an empty string if nil or empty.
+
+If STR is nil or an empty string, return an empty string.
+If STR is a traditional LATEX_CLASS_OPTIONS enclosed in [ ], return it as is.
+If the square brackets are missing, return STR enclosed in square brackets."
+  (if (or (not str) (length= str 0)) ""
+    (save-match-data
+      (concat "[" (replace-regexp-in-string
+                   "\\[?\\([^]]+\\)\\]?" "\\1" str)
+              "]"))))
+
 ;;;###autoload
 (defun org-latex-make-preamble (info &optional template snippet?)
   "Return a formatted LaTeX preamble.
@@ -2030,7 +2042,7 @@ specified in `org-latex-default-packages-alist' or
   (let* ((class (plist-get info :latex-class))
 	 (class-template
 	  (or template
-	      (let* ((class-options (plist-get info :latex-class-options))
+	      (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
diff --git a/testing/lisp/test-ox-latex.el b/testing/lisp/test-ox-latex.el
index 2c3b8f3bf..f7a170391 100644
--- a/testing/lisp/test-ox-latex.el
+++ b/testing/lisp/test-ox-latex.el
@@ -372,6 +372,7 @@ Fake test document
       (should (search-forward "\\documentclass" nil t))
       ;; And after this
       (should (search-forward "\\begin{document}" nil t))))
+
 (ert-deftest test-ox-latex/latex-default-example-with-options ()
   "Test #+ATTR_LATEX: :options with custom environment."
   (let ((org-latex-default-example-environment "Verbatim"))
@@ -389,6 +390,40 @@ How do you do?
       (goto-char (point-min))
       (should (search-forward "\\begin{document}\n" nil t))
       (should (search-forward "\\begin{Verbatim}[frame=double]\n" nil t)))))
+
+(ert-deftest test-ox-latex/simpler-class-options ()
+  "Test putting the square brackets around #+LATEX_CLASS_OPTIONS: automatically."
+  (org-test-with-exported-text
+   'latex
+   "
+#+LATEX_CLASS: article
+#+LATEX_CLASS_OPTIONS: 11pt,a4paper
+
+#+TITLE: Test options without brackets
+
+How do you do?
+"
+      (goto-char (point-min))
+      (should (search-forward "\\documentclass[11pt,a4paper]{article}\n" nil t))))
+
+(ert-deftest test-ox-latex/simpler-class-options-old ()
+  "Test that putting the square brackets around #+LATEX_CLASS_OPTIONS: automatically
+does not break the current behaviour."
+  (org-test-with-exported-text
+   'latex
+   "
+#+LATEX_CLASS: article
+#+LATEX_CLASS_OPTIONS: [11pt,a4paper]
+
+#+TITLE: Test options with brackets
+
+How do you do?
+"
+      (goto-char (point-min))
+      (should (search-forward "\\documentclass[11pt,a4paper]{article}\n" nil t))))
+
+
+
  (ert-deftest test-ox-latex/math-in-alt-title ()
   "Test math wrapping in ALT_TITLE properties."
   (org-test-with-exported-text
-- 
2.43.0

Reply via email to