package main import ( "bufio" "bytes" "io" "regexp" "strings" ) var ( boldItalicReg = regexp.MustCompile(`\*\*\*(.*?)\*\*\*`) boldReg = regexp.MustCompile(`\*\*(.*?)\*\*`) italicReg = regexp.MustCompile(`\*(.*?)\*`) strikeReg = regexp.MustCompile(`\~\~(.*?)\~\~`) underscoreReg = regexp.MustCompile(`__(.*?)__`) anchorReg = regexp.MustCompile(`\[(.*?)\]\((.*?)\)[^\)]`) imgReg = regexp.MustCompile(`\!\[(.*?)\]\((.*?)\)[^\)]`) escapeReg = regexp.MustCompile(`^\>(\s|)`) blockquoteReg = regexp.MustCompile(`\>\;(.*?)$`) backtipReg = regexp.MustCompile("`(.*?)`") h1Reg = regexp.MustCompile(`^#(\s|)(.*?)$`) h2Reg = regexp.MustCompile(`^##(\s|)(.*?)$`) h3Reg = regexp.MustCompile(`^###(\s|)(.*?)$`) h4Reg = regexp.MustCompile(`^####(\s|)(.*?)$`) h5Reg = regexp.MustCompile(`^#####(\s|)(.*?)$`) h6Reg = regexp.MustCompile(`^######(\s|)(.*?)$`) ) func NewMarkdown(input io.Reader) string { buf := bytes.NewBuffer(nil) inParagraph := false scanner := bufio.NewScanner(input) for scanner.Scan() { line := bytes.TrimSpace(scanner.Bytes()) if len(line) == 0 { buf.WriteByte('\n') if inParagraph { buf.WriteString("

") } continue } // wrap bold and italic text in "" and "" elements line = boldItalicReg.ReplaceAll(line, []byte(`$1`)) line = boldReg.ReplaceAll(line, []byte(`$1`)) line = italicReg.ReplaceAll(line, []byte(`$1`)) // wrap strikethrough text in "" tags line = strikeReg.ReplaceAll(line, []byte(`$1`)) // wrap underscored text in "" tags line = underscoreReg.ReplaceAll(line, []byte(`$1`)) // convert images to image tags line = imgReg.ReplaceAll(line, []byte(`$1`)) // convert links to anchor tags line = anchorReg.ReplaceAll(line, []byte(`$1 `)) // escape and wrap blockquotes in "
" tags line = escapeReg.ReplaceAll(line, []byte(`>`)) line = blockquoteReg.ReplaceAll(line, []byte(`
$1
`)) // wrap the content of backticks inside of "" tags line = backtipReg.ReplaceAll(line, []byte(`$1`)) // convert headings if line[0] == '#' { count := bytes.Count(line, []byte(`#`)) switch count { case 1: line = h1Reg.ReplaceAll(line, []byte(`

$2

`)) case 2: line = h2Reg.ReplaceAll(line, []byte(`

$2

`)) case 3: line = h3Reg.ReplaceAll(line, []byte(`

$2

`)) case 4: line = h4Reg.ReplaceAll(line, []byte(`

$2

`)) case 5: line = h5Reg.ReplaceAll(line, []byte(`
$2
`)) case 6: line = h6Reg.ReplaceAll(line, []byte(`
$2
`)) } } else { if !inParagraph { buf.WriteString("

") } buf.WriteByte(' ') inParagraph = true } buf.Write(line) buf.WriteByte('\n') } return buf.String() } func ParseMarkdown(md string) string { return NewMarkdown(strings.NewReader(md)) }