diff options
author | Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com> | 2021-03-30 07:55:24 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-03-30 07:55:24 +0200 |
commit | 2dc222cec4460595af8569165d1c498bb45aac84 (patch) | |
tree | 675e5fc3e25592664adc9ab0f77b4ea6a03cce30 /resources/page/permalinks.go | |
parent | 4d22ad580ec8c8e5e27cf4f5cce69b6828aa8501 (diff) |
Add slice syntax to sections permalinks config
Fixes #8363
Diffstat (limited to 'resources/page/permalinks.go')
-rw-r--r-- | resources/page/permalinks.go | 98 |
1 files changed, 97 insertions, 1 deletions
diff --git a/resources/page/permalinks.go b/resources/page/permalinks.go index 19ac52172..aaffcdc21 100644 --- a/resources/page/permalinks.go +++ b/resources/page/permalinks.go @@ -16,6 +16,7 @@ package page import ( "fmt" "os" + "path" "path/filepath" "regexp" "strconv" @@ -54,6 +55,13 @@ func (p PermalinkExpander) callback(attr string) (pageToPermaAttribute, bool) { return p.pageToPermalinkDate, true } + if strings.HasPrefix(attr, "sections[") { + fn := p.toSliceFunc(strings.TrimPrefix(attr, "sections")) + return func(p Page, s string) (string, error) { + return path.Join(fn(p.CurrentSection().SectionsEntries())...), nil + }, true + } + return nil, false } @@ -112,6 +120,7 @@ func (l PermalinkExpander) parse(patterns map[string]string) (map[string]func(Pa for k, pattern := range patterns { k = strings.Trim(k, sectionCutSet) + if !l.validate(pattern) { return nil, &permalinkExpandError{pattern: pattern, err: errPermalinkIllFormed} } @@ -165,7 +174,7 @@ func (l PermalinkExpander) parse(patterns map[string]string) (map[string]func(Pa // can return a string to go in that position in the page (or an error) type pageToPermaAttribute func(Page, string) (string, error) -var attributeRegexp = regexp.MustCompile(`:\w+`) +var attributeRegexp = regexp.MustCompile(`:\w+(\[.+\])?`) // validate determines if a PathPattern is well-formed func (l PermalinkExpander) validate(pp string) bool { @@ -263,3 +272,90 @@ func (l PermalinkExpander) pageToPermalinkSection(p Page, _ string) (string, err func (l PermalinkExpander) pageToPermalinkSections(p Page, _ string) (string, error) { return p.CurrentSection().SectionsPath(), nil } + +var ( + nilSliceFunc = func(s []string) []string { + return nil + } + allSliceFunc = func(s []string) []string { + return s + } +) + +// toSliceFunc returns a slice func that slices s according to the cut spec. +// The cut spec must be on form [low:high] (one or both can be omitted), +// also allowing single slice indices (e.g. [2]) and the special [last] keyword +// giving the last element of the slice. +// The returned function will be lenient and not panic in out of bounds situation. +// +// The current use case for this is to use parts of the sections path in permalinks. +func (l PermalinkExpander) toSliceFunc(cut string) func(s []string) []string { + cut = strings.ToLower(strings.TrimSpace(cut)) + if cut == "" { + return allSliceFunc + } + + if len(cut) < 3 || (cut[0] != '[' || cut[len(cut)-1] != ']') { + return nilSliceFunc + } + + toNFunc := func(s string, low bool) func(ss []string) int { + if s == "" { + if low { + return func(ss []string) int { + return 0 + } + } else { + return func(ss []string) int { + return len(ss) + } + } + } + + if s == "last" { + return func(ss []string) int { + return len(ss) - 1 + } + } + + n, _ := strconv.Atoi(s) + if n < 0 { + n = 0 + } + return func(ss []string) int { + // Prevent out of bound situations. It would not make + // much sense to panic here. + if n > len(ss) { + return len(ss) + } + return n + } + } + + opsStr := cut[1 : len(cut)-1] + opts := strings.Split(opsStr, ":") + + if !strings.Contains(opsStr, ":") { + toN := toNFunc(opts[0], true) + return func(s []string) []string { + if len(s) == 0 { + return nil + } + v := s[toN(s)] + if v == "" { + return nil + } + return []string{v} + } + } + + toN1, toN2 := toNFunc(opts[0], true), toNFunc(opts[1], false) + + return func(s []string) []string { + if len(s) == 0 { + return nil + } + return s[toN1(s):toN2(s)] + } + +} |