github.com/olli-ai/jx/v2@v2.0.400-0.20210921045218-14731b4dd448/pkg/cmd/templates/markdown.go (about)

     1  /*
     2  Copyright 2016 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package templates
    18  
    19  import (
    20  	"bytes"
    21  	"fmt"
    22  	"io"
    23  	"strings"
    24  
    25  	"github.com/russross/blackfriday"
    26  )
    27  
    28  const linebreak = "\n"
    29  
    30  // ASCIIRenderer implements blackfriday.Renderer
    31  var _ blackfriday.Renderer = &ASCIIRenderer{}
    32  
    33  // ASCIIRenderer is a blackfriday.Renderer intended for rendering markdown
    34  // documents as plain text, well suited for human reading on terminals.
    35  type ASCIIRenderer struct {
    36  	Indentation string
    37  
    38  	listItemCount uint
    39  	listLevel     uint
    40  }
    41  
    42  // NormalText gets a text chunk *after* the markdown syntax was already
    43  // processed and does a final cleanup on things we don't expect here, like
    44  // removing linebreaks on things that are not a paragraph break (auto unwrap).
    45  func (r *ASCIIRenderer) NormalText(out *bytes.Buffer, text []byte) {
    46  	raw := string(text)
    47  	lines := strings.Split(raw, linebreak)
    48  	for _, line := range lines {
    49  		trimmed := strings.Trim(line, " \n\t")
    50  		out.WriteString(trimmed)
    51  		out.WriteString(" ")
    52  	}
    53  }
    54  
    55  // List renders the start and end of a list.
    56  func (r *ASCIIRenderer) List(out *bytes.Buffer, text func() bool, flags int) {
    57  	r.listLevel++
    58  	out.WriteString(linebreak)
    59  	text()
    60  	r.listLevel--
    61  }
    62  
    63  // ListItem renders list items and supports both ordered and unordered lists.
    64  func (r *ASCIIRenderer) ListItem(out *bytes.Buffer, text []byte, flags int) {
    65  	if flags&blackfriday.LIST_ITEM_BEGINNING_OF_LIST != 0 {
    66  		r.listItemCount = 1
    67  	} else {
    68  		r.listItemCount++
    69  	}
    70  	indent := strings.Repeat(r.Indentation, int(r.listLevel))
    71  	var bullet string
    72  	if flags&blackfriday.LIST_TYPE_ORDERED != 0 {
    73  		bullet += fmt.Sprintf("%d.", r.listItemCount)
    74  	} else {
    75  		bullet += "*"
    76  	}
    77  	out.WriteString(indent + bullet + " ")
    78  	r.fw(out, text)
    79  	out.WriteString(linebreak)
    80  }
    81  
    82  // Paragraph renders the start and end of a paragraph.
    83  func (r *ASCIIRenderer) Paragraph(out *bytes.Buffer, text func() bool) {
    84  	out.WriteString(linebreak)
    85  	text()
    86  	out.WriteString(linebreak)
    87  }
    88  
    89  // BlockCode renders a chunk of text that represents source code.
    90  func (r *ASCIIRenderer) BlockCode(out *bytes.Buffer, text []byte, lang string) {
    91  	out.WriteString(linebreak)
    92  	lines := []string{}
    93  	for _, line := range strings.Split(string(text), linebreak) {
    94  		indented := r.Indentation + line
    95  		lines = append(lines, indented)
    96  	}
    97  	out.WriteString(strings.Join(lines, linebreak))
    98  }
    99  
   100  func (r *ASCIIRenderer) GetFlags() int {
   101  	return 0
   102  }
   103  
   104  func (r *ASCIIRenderer) HRule(out *bytes.Buffer) {
   105  	out.WriteString(linebreak + "----------" + linebreak)
   106  }
   107  
   108  func (r *ASCIIRenderer) LineBreak(out *bytes.Buffer) {
   109  	out.WriteString(linebreak)
   110  }
   111  
   112  func (r *ASCIIRenderer) TitleBlock(out *bytes.Buffer, text []byte) {
   113  	r.fw(out, text)
   114  }
   115  
   116  func (r *ASCIIRenderer) Header(out *bytes.Buffer, text func() bool, level int, id string) {
   117  	text()
   118  }
   119  
   120  func (r *ASCIIRenderer) BlockHtml(out *bytes.Buffer, text []byte) {
   121  	r.fw(out, text)
   122  }
   123  
   124  func (r *ASCIIRenderer) BlockQuote(out *bytes.Buffer, text []byte) {
   125  	r.fw(out, text)
   126  }
   127  
   128  func (r *ASCIIRenderer) TableRow(out *bytes.Buffer, text []byte) {
   129  	r.fw(out, text)
   130  }
   131  
   132  func (r *ASCIIRenderer) TableHeaderCell(out *bytes.Buffer, text []byte, align int) {
   133  	r.fw(out, text)
   134  }
   135  
   136  func (r *ASCIIRenderer) TableCell(out *bytes.Buffer, text []byte, align int) {
   137  	r.fw(out, text)
   138  }
   139  
   140  func (r *ASCIIRenderer) Footnotes(out *bytes.Buffer, text func() bool) {
   141  	text()
   142  }
   143  
   144  func (r *ASCIIRenderer) FootnoteItem(out *bytes.Buffer, name, text []byte, flags int) {
   145  	r.fw(out, text)
   146  }
   147  
   148  func (r *ASCIIRenderer) AutoLink(out *bytes.Buffer, link []byte, kind int) {
   149  	r.fw(out, link)
   150  }
   151  
   152  func (r *ASCIIRenderer) CodeSpan(out *bytes.Buffer, text []byte) { r.fw(out, text) }
   153  
   154  func (r *ASCIIRenderer) DoubleEmphasis(out *bytes.Buffer, text []byte) { r.fw(out, text) }
   155  
   156  func (r *ASCIIRenderer) Emphasis(out *bytes.Buffer, text []byte) { r.fw(out, text) }
   157  
   158  func (r *ASCIIRenderer) RawHtmlTag(out *bytes.Buffer, text []byte) { r.fw(out, text) }
   159  
   160  func (r *ASCIIRenderer) TripleEmphasis(out *bytes.Buffer, text []byte) { r.fw(out, text) }
   161  
   162  func (r *ASCIIRenderer) StrikeThrough(out *bytes.Buffer, text []byte) { r.fw(out, text) }
   163  
   164  func (r *ASCIIRenderer) FootnoteRef(out *bytes.Buffer, ref []byte, id int) { r.fw(out, ref) }
   165  
   166  func (r *ASCIIRenderer) Entity(out *bytes.Buffer, entity []byte) { r.fw(out, entity) }
   167  
   168  func (r *ASCIIRenderer) Smartypants(out *bytes.Buffer, text []byte) { r.fw(out, text) }
   169  
   170  func (r *ASCIIRenderer) DocumentHeader(out *bytes.Buffer) {}
   171  
   172  func (r *ASCIIRenderer) DocumentFooter(out *bytes.Buffer) {}
   173  
   174  func (r *ASCIIRenderer) TocHeaderWithAnchor(text []byte, level int, anchor string) {}
   175  
   176  func (r *ASCIIRenderer) TocHeader(text []byte, level int) {}
   177  
   178  func (r *ASCIIRenderer) TocFinalize() {
   179  
   180  }
   181  
   182  func (r *ASCIIRenderer) Table(out *bytes.Buffer, header []byte, body []byte, columnData []int) {
   183  	r.fw(out, header, body)
   184  }
   185  
   186  func (r *ASCIIRenderer) Link(out *bytes.Buffer, link []byte, title []byte, content []byte) {
   187  	r.fw(out, link)
   188  }
   189  
   190  func (r *ASCIIRenderer) Image(out *bytes.Buffer, link []byte, title []byte, alt []byte) {
   191  	r.fw(out, link)
   192  }
   193  
   194  func (r *ASCIIRenderer) fw(out io.Writer, text ...[]byte) {
   195  	for _, t := range text {
   196  		out.Write(t) //nolint:errcheck
   197  	}
   198  }