shortcodes.go (3469B)
1 // Copyright 2019 The Hugo Authors. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13
14 package tplimpl
15
16 import (
17 "strings"
18
19 "github.com/gohugoio/hugo/tpl"
20 )
21
22 // Currently lang, outFormat, suffix
23 const numTemplateVariants = 3
24
25 type shortcodeVariant struct {
26
27 // The possible variants: lang, outFormat, suffix
28 // gtag
29 // gtag.html
30 // gtag.no.html
31 // gtag.no.amp.html
32 // A slice of length numTemplateVariants.
33 variants []string
34
35 ts *templateState
36 }
37
38 type shortcodeTemplates struct {
39 variants []shortcodeVariant
40 }
41
42 func (s *shortcodeTemplates) indexOf(variants []string) int {
43 L:
44 for i, v1 := range s.variants {
45 for i, v2 := range v1.variants {
46 if v2 != variants[i] {
47 continue L
48 }
49 }
50 return i
51 }
52 return -1
53 }
54
55 func (s *shortcodeTemplates) fromVariants(variants tpl.TemplateVariants) (shortcodeVariant, bool) {
56 return s.fromVariantsSlice([]string{
57 variants.Language,
58 strings.ToLower(variants.OutputFormat.Name),
59 variants.OutputFormat.MediaType.FirstSuffix.Suffix,
60 })
61 }
62
63 func (s *shortcodeTemplates) fromVariantsSlice(variants []string) (shortcodeVariant, bool) {
64 var (
65 bestMatch shortcodeVariant
66 bestMatchWeight int
67 )
68
69 for _, variant := range s.variants {
70 w := s.compareVariants(variants, variant.variants)
71 if bestMatchWeight == 0 || w > bestMatchWeight {
72 bestMatch = variant
73 bestMatchWeight = w
74 }
75 }
76
77 return bestMatch, true
78 }
79
80 // calculate a weight for two string slices of same length.
81 // higher value means "better match".
82 func (s *shortcodeTemplates) compareVariants(a, b []string) int {
83 weight := 0
84 k := len(a)
85 for i, av := range a {
86 bv := b[i]
87 if av == bv {
88 // Add more weight to the left side (language...).
89 weight = weight + k - i
90 } else {
91 weight--
92 }
93 }
94 return weight
95 }
96
97 func templateVariants(name string) []string {
98 _, variants := templateNameAndVariants(name)
99 return variants
100 }
101
102 func templateNameAndVariants(name string) (string, []string) {
103 variants := make([]string, numTemplateVariants)
104
105 parts := strings.Split(name, ".")
106
107 if len(parts) <= 1 {
108 // No variants.
109 return name, variants
110 }
111
112 name = parts[0]
113 parts = parts[1:]
114 lp := len(parts)
115 start := len(variants) - lp
116
117 for i, j := start, 0; i < len(variants); i, j = i+1, j+1 {
118 variants[i] = parts[j]
119 }
120
121 if lp > 1 && lp < len(variants) {
122 for i := lp - 1; i > 0; i-- {
123 variants[i-1] = variants[i]
124 }
125 }
126
127 if lp == 1 {
128 // Suffix only. Duplicate it into the output format field to
129 // make HTML win over AMP.
130 variants[len(variants)-2] = variants[len(variants)-1]
131 }
132
133 return name, variants
134 }
135
136 func resolveTemplateType(name string) templateType {
137 if isShortcode(name) {
138 return templateShortcode
139 }
140
141 if strings.Contains(name, "partials/") {
142 return templatePartial
143 }
144
145 return templateUndefined
146 }
147
148 func isShortcode(name string) bool {
149 return strings.Contains(name, shortcodesPathPrefix)
150 }
151
152 func isInternal(name string) bool {
153 return strings.HasPrefix(name, internalPathPrefix)
154 }