github.com/linchen2chris/hugo@v0.0.0-20230307053224-cec209389705/tpl/transform/transform.go (about)

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