From 17dd1cb3c624c5b685fab7bc901678b16fba5cd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20A=2E=20Aranda=20Guti=C3=A9rrez?= Date: Wed, 1 Jan 2025 07:30:28 +0100 Subject: [PATCH] Fix unnumbered sections in ToC * etc/ORG-NEWS: Announce fix * lisp/ox-latex.el: (org-latex-headline): Fix adding unnumbered sections to ToC. Insert `\\addcontentsline{toc}{section}{section title}' to add unnumbered sections to ToC. * testing/lisp/test-ox-latex.el: Add two tests: one for a document with num:nil and one for a document with num:t and an unnumbered section. --- etc/ORG-NEWS | 5 +++ lisp/ox-latex.el | 18 ++++++++-- testing/lisp/test-ox-latex.el | 64 +++++++++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+), 3 deletions(-) diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS index 2d4616fab..7ed71c63c 100644 --- a/etc/ORG-NEWS +++ b/etc/ORG-NEWS @@ -437,6 +437,11 @@ For example, given =H:3= and =toc:2= in =#+OPTIONS:=, all headings at the 1st and 2nd level appear in the table of contents and those at the 3rd level do not. +*** LaTeX exporter now correctly adds unnumbered sections to the ToC + +If you add the =:ALT_TITLE:= property to an unnumbered section, it will +be added to the Table of Contents correctly. + * Version 9.7 ** Important announcements and breaking changes diff --git a/lisp/ox-latex.el b/lisp/ox-latex.el index 4b2e797d0..a4cfe2f2c 100644 --- a/lisp/ox-latex.el +++ b/lisp/ox-latex.el @@ -2402,7 +2402,7 @@ holding contextual information." (string-match-p "\\" 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. @@ -2419,8 +2419,20 @@ holding contextual information." (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)))))))) + (save-match-data + ;; Try to extract the section command from section-fmt + ;; This should givee us some protection against unexpeted stuff + (let ((matched (string-match "\\\\\\([a-z]+\\)[^a-z]" section-fmt))) + (if (or numberedp (not matched)) + ;; Just in case the section header is not a standard \\xyz*{} + (format section-fmt full-text + (concat headline-label pre-blanks contents)) + (let* ((section-label (match-string 1 section-fmt)) + (add-contents (format "\\addcontentsline{toc}{%s}{%s}\n" section-label opt-title))) + ;; prepend the addcontentsline as the first element in the generated section + ;; this assures that it will go directly after the section command + (format section-fmt full-text + (concat add-contents 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..8fcc0a810 100644 --- a/testing/lisp/test-ox-latex.el +++ b/testing/lisp/test-ox-latex.el @@ -28,6 +28,69 @@ (signal 'missing-test-dependency '("org-export-latex"))) +(ert-deftest test-ox-latex/unnumbered-toc () + "Test unnumbered toc elements" + (org-test-with-exported-text + 'latex + "#+OPTIONS: num:nil + +* Test +:PROPERTIES: +:ALT_TITLE: alt +:END: + +This is a test. +" + (goto-char (point-min)) + (should + (search-forward "\\begin{document}")) + (should + (search-forward "\\tableofcontents")) + (should + (search-forward "\\section*{Test}")) + (should + (search-forward "\\addcontentsline{toc}{section}{alt}")) + (should + (search-forward "\\label{")) + (should + (search-forward "This is a test.")))) + +(ert-deftest test-ox-latex/unnumbered-toc-mixed () + "Test unnumbered toc elements" + (org-test-with-exported-text + 'latex + "* Introduction: a test +:PROPERTIES: +:ALT_TITLE: Introduction +:END: + +A shorter test for alt title + +** State of the Art +:PROPERTIES: +:UNNUMBERED: t +:ALT_TITLE: SOTA +:END: + +And now an unnumbered section in the ToC +" + (goto-char (point-min)) + (should + (search-forward "\\begin{document} + +\\tableofcontents + +\\section[Introduction]{Introduction: a test} +\\label{sec:org")) + (should + (search-forward "} +A shorter test for alt title +\\subsection*{State of the Art} +\\addcontentsline{toc}{subsection}{SOTA} +\\label{sec:")) + (should + (search-forward "} +And now an unnumbered section in the ToC")))) (ert-deftest text-ox-latex/protect-square-brackets () "Test [foo] being interpreted as plain text even after LaTeX commands." @@ -127,5 +190,6 @@ Column & Column \\\\ (search-forward "\\href{https://orgmode.org/worg/images/orgmode/org-mode-unicorn.svg}{\\includegraphics[width=.9\\linewidth]{/wallpaper.png}}")))) + (provide 'test-ox-latex) ;;; test-ox-latex.el ends here -- 2.47.1