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}