-
Notifications
You must be signed in to change notification settings - Fork 0
/
bf.go
98 lines (78 loc) · 2.62 KB
/
bf.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
/*
Copyright © 2020 M.Watermann, 10247 Berlin, Germany
All rights reserved
EMail : <support@mwat.de>
*/
package nele
//lint:file-ignore ST1017 - I prefer Yoda conditions
/*
* This file provides a function to convert NarkDown to HTML.
*/
import (
"bytes"
"regexp"
"sync"
bf "github.com/russross/blackfriday/v2"
// bf "gopkg.in/russross/blackfriday.v2"
)
var (
// Instead of creating this objects with every call to `MDtoHTML()`
// we use some prepared global instances.
bfExtensions = bf.WithExtensions(
bf.Autolink |
bf.BackslashLineBreak |
bf.DefinitionLists |
bf.FencedCode |
bf.Footnotes |
bf.HeadingIDs |
bf.NoIntraEmphasis |
bf.SpaceHeadings |
bf.Strikethrough |
bf.Tables)
// WithRenderer allows overriding the default `blackfriday` renderer.
bfRenderer = bf.WithRenderer(
bf.NewHTMLRenderer(bf.HTMLRendererParameters{
Flags: bf.FootnoteReturnLinks |
bf.Smartypants |
bf.SmartypantsFractions |
bf.SmartypantsDashes |
bf.SmartypantsLatexDashes,
}),
)
// Guard against race conditions in `MDtoHTML()` when calling
// `blackfriday.Run()` concurrently.
bfMtx = new(sync.Mutex)
// Text to recognise a PREformatted section.
bfPre = []byte("</pre>")
// Text to recognise a PREformatted section with redundant CODE block.
bfPreCode = []byte("<pre><code ")
// RegEx to correct redundant markup created by 'bf';
// see `mdToHTML()`
bfPreCodeRE1 = regexp.MustCompile(`(?s)\s*(<pre>)<code>(.*?)\s*</code>(</pre>)\s*`)
bfPreCodeRE2 = regexp.MustCompile(`(?s)\s*(<pre)><code (class="language-\w+")>(.*?)\s*</code>(</pre>)\s*`)
// RegEx to correct back markup since Blackfriday v2.1.0';
// see `mdToHTML()`
bfSupRE = regexp.MustCompile(`<span aria-label='Return'>.*</span>`)
)
// MDtoHTML converts the `aMarkdown` data and returns HTML data.
//
// `aMarkdown` The raw Markdown text to convert.
func MDtoHTML(aMarkdown []byte) (rHTML []byte) {
var i int // re-use variable
bfMtx.Lock()
defer bfMtx.Unlock()
rHTML = bytes.TrimSpace(bf.Run(aMarkdown, bfRenderer, bfExtensions))
rHTML = bfSupRE.ReplaceAll(rHTML, []byte("<sup>[return]</sup>"))
// Testing for PRE first makes this implementation twice as fast
// if there's no PRE in the generated HTML and about the same
// speed if there actually is a PRE part.
if i = bytes.Index(rHTML, bfPre); 0 > i {
return // no need for further RegEx execution
}
rHTML = bfPreCodeRE1.ReplaceAll(rHTML, []byte("$1\n$2\n$3"))
if i = bytes.Index(rHTML, bfPreCode); 0 > i {
return // no need for the second RegEx execution
}
return bfPreCodeRE2.ReplaceAll(rHTML, []byte("$1 $2>\n$3\n$4"))
} // MDtoHTML()
/* _EoF_ */