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.

Reply via email to