feat: added automatic document navigation generation.
This commit is contained in:
parent
3776c1db93
commit
243bd2b9e9
3 changed files with 132 additions and 6 deletions
126
server/main.go
126
server/main.go
|
@ -3,6 +3,7 @@ package server
|
|||
import (
|
||||
"github.com/gomarkdown/markdown"
|
||||
"github.com/gomarkdown/markdown/html"
|
||||
"github.com/gomarkdown/markdown/ast"
|
||||
"github.com/gomarkdown/markdown/parser"
|
||||
"vultras.su/core/bond"
|
||||
"vultras.su/core/bond/contents"
|
||||
|
@ -11,7 +12,7 @@ import (
|
|||
"path"
|
||||
"os"
|
||||
"fmt"
|
||||
//"strings"
|
||||
"strings"
|
||||
"bytes"
|
||||
)
|
||||
|
||||
|
@ -32,6 +33,7 @@ type ServerOptions struct {
|
|||
WikiExt string
|
||||
WebPath string
|
||||
AddFileNavigation bool
|
||||
AddDocNavigation bool
|
||||
}
|
||||
|
||||
type Server struct {
|
||||
|
@ -88,6 +90,113 @@ func (srv *Server) pageFooter() string {
|
|||
return htmlFooter
|
||||
}
|
||||
|
||||
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 {
|
||||
fmt.Println("fooooooooooooooouuuuuuuuund", len(hs), hs)
|
||||
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 {
|
||||
fmt.Println("thefound: ", first, h)
|
||||
lasti = i+1
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
fmt.Println("in not found")
|
||||
return HeadingTrees{
|
||||
&HeadingTree{
|
||||
Heading: first,
|
||||
Children: makeHeadingTrees(rest),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println("through", lasti)
|
||||
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()
|
||||
}
|
||||
|
||||
func (srv *Server) ProcessToHtml(urlPath, filePath string, bts []byte) ([]byte, error) {
|
||||
var b bytes.Buffer
|
||||
doc := srv.makeMdParser().Parse(bts)
|
||||
|
@ -133,14 +242,21 @@ func (srv *Server) ProcessToHtml(urlPath, filePath string, bts []byte) ([]byte,
|
|||
fmt.Fprint(&b, "</nav></header>")
|
||||
}
|
||||
|
||||
fmt.Fprint(&b, "<main>", string(main_section), "</main>")
|
||||
fmt.Fprint(&b, "<div class=\"content\">")
|
||||
if srv.options.AddDocNavigation {
|
||||
headings := getDocumentHeadings(doc)
|
||||
trees := makeHeadingTrees(headings)
|
||||
docNav := RenderHeadingTrees(trees, true)
|
||||
fmt.Fprint(&b, docNav)
|
||||
}
|
||||
fmt.Fprint(&b, "<main>")
|
||||
fmt.Fprintf(&b, string(main_section))
|
||||
fmt.Fprintf(&b, "</main>")
|
||||
fmt.Fprintf(&b, "</div>")
|
||||
fmt.Fprint(&b, srv.pageFooter())
|
||||
return b.Bytes(), nil
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
var makeRootHandler = func(opts ServerOptions) bond.Handler {
|
||||
return bond.Root(bond.Path().
|
||||
Case(
|
||||
|
|
3
tool.go
3
tool.go
|
@ -16,7 +16,8 @@ var Tool = mtool.T("rwiki").Func(func(flags *mtool.Flags){
|
|||
flags.StringVar(&opts.WikiPath, "wiki", "wiki", "path to wiki files")
|
||||
flags.StringVar(&opts.WebPath, "web", "web", "path to static web files")
|
||||
flags.StringVar(&opts.WikiExt, "ext", ".pmd", "wiki file exitension")
|
||||
flags.BoolVar(&opts.AddFileNavigation, "nav", true, "generate navigation")
|
||||
flags.BoolVar(&opts.AddFileNavigation, "filenav", true, "generate file navigation")
|
||||
flags.BoolVar(&opts.AddDocNavigation, "docnav", true, "generate document navigation")
|
||||
|
||||
flags.Parse()
|
||||
srv := bond.Server{
|
||||
|
|
|
@ -6,7 +6,16 @@ teahuste| ehtua | shit
|
|||
--------|-------------|--------------
|
||||
cock| dick|die
|
||||
|
||||
* [X] check
|
||||
|
||||
```go
|
||||
func main() {
|
||||
}
|
||||
```
|
||||
|
||||
## Second header shit
|
||||
|
||||
|
||||
## another dick
|
||||
|
||||
### third level header
|
||||
|
|
Loading…
Reference in a new issue