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 }