Hello Org-mode maintainers, I'd like to submit a patch to fix a bug in ox-html's Table of Contents (TOC) generation. The bug occurs when an Org document's first headline is not at level 1 (e.g., it starts with **), causing an unbalanced <li> tag in the exported HTML. Try `C-c C-e h H' for text below:
------------------------>8<----------------------------------- #+title: test #+options: html-style:nil html-preamble:nil html-postamble:nil ** a * b ------------------------>8<----------------------------------- In the output buffer, you'll see something like this in TOC's div: ------------>8<------------ <ul> <li></li> </ul> </li> <li> ... ------------>8<------------ The issue lies within the `org-html--toc-text' function and its initialization logic. Specifically, this line: (let* ((prev-level (1- (cdar toc-entries))) For a standard document starting with top-level headline, prev-level is correctly initialized to 0, representing the document root. However, for non-top-level headline at the first place of toc-entires, The function incorrectly initializes prev-level to 1, which should be ZERO. Of course, I understand that writing a non-top-level headline at the beginning of a file is not considered good form. Still, I would hope that ox-html could handle such cases gracefully and produce valid HTML. Here is a possible fix: diff --git a/lisp/org/ox-html.el b/lisp/org/ox-html.el index e8ae3a134cb..9b5c89d5c77 100644 --- a/lisp/org/ox-html.el +++ b/lisp/org/ox-html.el @@ -2471,7 +2471,7 @@ org-html-toc (let* ((toc-id-counter (plist-get info :org-html--toc-counter)) (toc (concat (format "<div id=\"text-table-of-contents%s\" role=\"doc-toc\">" (if toc-id-counter (format "-%d" toc-id-counter) "")) - (org-html--toc-text toc-entries) + (org-html--toc-text toc-entries scope) "</div>\n"))) (plist-put info :org-html--toc-counter (1+ (or toc-id-counter 0))) (if scope toc @@ -2489,11 +2489,11 @@ org-html-toc toc (format "</%s>\n" outer-tag)))))))) -(defun org-html--toc-text (toc-entries) +(defun org-html--toc-text (toc-entries &optional scoped) "Return innards of a table of contents, as a string. TOC-ENTRIES is an alist where key is an entry title, as a string, and value is its relative level, as an integer." - (let* ((prev-level (1- (cdar toc-entries))) + (let* ((prev-level (or (and scoped (1- (cdar toc-entries))) 0)) (start-level prev-level)) (concat (mapconcat Regards.