aboutsummaryrefslogtreecommitdiffhomepage
path: root/common
diff options
context:
space:
mode:
authorBjørn Erik Pedersen <[email protected]>2024-03-17 11:12:33 +0100
committerBjørn Erik Pedersen <[email protected]>2024-05-14 13:12:08 +0200
commite2d66e3218e180bbfca06ca3a29ce01957c513e9 (patch)
treeed29bb99cf16b75b6334e2fc618d31e80203e5d5 /common
parent55dea41c1ab703f13b841389c6888815a033cf86 (diff)
downloadhugo-e2d66e3218e180bbfca06ca3a29ce01957c513e9.tar.gz
hugo-e2d66e3218e180bbfca06ca3a29ce01957c513e9.zip
Create pages from _content.gotmpl
Closes #12427 Closes #12485 Closes #6310 Closes #5074
Diffstat (limited to 'common')
-rw-r--r--common/maps/cache.go14
-rw-r--r--common/paths/pathparser.go51
-rw-r--r--common/paths/pathparser_test.go19
3 files changed, 59 insertions, 25 deletions
diff --git a/common/maps/cache.go b/common/maps/cache.go
index 7e23a2662..3723d318e 100644
--- a/common/maps/cache.go
+++ b/common/maps/cache.go
@@ -27,7 +27,12 @@ func NewCache[K comparable, T any]() *Cache[K, T] {
}
// Delete deletes the given key from the cache.
+// If c is nil, this method is a no-op.
func (c *Cache[K, T]) Get(key K) (T, bool) {
+ if c == nil {
+ var zero T
+ return zero, false
+ }
c.RLock()
v, found := c.m[key]
c.RUnlock()
@@ -60,6 +65,15 @@ func (c *Cache[K, T]) Set(key K, value T) {
c.Unlock()
}
+// ForEeach calls the given function for each key/value pair in the cache.
+func (c *Cache[K, T]) ForEeach(f func(K, T)) {
+ c.RLock()
+ defer c.RUnlock()
+ for k, v := range c.m {
+ f(k, v)
+ }
+}
+
// SliceCache is a simple thread safe cache backed by a map.
type SliceCache[T any] struct {
m map[string][]T
diff --git a/common/paths/pathparser.go b/common/paths/pathparser.go
index 951501406..5fa798fb0 100644
--- a/common/paths/pathparser.go
+++ b/common/paths/pathparser.go
@@ -25,8 +25,6 @@ import (
"github.com/gohugoio/hugo/identity"
)
-var defaultPathParser PathParser
-
// PathParser parses a path into a Path.
type PathParser struct {
// Maps the language code to its index in the languages/sites slice.
@@ -34,11 +32,9 @@ type PathParser struct {
// Reports whether the given language is disabled.
IsLangDisabled func(string) bool
-}
-// Parse parses component c with path s into Path using the default path parser.
-func Parse(c, s string) *Path {
- return defaultPathParser.Parse(c, s)
+ // Reports whether the given ext is a content file.
+ IsContentExt func(string) bool
}
// NormalizePathString returns a normalized path string using the very basic Hugo rules.
@@ -108,7 +104,6 @@ func (pp *PathParser) parse(component, s string) (*Path, error) {
var err error
// Preserve the original case for titles etc.
p.unnormalized, err = pp.doParse(component, s, pp.newPath(component))
-
if err != nil {
return nil, err
}
@@ -195,23 +190,26 @@ func (pp *PathParser) doParse(component, s string, p *Path) (*Path, error) {
}
}
- isContentComponent := p.component == files.ComponentFolderContent || p.component == files.ComponentFolderArchetypes
- isContent := isContentComponent && files.IsContentExt(p.Ext())
-
- if isContent {
+ if len(p.identifiers) > 0 {
+ isContentComponent := p.component == files.ComponentFolderContent || p.component == files.ComponentFolderArchetypes
+ isContent := isContentComponent && pp.IsContentExt(p.Ext())
id := p.identifiers[len(p.identifiers)-1]
b := p.s[p.posContainerHigh : id.Low-1]
- switch b {
- case "index":
- p.bundleType = PathTypeLeaf
- case "_index":
- p.bundleType = PathTypeBranch
- default:
- p.bundleType = PathTypeContentSingle
- }
+ if isContent {
+ switch b {
+ case "index":
+ p.bundleType = PathTypeLeaf
+ case "_index":
+ p.bundleType = PathTypeBranch
+ default:
+ p.bundleType = PathTypeContentSingle
+ }
- if slashCount == 2 && p.IsLeafBundle() {
- p.posSectionHigh = 0
+ if slashCount == 2 && p.IsLeafBundle() {
+ p.posSectionHigh = 0
+ }
+ } else if b == files.NameContentData && files.IsContentDataExt(p.Ext()) {
+ p.bundleType = PathTypeContentData
}
}
@@ -246,6 +244,9 @@ const (
// Branch bundles, e.g. /blog/_index.md
PathTypeBranch
+
+ // Content data file, _content.gotmpl.
+ PathTypeContentData
)
type Path struct {
@@ -521,10 +522,6 @@ func (p *Path) Identifiers() []string {
return ids
}
-func (p *Path) IsHTML() bool {
- return files.IsHTML(p.Ext())
-}
-
func (p *Path) BundleType() PathType {
return p.bundleType
}
@@ -541,6 +538,10 @@ func (p *Path) IsLeafBundle() bool {
return p.bundleType == PathTypeLeaf
}
+func (p *Path) IsContentData() bool {
+ return p.bundleType == PathTypeContentData
+}
+
func (p Path) ForBundleType(t PathType) *Path {
p.bundleType = t
return &p
diff --git a/common/paths/pathparser_test.go b/common/paths/pathparser_test.go
index 8c89ddd41..e8fee96e1 100644
--- a/common/paths/pathparser_test.go
+++ b/common/paths/pathparser_test.go
@@ -27,6 +27,9 @@ var testParser = &PathParser{
"no": 0,
"en": 1,
},
+ IsContentExt: func(ext string) bool {
+ return ext == "md"
+ },
}
func TestParse(t *testing.T) {
@@ -333,6 +336,22 @@ func TestParse(t *testing.T) {
c.Assert(p.Path(), qt.Equals, "/a/b/c.txt")
},
},
+ {
+ "Content data file gotmpl",
+ "/a/b/_content.gotmpl",
+ func(c *qt.C, p *Path) {
+ c.Assert(p.Path(), qt.Equals, "/a/b/_content.gotmpl")
+ c.Assert(p.Ext(), qt.Equals, "gotmpl")
+ c.Assert(p.IsContentData(), qt.IsTrue)
+ },
+ },
+ {
+ "Content data file yaml",
+ "/a/b/_content.yaml",
+ func(c *qt.C, p *Path) {
+ c.Assert(p.IsContentData(), qt.IsFalse)
+ },
+ },
}
for _, test := range tests {
c.Run(test.name, func(c *qt.C) {