package markdown import ( "html" "strings" ) // MarkdownToHTML converts a basic subset of markdown to HTML, for // use in the news posts, forums, or user blurbs. func MarkdownToHTML(s string) string { // Escape HTML entities first to sanitize user input s = html.EscapeString(s) // Handle headers first (line-based) lines := strings.Split(s, "\n") for i, line := range lines { line = strings.TrimSpace(line) if strings.HasPrefix(line, "### ") { lines[i] = "

" + line[4:] + "

" } else if strings.HasPrefix(line, "## ") { lines[i] = "

" + line[3:] + "

" } else if strings.HasPrefix(line, "# ") { lines[i] = "

" + line[2:] + "

" } } s = strings.Join(lines, "\n") // Handle code spans before other formatting s = replaceCodeSpans(s) // Handle links [text](url) s = replaceLinks(s) // Handle bold and italic s = replaceBoldItalic(s) // Handle line breaks last s = strings.ReplaceAll(s, "\n", "
") return `
` + s + "
" } func replaceCodeSpans(s string) string { for { start := strings.Index(s, "`") if start == -1 { break } end := strings.Index(s[start+1:], "`") if end == -1 { break } end += start + 1 code := s[start+1 : end] s = s[:start] + "" + code + "" + s[end+1:] } return s } func replaceLinks(s string) string { for { linkStart := strings.Index(s, "[") if linkStart == -1 { break } linkEnd := strings.Index(s[linkStart:], "](") if linkEnd == -1 { break } linkEnd += linkStart urlStart := linkEnd + 2 urlEnd := strings.Index(s[urlStart:], ")") if urlEnd == -1 { break } urlEnd += urlStart text := s[linkStart+1 : linkEnd] url := s[urlStart:urlEnd] s = s[:linkStart] + `` + text + "" + s[urlEnd+1:] } return s } func replaceBoldItalic(s string) string { // Handle bold first for strings.Contains(s, "**") { first := strings.Index(s, "**") if first == -1 { break } second := strings.Index(s[first+2:], "**") if second == -1 { break } second += first + 2 text := s[first+2 : second] s = s[:first] + "" + text + "" + s[second+2:] } // Handle italic for strings.Contains(s, "*") { first := strings.Index(s, "*") if first == -1 { break } second := strings.Index(s[first+1:], "*") if second == -1 { break } second += first + 1 text := s[first+1 : second] s = s[:first] + "" + text + "" + s[second+1:] } return s }