diff --git a/markitzero.go b/markitzero.go index 2af6e02..464de15 100644 --- a/markitzero.go +++ b/markitzero.go @@ -16,11 +16,11 @@ package main import ( - "bytes" "fmt" "regexp" "strings" + "golang.org/x/net/html" "humungus.tedunangst.com/r/webs/synlight" ) @@ -37,8 +37,27 @@ var re_lister = regexp.MustCompile(`((^|\n)(\+|-).*)+\n?`) var lighter = synlight.New(synlight.Options{Format: synlight.HTML}) -// fewer side effects than html.EscapeString -func fasterescaper(s []byte) []byte { +func markitzero(s string) string { + // prepare the string + s = strings.TrimSpace(s) + s = strings.Replace(s, "\r", "", -1) + + // save away the code blocks so we don't mess them up further + var bigcodes, lilcodes, images []string + s = re_bigcoder.ReplaceAllStringFunc(s, func(code string) string { + bigcodes = append(bigcodes, code) + return "``````" + }) + s = re_coder.ReplaceAllStringFunc(s, func(code string) string { + lilcodes = append(lilcodes, code) + return "`x`" + }) + s = re_imgfix.ReplaceAllStringFunc(s, func(img string) string { + images = append(images, img) + return "" + }) + + // fewer side effects than html.EscapeString buf := make([]byte, 0, len(s)) for _, c := range []byte(s) { switch c { @@ -52,130 +71,64 @@ func fasterescaper(s []byte) []byte { buf = append(buf, c) } } - return buf -} - -func replaceifmatch(re *regexp.Regexp, input []byte, repl []byte) []byte { - if !re.Match(input) { - return input - } - return re.ReplaceAll(input, repl) -} - -func replaceifmatchfn(re *regexp.Regexp, input []byte, repl func([]byte) []byte) []byte { - if !re.Match(input) { - return input - } - return re.ReplaceAllFunc(input, repl) -} - -func replacenocopy(input []byte, pat []byte, repl []byte) []byte { - if !bytes.Contains(input, pat) { - return input - } - return bytes.Replace(input, pat, repl, -1) -} - -func markitzero(ss string) string { - s := []byte(ss) - // prepare the string - s = bytes.TrimSpace(s) - s = replacenocopy(s, []byte("\r"), []byte("")) - - hascode := bytes.Contains(s, []byte("`")) - - // save away the code blocks so we don't mess them up further - var bigcodes, lilcodes, images [][]byte - if hascode { - s = replaceifmatchfn(re_bigcoder, s, func(code []byte) []byte { - bigcodes = append(bigcodes, code) - return []byte("``````") - }) - s = replaceifmatchfn(re_coder, s, func(code []byte) []byte { - lilcodes = append(lilcodes, code) - return []byte("`x`") - }) - } - s = replaceifmatchfn(re_imgfix, s, func(img []byte) []byte { - images = append(images, img) - return []byte("") - }) - - s = fasterescaper(s) + s = string(buf) // mark it zero - if bytes.Contains(s, []byte("http")) { - s = replaceifmatchfn(re_link, s, linkreplacer) - } - s = replaceifmatch(re_zerolink, s, []byte(`$1`)) - if bytes.Contains(s, []byte("**")) { - s = replaceifmatch(re_bolder, s, []byte("$1$2$3")) - } - if bytes.Contains(s, []byte("*")) { - s = replaceifmatch(re_italicer, s, []byte("$1$2$3")) - } - if bytes.Contains(s, []byte("> ")) { - s = replaceifmatch(re_quoter, s, []byte("
$1
$3
")) - s = replaceifmatch(re_reciter, s, []byte("$1$2$3")) - } - s = replacenocopy(s, []byte("\n---\n"), []byte("
")) + s = re_link.ReplaceAllStringFunc(s, linkreplacer) + s = re_zerolink.ReplaceAllString(s, `$1`) + s = re_bolder.ReplaceAllString(s, "$1$2$3") + s = re_italicer.ReplaceAllString(s, "$1$2$3") + s = re_quoter.ReplaceAllString(s, "
$1
$3
") + s = re_reciter.ReplaceAllString(s, "$1$2$3") + s = strings.Replace(s, "\n---\n", "
", -1) - if bytes.Contains(s, []byte("\n+")) || bytes.Contains(s, []byte("\n-")) { - s = replaceifmatchfn(re_lister, s, func(m []byte) []byte { - m = bytes.Trim(m, "\n") - items := bytes.Split(m, []byte("\n")) - r := []byte("
")...) - return r - }) - } + s = re_lister.ReplaceAllStringFunc(s, func(m string) string { + m = strings.Trim(m, "\n") + items := strings.Split(m, "\n") + r := "
" + return r + }) // restore images - s = replacenocopy(s, []byte("<img x>"), []byte("")) - s = replaceifmatchfn(re_imgfix, s, func([]byte) []byte { + s = strings.Replace(s, "<img x>", "", -1) + s = re_imgfix.ReplaceAllStringFunc(s, func(string) string { img := images[0] images = images[1:] return img }) // now restore the code blocks - if hascode { - s = replaceifmatchfn(re_coder, s, func([]byte) []byte { - code := lilcodes[0] - lilcodes = lilcodes[1:] - return fasterescaper(code) - }) - s = replaceifmatchfn(re_bigcoder, s, func([]byte) []byte { - code := bigcodes[0] - bigcodes = bigcodes[1:] - m := re_bigcoder.FindSubmatch(code) - var buf bytes.Buffer - buf.WriteString("
")
- lighter.Highlight(m[2], string(m[1]), &buf)
- buf.WriteString("
")
- return buf.Bytes()
- })
- s = replaceifmatch(re_coder, s, []byte("$1
"))
- }
+ s = re_coder.ReplaceAllStringFunc(s, func(string) string {
+ code := lilcodes[0]
+ lilcodes = lilcodes[1:]
+ code = html.EscapeString(code)
+ return code
+ })
+ s = re_bigcoder.ReplaceAllStringFunc(s, func(string) string {
+ code := bigcodes[0]
+ bigcodes = bigcodes[1:]
+ m := re_bigcoder.FindStringSubmatch(code)
+ return "
" + lighter.HighlightString(m[2], m[1]) + "
"
+ })
+ s = re_coder.ReplaceAllString(s, "$1
")
// some final fixups
- s = replacenocopy(s, []byte("\n"), []byte("
"))
- s = replacenocopy(s, []byte("
"), []byte("")) - s = replacenocopy(s, []byte("
"), []byte("")) - s = replacenocopy(s, []byte(""), []byte("")) - s = replacenocopy(s, []byte(""), []byte("
")) - s = replacenocopy(s, []byte("
"), []byte("")) - return string(s) + s = strings.Replace(s, "\n", "
", -1) + s = strings.Replace(s, "", "", -1) + s = strings.Replace(s, "
", "", -1) + s = strings.Replace(s, "", "", -1) + s = strings.Replace(s, "", "
", -1) + s = strings.Replace(s, "
", "", -1) + return s } -func linkreplacer(burl []byte) []byte { - url := string(burl) +func linkreplacer(url string) string { if url[0:2] == "](" { - return burl + return url } prefix := "" for !strings.HasPrefix(url, "http") { @@ -199,5 +152,5 @@ func linkreplacer(burl []byte) []byte { if addparen { url += ")" } - return []byte(prefix + url) + return prefix + url }