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 }