all repos — honk @ b30d68e27b3513d6b90a358701286eb3bbc7b66a

my fork of honk

markitzero.go (view raw)

  1//
  2// Copyright (c) 2019 Ted Unangst <tedu@tedunangst.com>
  3//
  4// Permission to use, copy, modify, and distribute this software for any
  5// purpose with or without fee is hereby granted, provided that the above
  6// copyright notice and this permission notice appear in all copies.
  7//
  8// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  9// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 10// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 11// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 12// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 13// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 14// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 15
 16package main
 17
 18import (
 19	"fmt"
 20	"regexp"
 21	"strings"
 22
 23	"golang.org/x/net/html"
 24	"humungus.tedunangst.com/r/webs/synlight"
 25)
 26
 27var re_bolder = regexp.MustCompile(`(^|\W)\*\*([\w\s,.!?':_-]+)\*\*($|\W)`)
 28var re_italicer = regexp.MustCompile(`(^|\W)\*([\w\s,.!?':_-]+)\*($|\W)`)
 29var re_bigcoder = regexp.MustCompile("```(.*)\n?((?s:.*?))\n?```\n?")
 30var re_coder = regexp.MustCompile("`([^`]*)`")
 31var re_quoter = regexp.MustCompile(`(?m:^&gt; (.*)\n?)`)
 32var re_link = regexp.MustCompile(`.?.?https?://[^\s"]+[\w/)]`)
 33var re_zerolink = regexp.MustCompile(`\[([^]]*)\]\(([^)]*\)?)\)`)
 34
 35var lighter = synlight.New(synlight.Options{Format: synlight.HTML})
 36
 37func markitzero(s string) string {
 38	// prepare the string
 39	s = strings.TrimSpace(s)
 40	s = strings.Replace(s, "\r", "", -1)
 41
 42	// save away the code blocks so we don't mess them up further
 43	var bigcodes, lilcodes []string
 44	s = re_bigcoder.ReplaceAllStringFunc(s, func(code string) string {
 45		bigcodes = append(bigcodes, code)
 46		return "``````"
 47	})
 48	s = re_coder.ReplaceAllStringFunc(s, func(code string) string {
 49		lilcodes = append(lilcodes, code)
 50		return "`x`"
 51	})
 52
 53	s = html.EscapeString(s)
 54	s = strings.Replace(s, "&#39;", "'", -1) // dammit go
 55
 56	// mark it zero
 57	s = re_bolder.ReplaceAllString(s, "$1<b>$2</b>$3")
 58	s = re_italicer.ReplaceAllString(s, "$1<i>$2</i>$3")
 59	s = re_quoter.ReplaceAllString(s, "<blockquote>$1</blockquote><p>")
 60	s = re_link.ReplaceAllStringFunc(s, linkreplacer)
 61	s = re_zerolink.ReplaceAllString(s, `<a class="mention u-url" href="$2">$1</a>`)
 62
 63	// now restore the code blocks
 64	s = re_coder.ReplaceAllStringFunc(s, func(string) string {
 65		code := lilcodes[0]
 66		lilcodes = lilcodes[1:]
 67		code = html.EscapeString(code)
 68		return code
 69	})
 70	s = re_bigcoder.ReplaceAllStringFunc(s, func(string) string {
 71		code := bigcodes[0]
 72		bigcodes = bigcodes[1:]
 73		m := re_bigcoder.FindStringSubmatch(code)
 74		return "<pre><code>" + lighter.HighlightString(m[2], m[1]) + "</code></pre><p>"
 75	})
 76	s = re_coder.ReplaceAllString(s, "<code>$1</code>")
 77
 78	// some final fixups
 79	s = strings.Replace(s, "\n", "<br>", -1)
 80	s = strings.Replace(s, "<br><blockquote>", "<blockquote>", -1)
 81	s = strings.Replace(s, "<br><pre>", "<pre>", -1)
 82	s = strings.Replace(s, "<p><br>", "<p>", -1)
 83	return s
 84}
 85
 86func linkreplacer(url string) string {
 87	if url[0:2] == "](" {
 88		return url
 89	}
 90	prefix := ""
 91	for !strings.HasPrefix(url, "http") {
 92		prefix += url[0:1]
 93		url = url[1:]
 94	}
 95	addparen := false
 96	adddot := false
 97	if strings.HasSuffix(url, ")") && strings.IndexByte(url, '(') == -1 {
 98		url = url[:len(url)-1]
 99		addparen = true
100	}
101	if strings.HasSuffix(url, ".") {
102		url = url[:len(url)-1]
103		adddot = true
104	}
105	url = fmt.Sprintf(`<a class="mention u-url" href="%s">%s</a>`, url, url)
106	if adddot {
107		url += "."
108	}
109	if addparen {
110		url += ")"
111	}
112	return prefix + url
113}