rwiki/server/heading.go

111 lines
1.8 KiB
Go
Raw Normal View History

package server
import (
"github.com/gomarkdown/markdown/ast"
"strings"
"fmt"
)
type Heading struct {
Id string
Level int
Text string
}
func getDocumentHeadings(doc ast.Node) []Heading {
ret := []Heading{}
ast.WalkFunc(doc, func(node ast.Node, entering bool) ast.WalkStatus {
heading, ok := node.(*ast.Heading)
if !ok {
return ast.GoToNext
}
children := node.GetChildren()
if len(children) > 0 && !entering {
leaf := children[0].AsLeaf()
if leaf == nil {
return ast.GoToNext
}
ret = append(ret, Heading{
Id: heading.HeadingID,
Level: heading.Level,
Text: string(leaf.Literal),
})
return ast.SkipChildren
}
return ast.GoToNext
})
return ret
}
type HeadingTree struct {
Heading Heading
Children HeadingTrees
}
type HeadingTrees []*HeadingTree
func makeHeadingTrees(hs []Heading) HeadingTrees {
if len(hs) == 0 {
return nil
}
if len(hs) == 1 {
return HeadingTrees{
&HeadingTree{
Heading: hs[0],
},
}
}
var (
lasti int
found bool
)
first := hs[0]
rest := hs[1:]
for i, h := range rest {
if first.Level >= h.Level {
lasti = i+1
found = true
break
}
}
if !found {
return HeadingTrees{
&HeadingTree{
Heading: first,
Children: makeHeadingTrees(rest),
},
}
}
return append(
makeHeadingTrees(hs[:lasti]),
makeHeadingTrees(hs[lasti:])... ,
)
}
func RenderHeadingTrees(trees HeadingTrees, first bool) string {
var b strings.Builder
fmt.Fprint(&b, "<nav")
if first {
fmt.Fprint(&b, " class=\"document\"")
}
fmt.Fprint(&b, ">")
for _, tree := range trees {
fmt.Fprintf(
&b, "<a href=\"#%s\">%s</a>",
tree.Heading.Id, tree.Heading.Text,
)
if len(tree.Children) > 0 {
fmt.Fprint(&b, RenderHeadingTrees(tree.Children, false))
}
}
fmt.Fprint(&b, "</nav>")
return b.String()
}