package notes import ( "bytes" "encoding/base64" "errors" "fmt" "io" "io/ioutil" "local/notes-server/filetree" "path" "regexp" "strings" "github.com/fairlyblank/md2min" "github.com/gomarkdown/markdown" "github.com/gomarkdown/markdown/ast" "github.com/gomarkdown/markdown/html" "github.com/gomarkdown/markdown/parser" "github.com/yuin/goldmark" blackfriday "gopkg.in/russross/blackfriday.v2" ) func (n *Notes) File(urlPath string) (string, error) { p := filetree.NewPathFromURL(urlPath) if p.IsDir() { return "", errors.New("path is dir") } b, _ := ioutil.ReadFile(p.Local) return n.gomarkdown(urlPath, b) return n.blackfriday(urlPath, b) return n.goldmark(urlPath, b) return n.md2min(urlPath, b) } func (n *Notes) blackfriday(urlPath string, b []byte) (string, error) { renderer := blackfriday.NewHTMLRenderer(blackfriday.HTMLRendererParameters{ Flags: blackfriday.TOC | blackfriday.Smartypants | blackfriday.SmartypantsFractions | blackfriday.SmartypantsDashes | blackfriday.SmartypantsQuotesNBSP | blackfriday.CompletePage, }) return string(blackfriday.Run( b, blackfriday.WithRenderer(renderer), )), nil } func (n *Notes) goldmark(urlPath string, b []byte) (string, error) { buff := bytes.NewBuffer(nil) err := goldmark.Convert(b, buff) return string(buff.Bytes()), err } func (n *Notes) md2min(urlPath string, b []byte) (string, error) { mdc := md2min.New("h1") buff := bytes.NewBuffer(nil) err := mdc.Parse(b, buff) return string(buff.Bytes()), err } func (n *Notes) gomarkdown(urlPath string, b []byte) (string, error) { renderer := html.NewRenderer(html.RendererOptions{ Flags: html.CommonFlags | html.TOC, RenderNodeHook: n.commentFormer(urlPath, b), }) ext := parser.NoExtensions for _, extension := range []parser.Extensions{ parser.NoIntraEmphasis, parser.Tables, parser.FencedCode, parser.Autolink, parser.Strikethrough, parser.SpaceHeadings, parser.HeadingIDs, parser.BackslashLineBreak, parser.DefinitionLists, parser.MathJax, parser.Titleblock, parser.AutoHeadingIDs, parser.Includes, } { ext |= extension } parser := parser.NewWithExtensions(ext) content := markdown.ToHTML(b, parser, renderer) return string(content) + "\n", nil } func (n *Notes) commentFormer(urlPath string, md []byte) html.RenderNodeFunc { urlPath = strings.TrimPrefix(urlPath, "/") urlPath = strings.TrimPrefix(urlPath, strings.Split(urlPath, "/")[0]) lines := bytes.Split(md, []byte("\n")) cur := -1 nextHeader := func() { cur++ for cur < len(lines) { for _, opener_closer := range [][]string{{"```", "```"}, {``, ``}} { if bytes.Contains(lines[cur], []byte(opener_closer[0])) { cur++ for cur < len(lines) && !bytes.Contains(lines[cur], []byte(opener_closer[1])) { cur++ } cur++ } } if cur >= len(lines) { break } line := lines[cur] ok, err := regexp.Match(`^\s*#+\s*.+$`, line) if err != nil { panic(err) } else if ok { return } cur++ } } return func(w io.Writer, node ast.Node, entering bool) (ast.WalkStatus, bool) { if heading, ok := node.(*ast.Heading); !n.ro && ok && !entering { nextHeader() fmt.Fprintf(w, `
`, path.Join("/comment", urlPath)+"#"+heading.HeadingID, cur) } return ast.GoToNext, false } } func (n *Notes) commentFormerOld() html.RenderNodeFunc { return func(w io.Writer, node ast.Node, entering bool) (ast.WalkStatus, bool) { if heading, ok := node.(*ast.Heading); ok { if !entering { literal := "" ast.WalkFunc(heading, func(n ast.Node, e bool) ast.WalkStatus { if leaf := n.AsLeaf(); e && leaf != nil { if literal != "" { literal += ".*" } literal += string(leaf.Literal) } return ast.GoToNext }) level := heading.Level id := base64.URLEncoding.EncodeToString([]byte(fmt.Sprintf(`^[ \t]*%s\s*%s(].*)?\s*$`, strings.Repeat("#", level), literal))) fmt.Fprintf(w, `
`, id) } } return ast.GoToNext, false } }