emacs-orgmode@gnu.org archives
 help / color / mirror / code / Atom feed
* PATCH: fix ToC generation in the Latex exporter
@ 2025-01-07 16:34 Pedro Andres Aranda Gutierrez
  0 siblings, 0 replies; only message in thread
From: Pedro Andres Aranda Gutierrez @ 2025-01-07 16:34 UTC (permalink / raw)
  To: Org Mode List, Ihor Radchenko, Ihor Radchenko; +Cc: rudolf


[-- Attachment #1.1: Type: text/plain, Size: 529 bytes --]

Hi

Please find attached a patch to fix ToC generation in the LaTeX exporter.
With this, you don't need to reach back to @@latex @@ constructs to get
your ToC alright. I have added an option to generate ToC's that is closer
to LaTeX (num:latex) tha to org

Let me know... /PA

-- 
Fragen sind nicht da, um beantwortet zu werden,
Fragen sind da um gestellt zu werden
Georg Kreisler

Headaches with a Juju log:
unit-basic-16: 09:17:36 WARNING juju.worker.uniter.operation we should run
a leader-deposed hook here, but we can't yet

[-- Attachment #1.2: Type: text/html, Size: 887 bytes --]

[-- Attachment #2: 0001-ox-latex-fix-toc-generation.patch --]
[-- Type: text/x-patch, Size: 10403 bytes --]

From a2819314514ddd4e2ccd48301827ed4c1c875d85 Mon Sep 17 00:00:00 2001
From: "Pedro A. Aranda Gutiérrez" <paaguti@gmail.com>
Date: Tue, 7 Jan 2025 17:20:26 +0100
Subject: [PATCH] ox-latex: fix toc generation

* lisp/ox-latex.el: Add variable `org-latex-unnumbered-section-re'
to filter the unnumbered section.
(org-latex-headline): fix 'num:t' toc generation to match other
exporters and add a new 'num:latex' option that behaves closer to
toc generation criteria in LaTeX
* testing/lisp/test-ox-latex.el: test the fix and new toc generation
option.
* doc/org-manual.org: Document the fix and new toc generation option
* etc/ORG-NEWS: Announce fix to toc generation and the new `num:latex'
option


---
 doc/org-manual.org            |  25 ++++++++
 etc/ORG-NEWS                  |  13 ++++
 lisp/ox-latex.el              |  46 ++++++++++++--
 testing/lisp/test-ox-latex.el | 111 ++++++++++++++++++++++++++++++++++
 4 files changed, 189 insertions(+), 6 deletions(-)

diff --git a/doc/org-manual.org b/doc/org-manual.org
index e88317379..186ad1258 100644
--- a/doc/org-manual.org
+++ b/doc/org-manual.org
@@ -14852,6 +14852,31 @@ some text in German...
 \end{foreigndisplayquote}
 #+end_example

+*** Controlling the way the table of contents is generated
+
+=org= handles the table of contents slightly different as LaTeX. It
+will be generated when the =#+OPTIONS:= include =toc:t= and include
+all headings, regardless of whether they are numbered (=num:t= )or
+unnumbered (=num:nil=).
+
+If you want the table of contents to follow the LaTeX behaviour
+closer, you will can set =num:latex= in the options line. In this
+case, the following rules apply:
+
+1. Numbered headings are included in the header. If you want an
+   alternative title to appear in the table of contents, use the
+   =:ALT_TITLE:= property for the section.
+
+2. Unnumbered headings are not included in the table of contents,
+   unless you set the =:UNNUMBERED:= property to =toc= or you include
+   the =:ALT_TITLE:= property in the section's properies.
+
+If your LaTeX output uses special commands for unnumbered headings
+instead of the expected =\chapter*{}= or =\section*{}=,
+=\subsection*{}= etc. you need to configure
+=org-latex-unnumbered-section-re= to add the headings to the
+table of contents.
+
 ** Markdown Export
 :PROPERTIES:
 :DESCRIPTION: Exporting to Markdown.
diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS
index c9bb192de..c9cb3980e 100644
--- a/etc/ORG-NEWS
+++ b/etc/ORG-NEWS
@@ -291,6 +291,19 @@ slide to specific animation steps.
 This text will be displayed on animation step 2 and later.
 #+END_SRC

+*** ox-latex: The way the table of contents handles unnumbered sections has changed
+
+The document option ~num~ can now be ~t~, ~nil~ or ~latex~. The LaTeX
+exporter will now follow the convention of the other exporters and
+export all unnumbered sections to the table of contents (ToC).
+
+If you want to follow your "LaTeX intuition" and control which unnumbered
+sections appear in the ToC, set ~num:latex~ in the document
+~#+OPTIONS:~. In this case, you will be able include the unnumbered
+section in the table of contents by either adding an ~:ALT_TITLE:~ or
+setting ~:UNNUMBERED:~ to ~toc~. Setting ~:UNNUMBERED:~ to ~t~ will
+exclude the section from the ToC.
+
 ** 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 16f8f5af2..3acc24e20 100644
--- a/lisp/ox-latex.el
+++ b/lisp/ox-latex.el
@@ -319,6 +319,10 @@ cdr is a property list.  Valid keywords for this list can be:
       "empheq")))
   "Regexp of LaTeX math environments.")

+(defconst org-latex-unnumbered-section-re
+ "^\\\\\\(chapter\\|\\(sub\\)*section\\)[*]"
+ "Regexp to get the unnumbered section tag")
+
 \f
 ;;; User Configurable Variables

@@ -2276,6 +2280,8 @@ holding contextual information."
   (unless (org-element-property :footnote-section-p headline)
     (let* ((class (plist-get info :latex-class))
 	   (level (org-export-get-relative-level headline info))
+           (sec-num (plist-get info :section-numbers))
+           (unnumbered-type (org-export-get-node-property :UNNUMBERED headline t))
 	   (numberedp (org-export-numbered-headline-p headline info))
 	   (class-sectioning (assoc class (plist-get info :latex-classes)))
 	   ;; Section formatting will set two placeholders: one for
@@ -2378,7 +2384,8 @@ holding contextual information."
 	;; This is a standard headline.  Export it as a section.  Add
 	;; an alternative heading when possible, and when this is not
 	;; identical to the usual heading.
-	(let ((opt-title
+	(let (;; (alt-title (org-export-get-alt-title headline info))
+              (opt-title
 	       (funcall (plist-get info :latex-format-headline-function)
 			todo todo-type priority
 			(org-export-data-with-backend
@@ -2402,10 +2409,10 @@ holding contextual information."
 				  (string-match-p "\\<local\\>" v)
 				  (format "\\stopcontents[level-%d]" level)))))
 		    info t)))))
-	  (if (and (or (and opt-title (not (equal opt-title full-text)))
+	  (if (and numberedp (or (and opt-title (not (equal opt-title full-text)))
                        ;; Heading contains footnotes.  Add optional title
                        ;; version without footnotes to avoid footnotes in
-                       ;; TOC/footers.
+                       ;; TOC/footers for numbered sections *only*
                        (and (not (equal full-text-no-footnote full-text))
                             (setq opt-title full-text-no-footnote)))
 		   (string-match "\\`\\\\\\(.+?\\){" section-fmt))
@@ -2418,9 +2425,36 @@ holding contextual information."
 		      full-text
 		      (concat headline-label pre-blanks contents))
 	    ;; Impossible to add an alternative heading.  Fallback to
-	    ;; regular sectioning format string.
-	    (format section-fmt full-text
-		    (concat headline-label pre-blanks contents))))))))
+	    ;; regular sectioning format string for a numbered section
+            (if numberedp
+	        (format section-fmt full-text
+		        (concat headline-label pre-blanks contents))
+              ;; If the section is unnumbered, we can still do something
+              ;;
+              (save-match-data
+                (let ((candidate (string-match org-latex-unnumbered-section-re section-fmt)))
+
+                  (when (or
+                         ;; Always suppress :UNNUMBERED: notoc
+                         (string= unnumbered-type "notoc")
+                         ;; When numbering mode is 'latex'
+                         ;; suppress unnumbered 't' without alternative title
+                         ;; :ALT_TITLE:
+                         (and (string= sec-num "latex")
+                              (string= unnumbered-type "t")
+                              (string= opt-title full-text)))
+                    (setq candidate nil))
+	          (format section-fmt full-text
+                          (concat
+                           ;; Match only the 'canonical' chapter, section,subsection, etc
+                           (when candidate
+                           ;; opt-title carries the section carries ALT_TITLE if defined
+                           ;; or the subsection title if ALT_TITLE is not defined (!)
+                             (format "\\addcontentsline{toc}{%s}{%s}\n"
+                                     (match-string 1 section-fmt)
+                                     opt-title))
+                           headline-label
+                           pre-blanks contents)))))))))))

 (defun org-latex-format-headline-default-function
     (todo _todo-type priority text tags _info)
diff --git a/testing/lisp/test-ox-latex.el b/testing/lisp/test-ox-latex.el
index 892ac4437..fd3c2444d 100644
--- a/testing/lisp/test-ox-latex.el
+++ b/testing/lisp/test-ox-latex.el
@@ -127,5 +127,116 @@ Column & Column \\\\
      (search-forward
       "\\href{https://orgmode.org/worg/images/orgmode/org-mode-unicorn.svg}{\\includegraphics[width=.9\\linewidth]{/wallpaper.png}}"))))

+(ert-deftest test-ox-latex/num-latex ()
+  "Test toc treatment for num:latex"
+  (org-test-with-exported-text
+   'latex
+   "#+TITLE: num-latex
+#+OPTIONS: toc:t H:3 num:latex
+
+* Section
+
+** Subsection 1
+:PROPERTIES:
+:UNNUMBERED: t
+:END:
+
+** Subsection 2
+:PROPERTIES:
+:UNNUMBERED: toc
+:END:
+
+** Subsection 3
+:PROPERTIES:
+:UNNUMBERED: toc
+:ALT_TITLE: Alternative
+:END:
+
+* Section 2
+:PROPERTIES:
+:ALT_TITLE: SECTION 2
+:END:
+"
+   (goto-char (point-min))
+   (should
+    (search-forward "\\begin{document}
+
+\\maketitle
+\\tableofcontents
+
+\\section{Section}
+\\label{"))
+   (should (search-forward "}
+
+\\subsection*{Subsection 1}
+\\label{"))
+   (should (search-forward "}
+\\subsection*{Subsection 2}
+\\addcontentsline{toc}{subsection}{Subsection 2}
+\\label{"))
+  (should (search-forward "}
+\\subsection*{Subsection 3}
+\\addcontentsline{toc}{subsection}{Alternative}
+\\label{"))
+  (should (search-forward "}
+\\section[SECTION 2]{Section 2}
+\\label{"))
+  (should (search-forward "}
+\\end{document}"))))
+
+(ert-deftest test-ox-latex/org-toc ()
+    "Test table of contents generation à la org"
+  (org-test-with-exported-text
+   'latex
+   "#+TITLE: num-latex
+#+OPTIONS: toc:t H:3 num:t
+
+* Section
+
+** Subsection 1
+:PROPERTIES:
+:UNNUMBERED: t
+:END:
+
+** Subsection 2
+:PROPERTIES:
+:UNNUMBERED: toc
+:END:
+
+** Subsection 3
+:PROPERTIES:
+:UNNUMBERED: toc
+:ALT_TITLE: Alternative
+:END:
+
+* Section 2
+:PROPERTIES:
+:ALT_TITLE: SECTION 2
+:END:
+"
+   (should
+    (search-forward "\\begin{document}
+
+\\maketitle
+\\tableofcontents"))
+   (should
+    (search-forward "\\section{Section}
+\\label{"))
+   (should ;; test :UNNUMBERED: t
+    (search-forward "\\subsection*{Subsection 1}
+\\addcontentsline{toc}{subsection}{Subsection 1}
+\\label{"))
+   (should ;; test :UNNUMBERED: toc
+    (search-forward "\\subsection*{Subsection 2}
+\\addcontentsline{toc}{subsection}{Subsection 2}
+\\label{"))
+   (should ;; test :UNNUMBERED: t with :ALT_TITLE:
+    (search-forward "\\subsection*{Subsection 3}
+\\addcontentsline{toc}{subsection}{Alternative}
+\\label{"))
+   (should ;; test :ALT_TITLE: only
+    (search-forward "\\section[SECTION 2]{Section 2}
+\\label{"))))
+
 (provide 'test-ox-latex)
 ;;; test-ox-latex.el ends here
--
2.34.1

^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2025-01-07 17:04 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-01-07 16:34 PATCH: fix ToC generation in the Latex exporter Pedro Andres Aranda Gutierrez

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).