diff --git a/build.go b/build.go
index 08af6d5..8a0f7c3 100644
--- a/build.go
+++ b/build.go
@@ -64,12 +64,11 @@ func Build(bc BuildConfig) error {
// chroma styles
var chromaStylesBuff bytes.Buffer
- chromaStyle := bc.ChromaStyle
- if chromaStyle == nil {
- chromaStyle = styles.Get("swapoff")
+ if bc.ChromaStyle == nil {
+ bc.ChromaStyle = styles.Get("swapoff")
}
- if err := chromaHTML.New().WriteCSS(&chromaStylesBuff, chromaStyle); err != nil {
+ if err := chromaHTML.New().WriteCSS(&chromaStylesBuff, bc.ChromaStyle); err != nil {
return err
}
@@ -96,15 +95,13 @@ func Build(bc BuildConfig) error {
}
// posts
- allPostsByLangTag, visiblePostsByLangTag, invisiblePostsByLangTag, err := generatePostsLists(
- gat,
- bc.InPath,
- c.Langs,
- assetsOutPath,
- chromaStyle,
- c.ResponsiveImgMediaQueries,
- c.ResponsiveImgSizes,
- c.Latex,
+ postsLists, err := generatePostsLists(
+ generatePostsListsInput{
+ bc: &bc,
+ c: c,
+ gat: gat,
+ assetsOutPath: assetsOutPath,
+ },
)
if err != nil {
return err
@@ -114,7 +111,7 @@ func Build(bc BuildConfig) error {
baseTemplate, err := createBaseTemplateWithIncludes(
bc.TemplateFuncs,
path.Join(bc.InPath, "includes"),
- invisiblePostsByLangTag,
+ postsLists.invisiblePostsByLangTag,
gat,
c.URL,
c.ResponsiveImgSizes,
@@ -155,7 +152,7 @@ func Build(bc BuildConfig) error {
// home page
homePageTemplateData := TemplateData{
- Posts: visiblePostsByLangTag[l.Tag],
+ Posts: postsLists.visiblePostsByLangTag[l.Tag],
Lang: l,
Author: c.Author,
Color: c.Color,
@@ -189,7 +186,7 @@ func Build(bc BuildConfig) error {
Img: c.defaultImgByLangTag[l.Tag],
Lang: l,
Page: "404",
- Posts: visiblePostsByLangTag[l.Tag],
+ Posts: postsLists.visiblePostsByLangTag[l.Tag],
Title: fmt.Sprintf("Not found - %v", c.Title),
ResponsiveImgMediaQueries: c.ResponsiveImgMediaQueries,
URL: "/404.html",
@@ -202,14 +199,14 @@ func Build(bc BuildConfig) error {
}
// post page
- if len(visiblePostsByLangTag) > 0 || len(invisiblePostsByLangTag) > 0 {
+ if len(postsLists.visiblePostsByLangTag) > 0 || len(postsLists.invisiblePostsByLangTag) > 0 {
postsDirOutPath := path.Join(langOutPath, "posts")
err = os.Mkdir(postsDirOutPath, os.ModeDir|os.ModePerm)
if err != nil {
return err
}
- for _, p := range allPostsByLangTag[l.Tag] {
+ for _, p := range postsLists.allPostsByLangTag[l.Tag] {
postDirPath := path.Join(postsDirOutPath, p.Slug)
err := os.Mkdir(postDirPath, os.ModeDir|os.ModePerm)
if err != nil {
@@ -225,7 +222,7 @@ func Build(bc BuildConfig) error {
Lang: l,
Author: c.Author,
ResponsiveImgMediaQueries: c.ResponsiveImgMediaQueries,
- Posts: visiblePostsByLangTag[l.Tag],
+ Posts: postsLists.visiblePostsByLangTag[l.Tag],
}
postPageTemplateData.AlternateLinks = generateAlternateLinks(nil, []string{"posts", p.Slug}, c.Langs)
diff --git a/posts.go b/posts.go
index 90709b3..15970df 100644
--- a/posts.go
+++ b/posts.go
@@ -12,7 +12,6 @@ import (
"strings"
"time"
- "github.com/alecthomas/chroma"
chromaHTML "github.com/alecthomas/chroma/formatters/html"
"github.com/alecthomas/chroma/lexers"
"github.com/efreitasn/egen/internal/latex"
@@ -35,23 +34,6 @@ var (
}
)
-// Post is a post received by a template.
-type Post struct {
- Title string
- Content template.HTML
- Slug string
- Excerpt string
- Img *Img
- Date time.Time
- LastUpdateDate time.Time
- Lang *Lang
- // relative
- URL string
- // pat is a tree composed of any files in the post's path
- // whose name doesn't match any item in nonPostAssetsRxs.
- pat *assetsTreeNode
-}
-
type postYAMLFrontMatter struct {
Title string `yaml:"title"`
Excerpt string `yaml:"excerpt"`
@@ -65,26 +47,32 @@ type postYAMLDataFileContent struct {
Img AssetRelPath
}
-func generatePostsLists(
- gat *assetsTreeNode,
- inPath string,
- langs []*Lang,
- assetsOutPath string,
- chromaStyle *chroma.Style,
- responsiveImgMediaQueries string,
- responsiveImgSizes []int,
- latex bool,
-) (allPostsByLangTag, visiblePostsByLangTag, invisiblePostsByLangTag map[string][]*Post, err error) {
- postsInPath := path.Join(inPath, "posts")
+type (
+ generatePostsListsInput struct {
+ bc *BuildConfig
+ c *config
+ gat *assetsTreeNode
+ assetsOutPath string
+ }
+
+ generatePostsListsOutput struct {
+ allPostsByLangTag, visiblePostsByLangTag, invisiblePostsByLangTag map[string][]*Post
+ }
+)
+
+func generatePostsLists(input generatePostsListsInput) (*generatePostsListsOutput, error) {
+ postsInPath := path.Join(input.bc.InPath, "posts")
postsFileInfos, err := os.ReadDir(postsInPath)
if err != nil {
- return nil, nil, nil, err
+ return nil, err
}
- allPostsByLangTag = make(map[string][]*Post)
- visiblePostsByLangTag = make(map[string][]*Post)
- invisiblePostsByLangTag = make(map[string][]*Post)
+ output := generatePostsListsOutput{
+ allPostsByLangTag: make(map[string][]*Post),
+ visiblePostsByLangTag: make(map[string][]*Post),
+ invisiblePostsByLangTag: make(map[string][]*Post),
+ }
for _, postsFileInfo := range postsFileInfos {
if !postsFileInfo.IsDir() {
@@ -96,13 +84,13 @@ func generatePostsLists(
pat, err := generateAssetsTree(postDirPath, nonPostAssetsRxs)
if err != nil {
- return nil, nil, nil, fmt.Errorf("generating pat for %v post: %v", postSlug, err)
+ return nil, fmt.Errorf("generating pat for %v post: %v", postSlug, err)
}
// this condition exists so that assetsPathOut is only created if the post
// has at least one asset.
if pat.firstChild != nil {
- assetsPathOut := path.Join(assetsOutPath, postSlug)
+ assetsPathOut := path.Join(input.assetsOutPath, postSlug)
// it's checked whether assetsPathOut already exists because it could've
// been already created when generating the global assets tree (GAT) if
@@ -111,33 +99,33 @@ func generatePostsLists(
if os.IsNotExist(err) {
err := os.Mkdir(assetsPathOut, os.ModeDir|os.ModePerm)
if err != nil {
- return nil, nil, nil, fmt.Errorf("creating %v: %v", assetsPathOut, err)
+ return nil, fmt.Errorf("creating %v: %v", assetsPathOut, err)
}
} else {
- return nil, nil, nil, err
+ return nil, err
}
}
if err = pat.process(assetsPathOut, false); err != nil {
- return nil, nil, nil, fmt.Errorf("processing pat: %v", err)
+ return nil, fmt.Errorf("processing pat: %v", err)
}
}
// data.yaml file
postYAMLDataFile, err := os.Open(path.Join(postDirPath, "data.yaml"))
if err != nil {
- return nil, nil, nil, fmt.Errorf("opening %v data.yaml: %v", postSlug, err)
+ return nil, fmt.Errorf("opening %v data.yaml: %v", postSlug, err)
}
var postYAMLData postYAMLDataFileContent
err = yaml.NewDecoder(postYAMLDataFile).Decode(&postYAMLData)
if err != nil {
- return nil, nil, nil, fmt.Errorf("decoding %v data.yaml: %v", postSlug, err)
+ return nil, fmt.Errorf("decoding %v data.yaml: %v", postSlug, err)
}
postDate, err := time.Parse(time.RFC3339, postYAMLData.Date)
if err != nil {
- return nil, nil, nil, fmt.Errorf("parsing %v data.yaml date: %v", postSlug, err)
+ return nil, fmt.Errorf("parsing %v data.yaml date: %v", postSlug, err)
}
var postLastUpdateDate time.Time
@@ -145,12 +133,12 @@ func generatePostsLists(
if postYAMLData.LastUpdateDate != "" {
postLastUpdateDate, err = time.Parse(time.RFC3339, postYAMLData.LastUpdateDate)
if err != nil {
- return nil, nil, nil, fmt.Errorf("parsing %v data.yaml lastUpdateDate: %v", postSlug, err)
+ return nil, fmt.Errorf("parsing %v data.yaml lastUpdateDate: %v", postSlug, err)
}
}
// content_*.md files
- for _, l := range langs {
+ for _, l := range input.c.Langs {
var postURL string
if l.Default {
@@ -173,32 +161,34 @@ func generatePostsLists(
postContent, err := os.ReadFile(postContentFilePath)
if err != nil {
if os.IsNotExist(err) {
- return nil, nil, nil, fmt.Errorf("%v for %v post doesn't exist", postContentFilename, postSlug)
+ return nil, fmt.Errorf("%v for %v post doesn't exist", postContentFilename, postSlug)
}
- return nil, nil, nil, err
+ return nil, err
}
if !postContentRegExp.Match(postContent) {
- return nil, nil, nil, fmt.Errorf("post content at %v is invalid", postContentFilePath)
+ return nil, fmt.Errorf("post content at %v is invalid", postContentFilePath)
}
matchesIndexes := postContentRegExp.FindSubmatchIndex(postContent)
postContentYAML := postContent[matchesIndexes[2]:matchesIndexes[3]]
postContentMD := postContent[matchesIndexes[4]:matchesIndexes[5]]
+ p.generateContent(input, l, postContentMD)
+
// yaml
var yamlData postYAMLFrontMatter
err = yaml.Unmarshal(postContentYAML, &yamlData)
if err != nil {
- return nil, nil, nil, fmt.Errorf("parsing YAML content of %v: %v", postContentFilePath, err)
+ return nil, fmt.Errorf("parsing YAML content of %v: %v", postContentFilePath, err)
}
if yamlData.Title == "" {
- return nil, nil, nil, fmt.Errorf("title field in %v post frontmatter in %v cannot be empty", p.Slug, l.Tag)
+ return nil, fmt.Errorf("title field in %v post frontmatter in %v cannot be empty", p.Slug, l.Tag)
}
if yamlData.Excerpt == "" {
- return nil, nil, nil, fmt.Errorf("excerpt field in %v post frontmatter in %v cannot be empty", p.Slug, l.Tag)
+ return nil, fmt.Errorf("excerpt field in %v post frontmatter in %v cannot be empty", p.Slug, l.Tag)
}
p.Title = yamlData.Title
@@ -206,7 +196,7 @@ func generatePostsLists(
if postYAMLData.Img != "" {
if yamlData.ImgAlt == "" {
- return nil, nil, nil, fmt.Errorf("img alt in %v for %v post not provided", l.Tag, p.Slug)
+ return nil, fmt.Errorf("img alt in %v for %v post not provided", l.Tag, p.Slug)
}
p.Img = &Img{
@@ -215,414 +205,452 @@ func generatePostsLists(
}
}
- mdProcessor := blackfriday.New(blackfriday.WithExtensions(blackfriday.CommonExtensions))
- rootNode := mdProcessor.Parse(postContentMD)
- latexBlockMap := map[*blackfriday.Node]struct{}{}
- inlineLatexMap := map[*blackfriday.Node]struct{}{}
+ if output.allPostsByLangTag[l.Tag] == nil {
+ output.allPostsByLangTag[l.Tag] = make([]*Post, 0, 1)
+ }
- rootNode.Walk(func(node *blackfriday.Node, entering bool) blackfriday.WalkStatus {
- switch {
- // Remove img tags from inside p tags.
- case node.Type == blackfriday.Image && entering:
- oldParent := node.Parent
+ output.allPostsByLangTag[l.Tag] = append(output.allPostsByLangTag[l.Tag], &p)
- if oldParent.Type == blackfriday.Paragraph {
- newParent := oldParent.Parent
+ if postYAMLData.Feed {
+ if output.visiblePostsByLangTag[l.Tag] == nil {
+ output.visiblePostsByLangTag[l.Tag] = make([]*Post, 0, 1)
+ }
- // this should never happen
- if newParent.Type == blackfriday.Paragraph {
- node.Unlink()
+ output.visiblePostsByLangTag[l.Tag] = append(output.visiblePostsByLangTag[l.Tag], &p)
+ } else {
+ if output.invisiblePostsByLangTag[l.Tag] == nil {
+ output.invisiblePostsByLangTag[l.Tag] = make([]*Post, 0, 1)
+ }
- return blackfriday.GoToNext
- }
+ output.invisiblePostsByLangTag[l.Tag] = append(output.invisiblePostsByLangTag[l.Tag], &p)
+ }
+ }
+ }
- oldParentChildren := getBFNodeChildren(oldParent)
- nodeOldParentIndex := findBFNodeIndex(node, oldParent)
+ return &output, nil
+}
- var oldParentChildrenAfterNode []*blackfriday.Node
- if nodeOldParentIndex+1 < len(oldParentChildren) {
- oldParentChildrenAfterNode = oldParentChildren[nodeOldParentIndex+1:]
- }
+// Post is a post received by a template.
+type Post struct {
+ Title string
+ Content template.HTML
+ Slug string
+ Excerpt string
+ Img *Img
+ Date time.Time
+ LastUpdateDate time.Time
+ Lang *Lang
+ // relative
+ URL string
+ // pat is a tree composed of any files in the post's path
+ // whose name doesn't match any item in nonPostAssetsRxs.
+ pat *assetsTreeNode
+}
- if oldParent.Next == nil {
- newParent.AppendChild(node)
+func (p *Post) generateContent(input generatePostsListsInput, l *Lang, markdown []byte) error {
+ mdProcessor := blackfriday.New(blackfriday.WithExtensions(blackfriday.CommonExtensions))
+ rootNode := mdProcessor.Parse(markdown)
- if oldParentChildrenAfterNode != nil {
- pNode := blackfriday.NewNode(blackfriday.Paragraph)
+ latexBlockMap, inlineLatexMap := p.processContentBFTree(input, rootNode)
- for _, c := range oldParentChildrenAfterNode {
- pNode.AppendChild(c)
- }
- newParent.AppendChild(pNode)
- }
- } else {
- oldParentNewParentIndex := findBFNodeIndex(oldParent, newParent)
- newParentChildren := getBFNodeChildren(newParent)
- newParentChildrenAfterOldParent := newParentChildren[oldParentNewParentIndex+1:]
+ err := latexGenerator.SetDirPath(input.bc.InPath)
+ if err != nil {
+ return fmt.Errorf("setting latex image generator dir path: %w", err)
+ }
- newParent.AppendChild(node)
+ err = p.renderContentBFTree(input, l, rootNode, latexBlockMap, inlineLatexMap)
+ if err != nil {
+ return err
+ }
- if oldParentChildrenAfterNode != nil {
- pNode := blackfriday.NewNode(blackfriday.Paragraph)
+ return nil
+}
- for _, c := range oldParentChildrenAfterNode {
- pNode.AppendChild(c)
- }
+func (p *Post) processContentBFTree(input generatePostsListsInput, rootNode *blackfriday.Node) (latexBlockMap, inlineLatexMap map[*blackfriday.Node]struct{}) {
+ latexBlockMap = map[*blackfriday.Node]struct{}{}
+ inlineLatexMap = map[*blackfriday.Node]struct{}{}
- newParent.AppendChild(pNode)
- }
+ rootNode.Walk(func(node *blackfriday.Node, entering bool) blackfriday.WalkStatus {
+ switch {
+ // Remove img tags from inside p tags.
+ case node.Type == blackfriday.Image && entering:
+ oldParent := node.Parent
- for _, c := range newParentChildrenAfterOldParent {
- newParent.AppendChild(c)
- }
+ if oldParent.Type == blackfriday.Paragraph {
+ newParent := oldParent.Parent
+
+ // this should never happen
+ if newParent.Type == blackfriday.Paragraph {
+ node.Unlink()
+
+ return blackfriday.GoToNext
+ }
+
+ oldParentChildren := getBFNodeChildren(oldParent)
+ nodeOldParentIndex := findBFNodeIndex(node, oldParent)
+
+ var oldParentChildrenAfterNode []*blackfriday.Node
+ if nodeOldParentIndex+1 < len(oldParentChildren) {
+ oldParentChildrenAfterNode = oldParentChildren[nodeOldParentIndex+1:]
+ }
+
+ if oldParent.Next == nil {
+ newParent.AppendChild(node)
+
+ if oldParentChildrenAfterNode != nil {
+ pNode := blackfriday.NewNode(blackfriday.Paragraph)
+
+ for _, c := range oldParentChildrenAfterNode {
+ pNode.AppendChild(c)
}
+ newParent.AppendChild(pNode)
+ }
+ } else {
+ oldParentNewParentIndex := findBFNodeIndex(oldParent, newParent)
+ newParentChildren := getBFNodeChildren(newParent)
+ newParentChildrenAfterOldParent := newParentChildren[oldParentNewParentIndex+1:]
+
+ newParent.AppendChild(node)
- if len(oldParentChildren) == 1 {
- oldParent.Unlink()
+ if oldParentChildrenAfterNode != nil {
+ pNode := blackfriday.NewNode(blackfriday.Paragraph)
+
+ for _, c := range oldParentChildrenAfterNode {
+ pNode.AppendChild(c)
}
+
+ newParent.AppendChild(pNode)
}
- case node.Type == blackfriday.Text && entering:
- if latex {
- for i := 0; i < len(node.Literal); {
- if node.Literal[i] == '$' {
- if i != 0 && node.Literal[i-1] == '\\' {
- node.Literal = slices.Delete(node.Literal, i-1, i)
- i++
- continue
- }
+ for _, c := range newParentChildrenAfterOldParent {
+ newParent.AppendChild(c)
+ }
+ }
- if len(node.Literal) > i+1 && node.Literal[i+1] == '$' {
- var (
- found bool
-
- start = i + 2
- end = start
- )
-
- for ; end < len(node.Literal); end++ {
- if node.Literal[end] == '$' && node.Literal[end-1] != '\\' && len(node.Literal) > end+1 && node.Literal[end+1] == '$' {
- found = true
- break
- }
- }
-
- if !found {
- return blackfriday.GoToNext
- }
-
- content := node.Literal[start:end]
-
- // If it's empty (i.e. $$$$), remove it.
- if len(content) == 0 {
- node.Literal = slices.Delete(node.Literal, start-2, end+2)
- i++
- continue
- }
-
- // If the first $ is not on the 0th position, then the current block needs to be
- // splitted.
- if i != 0 {
- textNode := blackfriday.NewNode(blackfriday.Text)
- textNode.Literal = node.Literal[:i]
-
- node.InsertBefore(textNode)
- }
-
- // The content after the ending $$, if there's any, is the caption.
- node.Title = node.Literal[end+2:]
- node.Literal = content
- latexBlockMap[node] = struct{}{}
-
- return blackfriday.GoToNext
- }
+ if len(oldParentChildren) == 1 {
+ oldParent.Unlink()
+ }
+ }
- // Inline latex.
- var (
- found bool
+ case node.Type == blackfriday.Text && entering:
+ if input.c.Latex {
+ for i := 0; i < len(node.Literal); {
+ if node.Literal[i] == '$' {
+ if i != 0 && node.Literal[i-1] == '\\' {
+ node.Literal = slices.Delete(node.Literal, i-1, i)
+ i++
+ continue
+ }
- start = i + 1
- end = start
- )
+ if len(node.Literal) > i+1 && node.Literal[i+1] == '$' {
+ var (
+ found bool
- for ; end < len(node.Literal); end++ {
- if node.Literal[end] == '$' && node.Literal[end-1] != '\\' {
- found = true
- break
- }
- }
+ start = i + 2
+ end = start
+ )
- if !found {
- return blackfriday.GoToNext
+ for ; end < len(node.Literal); end++ {
+ if node.Literal[end] == '$' && node.Literal[end-1] != '\\' && len(node.Literal) > end+1 && node.Literal[end+1] == '$' {
+ found = true
+ break
}
+ }
- content := node.Literal[start:end]
+ if !found {
+ return blackfriday.GoToNext
+ }
- // If it's empty (i.e. $$), remove it.
- if len(content) == 0 {
- node.Literal = slices.Delete(node.Literal, start-1, end+1)
- i++
- continue
- }
+ content := node.Literal[start:end]
- // If the starting $ is not on the 0th position, then a text node needs to be inserted
- // before the current node.
- if i != 0 {
- textNode := blackfriday.NewNode(blackfriday.Text)
- textNode.Literal = node.Literal[:i]
+ // If it's empty (i.e. $$$$), remove it.
+ if len(content) == 0 {
+ node.Literal = slices.Delete(node.Literal, start-2, end+2)
+ i++
+ continue
+ }
- node.InsertBefore(textNode)
- }
+ // If the first $ is not on the 0th position, then the current block needs to be
+ // splitted.
+ if i != 0 {
+ textNode := blackfriday.NewNode(blackfriday.Text)
+ textNode.Literal = node.Literal[:i]
- // If the ending $ is not on the last position, then a text node needs to be inserted
- // after the current node.
- if end != len(node.Literal)-1 {
- textNode := blackfriday.NewNode(blackfriday.Text)
- textNode.Literal = node.Literal[end+1:]
-
- if node.Next == nil {
- node.Parent.AppendChild(textNode)
- } else {
- node.Next.InsertBefore(textNode)
- }
- }
+ node.InsertBefore(textNode)
+ }
- node.Literal = content
- inlineLatexMap[node] = struct{}{}
+ // The content after the ending $$, if there's any, is the caption.
+ node.Title = node.Literal[end+2:]
+ node.Literal = content
+ latexBlockMap[node] = struct{}{}
- return blackfriday.GoToNext
+ return blackfriday.GoToNext
+ }
+
+ // Inline latex.
+ var (
+ found bool
+
+ start = i + 1
+ end = start
+ )
+
+ for ; end < len(node.Literal); end++ {
+ if node.Literal[end] == '$' && node.Literal[end-1] != '\\' {
+ found = true
+ break
}
+ }
+
+ if !found {
+ return blackfriday.GoToNext
+ }
+
+ content := node.Literal[start:end]
+ // If it's empty (i.e. $$), remove it.
+ if len(content) == 0 {
+ node.Literal = slices.Delete(node.Literal, start-1, end+1)
i++
+ continue
}
- }
- }
- return blackfriday.GoToNext
- })
+ // If the starting $ is not on the 0th position, then a text node needs to be inserted
+ // before the current node.
+ if i != 0 {
+ textNode := blackfriday.NewNode(blackfriday.Text)
+ textNode.Literal = node.Literal[:i]
- var htmlBuff bytes.Buffer
+ node.InsertBefore(textNode)
+ }
- var bfTraverseErr error
- r := blackfriday.NewHTMLRenderer(blackfriday.HTMLRendererParameters{
- Flags: blackfriday.HrefTargetBlank | blackfriday.NoreferrerLinks,
- })
+ // If the ending $ is not on the last position, then a text node needs to be inserted
+ // after the current node.
+ if end != len(node.Literal)-1 {
+ textNode := blackfriday.NewNode(blackfriday.Text)
+ textNode.Literal = node.Literal[end+1:]
- err = latexGenerator.SetDirPath(inPath)
- if err != nil {
- return nil, nil, nil, fmt.Errorf("setting latex image generator dir path: %w", err)
- }
+ if node.Next == nil {
+ node.Parent.AppendChild(textNode)
+ } else {
+ node.Next.InsertBefore(textNode)
+ }
+ }
+
+ node.Literal = content
+ inlineLatexMap[node] = struct{}{}
- // traverse the tree to render each node
- rootNode.Walk(func(bfNode *blackfriday.Node, entering bool) blackfriday.WalkStatus {
- switch {
- case bfNode.Type == blackfriday.CodeBlock && entering:
- if !mdCodeBlockInfoRegExp.Match(bfNode.Info) {
return blackfriday.GoToNext
}
- cbInfoMatches := mdCodeBlockInfoRegExp.FindStringSubmatch(string(bfNode.Info))
- lang := cbInfoMatches[1]
+ i++
+ }
+ }
+ }
- hLines := make([][2]int, 0)
+ return blackfriday.GoToNext
+ })
- if cbInfoMatches[2] != "" {
- hLinesMatches := mdCodeBlockInfoHLinesRegExp.FindAllStringSubmatch(cbInfoMatches[2], -1)
+ return latexBlockMap, inlineLatexMap
+}
- for _, hLinesMatch := range hLinesMatches {
- startLine, err := strconv.Atoi(hLinesMatch[1])
- if err != nil {
- return blackfriday.GoToNext
- }
+func (p *Post) renderContentBFTree(input generatePostsListsInput, l *Lang, rootNode *blackfriday.Node, latexBlockMap, inlineLatexMap map[*blackfriday.Node]struct{}) error {
+ var (
+ traverseErr error
+ htmlBuff bytes.Buffer
+ )
- endLine, err := strconv.Atoi(hLinesMatch[2])
- if err != nil {
- return blackfriday.GoToNext
- }
+ r := blackfriday.NewHTMLRenderer(blackfriday.HTMLRendererParameters{
+ Flags: blackfriday.HrefTargetBlank | blackfriday.NoreferrerLinks,
+ })
- hLines = append(hLines, [2]int{
- startLine,
- endLine,
- })
- }
- }
+ rootNode.Walk(func(bfNode *blackfriday.Node, entering bool) blackfriday.WalkStatus {
+ switch {
+ case bfNode.Type == blackfriday.CodeBlock && entering:
+ if !mdCodeBlockInfoRegExp.Match(bfNode.Info) {
+ return blackfriday.GoToNext
+ }
- lexer := lexers.Get(lang)
- if lexer == nil {
- bfTraverseErr = fmt.Errorf("no lexer found for %v code in %v post (%v)", lang, p.Slug, l.Tag)
+ cbInfoMatches := mdCodeBlockInfoRegExp.FindStringSubmatch(string(bfNode.Info))
+ lang := cbInfoMatches[1]
- return blackfriday.Terminate
- }
+ hLines := make([][2]int, 0)
- iterator, _ := lexer.Tokenise(nil, string(bfNode.Literal))
- formatter := chromaHTML.New(
- chromaHTML.WithClasses(true),
- chromaHTML.HighlightLines(hLines),
- )
+ if cbInfoMatches[2] != "" {
+ hLinesMatches := mdCodeBlockInfoHLinesRegExp.FindAllStringSubmatch(cbInfoMatches[2], -1)
- var formattedCode bytes.Buffer
- err := formatter.Format(&formattedCode, chromaStyle, iterator)
+ for _, hLinesMatch := range hLinesMatches {
+ startLine, err := strconv.Atoi(hLinesMatch[1])
if err != nil {
- bfTraverseErr = err
-
- return blackfriday.Terminate
+ return blackfriday.GoToNext
}
- if _, err = htmlBuff.Write(formattedCode.Bytes()); err != nil {
- bfTraverseErr = err
-
- return blackfriday.Terminate
+ endLine, err := strconv.Atoi(hLinesMatch[2])
+ if err != nil {
+ return blackfriday.GoToNext
}
- return blackfriday.GoToNext
+ hLines = append(hLines, [2]int{
+ startLine,
+ endLine,
+ })
+ }
+ }
- case bfNode.Type == blackfriday.Image && entering:
- if bfNode.FirstChild == nil || string(bfNode.FirstChild.Literal) == "" {
- bfTraverseErr = fmt.Errorf("%v img in %v post in %v must have an alt attribute", string(bfNode.LinkData.Destination), p.Slug, l.Tag)
+ lexer := lexers.Get(lang)
+ if lexer == nil {
+ traverseErr = fmt.Errorf("no lexer found for %v code in %v post (%v)", lang, p.Slug, l.Tag)
- return blackfriday.Terminate
- }
-
- title := string(bfNode.Title)
- alt := string(bfNode.FirstChild.Literal)
+ return blackfriday.Terminate
+ }
- node, searchedInPAT := findByRelPathInGATOrPAT(gat, p.pat, AssetRelPath(bfNode.LinkData.Destination))
- if node == nil {
- bfTraverseErr = fmt.Errorf(
- "%v img not found in %v post",
- string(bfNode.LinkData.Destination),
- p.Slug,
- )
+ iterator, _ := lexer.Tokenise(nil, string(bfNode.Literal))
+ formatter := chromaHTML.New(
+ chromaHTML.WithClasses(true),
+ chromaHTML.HighlightLines(hLines),
+ )
- return blackfriday.Terminate
- }
+ var formattedCode bytes.Buffer
+ err := formatter.Format(&formattedCode, input.bc.ChromaStyle, iterator)
+ if err != nil {
+ traverseErr = err
- node.addSizes(responsiveImgSizes...)
+ return blackfriday.Terminate
+ }
- if err := node.processSizes(); err != nil {
- bfTraverseErr = fmt.Errorf("while processing sizes for %v img: %v", node.path, err)
+ if _, err = htmlBuff.Write(formattedCode.Bytes()); err != nil {
+ traverseErr = err
- return blackfriday.Terminate
- }
+ return blackfriday.Terminate
+ }
- var figcaption string
- if title != "" {
- figcaption = fmt.Sprintf("%v", title)
- }
+ return blackfriday.GoToNext
- var src string
- if searchedInPAT {
- src = node.assetLink(postSlug, node.findOriginalSize())
- } else {
- src = node.assetLink("", node.findOriginalSize())
- }
+ case bfNode.Type == blackfriday.Image && entering:
+ if bfNode.FirstChild == nil || string(bfNode.FirstChild.Literal) == "" {
+ traverseErr = fmt.Errorf("%v img in %v post in %v must have an alt attribute", string(bfNode.LinkData.Destination), p.Slug, l.Tag)
- var img string
- if responsiveImgMediaQueries != "" {
- var srcset string
- if searchedInPAT {
- srcset = node.generateSrcSetValue(postSlug)
- } else {
- srcset = node.generateSrcSetValue("")
- }
+ return blackfriday.Terminate
+ }
- img = fmt.Sprintf(`
`, srcset, responsiveImgMediaQueries, src, alt)
- } else {
- img = fmt.Sprintf(`
`, src, alt)
- }
+ title := string(bfNode.Title)
+ alt := string(bfNode.FirstChild.Literal)
- htmlBuff.WriteString(
- fmt.Sprintf(`%v%v`, src, img, figcaption),
- )
+ node, searchedInPAT := findByRelPathInGATOrPAT(input.gat, p.pat, AssetRelPath(bfNode.LinkData.Destination))
+ if node == nil {
+ traverseErr = fmt.Errorf(
+ "%v img not found in %v post",
+ string(bfNode.LinkData.Destination),
+ p.Slug,
+ )
- return blackfriday.SkipChildren
+ return blackfriday.Terminate
+ }
- case bfNode.Type == blackfriday.Text && mapContains(latexBlockMap, bfNode):
- if !entering {
- return blackfriday.GoToNext
- }
+ node.addSizes(input.c.ResponsiveImgSizes...)
- svgBs, err := latexGenerator.SVGBlock(bfNode.Literal)
- if err != nil {
- bfTraverseErr = fmt.Errorf("generating latex block in %v post: %w", p.Slug, err)
+ if err := node.processSizes(); err != nil {
+ traverseErr = fmt.Errorf("while processing sizes for %v img: %v", node.path, err)
- return blackfriday.Terminate
- }
+ return blackfriday.Terminate
+ }
- var figCaption string
- if len(bfNode.Title) > 0 {
- figCaption = fmt.Sprintf("%s", bfNode.Title)
- }
+ var figcaption string
+ if title != "" {
+ figcaption = fmt.Sprintf("%v", title)
+ }
- fmt.Fprintf(
- &htmlBuff,
- `%s
%s`,
- svgBs,
- figCaption,
- )
+ var src string
+ if searchedInPAT {
+ src = node.assetLink(p.Slug, node.findOriginalSize())
+ } else {
+ src = node.assetLink("", node.findOriginalSize())
+ }
- return blackfriday.GoToNext
+ var img string
+ if input.c.ResponsiveImgMediaQueries != "" {
+ var srcset string
+ if searchedInPAT {
+ srcset = node.generateSrcSetValue(p.Slug)
+ } else {
+ srcset = node.generateSrcSetValue("")
+ }
- case bfNode.Type == blackfriday.Text && mapContains(inlineLatexMap, bfNode):
- if !entering {
- return blackfriday.GoToNext
- }
+ img = fmt.Sprintf(`
`, srcset, input.c.ResponsiveImgMediaQueries, src, alt)
+ } else {
+ img = fmt.Sprintf(`
`, src, alt)
+ }
- svgBs, err := latexGenerator.SVGInline(bfNode.Literal)
- if err != nil {
- bfTraverseErr = fmt.Errorf("generating inline latex in %v post: %w", p.Slug, err)
+ htmlBuff.WriteString(
+ fmt.Sprintf(`%v%v`, src, img, figcaption),
+ )
- return blackfriday.Terminate
- }
+ return blackfriday.SkipChildren
- fmt.Fprintf(&htmlBuff, `%s`, svgBs)
+ case bfNode.Type == blackfriday.Text && mapContains(latexBlockMap, bfNode):
+ if !entering {
+ return blackfriday.GoToNext
+ }
- return blackfriday.GoToNext
+ svgBs, err := latexGenerator.SVGBlock(bfNode.Literal)
+ if err != nil {
+ traverseErr = fmt.Errorf("generating latex block in %v post: %w", p.Slug, err)
- case bfNode.Type == blackfriday.Paragraph:
- firstChildIsEmpty := bfNode.FirstChild == nil || len(strings.Trim(string(bfNode.FirstChild.Literal), "\n\t ")) == 0
- onlyChildIsLatexBlock := bfNode.FirstChild != nil && mapContains(latexBlockMap, bfNode.FirstChild) && bfNode.FirstChild.Next == nil
+ return blackfriday.Terminate
+ }
- if firstChildIsEmpty || onlyChildIsLatexBlock {
- return blackfriday.GoToNext
- }
+ var figCaption string
+ if len(bfNode.Title) > 0 {
+ figCaption = fmt.Sprintf("%s", bfNode.Title)
+ }
- bfNode.FirstChild.Literal = bytes.TrimLeft(bfNode.FirstChild.Literal, "\n\t ")
- bfNode.LastChild.Literal = bytes.TrimRight(bfNode.LastChild.Literal, "\n\t ")
+ fmt.Fprintf(
+ &htmlBuff,
+ `%s
%s`,
+ svgBs,
+ figCaption,
+ )
- return r.RenderNode(&htmlBuff, bfNode, entering)
+ return blackfriday.GoToNext
- default:
- return r.RenderNode(&htmlBuff, bfNode, entering)
- }
- })
- if bfTraverseErr != nil {
- return nil, nil, nil, bfTraverseErr
+ case bfNode.Type == blackfriday.Text && mapContains(inlineLatexMap, bfNode):
+ if !entering {
+ return blackfriday.GoToNext
}
- p.Content = template.HTML(htmlBuff.Bytes())
+ svgBs, err := latexGenerator.SVGInline(bfNode.Literal)
+ if err != nil {
+ traverseErr = fmt.Errorf("generating inline latex in %v post: %w", p.Slug, err)
- if allPostsByLangTag[l.Tag] == nil {
- allPostsByLangTag[l.Tag] = make([]*Post, 0, 1)
+ return blackfriday.Terminate
}
- allPostsByLangTag[l.Tag] = append(allPostsByLangTag[l.Tag], &p)
+ fmt.Fprintf(&htmlBuff, `%s`, svgBs)
- if postYAMLData.Feed {
- if visiblePostsByLangTag[l.Tag] == nil {
- visiblePostsByLangTag[l.Tag] = make([]*Post, 0, 1)
- }
+ return blackfriday.GoToNext
- visiblePostsByLangTag[l.Tag] = append(visiblePostsByLangTag[l.Tag], &p)
- } else {
- if invisiblePostsByLangTag[l.Tag] == nil {
- invisiblePostsByLangTag[l.Tag] = make([]*Post, 0, 1)
- }
+ case bfNode.Type == blackfriday.Paragraph:
+ firstChildIsEmpty := bfNode.FirstChild == nil || len(strings.Trim(string(bfNode.FirstChild.Literal), "\n\t ")) == 0
+ onlyChildIsLatexBlock := bfNode.FirstChild != nil && mapContains(latexBlockMap, bfNode.FirstChild) && bfNode.FirstChild.Next == nil
- invisiblePostsByLangTag[l.Tag] = append(invisiblePostsByLangTag[l.Tag], &p)
+ if firstChildIsEmpty || onlyChildIsLatexBlock {
+ return blackfriday.GoToNext
}
+
+ bfNode.FirstChild.Literal = bytes.TrimLeft(bfNode.FirstChild.Literal, "\n\t ")
+ bfNode.LastChild.Literal = bytes.TrimRight(bfNode.LastChild.Literal, "\n\t ")
+
+ return r.RenderNode(&htmlBuff, bfNode, entering)
+
+ default:
+ return r.RenderNode(&htmlBuff, bfNode, entering)
}
+ })
+ if traverseErr != nil {
+ return traverseErr
}
- return allPostsByLangTag, visiblePostsByLangTag, invisiblePostsByLangTag, nil
+ p.Content = template.HTML(htmlBuff.Bytes())
+
+ return nil
}