Closed maltegrosse closed 3 years ago
For HTML generation, you can use RenderNodeHook (https://github.com/gomarkdown/markdown/blob/master/html/renderer.go#L105) and over-write generation of ast.Heading (https://github.com/gomarkdown/markdown/blob/master/html/renderer.go#L977).
You can also traverse ast you get from the parser and change node.Level
in ast.Heading
nodes.
Thank you, can u give me some pseudo code example for it?
so, it was quite tricky but thanks to @Josua-SR I could manage it. it would be great if u could somehow add the toc level as an input parameter. for others:
/*
* Custom Renderer Interface for special TOC handling
*/
type CustomHTMLRenderer struct {
r *html.Renderer
}
func (c *CustomHTMLRenderer) RenderNode(w io.Writer, node ast.Node, entering bool) ast.WalkStatus {
return c.r.RenderNode(w, node, entering)
}
func (c *CustomHTMLRenderer) RenderHeader(w io.Writer, ast ast.Node) {
// render as usual
c.r.RenderHeader(w, ast)
// generate custom toc
c.writeTOC(w, ast)
}
func (c *CustomHTMLRenderer) RenderFooter(w io.Writer, ast ast.Node) {
c.r.RenderFooter(w, ast)
}
func newCustomHTMLRenderer(r *html.Renderer) *CustomHTMLRenderer {
return &CustomHTMLRenderer{
r: r,
}
}
/*
* forked writeTOC function
*/
func (c *CustomHTMLRenderer) writeTOC(w io.Writer, doc ast.Node) {
buf := bytes.Buffer{}
inHeading := false
tocLevel := 0
headingCount := 0
ast.WalkFunc(doc, func(node ast.Node, entering bool) ast.WalkStatus {
if nodeData, ok := node.(*ast.Heading); ok && !nodeData.IsTitleblock {
if (nodeData.Level >= 3) {
return ast.GoToNext
}
inHeading = entering
if !entering {
buf.WriteString("</a>")
return ast.GoToNext
}
if nodeData.HeadingID == "" {
nodeData.HeadingID = fmt.Sprintf("toc_%d", headingCount)
}
if nodeData.Level == tocLevel {
buf.WriteString("</li>\n\n<li>")
} else if nodeData.Level < tocLevel {
for nodeData.Level < tocLevel {
tocLevel--
buf.WriteString("</li>\n</ul>")
}
buf.WriteString("</li>\n\n<li>")
} else {
for nodeData.Level > tocLevel {
tocLevel++
buf.WriteString("\n<ul>\n<li>")
}
}
fmt.Fprintf(&buf, `<a href="#%s">`, nodeData.HeadingID)
headingCount++
return ast.GoToNext
}
if inHeading {
return c.r.RenderNode(&buf, node, entering)
}
return ast.GoToNext
})
for ; tocLevel > 0; tocLevel-- {
buf.WriteString("</li>\n</ul>")
}
if buf.Len() > 0 {
io.WriteString(w, "<nav>\n")
w.Write(buf.Bytes())
io.WriteString(w, "\n\n</nav>\n")
}
//c.r.lastOutputLen = buf.Len() // TODO: this is about internal state :(
}
htmlFlags := html.CommonFlags // make sure to remove the | html.TOC
opts := html.RendererOptions{Flags: htmlFlags}
renderer := newCustomHTMLRenderer(html.NewRenderer(opts))
// continue as always....
hint: html import can clash with other imports...
"github.com/gomarkdown/markdown"
"github.com/gomarkdown/markdown/ast"
"github.com/gomarkdown/markdown/html"
"github.com/gomarkdown/markdown/parser"
Hello, is there any possibility to limit the toc level? e.g. max 2 levels ->
# headline and ## sub-headline