From 679e1686dbcb2f48866df1c2cc0ac64bc6048af7 Mon Sep 17 00:00:00 2001 From: Russ Ross Date: Mon, 30 May 2011 15:36:31 -0600 Subject: [PATCH] performance fix: with autolinking on, it is almost twice as fast now --- html.go | 7 +++++-- inline.go | 31 ++++++++++++++++++++++--------- markdown.go | 9 +-------- 3 files changed, 28 insertions(+), 19 deletions(-) diff --git a/html.go b/html.go index 496bd78..7b185b8 100644 --- a/html.go +++ b/html.go @@ -427,9 +427,12 @@ func htmlAutolink(out *bytes.Buffer, link []byte, kind int, opaque interface{}) * an actual URI, e.g. `mailto:foo@bar.com`, we don't * want to print the `mailto:` prefix */ - if bytes.HasPrefix(link, []byte("mailto:")) { + switch { + case bytes.HasPrefix(link, []byte("mailto://")): + attrEscape(out, link[9:]) + case bytes.HasPrefix(link, []byte("mailto:")): attrEscape(out, link[7:]) - } else { + default: attrEscape(out, link) } diff --git a/inline.go b/inline.go index aa12202..4925391 100644 --- a/inline.go +++ b/inline.go @@ -536,14 +536,22 @@ func inlineEntity(out *bytes.Buffer, rndr *render, data []byte, offset int) int } func inlineAutolink(out *bytes.Buffer, rndr *render, data []byte, offset int) int { - orig_data := data - data = data[offset:] + // quick check to rule out most false hits on ':' + if len(data) < offset + 3 || data[offset+1] != '/' || data[offset+2] != '/' { + return 0 + } - if offset > 0 { - if !isspace(orig_data[offset-1]) && !ispunct(orig_data[offset-1]) { - return 0 - } - } + // scan backward for a word boundary + rewind := 0 + for offset - rewind > 0 && rewind <= 7 && !isspace(data[offset-rewind-1]) && !isspace(data[offset-rewind-1]) { + rewind++ + } + if rewind > 6 { // longest supported protocol is "mailto" which has 6 letters + return 0 + } + + orig_data := data + data = data[offset-rewind:] if !isSafeLink(data) { return 0 @@ -577,7 +585,7 @@ func inlineAutolink(out *bytes.Buffer, rndr *render, data []byte, offset int) in } if copen != 0 { - buf_end := offset + link_end - 2 + buf_end := offset - rewind + link_end - 2 open_delim := 1 @@ -618,6 +626,11 @@ func inlineAutolink(out *bytes.Buffer, rndr *render, data []byte, offset int) in } } + // we were triggered on the ':', so we need to rewind the output a bit + if out.Len() >= rewind { + out.Truncate(len(out.Bytes()) - rewind) + } + if rndr.mk.autolink != nil { u_link := bytes.NewBuffer(nil) unescapeText(u_link, data[:link_end]) @@ -625,7 +638,7 @@ func inlineAutolink(out *bytes.Buffer, rndr *render, data []byte, offset int) in rndr.mk.autolink(out, u_link.Bytes(), LINK_TYPE_NORMAL, rndr.mk.opaque) } - return link_end + return link_end - rewind } var validUris = [][]byte{[]byte("http://"), []byte("https://"), []byte("ftp://"), []byte("mailto://")} diff --git a/markdown.go b/markdown.go index 99dc335..8d2f52b 100644 --- a/markdown.go +++ b/markdown.go @@ -187,14 +187,7 @@ func Markdown(input []byte, renderer *Renderer, extensions uint32) []byte { rndr.inline['&'] = inlineEntity if extensions&EXTENSION_AUTOLINK != 0 { - rndr.inline['h'] = inlineAutolink // http, https - rndr.inline['H'] = inlineAutolink - - rndr.inline['f'] = inlineAutolink // ftp - rndr.inline['F'] = inlineAutolink - - rndr.inline['m'] = inlineAutolink // mailto - rndr.inline['M'] = inlineAutolink + rndr.inline[':'] = inlineAutolink } // first pass: look for references, copy everything else