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, "") for _, tree := range trees { fmt.Fprintf( &b, "%s", tree.Heading.Id, tree.Heading.Text, ) if len(tree.Children) > 0 { fmt.Fprint(&b, RenderHeadingTrees(tree.Children, false)) } } fmt.Fprint(&b, "") return b.String() }