all repos — grayfriday @ ea3d80e2d0a45d833353ec54f28c4d74ce7aed5c

blackfriday fork with a few changes

clean up main markdown function: split out first and second passes
Russ Ross russ@russross.com
Sun, 26 Jun 2011 09:51:36 -0600
commit

ea3d80e2d0a45d833353ec54f28c4d74ce7aed5c

parent

f5e3dc8073dcaef4a37da1bfee94d67f0866bd3c

2 files changed, 31 insertions(+), 25 deletions(-)

jump to
M html.gohtml.go

@@ -23,10 +23,8 @@ HTML_SKIP_HTML = 1 << iota

HTML_SKIP_STYLE HTML_SKIP_IMAGES HTML_SKIP_LINKS - HTML_EXPAND_TABS HTML_SAFELINK HTML_TOC - HTML_HARD_WRAP HTML_GITHUB_BLOCKCODE HTML_USE_XHTML HTML_USE_SMARTYPANTS

@@ -36,7 +34,7 @@ )

type htmlOptions struct { flags int - closeTag string // how to end singleton tags: usually " />\n", possibly ">\n" + closeTag string // how to end singleton tags: either " />\n" or ">\n" tocData struct { headerCount int currentLevel int
M markdown.gomarkdown.go

@@ -194,8 +194,19 @@ if extensions&EXTENSION_AUTOLINK != 0 {

rndr.inline[':'] = inlineAutoLink } - // first pass: look for references, copy everything else - var text bytes.Buffer + first := FirstPass(rndr, input) + second := SecondPass(rndr, first) + + return second +} + +// first pass: +// - extract references +// - expand tabs +// - normalize newlines +// - copy everything else +func FirstPass(rndr *render, input []byte) []byte { + var out bytes.Buffer beg, end := 0, 0 for beg < len(input) { // iterate over lines if end = isReference(rndr, input[beg:]); end > 0 {

@@ -208,35 +219,32 @@ }

// add the line body if present if end > beg { - expandTabs(&text, input[beg:end]) + expandTabs(&out, input[beg:end]) + } else { + out.WriteByte('\n') } - for end < len(input) && (input[end] == '\n' || input[end] == '\r') { - // add one \n per newline - if input[end] == '\n' || (end+1 < len(input) && input[end+1] != '\n') { - text.WriteByte('\n') - } + if end < len(input) && input[end] == '\r' { + end++ + } + if end < len(input) && input[end] == '\n' { end++ } beg = end } } + return out.Bytes() +} - // second pass: actual rendering +// second pass: actual rendering +func SecondPass(rndr *render, input []byte) []byte { var output bytes.Buffer if rndr.mk.DocumentHeader != nil { rndr.mk.DocumentHeader(&output, rndr.mk.Opaque) } - if text.Len() > 0 { - // add a final newline if not already present - finalchar := text.Bytes()[text.Len()-1] - if finalchar != '\n' && finalchar != '\r' { - text.WriteByte('\n') - } - parseBlock(&output, rndr, text.Bytes()) - } + parseBlock(&output, rndr, input) if rndr.mk.DocumentFooter != nil { rndr.mk.DocumentFooter(&output, rndr.mk.Opaque)

@@ -274,8 +282,8 @@

// Check whether or not data starts with a reference link. // If so, it is parsed and stored in the list of references // (in the render struct). -// Returns the number of bytes to skip to move past it, or zero -// if there is the first line is not a reference. +// Returns the number of bytes to skip to move past it, +// or zero if the first line is not a reference. func isReference(rndr *render, data []byte) int { // up to 3 optional leading spaces if len(data) < 4 {

@@ -284,9 +292,6 @@ }

i := 0 for i < 3 && data[i] == ' ' { i++ - } - if data[i] == ' ' { - return 0 } // id part: anything but a newline between brackets

@@ -440,6 +445,7 @@ return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')

} // Replace tab characters with spaces, aligning to the next TAB_SIZE column. +// always ends output with a newline func expandTabs(out *bytes.Buffer, line []byte) { // first, check for common cases: no tabs, or only tabs at beginning of line i, prefix := 0, 0

@@ -461,6 +467,7 @@ for i = 0; i < prefix*TAB_SIZE; i++ {

out.WriteByte(' ') } out.Write(line[prefix:]) + out.WriteByte('\n') return }

@@ -494,4 +501,5 @@ }

i++ } + out.WriteByte('\n') }