From: Nikita Shubin Date: Sun, 8 May 2022 07:13:27 +0000 (+0300) Subject: hugolib: markdown_title: add title from markdown X-Git-Url: http://git.maquefel.me/?a=commitdiff_plain;h=9c80f18328d4a168b0ee4fa55f930c322c67b966;p=brevno-suite%2Fhugo hugolib: markdown_title: add title from markdown Getting title from the page itself, as first encountered header in markdown file. Currently it's inefficient as we parsing page twice, the first in some ealier point when hugo renders markdown, so it should be embedded somewhere in that place. But currently i don't care about if a PoC implementation. Signed-off-by: Nikita Shubin --- diff --git a/hugolib/content_map_page.go b/hugolib/content_map_page.go index 21a4e8f2..7954c606 100644 --- a/hugolib/content_map_page.go +++ b/hugolib/content_map_page.go @@ -141,6 +141,12 @@ func (m *pageMap) newPageFromContentNode(n *contentNode, parentBucket *pagesMapB } ps.codeowners = owners + mi, err := s.h.markdownTitleInfoForPage(ps) + if err != nil { + return nil, errors.Wrap(err, "failed to load MarkdownTitle data") + } + ps.markdownTitleInfo = mi + r, err := content() if err != nil { return nil, err diff --git a/hugolib/hugo_sites.go b/hugolib/hugo_sites.go index d67652da..b69cd61c 100644 --- a/hugolib/hugo_sites.go +++ b/hugolib/hugo_sites.go @@ -81,6 +81,8 @@ type HugoSites struct { gitInfo *gitInfo codeownerInfo *codeownerInfo + markdownTitleInfo *markdownTitleInfo + // As loaded from the /data dirs data map[string]any @@ -181,6 +183,8 @@ type hugoSitesInit struct { // Loads the Git info and CODEOWNERS for all the pages if enabled. gitInfo *lazy.Init + markdownTitleInfo *lazy.Init + // Maps page translations. translations *lazy.Init } @@ -189,6 +193,7 @@ func (h *hugoSitesInit) Reset() { h.data.Reset() h.layouts.Reset() h.gitInfo.Reset() + h.markdownTitleInfo.Reset() h.translations.Reset() } @@ -224,6 +229,19 @@ func (h *HugoSites) codeownersForPage(p page.Page) ([]string, error) { return h.codeownerInfo.forPage(p), nil } + +func (h *HugoSites) markdownTitleInfoForPage(p page.Page) (*MarkdownTitleInfo, error) { + if _, err := h.init.markdownTitleInfo.Do(); err != nil { + return nil, err + } + + if h.markdownTitleInfo == nil { + return nil, nil + } + + return h.markdownTitleInfo.forPage(p), nil +} + func (h *HugoSites) siteInfos() page.Sites { infos := make(page.Sites, len(h.Sites)) for i, site := range h.Sites { @@ -353,6 +371,7 @@ func newHugoSites(cfg deps.DepsCfg, sites ...*Site) (*HugoSites, error) { data: lazy.New(), layouts: lazy.New(), gitInfo: lazy.New(), + markdownTitleInfo: lazy.New(), translations: lazy.New(), }, } @@ -396,6 +415,14 @@ func newHugoSites(cfg deps.DepsCfg, sites ...*Site) (*HugoSites, error) { return nil, nil }) + h.init.markdownTitleInfo.Add(func() (any, error) { + err := h.loadMarkdownTitleInfo() + if err != nil { + return nil, errors.Wrap(err, "failed to load MarkdownTitle info") + } + return nil, nil + }) + for _, s := range sites { s.h = h } @@ -444,6 +471,18 @@ func (h *HugoSites) loadGitInfo() error { return nil } +func (h *HugoSites) loadMarkdownTitleInfo() error { + if h.Cfg.GetBool("enableMarkdownTitleInfo") { + mi, err := newMarkdownTitleInfo(h.Cfg) + if err != nil { + h.Log.Errorln("Failed to read MarkdownTitle:", err) + } else { + h.markdownTitleInfo = mi + } + } + return nil +} + func (l configLoader) applyDeps(cfg deps.DepsCfg, sites ...*Site) error { if cfg.TemplateProvider == nil { cfg.TemplateProvider = tplimpl.DefaultTemplateProvider diff --git a/hugolib/markdown_title.go b/hugolib/markdown_title.go new file mode 100644 index 00000000..67d4ea77 --- /dev/null +++ b/hugolib/markdown_title.go @@ -0,0 +1,66 @@ +package hugolib + +import ( + "path/filepath" + "strings" + "os" + + "github.com/yuin/goldmark" + "github.com/yuin/goldmark/text" + "github.com/yuin/goldmark/ast" + + "github.com/gohugoio/hugo/config" + "github.com/gohugoio/hugo/resources/page" +) + +type MarkdownTitleInfo struct { + Title string `json:"title"` // Title +} + +type MarkdownTitleMap map[string]*MarkdownTitleInfo + +type markdownTitleInfo struct { + contentDir string + Map MarkdownTitleMap +} + +func findTitle(n ast.Node, source []byte) (string, bool) { + ret := "" + if n.Kind() == ast.KindHeading { + return string(n.Text(source)[:]), true + } + for c := n.FirstChild(); c != nil; c = c.NextSibling() { + ret, res := findTitle(c, source) + if res { + return ret, true + } + } + + return ret, false +} + +func (m *markdownTitleInfo) forPage(p page.Page) *MarkdownTitleInfo { + markdown := goldmark.New() + name := strings.TrimPrefix(filepath.ToSlash(p.File().Filename()), m.contentDir) + // name = strings.TrimPrefix(name, "/") + + source, err := os.ReadFile(name) + if err != nil { + return nil + } + + // Parse file and return title + n := markdown.Parser().Parse(text.NewReader([]byte(source))) + title, res := findTitle(n, source) + if !res { + return &MarkdownTitleInfo{Title: ""} + } + + return &MarkdownTitleInfo{Title: title} +} + +func newMarkdownTitleInfo(cfg config.Provider) (*markdownTitleInfo, error) { + contentDir := cfg.GetString("contentDir") + + return &markdownTitleInfo{contentDir: contentDir}, nil +} diff --git a/hugolib/page.go b/hugolib/page.go index 77165c07..5fae15ee 100644 --- a/hugolib/page.go +++ b/hugolib/page.go @@ -160,6 +160,10 @@ func (p *pageState) CodeOwners() []string { return p.codeowners } +func (p *pageState) MarkdownTitleInfo() *MarkdownTitleInfo { + return p.markdownTitleInfo +} + // GetTerms gets the terms defined on this page in the given taxonomy. // The pages returned will be ordered according to the front matter. func (p *pageState) GetTerms(taxonomy string) page.Pages { diff --git a/hugolib/page__common.go b/hugolib/page__common.go index e55bb7e2..b0ab4489 100644 --- a/hugolib/page__common.go +++ b/hugolib/page__common.go @@ -106,6 +106,8 @@ type pageCommon struct { gitInfo *gitmap.GitInfo codeowners []string + markdownTitleInfo *MarkdownTitleInfo + // Positional navigation posNextPrev *nextPrev posNextPrevSection *nextPrev