1// Package escape escapes characters that are commonly used in
2// markdown like the * for strong/italic.
3package escape
4
5import (
6 "regexp"
7 "strings"
8)
9
10var backslash = regexp.MustCompile(`\\(\S)`)
11var heading = regexp.MustCompile(`(?m)^(#{1,6} )`)
12var orderedList = regexp.MustCompile(`(?m)^(\W* {0,3})(\d+)\. `)
13var unorderedList = regexp.MustCompile(`(?m)^([^\\\w]*)[*+-] `)
14var horizontalDivider = regexp.MustCompile(`(?m)^([-*_] *){3,}$`)
15var blockquote = regexp.MustCompile(`(?m)^(\W* {0,3})> `)
16var link = regexp.MustCompile(`([\[\]])`)
17
18var replacer = strings.NewReplacer(
19 `*`, `\*`,
20 `_`, `\_`,
21 "`", "\\`",
22 `|`, `\|`,
23)
24
25// MarkdownCharacters escapes common markdown characters so that
26// `<p>**Not Bold**</p> ends up as correct markdown `\*\*Not Strong\*\*`.
27// No worry, the escaped characters will display fine, just without the formatting.
28func MarkdownCharacters(text string) string {
29 // Escape backslash escapes!
30 text = backslash.ReplaceAllString(text, `\\$1`)
31
32 // Escape headings
33 text = heading.ReplaceAllString(text, `\$1`)
34
35 // Escape hr
36 text = horizontalDivider.ReplaceAllStringFunc(text, func(t string) string {
37 if strings.Contains(t, "-") {
38 return strings.Replace(t, "-", `\-`, 3)
39 } else if strings.Contains(t, "_") {
40 return strings.Replace(t, "_", `\_`, 3)
41 }
42 return strings.Replace(t, "*", `\*`, 3)
43 })
44
45 // Escape ol bullet points
46 text = orderedList.ReplaceAllString(text, `$1$2\. `)
47
48 // Escape ul bullet points
49 text = unorderedList.ReplaceAllStringFunc(text, func(t string) string {
50 return regexp.MustCompile(`([*+-])`).ReplaceAllString(t, `\$1`)
51 })
52
53 // Escape blockquote indents
54 text = blockquote.ReplaceAllString(text, `$1\> `)
55
56 // Escape em/strong *
57 // Escape em/strong _
58 // Escape code _
59 text = replacer.Replace(text)
60
61 // Escape link & image brackets
62 text = link.ReplaceAllString(text, `\$1`)
63
64 return text
65}