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 }