all repos — honk @ c1ce92979487d16774650c7e3a6052fb79c63f41

my fork of honk

move markdown to another module
Ted Unangst tedu@tedunangst.com
Mon, 20 Jul 2020 22:34:11 -0400
commit

c1ce92979487d16774650c7e3a6052fb79c63f41

parent

7022da1a0a30c3f0f9b8d5590bfec0b19e1ba779

3 files changed, 5 insertions(+), 342 deletions(-)

jump to
M go.modgo.mod

@@ -11,3 +11,5 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859

humungus.tedunangst.com/r/go-sqlite3 v1.1.3 humungus.tedunangst.com/r/webs v0.6.41 ) + +replace humungus.tedunangst.com/r/webs => ../webs
M markitzero.gomarkitzero.go

@@ -16,200 +16,10 @@

package main import ( - "fmt" - "regexp" - "strings" - - "golang.org/x/net/html" - "humungus.tedunangst.com/r/webs/synlight" + mz "humungus.tedunangst.com/r/webs/markitzero" ) -var re_bolder = regexp.MustCompile(`(^|\W)\*\*((?s:.*?))\*\*($|\W)`) -var re_italicer = regexp.MustCompile(`(^|\W)\*((?s:.*?))\*($|\W)`) -var re_bigcoder = regexp.MustCompile("```(.*)\n?((?s:.*?))\n?```\n?") -var re_coder = regexp.MustCompile("`([^`]*)`") -var re_quoter = regexp.MustCompile(`(?m:^&gt; (.*)(\n- ?(.*))?\n?)`) -var re_reciter = regexp.MustCompile(`(<cite><a href=".*?">)https://twitter.com/([^/]+)/.*?(</a></cite>)`) -var re_link = regexp.MustCompile(`.?.?https?://[^\s"]+[\w/)!]`) -var re_zerolink = regexp.MustCompile(`\[([^]]*)\]\(([^)]*\)?)\)`) -var re_imgfix = regexp.MustCompile(`<img ([^>]*)>`) -var re_lister = regexp.MustCompile(`((^|\n)(\+|-).*)+\n?`) -var re_tabler = regexp.MustCompile(`((^|\n)\|.*)+\n?`) -var re_header = regexp.MustCompile(`(^|\n)(#+) (.*)\n?`) - -var lighter = synlight.New(synlight.Options{Format: synlight.HTML}) - -var allowInlineHtml = false - func markitzero(s string) string { - // prepare the string - s = strings.TrimSpace(s) - s = strings.Replace(s, "\r", "", -1) - - codeword := "`elided big code`" - - // 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 codeword - }) - 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 "<img x>" - }) - - // fewer side effects than html.EscapeString - buf := make([]byte, 0, len(s)) - for _, c := range []byte(s) { - switch c { - case '&': - buf = append(buf, []byte("&amp;")...) - case '<': - buf = append(buf, []byte("&lt;")...) - case '>': - buf = append(buf, []byte("&gt;")...) - default: - buf = append(buf, c) - } - } - s = string(buf) - - // mark it zero - if strings.Contains(s, "http") { - s = re_link.ReplaceAllStringFunc(s, linkreplacer) - } - s = re_zerolink.ReplaceAllString(s, `<a href="$2">$1</a>`) - if strings.Contains(s, "*") { - s = re_bolder.ReplaceAllString(s, "$1<b>$2</b>$3") - s = re_italicer.ReplaceAllString(s, "$1<i>$2</i>$3") - } - s = re_quoter.ReplaceAllString(s, "<blockquote>$1<br><cite>$3</cite></blockquote><p>") - s = re_reciter.ReplaceAllString(s, "$1$2$3") - s = strings.Replace(s, "\n---\n", "<hr><p>", -1) - - s = re_lister.ReplaceAllStringFunc(s, func(m string) string { - m = strings.Trim(m, "\n") - items := strings.Split(m, "\n") - r := "<ul>" - for _, item := range items { - r += "<li>" + strings.Trim(item[1:], " ") - } - r += "</ul><p>" - return r - }) - s = re_tabler.ReplaceAllStringFunc(s, func(m string) string { - m = strings.Trim(m, "\n") - rows := strings.Split(m, "\n") - var r strings.Builder - r.WriteString("<table>") - alignments := make(map[int]string) - for _, row := range rows { - hastr := false - cells := strings.Split(row, "|") - for i, cell := range cells { - cell = strings.TrimSpace(cell) - if cell == "" && (i == 0 || i == len(cells)-1) { - continue - } - switch cell { - case ":---": - alignments[i] = ` style="text-align: left"` - continue - case ":---:": - alignments[i] = ` style="text-align: center"` - continue - case "---:": - alignments[i] = ` style="text-align: right"` - continue - } - if !hastr { - r.WriteString("<tr>") - hastr = true - } - fmt.Fprintf(&r, "<td%s>", alignments[i]) - r.WriteString(cell) - } - } - r.WriteString("</table><p>") - return r.String() - }) - s = re_header.ReplaceAllStringFunc(s, func(s string) string { - s = strings.TrimSpace(s) - m := re_header.FindStringSubmatch(s) - num := len(m[2]) - return fmt.Sprintf("<h%d>%s</h%d><p>", num, m[3], num) - }) - - // restore images - s = strings.Replace(s, "&lt;img x&gt;", "<img x>", -1) - s = re_imgfix.ReplaceAllStringFunc(s, func(string) string { - img := images[0] - images = images[1:] - return img - }) - - s = strings.Replace(s, "\n\n", "<p>", -1) - s = strings.Replace(s, "\n", "<br>", -1) - - // now restore the code blocks - s = re_coder.ReplaceAllStringFunc(s, func(string) string { - code := lilcodes[0] - lilcodes = lilcodes[1:] - if code == codeword && len(bigcodes) > 0 { - code := bigcodes[0] - bigcodes = bigcodes[1:] - m := re_bigcoder.FindStringSubmatch(code) - if allowInlineHtml && m[1] == "inlinehtml" { - return m[2] - } - return "<pre><code>" + lighter.HighlightString(m[2], m[1]) + "</code></pre><p>" - } - code = html.EscapeString(code) - return code - }) - - s = re_coder.ReplaceAllString(s, "<code>$1</code>") - - // some final fixups - s = strings.Replace(s, "<br><blockquote>", "<blockquote>", -1) - s = strings.Replace(s, "<br><cite></cite>", "", -1) - s = strings.Replace(s, "<br><pre>", "<pre>", -1) - s = strings.Replace(s, "<br><ul>", "<ul>", -1) - s = strings.Replace(s, "<br><table>", "<table>", -1) - s = strings.Replace(s, "<p><br>", "<p>", -1) - return s -} - -func linkreplacer(url string) string { - if url[0:2] == "](" { - return url - } - prefix := "" - for !strings.HasPrefix(url, "http") { - prefix += url[0:1] - url = url[1:] - } - addparen := false - adddot := false - if strings.HasSuffix(url, ")") && strings.IndexByte(url, '(') == -1 { - url = url[:len(url)-1] - addparen = true - } - if strings.HasSuffix(url, ".") { - url = url[:len(url)-1] - adddot = true - } - url = fmt.Sprintf(`<a href="%s">%s</a>`, url, url) - if adddot { - url += "." - } - if addparen { - url += ")" - } - return prefix + url + var marker mz.Marker + return marker.Mark(s) }
D markitzero_test.go

@@ -1,149 +0,0 @@

-package main - -import ( - "strings" - "testing" -) - -func doonezerotest(t *testing.T, input, output string) { - result := markitzero(input) - if result != output { - t.Errorf("\nexpected:\n%s\noutput:\n%s", output, result) - } -} - -func TestBasictest(t *testing.T) { - input := `link to https://example.com/ with **bold** text` - output := `link to <a href="https://example.com/">https://example.com/</a> with <b>bold</b> text` - doonezerotest(t, input, output) -} - -func TestMultibold(t *testing.T) { - input := `**in** out **in**` - output := `<b>in</b> out <b>in</b>` - doonezerotest(t, input, output) -} - -func TestLinebreak1(t *testing.T) { - input := "hello\n> a quote\na comment" - output := "hello<blockquote>a quote</blockquote><p>a comment" - doonezerotest(t, input, output) -} - -func TestLinebreak2(t *testing.T) { - input := "hello\n\n> a quote\n\na comment" - output := "hello<p><blockquote>a quote</blockquote><p>a comment" - doonezerotest(t, input, output) -} - -func TestLinebreak3(t *testing.T) { - input := "hello\n\n```\nfunc(s string)\n```\n\ndoes it go?" - output := "hello<p><pre><code>func(s string)</code></pre><p>does it go?" - doonezerotest(t, input, output) -} - -func TestCodeStyles(t *testing.T) { - input := "hello\n\n```go\nfunc(s string)\n```\n\ndoes it go?" - output := "hello<p><pre><code><span class=kw>func</span><span class=op>(</span>s <span class=tp>string</span><span class=op>)</span></code></pre><p>does it go?" - doonezerotest(t, input, output) -} - -func TestSimplelink(t *testing.T) { - input := "This is a [link](https://example.com)." - output := `This is a <a href="https://example.com">link</a>.` - doonezerotest(t, input, output) -} - -func TestSimplelink2(t *testing.T) { - input := "See (http://example.com) for examples." - output := `See (<a href="http://example.com">http://example.com</a>) for examples.` - doonezerotest(t, input, output) -} - -func TestWikilink(t *testing.T) { - input := "I watched [Hackers](https://en.wikipedia.org/wiki/Hackers_(film))" - output := `I watched <a href="https://en.wikipedia.org/wiki/Hackers_(film)">Hackers</a>` - doonezerotest(t, input, output) -} - -func TestQuotedlink(t *testing.T) { - input := `quoted "https://example.com/link" here` - output := `quoted "<a href="https://example.com/link">https://example.com/link</a>" here` - doonezerotest(t, input, output) -} - -func TestLinkinQuote(t *testing.T) { - input := `> a quote and https://example.com/link` - output := `<blockquote>a quote and <a href="https://example.com/link">https://example.com/link</a></blockquote><p>` - doonezerotest(t, input, output) -} - -func TestBoldLink(t *testing.T) { - input := `**b https://example.com/link b**` - output := `<b>b <a href="https://example.com/link">https://example.com/link</a> b</b>` - doonezerotest(t, input, output) -} - -func TestHonklink(t *testing.T) { - input := `https://en.wikipedia.org/wiki/Honk!` - output := `<a href="https://en.wikipedia.org/wiki/Honk!">https://en.wikipedia.org/wiki/Honk!</a>` - doonezerotest(t, input, output) -} - -func TestImagelink(t *testing.T) { - input := `an image <img alt="caption" src="https://example.com/wherever"> and linked [<img src="there">](example.com)` - output := `an image <img alt="caption" src="https://example.com/wherever"> and linked <a href="example.com"><img src="there"></a>` - doonezerotest(t, input, output) -} - -func TestLists(t *testing.T) { - input := `hello -+ a list -+ the list - -para - -- singleton` - output := `hello<ul><li>a list<li>the list</ul><p>para<ul><li>singleton</ul><p>` - doonezerotest(t, input, output) -} - -func TestTables(t *testing.T) { - input := `hello - -| col1 | col 2 | -| row2 | cell4 | - -para -` - output := `hello<table><tr><td>col1<td>col 2<tr><td>row2<td>cell4</table><p>para` - doonezerotest(t, input, output) -} - -func TestHeaders(t *testing.T) { - input := `hello -## fruits -Love 'em. Eat 'em. -` - output := `hello<h2>fruits</h2><p>Love 'em. Eat 'em.` - doonezerotest(t, input, output) -} - -var benchData, simpleData string - -func init() { - benchData = strings.Repeat("hello there sir. It is a **fine** day for some testing!\n", 100) - simpleData = strings.Repeat("just a few words\n", 100) -} - -func BenchmarkModerateSize(b *testing.B) { - for n := 0; n < b.N; n++ { - markitzero(benchData) - } -} - -func BenchmarkSimpleData(b *testing.B) { - for n := 0; n < b.N; n++ { - markitzero(simpleData) - } -}