123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198 |
- package server
- import (
- "github.com/gomarkdown/markdown"
- "github.com/gomarkdown/markdown/html"
- "github.com/gomarkdown/markdown/parser"
- "vultras.su/core/bond"
- "vultras.su/core/bond/contents"
- "vultras.su/util/pp"
- "path/filepath"
- "path"
- "os"
- "fmt"
- //"strings"
- "bytes"
- )
- const htmlHead = `
- <!doctype html>
- <html><head>
- <title>Title</title>
- <meta name="viewport" content="width=device-width, initial-scale=1" />
- <link rel="stylesheet" href="/web/main.css">
- </head><body>
- `
- const htmlFooter = `
- </body></html>
- `
- type ServerOptions struct {
- WikiPath string
- WikiExt string
- WebPath string
- AddFileNavigation bool
- AddDocNavigation bool
- }
- type Server struct {
- handler bond.Handler
- options ServerOptions
- prep *pp.Preprocessor
- }
- func (srv *Server) makeMdParser() *parser.Parser {
- return parser.NewWithExtensions(
- parser.CommonExtensions | parser.AutoHeadingIDs |
- parser.NoEmptyLineBeforeBlock | parser.Attributes |
- parser.Tables,
- )
- }
- func (srv *Server) makeHtmlRenderer() *html.Renderer {
- return html.NewRenderer(
- html.RendererOptions{
- Flags: html.CommonFlags | html.HrefTargetBlank,
- },
- )
- }
- func New(opts ServerOptions) *Server {
- srv := &Server{}
- srv.handler = makeRootHandler(opts)
- srv.options = opts
- srv.prep = pp.NewPp(pp.NewTengo())
- return srv
- }
- func (srv *Server) Handle(c *bond.Context) {
- c.Data = ContextData{
- Server: srv,
- }
- srv.handler.Handle(c)
- }
- func (srv *Server) ProcessPmd(pth string, bts []byte) ([]byte, error) {
- prep, err := srv.prep.Process(pth, string(bts))
- if err != nil {
- return nil, err
- }
- return []byte(prep), nil
- }
- func (srv *Server) pageHead() string {
- return htmlHead
- }
- func (srv *Server) pageFooter() string {
- return htmlFooter
- }
- func (srv *Server) ProcessToHtml(urlPath, filePath string, bts []byte) ([]byte, error) {
- var b bytes.Buffer
- doc := srv.makeMdParser().Parse(bts)
- main_section := markdown.Render(doc, srv.makeHtmlRenderer())
- fmt.Fprint(&b, srv.pageHead())
- if srv.options.AddFileNavigation {
- fileDirPath := filepath.Dir(filePath)
- urlDirPath := path.Dir(urlPath)
- entries, err := os.ReadDir(fileDirPath)
- if err != nil {
- fmt.Println("leaving", fileDirPath)
- return nil, err
- }
- fmt.Fprint(&b, "<header>")
- fmt.Fprint(&b, "<nav class=\"base\">")
- fmt.Fprintf(
- &b, "<a class=\"prev\" href=\"..\">"+
- "<<<</a>"+
- "<a class=\"home\"href=\".\">%s</a>",
- srv.makeFileName(fileDirPath, "index"+srv.options.WikiExt),
- )
- fmt.Fprint(&b, "</nav>")
- fmt.Fprint(&b, "<nav class=\"dirs\">")
- for _, entry := range entries {
- if !entry.IsDir() {
- continue
- }
- fmt.Fprintf(
- &b, "<a href=%s>%s</a>",
- srv.makeFileLink(urlDirPath, entry.Name()) + "/",
- srv.makeFileName(fileDirPath, entry.Name()),
- )
- }
- fmt.Fprint(&b, "</nav>")
- fmt.Fprint(&b, "<nav class=\"files\">")
- for _, entry := range entries {
- if entry.IsDir() || entry.Name() == "index" + srv.options.WikiExt{
- continue
- }
- fmt.Fprintf(
- &b, "<a href=\"%s\">%s</a>",
- srv.makeFileLink(urlDirPath, entry.Name()) ,
- srv.makeFileName(fileDirPath, entry.Name()),
- )
- }
- fmt.Fprint(&b, "</nav>")
- headings := getDocumentHeadings(doc)
- trees := makeHeadingTrees(headings)
- docNav := RenderHeadingTrees(trees, true)
- fmt.Fprint(&b, docNav)
- fmt.Fprint(&b, "</header>")
- }
- fmt.Fprint(&b, "<main>")
- fmt.Fprint(&b, string(main_section))
- fmt.Fprint(&b, "</main>")
- fmt.Fprint(&b, srv.pageFooter())
- return b.Bytes(), nil
- }
- var makeRootHandler = func(opts ServerOptions) bond.Handler {
- return bond.Path().
- Case(
- "web",
- bond.StaticDir(opts.WebPath),
- ).Case(
- "api",
- nil,
- ).Default(
- Func(func(c *Context){
- pth := c.wikiFilePath(c.Path())
- bts, err := os.ReadFile(pth)
- if err != nil {
- pth = c.wikiFilePath(c.Path()+"/")
- bts, err = os.ReadFile(pth)
- if err != nil {
- c.NotFound()
- return
- }
- }
- prep, err := c.ProcessPmd(pth, bts)
- if err != nil {
- c.InternalServerError(err)
- return
- }
- fmt.Println(c.Path(), pth)
- bts, err = c.ProcessToHtml(c.Path(), pth, prep)
- if err != nil {
- c.InternalServerError(err)
- return
- }
- c.SetContentType(contents.Html, contents.Utf8)
- c.W.Write(bts)
- }),
- )
- }
|