github.com/jbramsden/hugo@v0.47.1/helpers/content_renderer.go (about)

     1  // Copyright 2016 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 helpers
    15  
    16  import (
    17  	"bytes"
    18  	"strings"
    19  
    20  	"github.com/gohugoio/hugo/config"
    21  	"github.com/miekg/mmark"
    22  	"github.com/russross/blackfriday"
    23  )
    24  
    25  // HugoHTMLRenderer wraps a blackfriday.Renderer, typically a blackfriday.Html
    26  // Enabling Hugo to customise the rendering experience
    27  type HugoHTMLRenderer struct {
    28  	cs *ContentSpec
    29  	*RenderingContext
    30  	blackfriday.Renderer
    31  }
    32  
    33  // BlockCode renders a given text as a block of code.
    34  // Pygments is used if it is setup to handle code fences.
    35  func (r *HugoHTMLRenderer) BlockCode(out *bytes.Buffer, text []byte, lang string) {
    36  	if r.Cfg.GetBool("pygmentsCodeFences") && (lang != "" || r.Cfg.GetBool("pygmentsCodeFencesGuessSyntax")) {
    37  		opts := r.Cfg.GetString("pygmentsOptions")
    38  		str := strings.Trim(string(text), "\n\r")
    39  		highlighted, _ := r.cs.Highlight(str, lang, opts)
    40  		out.WriteString(highlighted)
    41  	} else {
    42  		r.Renderer.BlockCode(out, text, lang)
    43  	}
    44  }
    45  
    46  // ListItem adds task list support to the Blackfriday renderer.
    47  func (r *HugoHTMLRenderer) ListItem(out *bytes.Buffer, text []byte, flags int) {
    48  	if !r.Config.TaskLists {
    49  		r.Renderer.ListItem(out, text, flags)
    50  		return
    51  	}
    52  
    53  	switch {
    54  	case bytes.HasPrefix(text, []byte("[ ] ")):
    55  		text = append([]byte(`<label><input type="checkbox" disabled class="task-list-item">`), text[3:]...)
    56  		text = append(text, []byte(`</label>`)...)
    57  
    58  	case bytes.HasPrefix(text, []byte("[x] ")) || bytes.HasPrefix(text, []byte("[X] ")):
    59  		text = append([]byte(`<label><input type="checkbox" checked disabled class="task-list-item">`), text[3:]...)
    60  		text = append(text, []byte(`</label>`)...)
    61  	}
    62  
    63  	r.Renderer.ListItem(out, text, flags)
    64  }
    65  
    66  // List adds task list support to the Blackfriday renderer.
    67  func (r *HugoHTMLRenderer) List(out *bytes.Buffer, text func() bool, flags int) {
    68  	if !r.Config.TaskLists {
    69  		r.Renderer.List(out, text, flags)
    70  		return
    71  	}
    72  	marker := out.Len()
    73  	r.Renderer.List(out, text, flags)
    74  	if out.Len() > marker {
    75  		list := out.Bytes()[marker:]
    76  		if bytes.Contains(list, []byte("task-list-item")) {
    77  			// Find the index of the first >, it might be 3 or 4 depending on whether
    78  			// there is a new line at the start, but this is safer than just hardcoding it.
    79  			closingBracketIndex := bytes.Index(list, []byte(">"))
    80  			// Rewrite the buffer from the marker
    81  			out.Truncate(marker)
    82  			// Safely assuming closingBracketIndex won't be -1 since there is a list
    83  			// May be either dl, ul or ol
    84  			list := append(list[:closingBracketIndex], append([]byte(` class="task-list"`), list[closingBracketIndex:]...)...)
    85  			out.Write(list)
    86  		}
    87  	}
    88  }
    89  
    90  // HugoMmarkHTMLRenderer wraps a mmark.Renderer, typically a mmark.html,
    91  // enabling Hugo to customise the rendering experience.
    92  type HugoMmarkHTMLRenderer struct {
    93  	cs *ContentSpec
    94  	mmark.Renderer
    95  	Cfg config.Provider
    96  }
    97  
    98  // BlockCode renders a given text as a block of code.
    99  // Pygments is used if it is setup to handle code fences.
   100  func (r *HugoMmarkHTMLRenderer) BlockCode(out *bytes.Buffer, text []byte, lang string, caption []byte, subfigure bool, callouts bool) {
   101  	if r.Cfg.GetBool("pygmentsCodeFences") && (lang != "" || r.Cfg.GetBool("pygmentsCodeFencesGuessSyntax")) {
   102  		str := strings.Trim(string(text), "\n\r")
   103  		highlighted, _ := r.cs.Highlight(str, lang, "")
   104  		out.WriteString(highlighted)
   105  	} else {
   106  		r.Renderer.BlockCode(out, text, lang, caption, subfigure, callouts)
   107  	}
   108  }