123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110 |
- 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()
- }
|