transform.go (3992B)
1 // Copyright 2017 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 transform provides template functions for transforming content. 15 package transform 16 17 import ( 18 "html" 19 "html/template" 20 21 "github.com/alecthomas/chroma/v2/lexers" 22 "github.com/gohugoio/hugo/cache/namedmemcache" 23 "github.com/gohugoio/hugo/markup/converter/hooks" 24 "github.com/gohugoio/hugo/markup/highlight" 25 "github.com/gohugoio/hugo/tpl" 26 27 "github.com/gohugoio/hugo/deps" 28 "github.com/gohugoio/hugo/helpers" 29 "github.com/spf13/cast" 30 ) 31 32 // New returns a new instance of the transform-namespaced template functions. 33 func New(deps *deps.Deps) *Namespace { 34 cache := namedmemcache.New() 35 deps.BuildStartListeners.Add( 36 func() { 37 cache.Clear() 38 }) 39 40 return &Namespace{ 41 cache: cache, 42 deps: deps, 43 } 44 } 45 46 // Namespace provides template functions for the "transform" namespace. 47 type Namespace struct { 48 cache *namedmemcache.Cache 49 deps *deps.Deps 50 } 51 52 // Emojify returns a copy of s with all emoji codes replaced with actual emojis. 53 // 54 // See http://www.emoji-cheat-sheet.com/ 55 func (ns *Namespace) Emojify(s any) (template.HTML, error) { 56 ss, err := cast.ToStringE(s) 57 if err != nil { 58 return "", err 59 } 60 61 return template.HTML(helpers.Emojify([]byte(ss))), nil 62 } 63 64 // Highlight returns a copy of s as an HTML string with syntax 65 // highlighting applied. 66 func (ns *Namespace) Highlight(s any, lang string, opts ...any) (template.HTML, error) { 67 ss, err := cast.ToStringE(s) 68 if err != nil { 69 return "", err 70 } 71 72 var optsv any 73 if len(opts) > 0 { 74 optsv = opts[0] 75 } 76 77 hl := ns.deps.ContentSpec.Converters.GetHighlighter() 78 highlighted, _ := hl.Highlight(ss, lang, optsv) 79 return template.HTML(highlighted), nil 80 } 81 82 // HighlightCodeBlock highlights a code block on the form received in the codeblock render hooks. 83 func (ns *Namespace) HighlightCodeBlock(ctx hooks.CodeblockContext, opts ...any) (highlight.HightlightResult, error) { 84 var optsv any 85 if len(opts) > 0 { 86 optsv = opts[0] 87 } 88 89 hl := ns.deps.ContentSpec.Converters.GetHighlighter() 90 91 return hl.HighlightCodeBlock(ctx, optsv) 92 } 93 94 // CanHighlight returns whether the given code language is supported by the Chroma highlighter. 95 func (ns *Namespace) CanHighlight(language string) bool { 96 return lexers.Get(language) != nil 97 } 98 99 // HTMLEscape returns a copy of s with reserved HTML characters escaped. 100 func (ns *Namespace) HTMLEscape(s any) (string, error) { 101 ss, err := cast.ToStringE(s) 102 if err != nil { 103 return "", err 104 } 105 106 return html.EscapeString(ss), nil 107 } 108 109 // HTMLUnescape returns a copy of s with HTML escape requences converted to plain 110 // text. 111 func (ns *Namespace) HTMLUnescape(s any) (string, error) { 112 ss, err := cast.ToStringE(s) 113 if err != nil { 114 return "", err 115 } 116 117 return html.UnescapeString(ss), nil 118 } 119 120 // Markdownify renders s from Markdown to HTML. 121 func (ns *Namespace) Markdownify(s any) (template.HTML, error) { 122 123 home := ns.deps.Site.Home() 124 if home == nil { 125 panic("home must not be nil") 126 } 127 ss, err := home.RenderString(s) 128 if err != nil { 129 return "", err 130 } 131 132 // Strip if this is a short inline type of text. 133 bb := ns.deps.ContentSpec.TrimShortHTML([]byte(ss)) 134 135 return helpers.BytesToHTML(bb), nil 136 } 137 138 // Plainify returns a copy of s with all HTML tags removed. 139 func (ns *Namespace) Plainify(s any) (string, error) { 140 ss, err := cast.ToStringE(s) 141 if err != nil { 142 return "", err 143 } 144 145 return tpl.StripHTML(ss), nil 146 } 147 148 // For internal use. 149 func (ns *Namespace) Reset() { 150 ns.cache.Clear() 151 }