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 (
|
import (
|
||||||
"github.com/gomarkdown/markdown"
|
"github.com/gomarkdown/markdown"
|
||||||
"github.com/gomarkdown/markdown/html"
|
"github.com/gomarkdown/markdown/html"
|
||||||
|
"github.com/gomarkdown/markdown/ast"
|
||||||
"github.com/gomarkdown/markdown/parser"
|
"github.com/gomarkdown/markdown/parser"
|
||||||
"vultras.su/core/bond"
|
"vultras.su/core/bond"
|
||||||
"vultras.su/core/bond/contents"
|
"vultras.su/core/bond/contents"
|
||||||
|
@ -11,7 +12,7 @@ import (
|
||||||
"path"
|
"path"
|
||||||
"os"
|
"os"
|
||||||
"fmt"
|
"fmt"
|
||||||
//"strings"
|
"strings"
|
||||||
"bytes"
|
"bytes"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -32,6 +33,7 @@ type ServerOptions struct {
|
||||||
WikiExt string
|
WikiExt string
|
||||||
WebPath string
|
WebPath string
|
||||||
AddFileNavigation bool
|
AddFileNavigation bool
|
||||||
|
AddDocNavigation bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type Server struct {
|
type Server struct {
|
||||||
|
@ -88,6 +90,113 @@ func (srv *Server) pageFooter() string {
|
||||||
return htmlFooter
|
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) {
|
func (srv *Server) ProcessToHtml(urlPath, filePath string, bts []byte) ([]byte, error) {
|
||||||
var b bytes.Buffer
|
var b bytes.Buffer
|
||||||
doc := srv.makeMdParser().Parse(bts)
|
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, "</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())
|
fmt.Fprint(&b, srv.pageFooter())
|
||||||
return b.Bytes(), nil
|
return b.Bytes(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var makeRootHandler = func(opts ServerOptions) bond.Handler {
|
var makeRootHandler = func(opts ServerOptions) bond.Handler {
|
||||||
return bond.Root(bond.Path().
|
return bond.Root(bond.Path().
|
||||||
Case(
|
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.WikiPath, "wiki", "wiki", "path to wiki files")
|
||||||
flags.StringVar(&opts.WebPath, "web", "web", "path to static web files")
|
flags.StringVar(&opts.WebPath, "web", "web", "path to static web files")
|
||||||
flags.StringVar(&opts.WikiExt, "ext", ".pmd", "wiki file exitension")
|
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()
|
flags.Parse()
|
||||||
srv := bond.Server{
|
srv := bond.Server{
|
||||||
|
|
|
@ -6,7 +6,16 @@ teahuste| ehtua | shit
|
||||||
--------|-------------|--------------
|
--------|-------------|--------------
|
||||||
cock| dick|die
|
cock| dick|die
|
||||||
|
|
||||||
|
* [X] check
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func main() {
|
func main() {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Second header shit
|
||||||
|
|
||||||
|
|
||||||
|
## another dick
|
||||||
|
|
||||||
|
### third level header
|
||||||
|
|
Loading…
Reference in a new issue