Skip to content

Commit

Permalink
Fixed TOC nesting with non-sequential headings (#1059)
Browse files Browse the repository at this point in the history
* Fixed TOC nesting with non-sequential headings

* Skipped lists now appear as empty markers with proper indentation

* Appropriately nest TOC
  • Loading branch information
mossr authored Oct 25, 2023
1 parent fde286d commit 23bb45e
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 20 deletions.
59 changes: 53 additions & 6 deletions src/converter/html/functions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -170,31 +170,78 @@ function hfun_toc(params::Vector{String})::String
inner = ""
headers = filter(p -> min p.second[3] max, PAGE_HEADERS)
isempty(headers) && return ""
levels = [h[3] for (rs,h) headers]

# find index of the top-most ancestor of each family
top_lvl_ancestor_idx = Vector{Int}(undef, length(levels))
for (i, lvl) in enumerate(levels)
if i == 1
top_lvl_ancestor_idx[i] = 1
else
a = i
for ai in reverse(1:i-1)
if lvl > levels[ai]
a = ai
break
end
end
top_lvl_ancestor_idx[i] = a
end
end

# get all the levels of the members in a family
families = map(top_lvl_idx->levels[findall(top_lvl_ancestor_idx .== top_lvl_idx)], top_lvl_ancestor_idx)

# indicate the smallest level (that which will be the most left aligned)
top_most_lvl = minimum(levels[top_lvl_ancestor_idx])

# get offset of level relative to the left-most level (i.e., the min.)
ancestor_offset_relative_to_min = map(member->top_most_lvl - member[1], families)

# indicators if any members of the family should be nested with empty bullets
make_empty_nest = map(fam_diff->any(fam_diff .< 0), diff.(families))

baselvl = minimum(h[3] for h in values(headers)) - 1
curlvl = baselvl
for (rs, h) headers
curlvl = first(families)[1] - 1
curskip = 0

for (li, (rs, h)) enumerate(headers)
lvl = h[3]
sep = abs(lvl - curlvl)
skipped_lvl = sep [0, 1]
make_empty = make_empty_nest[li]
skip = skipped_lvl ? sep - 1 : 0
if skip != 0
curskip = skip
end
if lvl curlvl
# Close previous list item
inner *= "</li>"
# Close additional sublists for each level eliminated
for i = curlvl-1:-1:lvl
close_length = make_empty ? curlvl - lvl : curlvl - lvl - skip
for i = fill(nothing, close_length)
inner *= "</ol></li>"
end
# Reopen for this list item
inner *= "<li>"
elseif lvl > curlvl
# Open additional sublists for each level added
for i = curlvl+1:lvl
if make_empty
# hide marker for the empty nested sublists
for i = fill(nothing, skip)
inner *= "<ol><li style=\"list-style-type: none;\">"
end
end
for i = fill(nothing, lvl - curlvl - skip)
inner *= "<ol><li>"
end
end
inner *= html_ahref_key(rs, h[1])
curlvl = lvl
curlvl = lvl + ancestor_offset_relative_to_min[li]
# At this point, number of sublists (<ol><li>) open equals curlvl
end
# Close remaining lists, as if going down to the base level
for i = curlvl-1:-1:baselvl
for i = fill(nothing, curlvl - baselvl + curskip + sum(ancestor_offset_relative_to_min))
inner *= "</li></ol>"
end
toc = "<div class=\"franklin-toc\">" * inner * "</div>"
Expand Down
69 changes: 55 additions & 14 deletions test/converter/md/markdown2.jl
Original file line number Diff line number Diff line change
Expand Up @@ -31,33 +31,74 @@ end
fs()
h = raw"""
@def fd_rpath = "pages/ff/aa.md"
@def mintoclevel = 1
@def maxtoclevel = 4
\toc
## Hello `fd`
#### weirdly nested
### Goodbye!
## Done
### Part of family 1: should not be nested `fd`
## Top-most ancestor of family 2
#### should be empty nested
### part of family 2
## Top-most ancestor of family 3
#### child1
#### child2
#### child3
#### child4
## Top-most ancestor of family 4
done.
""" |> seval
@test isapproxstr(h, raw"""
<div class="franklin-toc">
<div class="franklin-toc">
<ol>
<li><a href="#hello_fd">Hello <code>fd</code></a>
<li>
<a href="#part_of_family_1_should_not_be_nested_fd">Part of family 1: should not be nested <code>fd</code></a>
</li>
<li>
<a href="#top-most_ancestor_of_family_2">Top-most ancestor of family 2</a>
<ol>
<li>
<li style="list-style-type: none;">
<ol>
<li><a href="#weirdly_nested">weirdly nested</a></li>
<li>
<a href="#should_be_empty_nested">should be empty nested</a>
</li>
</ol>
</li>
<li><a href="#goodbye">Goodbye&#33;</a></li>
<li>
<a href="#part_of_family_2">part of family 2</a>
</li>
</ol>
</li>
<li><a href="#done">Done</a></li>
<li>
<a href="#top-most_ancestor_of_family_3">Top-most ancestor of family 3</a>
<ol>
<li>
<a href="#child1">child1</a>
</li>
<li>
<a href="#child2">child2</a>
</li>
<li>
<a href="#child3">child3</a>
</li>
<li>
<a href="#child4">child4</a>
</li>
</ol>
</li>
<li>
<a href="#top-most_ancestor_of_family_4">Top-most ancestor of family 4</a>
</li>
</ol>
</div>
<h2 id="hello_fd"><a href="#hello_fd" class="header-anchor">Hello <code>fd</code></a></h2>
<h4 id="weirdly_nested"><a href="#weirdly_nested" class="header-anchor">weirdly nested</a></h4>
<h3 id="goodbye"><a href="#goodbye" class="header-anchor">Goodbye&#33;</a></h3>
<h2 id="done"><a href="#done" class="header-anchor">Done</a></h2>
<h3 id="part_of_family_1_should_not_be_nested_fd"><a href="#part_of_family_1_should_not_be_nested_fd" class="header-anchor">Part of family 1: should not be nested <code>fd</code></a></h3>
<h2 id="top-most_ancestor_of_family_2"><a href="#top-most_ancestor_of_family_2" class="header-anchor">Top-most ancestor of family 2</a></h2>
<h4 id="should_be_empty_nested"><a href="#should_be_empty_nested" class="header-anchor">should be empty nested</a></h4>
<h3 id="part_of_family_2"><a href="#part_of_family_2" class="header-anchor">part of family 2</a></h3>
<h2 id="top-most_ancestor_of_family_3"><a href="#top-most_ancestor_of_family_3" class="header-anchor">Top-most ancestor of family 3</a></h2>
<h4 id="child1"><a href="#child1" class="header-anchor">child1</a></h4>
<h4 id="child2"><a href="#child2" class="header-anchor">child2</a></h4>
<h4 id="child3"><a href="#child3" class="header-anchor">child3</a></h4>
<h4 id="child4"><a href="#child4" class="header-anchor">child4</a></h4>
<h2 id="top-most_ancestor_of_family_4"><a href="#top-most_ancestor_of_family_4" class="header-anchor">Top-most ancestor of family 4</a></h2>
<p>done.</p>
""")
end
Expand Down

0 comments on commit 23bb45e

Please sign in to comment.