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 }