diff --git a/src/converter/html/functions.jl b/src/converter/html/functions.jl index dbed994c1..723142df7 100644 --- a/src/converter/html/functions.jl +++ b/src/converter/html/functions.jl @@ -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 *= "" # 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 *= "" end # Reopen for this list item inner *= "
  • " 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 *= "
    1. " + end + end + for i = fill(nothing, lvl - curlvl - skip) inner *= "
      1. " 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 (
        1. ) 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 *= "
        " end toc = "
        " * inner * "
        " diff --git a/test/converter/md/markdown2.jl b/test/converter/md/markdown2.jl index 457ea06df..06e1c4378 100644 --- a/test/converter/md/markdown2.jl +++ b/test/converter/md/markdown2.jl @@ -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""" -