diff options
Diffstat (limited to 'vendor/github.com/gomarkdown')
-rw-r--r-- | vendor/github.com/gomarkdown/markdown/.gitpod | 7 | ||||
-rw-r--r-- | vendor/github.com/gomarkdown/markdown/README.md | 23 | ||||
-rw-r--r-- | vendor/github.com/gomarkdown/markdown/ast/attribute.go | 10 | ||||
-rw-r--r-- | vendor/github.com/gomarkdown/markdown/ast/node.go | 9 | ||||
-rw-r--r-- | vendor/github.com/gomarkdown/markdown/go.mod | 5 | ||||
-rw-r--r-- | vendor/github.com/gomarkdown/markdown/go.sum | 1 | ||||
-rw-r--r-- | vendor/github.com/gomarkdown/markdown/html/renderer.go | 41 | ||||
-rw-r--r-- | vendor/github.com/gomarkdown/markdown/markdown.go | 26 | ||||
-rw-r--r-- | vendor/github.com/gomarkdown/markdown/parser/block.go | 332 | ||||
-rw-r--r-- | vendor/github.com/gomarkdown/markdown/parser/block_table.go | 311 | ||||
-rw-r--r-- | vendor/github.com/gomarkdown/markdown/parser/inline.go | 2 | ||||
-rw-r--r-- | vendor/github.com/gomarkdown/markdown/parser/parser.go | 24 | ||||
-rw-r--r-- | vendor/github.com/gomarkdown/markdown/tracking-perf.md | 189 |
13 files changed, 428 insertions, 552 deletions
diff --git a/vendor/github.com/gomarkdown/markdown/.gitpod b/vendor/github.com/gomarkdown/markdown/.gitpod deleted file mode 100644 index ad5feff6..00000000 --- a/vendor/github.com/gomarkdown/markdown/.gitpod +++ /dev/null @@ -1,7 +0,0 @@ -checkoutLocation: "src/github.com/gomarkdown/markdown" -workspaceLocation: "." -tasks: - - command: > - cd /workspace/src/github.com/gomarkdown/markdown && - go get -v ./... && - go test -c diff --git a/vendor/github.com/gomarkdown/markdown/README.md b/vendor/github.com/gomarkdown/markdown/README.md index a40c7a94..7efc1919 100644 --- a/vendor/github.com/gomarkdown/markdown/README.md +++ b/vendor/github.com/gomarkdown/markdown/README.md @@ -25,6 +25,7 @@ Some tools using this package: - https://github.com/romanyx/mdopen : view markdown files in the default browser - https://github.com/ystyle/sqlmanager : a library for manager sql with markdown like beetsql - https://gitlab.com/kendellfab/fazer : library for making templates +- https://github.com/blmayer/tasker : a simple task list web app ## Usage @@ -130,6 +131,12 @@ maybeUnsafeHTML := markdown.ToHTML(md, nil, nil) html := bluemonday.UGCPolicy().SanitizeBytes(maybeUnsafeHTML) ``` +## Windows / Mac newlines + +The library only supports Unix newlines. If you have markdown text with possibly +Windows / Mac newlines, normalize newlines before caling this librar using +`d = markdown.NormalizeNewlines(d)` + ## mdtohtml command-line tool https://github.com/gomarkdown/mdtohtml is a command-line markdown to html @@ -259,10 +266,10 @@ implements the following extensions: should be crossed out. - **Hard line breaks**. With this extension enabled newlines in the input - translate into line breaks in the output. This extension is off by default. + translates into line breaks in the output. This extension is off by default. -- **Non blocking space**. With this extension enabled spaces preceeded by an backslash n the input - translate non-blocking spaces in the output. This extension is off by default. +- **Non blocking space**. With this extension enabled spaces preceeded by a backslash + in the input translates non-blocking spaces in the output. This extension is off by default. - **Smart quotes**. Smartypants-style punctuation substitution is supported, turning normal double- and single-quote marks into @@ -281,9 +288,9 @@ implements the following extensions: <sup>4</sup>⁄<sub>5</sub>. - **MathJaX Support** is an additional feature which is supported by - many markdown editor. It translate inline math equation quoted by `$` - and display math block quoted by `$$` into MathJax compatible format. - hyphen `_` won't break LaTeX render within a math element any more. + many markdown editor. It translates inline math equations quoted by `$` + and displays math blocks quoted by `$$` into MathJax compatible format. + Hyphens (`_`) won't break LaTeX render within a math element any more. ``` $$ @@ -299,13 +306,13 @@ implements the following extensions: $$ ``` -- **Ordered list start number**. With this extension enabled an ordered list will start with the +- **Ordered list start number**. With this extension enabled an ordered list will start with the number that was used to start it. - **Super and subscript**. With this extension enabled sequences between ^ will indicate superscript and ~ will become a subscript. For example: H~2~O is a liquid, 2^10^ is 1024. -- **Block level attributes**, allow setting attributes (ID, classes and key/value pairs) on block +- **Block level attributes** allow setting attributes (ID, classes and key/value pairs) on block level elements. The attribute must be enclosed with braces and be put on a line before the element. diff --git a/vendor/github.com/gomarkdown/markdown/ast/attribute.go b/vendor/github.com/gomarkdown/markdown/ast/attribute.go deleted file mode 100644 index 002c6a2e..00000000 --- a/vendor/github.com/gomarkdown/markdown/ast/attribute.go +++ /dev/null @@ -1,10 +0,0 @@ -package ast - -// An attribute can be attached to block elements. They are specified as -// {#id .classs key="value"} where quotes for values are mandatory, multiple -// key/value pairs are separated by whitespace. -type Attribute struct { - ID []byte - Classes [][]byte - Attrs map[string][]byte -} diff --git a/vendor/github.com/gomarkdown/markdown/ast/node.go b/vendor/github.com/gomarkdown/markdown/ast/node.go index 7881f6e7..0d7175c5 100644 --- a/vendor/github.com/gomarkdown/markdown/ast/node.go +++ b/vendor/github.com/gomarkdown/markdown/ast/node.go @@ -1,5 +1,14 @@ package ast +// An attribute can be attached to block elements. They are specified as +// {#id .classs key="value"} where quotes for values are mandatory, multiple +// key/value pairs are separated by whitespace. +type Attribute struct { + ID []byte + Classes [][]byte + Attrs map[string][]byte +} + // ListType contains bitwise or'ed flags for list and list item objects. type ListType int diff --git a/vendor/github.com/gomarkdown/markdown/go.mod b/vendor/github.com/gomarkdown/markdown/go.mod deleted file mode 100644 index 899e3237..00000000 --- a/vendor/github.com/gomarkdown/markdown/go.mod +++ /dev/null @@ -1,5 +0,0 @@ -module github.com/gomarkdown/markdown - -go 1.12 - -require golang.org/dl v0.0.0-20190829154251-82a15e2f2ead // indirect diff --git a/vendor/github.com/gomarkdown/markdown/go.sum b/vendor/github.com/gomarkdown/markdown/go.sum deleted file mode 100644 index 1406b01f..00000000 --- a/vendor/github.com/gomarkdown/markdown/go.sum +++ /dev/null @@ -1 +0,0 @@ -golang.org/dl v0.0.0-20190829154251-82a15e2f2ead/go.mod h1:IUMfjQLJQd4UTqG1Z90tenwKoCX93Gn3MAQJMOSBsDQ= diff --git a/vendor/github.com/gomarkdown/markdown/html/renderer.go b/vendor/github.com/gomarkdown/markdown/html/renderer.go index 1b466876..68868573 100644 --- a/vendor/github.com/gomarkdown/markdown/html/renderer.go +++ b/vendor/github.com/gomarkdown/markdown/html/renderer.go @@ -304,25 +304,6 @@ func isRelativeLink(link []byte) (yes bool) { return false } -func (r *Renderer) ensureUniqueHeadingID(id string) string { - for count, found := r.headingIDs[id]; found; count, found = r.headingIDs[id] { - tmp := fmt.Sprintf("%s-%d", id, count+1) - - if _, tmpFound := r.headingIDs[tmp]; !tmpFound { - r.headingIDs[id] = count + 1 - id = tmp - } else { - id = id + "-1" - } - } - - if _, found := r.headingIDs[id]; !found { - r.headingIDs[id] = 0 - } - - return id -} - func (r *Renderer) addAbsPrefix(link []byte) []byte { if r.opts.AbsolutePrefix != "" && isRelativeLink(link) && link[0] != '.' { newDest := r.opts.AbsolutePrefix @@ -701,8 +682,28 @@ func (r *Renderer) headingEnter(w io.Writer, nodeData *ast.Heading) { if class != "" { attrs = []string{`class="` + class + `"`} } + + ensureUniqueHeadingID := func(id string) string { + for count, found := r.headingIDs[id]; found; count, found = r.headingIDs[id] { + tmp := fmt.Sprintf("%s-%d", id, count+1) + + if _, tmpFound := r.headingIDs[tmp]; !tmpFound { + r.headingIDs[id] = count + 1 + id = tmp + } else { + id = id + "-1" + } + } + + if _, found := r.headingIDs[id]; !found { + r.headingIDs[id] = 0 + } + + return id + } + if nodeData.HeadingID != "" { - id := r.ensureUniqueHeadingID(nodeData.HeadingID) + id := ensureUniqueHeadingID(nodeData.HeadingID) if r.opts.HeadingIDPrefix != "" { id = r.opts.HeadingIDPrefix + id } diff --git a/vendor/github.com/gomarkdown/markdown/markdown.go b/vendor/github.com/gomarkdown/markdown/markdown.go index fd5c1cfb..537eb27b 100644 --- a/vendor/github.com/gomarkdown/markdown/markdown.go +++ b/vendor/github.com/gomarkdown/markdown/markdown.go @@ -83,3 +83,29 @@ func ToHTML(markdown []byte, p *parser.Parser, renderer Renderer) []byte { } return Render(doc, renderer) } + +// NormalizeNewlines converts Windows and Mac newlines to Unix newlines +// The parser only supports Unix newlines. If your mardown content +// might contain Windows or Mac newlines, use this function to convert to Unix newlines +func NormalizeNewlines(d []byte) []byte { + wi := 0 + n := len(d) + for i := 0; i < n; i++ { + c := d[i] + // 13 is CR + if c != 13 { + d[wi] = c + wi++ + continue + } + // replace CR (mac / win) with LF (unix) + d[wi] = 10 + wi++ + if i < n-1 && d[i+1] == 10 { + // this was CRLF, so skip the LF + i++ + } + + } + return d[:wi] +} diff --git a/vendor/github.com/gomarkdown/markdown/parser/block.go b/vendor/github.com/gomarkdown/markdown/parser/block.go index 95438174..7d7e9f9c 100644 --- a/vendor/github.com/gomarkdown/markdown/parser/block.go +++ b/vendor/github.com/gomarkdown/markdown/parser/block.go @@ -74,9 +74,9 @@ var ( } ) -// sanitizeAnchorName returns a sanitized anchor name for the given text. +// sanitizeHeadingID returns a sanitized anchor name for the given text. // Taken from https://github.com/shurcooL/sanitized_anchor_name/blob/master/main.go#L14:1 -func sanitizeAnchorName(text string) string { +func sanitizeHeadingID(text string) string { var anchorName []rune var futureDash = false for _, r := range text { @@ -91,6 +91,9 @@ func sanitizeAnchorName(text string) string { futureDash = true } } + if len(anchorName) == 0 { + return "empty" + } return string(anchorName) } @@ -278,12 +281,6 @@ func (p *Parser) block(data []byte) { } } - // table: - // - // Name | Age | Phone - // ------|-----|--------- - // Bob | 31 | 555-1234 - // Alice | 27 | 555-4321 if p.extensions&Tables != 0 { if i := p.table(data); i > 0 { data = data[i:] @@ -422,13 +419,14 @@ func (p *Parser) prefixHeading(data []byte) int { end-- } if end > i { - if id == "" && p.extensions&AutoHeadingIDs != 0 { - id = sanitizeAnchorName(string(data[i:end])) - } block := &ast.Heading{ HeadingID: id, Level: level, } + if id == "" && p.extensions&AutoHeadingIDs != 0 { + block.HeadingID = sanitizeHeadingID(string(data[i:end])) + p.allHeadingsWithAutoID = append(p.allHeadingsWithAutoID, block) + } block.Content = data[i:end] p.addBlock(block) } @@ -492,14 +490,15 @@ func (p *Parser) prefixSpecialHeading(data []byte) int { end-- } if end > i { - if id == "" && p.extensions&AutoHeadingIDs != 0 { - id = sanitizeAnchorName(string(data[i:end])) - } block := &ast.Heading{ HeadingID: id, IsSpecial: true, Level: 1, // always level 1. } + if id == "" && p.extensions&AutoHeadingIDs != 0 { + block.HeadingID = sanitizeHeadingID(string(data[i:end])) + p.allHeadingsWithAutoID = append(p.allHeadingsWithAutoID, block) + } block.Literal = data[i:end] block.Content = data[i:end] p.addBlock(block) @@ -647,7 +646,7 @@ func (p *Parser) html(data []byte, doRender bool) int { if doRender { // trim newlines end := backChar(data, i, '\n') - htmlBLock := &ast.HTMLBlock{ast.Leaf{Content: data[:end]}} + htmlBLock := &ast.HTMLBlock{Leaf: ast.Leaf{Content: data[:end]}} p.addBlock(htmlBLock) finalizeHTMLBlock(htmlBLock) } @@ -669,7 +668,7 @@ func (p *Parser) htmlComment(data []byte, doRender bool) int { if doRender { // trim trailing newlines end := backChar(data, size, '\n') - htmlBLock := &ast.HTMLBlock{ast.Leaf{Content: data[:end]}} + htmlBLock := &ast.HTMLBlock{Leaf: ast.Leaf{Content: data[:end]}} p.addBlock(htmlBLock) finalizeHTMLBlock(htmlBLock) } @@ -701,7 +700,7 @@ func (p *Parser) htmlHr(data []byte, doRender bool) int { if doRender { // trim newlines end := backChar(data, size, '\n') - htmlBlock := &ast.HTMLBlock{ast.Leaf{Content: data[:end]}} + htmlBlock := &ast.HTMLBlock{Leaf: ast.Leaf{Content: data[:end]}} p.addBlock(htmlBlock) finalizeHTMLBlock(htmlBlock) } @@ -1005,294 +1004,6 @@ func finalizeCodeBlock(code *ast.CodeBlock) { code.Content = nil } -func (p *Parser) table(data []byte) int { - i, columns, table := p.tableHeader(data) - if i == 0 { - return 0 - } - - p.addBlock(&ast.TableBody{}) - - for i < len(data) { - pipes, rowStart := 0, i - for ; i < len(data) && data[i] != '\n'; i++ { - if data[i] == '|' { - pipes++ - } - } - - if pipes == 0 { - i = rowStart - break - } - - // include the newline in data sent to tableRow - i = skipCharN(data, i, '\n', 1) - - if p.tableFooter(data[rowStart:i]) { - continue - } - - p.tableRow(data[rowStart:i], columns, false) - } - if captionContent, id, consumed := p.caption(data[i:], []byte("Table: ")); consumed > 0 { - caption := &ast.Caption{} - p.Inline(caption, captionContent) - - // Some switcheroo to re-insert the parsed table as a child of the captionfigure. - figure := &ast.CaptionFigure{} - figure.HeadingID = id - table2 := &ast.Table{} - // Retain any block level attributes. - table2.AsContainer().Attribute = table.AsContainer().Attribute - children := table.GetChildren() - ast.RemoveFromTree(table) - - table2.SetChildren(children) - ast.AppendChild(figure, table2) - ast.AppendChild(figure, caption) - - p.addChild(figure) - p.finalize(figure) - - i += consumed - } - - return i -} - -// check if the specified position is preceded by an odd number of backslashes -func isBackslashEscaped(data []byte, i int) bool { - backslashes := 0 - for i-backslashes-1 >= 0 && data[i-backslashes-1] == '\\' { - backslashes++ - } - return backslashes&1 == 1 -} - -// tableHeaders parses the header. If recognized it will also add a table. -func (p *Parser) tableHeader(data []byte) (size int, columns []ast.CellAlignFlags, table ast.Node) { - i := 0 - colCount := 1 - headerIsUnderline := true - for i = 0; i < len(data) && data[i] != '\n'; i++ { - if data[i] == '|' && !isBackslashEscaped(data, i) { - colCount++ - } - if data[i] != '-' && data[i] != ' ' && data[i] != ':' && data[i] != '|' { - headerIsUnderline = false - } - } - - // doesn't look like a table header - if colCount == 1 { - return - } - - // include the newline in the data sent to tableRow - j := skipCharN(data, i, '\n', 1) - header := data[:j] - - // column count ignores pipes at beginning or end of line - if data[0] == '|' { - colCount-- - } - if i > 2 && data[i-1] == '|' && !isBackslashEscaped(data, i-1) { - colCount-- - } - - // if the header looks like a underline, then we omit the header - // and parse the first line again as underline - if headerIsUnderline { - header = nil - i = 0 - } else { - i++ // move past newline - } - - columns = make([]ast.CellAlignFlags, colCount) - - // move on to the header underline - if i >= len(data) { - return - } - - if data[i] == '|' && !isBackslashEscaped(data, i) { - i++ - } - i = skipChar(data, i, ' ') - - // each column header is of form: / *:?-+:? *|/ with # dashes + # colons >= 3 - // and trailing | optional on last column - col := 0 - n := len(data) - for i < n && data[i] != '\n' { - dashes := 0 - - if data[i] == ':' { - i++ - columns[col] |= ast.TableAlignmentLeft - dashes++ - } - for i < n && data[i] == '-' { - i++ - dashes++ - } - if i < n && data[i] == ':' { - i++ - columns[col] |= ast.TableAlignmentRight - dashes++ - } - for i < n && data[i] == ' ' { - i++ - } - if i == n { - return - } - // end of column test is messy - switch { - case dashes < 3: - // not a valid column - return - - case data[i] == '|' && !isBackslashEscaped(data, i): - // marker found, now skip past trailing whitespace - col++ - i++ - for i < n && data[i] == ' ' { - i++ - } - - // trailing junk found after last column - if col >= colCount && i < len(data) && data[i] != '\n' { - return - } - - case (data[i] != '|' || isBackslashEscaped(data, i)) && col+1 < colCount: - // something else found where marker was required - return - - case data[i] == '\n': - // marker is optional for the last column - col++ - - default: - // trailing junk found after last column - return - } - } - if col != colCount { - return - } - - table = &ast.Table{} - p.addBlock(table) - if header != nil { - p.addBlock(&ast.TableHeader{}) - p.tableRow(header, columns, true) - } - size = skipCharN(data, i, '\n', 1) - return -} - -func (p *Parser) tableRow(data []byte, columns []ast.CellAlignFlags, header bool) { - p.addBlock(&ast.TableRow{}) - i, col := 0, 0 - - if data[i] == '|' && !isBackslashEscaped(data, i) { - i++ - } - - n := len(data) - colspans := 0 // keep track of total colspan in this row. - for col = 0; col < len(columns) && i < n; col++ { - colspan := 0 - for i < n && data[i] == ' ' { - i++ - } - - cellStart := i - - for i < n && (data[i] != '|' || isBackslashEscaped(data, i)) && data[i] != '\n' { - i++ - } - - cellEnd := i - - // skip the end-of-cell marker, possibly taking us past end of buffer - // each _extra_ | means a colspan - for i < len(data) && data[i] == '|' && !isBackslashEscaped(data, i) { - i++ - colspan++ - } - // only colspan > 1 make sense. - if colspan < 2 { - colspan = 0 - } - - for cellEnd > cellStart && cellEnd-1 < n && data[cellEnd-1] == ' ' { - cellEnd-- - } - - block := &ast.TableCell{ - IsHeader: header, - Align: columns[col], - ColSpan: colspan, - } - block.Content = data[cellStart:cellEnd] - if cellStart == cellEnd && colspans > 0 { - // an empty cell that we should ignore, it exists because of colspan - colspans-- - } else { - p.addBlock(block) - } - - if colspan > 0 { - colspans += colspan - 1 - } - } - - // pad it out with empty columns to get the right number - for ; col < len(columns); col++ { - block := &ast.TableCell{ - IsHeader: header, - Align: columns[col], - } - p.addBlock(block) - } - - // silently ignore rows with too many cells -} - -// tableFooter parses the (optional) table footer. -func (p *Parser) tableFooter(data []byte) bool { - colCount := 1 - i := 0 - n := len(data) - for i < 3 && i < n && data[i] == ' ' { // ignore up to 3 spaces - i++ - } - for ; i < n && data[i] != '\n'; i++ { - if data[i] == '|' && !isBackslashEscaped(data, i) { - colCount++ - continue - } - // remaining data must be the = character - if data[i] != '=' { - return false - } - } - - // doesn't look like a table footer - if colCount == 1 { - return false - } - - p.addBlock(&ast.TableFooter{}) - - return true -} - // returns blockquote prefix length func (p *Parser) quotePrefix(data []byte) int { i := 0 @@ -1887,15 +1598,14 @@ func (p *Parser) paragraph(data []byte) int { eol-- } - id := "" + block := &ast.Heading{ + Level: level, + } if p.extensions&AutoHeadingIDs != 0 { - id = sanitizeAnchorName(string(data[prev:eol])) + block.HeadingID = sanitizeHeadingID(string(data[prev:eol])) + p.allHeadingsWithAutoID = append(p.allHeadingsWithAutoID, block) } - block := &ast.Heading{ - Level: level, - HeadingID: id, - } block.Content = data[prev:eol] p.addBlock(block) diff --git a/vendor/github.com/gomarkdown/markdown/parser/block_table.go b/vendor/github.com/gomarkdown/markdown/parser/block_table.go new file mode 100644 index 00000000..f6c06dff --- /dev/null +++ b/vendor/github.com/gomarkdown/markdown/parser/block_table.go @@ -0,0 +1,311 @@ +package parser + +import "github.com/gomarkdown/markdown/ast" + +// check if the specified position is preceded by an odd number of backslashes +func isBackslashEscaped(data []byte, i int) bool { + backslashes := 0 + for i-backslashes-1 >= 0 && data[i-backslashes-1] == '\\' { + backslashes++ + } + return backslashes&1 == 1 +} + +func (p *Parser) tableRow(data []byte, columns []ast.CellAlignFlags, header bool) { + p.addBlock(&ast.TableRow{}) + col := 0 + + i := skipChar(data, 0, '|') + + n := len(data) + colspans := 0 // keep track of total colspan in this row. + for col = 0; col < len(columns) && i < n; col++ { + colspan := 0 + i = skipChar(data, i, ' ') + + cellStart := i + + for i < n && (data[i] != '|' || isBackslashEscaped(data, i)) && data[i] != '\n' { + i++ + } + + cellEnd := i + + // skip the end-of-cell marker, possibly taking us past end of buffer + // each _extra_ | means a colspan + for i < len(data) && data[i] == '|' && !isBackslashEscaped(data, i) { + i++ + colspan++ + } + // only colspan > 1 make sense. + if colspan < 2 { + colspan = 0 + } + + for cellEnd > cellStart && cellEnd-1 < n && data[cellEnd-1] == ' ' { + cellEnd-- + } + + block := &ast.TableCell{ + IsHeader: header, + Align: columns[col], + ColSpan: colspan, + } + block.Content = data[cellStart:cellEnd] + if cellStart == cellEnd && colspans > 0 { + // an empty cell that we should ignore, it exists because of colspan + colspans-- + } else { + p.addBlock(block) + } + + if colspan > 0 { + colspans += colspan - 1 + } + } + + // pad it out with empty columns to get the right number + for ; col < len(columns); col++ { + block := &ast.TableCell{ + IsHeader: header, + Align: columns[col], + } + p.addBlock(block) + } + + // silently ignore rows with too many cells +} + +// tableFooter parses the (optional) table footer. +func (p *Parser) tableFooter(data []byte) bool { + colCount := 1 + + // ignore up to 3 spaces + n := len(data) + i := skipCharN(data, 0, ' ', 3) + for ; i < n && data[i] != '\n'; i++ { + if data[i] == '|' && !isBackslashEscaped(data, i) { + colCount++ + continue + } + // remaining data must be the = character + if data[i] != '=' { + return false + } + } + + // doesn't look like a table footer + if colCount == 1 { + return false + } + + p.addBlock(&ast.TableFooter{}) + + return true +} + +// tableHeaders parses the header. If recognized it will also add a table. +func (p *Parser) tableHeader(data []byte) (size int, columns []ast.CellAlignFlags, table ast.Node) { + i := 0 + colCount := 1 + headerIsUnderline := true + headerIsWithEmptyFields := true + for i = 0; i < len(data) && data[i] != '\n'; i++ { + if data[i] == '|' && !isBackslashEscaped(data, i) { + colCount++ + } + if data[i] != '-' && data[i] != ' ' && data[i] != ':' && data[i] != '|' { + headerIsUnderline = false + } + if data[i] != ' ' && data[i] != '|' { + headerIsWithEmptyFields = false + } + } + + // doesn't look like a table header + if colCount == 1 { + return + } + + // include the newline in the data sent to tableRow + j := skipCharN(data, i, '\n', 1) + header := data[:j] + + // column count ignores pipes at beginning or end of line + if data[0] == '|' { + colCount-- + } + { + tmp := header + // remove whitespace from the end + for len(tmp) > 0 { + lastIdx := len(tmp) - 1 + if tmp[lastIdx] == '\n' || tmp[lastIdx] == ' ' { + tmp = tmp[:lastIdx] + } else { + break + } + } + n := len(tmp) + if n > 2 && tmp[n-1] == '|' && !isBackslashEscaped(tmp, n-1) { + colCount-- + } + } + + // if the header looks like a underline, then we omit the header + // and parse the first line again as underline + if headerIsUnderline && !headerIsWithEmptyFields { + header = nil + i = 0 + } else { + i++ // move past newline + } + + columns = make([]ast.CellAlignFlags, colCount) + + // move on to the header underline + if i >= len(data) { + return + } + + if data[i] == '|' && !isBackslashEscaped(data, i) { + i++ + } + i = skipChar(data, i, ' ') + + // each column header is of form: / *:?-+:? *|/ with # dashes + # colons >= 3 + // and trailing | optional on last column + col := 0 + n := len(data) + for i < n && data[i] != '\n' { + dashes := 0 + + if data[i] == ':' { + i++ + columns[col] |= ast.TableAlignmentLeft + dashes++ + } + for i < n && data[i] == '-' { + i++ + dashes++ + } + if i < n && data[i] == ':' { + i++ + columns[col] |= ast.TableAlignmentRight + dashes++ + } + for i < n && data[i] == ' ' { + i++ + } + if i == n { + return + } + // end of column test is messy + switch { + case dashes < 3: + // not a valid column + return + + case data[i] == '|' && !isBackslashEscaped(data, i): + // marker found, now skip past trailing whitespace + col++ + i++ + for i < n && data[i] == ' ' { + i++ + } + + // trailing junk found after last column + if col >= colCount && i < len(data) && data[i] != '\n' { + return + } + + case (data[i] != '|' || isBackslashEscaped(data, i)) && col+1 < colCount: + // something else found where marker was required + return + + case data[i] == '\n': + // marker is optional for the last column + col++ + + default: + // trailing junk found after last column + return + } + } + if col != colCount { + return + } + + table = &ast.Table{} + p.addBlock(table) + if header != nil { + p.addBlock(&ast.TableHeader{}) + p.tableRow(header, columns, true) + } + size = skipCharN(data, i, '\n', 1) + return +} + +/* +Table: + +Name | Age | Phone +------|-----|--------- +Bob | 31 | 555-1234 +Alice | 27 | 555-4321 +*/ +func (p *Parser) table(data []byte) int { + i, columns, table := p.tableHeader(data) + if i == 0 { + return 0 + } + + p.addBlock(&ast.TableBody{}) + + for i < len(data) { + pipes, rowStart := 0, i + for ; i < len(data) && data[i] != '\n'; i++ { + if data[i] == '|' { + pipes++ + } + } + + if pipes == 0 { + i = rowStart + break + } + + // include the newline in data sent to tableRow + i = skipCharN(data, i, '\n', 1) + + if p.tableFooter(data[rowStart:i]) { + continue + } + + p.tableRow(data[rowStart:i], columns, false) + } + if captionContent, id, consumed := p.caption(data[i:], []byte("Table: ")); consumed > 0 { + caption := &ast.Caption{} + p.Inline(caption, captionContent) + + // Some switcheroo to re-insert the parsed table as a child of the captionfigure. + figure := &ast.CaptionFigure{} + figure.HeadingID = id + table2 := &ast.Table{} + // Retain any block level attributes. + table2.AsContainer().Attribute = table.AsContainer().Attribute + children := table.GetChildren() + ast.RemoveFromTree(table) + + table2.SetChildren(children) + ast.AppendChild(figure, table2) + ast.AppendChild(figure, caption) + + p.addChild(figure) + p.finalize(figure) + + i += consumed + } + + return i +} diff --git a/vendor/github.com/gomarkdown/markdown/parser/inline.go b/vendor/github.com/gomarkdown/markdown/parser/inline.go index 9bb5b30b..bc30326d 100644 --- a/vendor/github.com/gomarkdown/markdown/parser/inline.go +++ b/vendor/github.com/gomarkdown/markdown/parser/inline.go @@ -1293,7 +1293,7 @@ func math(p *Parser, data []byte, offset int) (int, ast.Node) { } func newTextNode(d []byte) *ast.Text { - return &ast.Text{ast.Leaf{Literal: d}} + return &ast.Text{Leaf: ast.Leaf{Literal: d}} } func normalizeURI(s []byte) []byte { diff --git a/vendor/github.com/gomarkdown/markdown/parser/parser.go b/vendor/github.com/gomarkdown/markdown/parser/parser.go index c7302dfd..7712a29f 100644 --- a/vendor/github.com/gomarkdown/markdown/parser/parser.go +++ b/vendor/github.com/gomarkdown/markdown/parser/parser.go @@ -6,6 +6,7 @@ package parser import ( "bytes" "fmt" + "strconv" "strings" "unicode/utf8" @@ -113,6 +114,10 @@ type Parser struct { attr *ast.Attribute includeStack *incStack + + // collect headings where we auto-generated id so that we can + // ensure they are unique at the end + allHeadingsWithAutoID []*ast.Heading } // New creates a markdown parser with CommonExtensions. @@ -282,6 +287,25 @@ func (p *Parser) Parse(input []byte) ast.Node { if p.Opts.Flags&SkipFootnoteList == 0 { p.parseRefsToAST() } + + // ensure HeadingIDs generated with AutoHeadingIDs are unique + // this is delayed here (as opposed to done when we create the id) + // so that we can preserve more original ids when there are conflicts + taken := map[string]bool{} + for _, h := range p.allHeadingsWithAutoID { + id := h.HeadingID + if id == "" { + continue + } + n := 0 + for taken[id] { + n++ + id = h.HeadingID + "-" + strconv.Itoa(n) + } + h.HeadingID = id + taken[id] = true + } + return p.Doc } diff --git a/vendor/github.com/gomarkdown/markdown/tracking-perf.md b/vendor/github.com/gomarkdown/markdown/tracking-perf.md deleted file mode 100644 index 40b95183..00000000 --- a/vendor/github.com/gomarkdown/markdown/tracking-perf.md +++ /dev/null @@ -1,189 +0,0 @@ -## Tracking perf changes - -Initial performance: -``` -goos: darwin -goarch: amd64 -pkg: github.com/gomarkdown/markdown -BenchmarkEscapeHTML-8 2000000 823 ns/op 0 B/op 0 allocs/op -BenchmarkSmartDoubleQuotes-8 300000 5033 ns/op 9872 B/op 56 allocs/op -BenchmarkReferenceAmps-8 100000 19538 ns/op 26776 B/op 150 allocs/op -BenchmarkReferenceAutoLinks-8 100000 17574 ns/op 24544 B/op 132 allocs/op -BenchmarkReferenceBackslashEscapes-8 30000 50977 ns/op 76752 B/op 243 allocs/op -BenchmarkReferenceBlockquotesWithCodeBlocks-8 200000 8546 ns/op 12864 B/op 65 allocs/op -BenchmarkReferenceCodeBlocks-8 200000 9000 ns/op 14912 B/op 70 allocs/op -BenchmarkReferenceCodeSpans-8 200000 8856 ns/op 14992 B/op 69 allocs/op -BenchmarkReferenceHardWrappedPara-8 200000 6599 ns/op 11312 B/op 57 allocs/op -BenchmarkReferenceHorizontalRules-8 100000 15483 ns/op 23536 B/op 98 allocs/op -BenchmarkReferenceInlineHTMLAdvances-8 200000 6839 ns/op 12150 B/op 62 allocs/op -BenchmarkReferenceInlineHTMLSimple-8 100000 19940 ns/op 28488 B/op 117 allocs/op -BenchmarkReferenceInlineHTMLComments-8 200000 7455 ns/op 13440 B/op 64 allocs/op -BenchmarkReferenceLinksInline-8 100000 16425 ns/op 23664 B/op 147 allocs/op -BenchmarkReferenceLinksReference-8 30000 54895 ns/op 66464 B/op 416 allocs/op -BenchmarkReferenceLinksShortcut-8 100000 17647 ns/op 23776 B/op 158 allocs/op -BenchmarkReferenceLiterQuotesInTitles-8 200000 9367 ns/op 14832 B/op 95 allocs/op -BenchmarkReferenceMarkdownBasics-8 10000 129772 ns/op 130848 B/op 378 allocs/op -BenchmarkReferenceMarkdownSyntax-8 3000 502365 ns/op 461411 B/op 1411 allocs/op -BenchmarkReferenceNestedBlockquotes-8 200000 7028 ns/op 12688 B/op 64 allocs/op -BenchmarkReferenceOrderedAndUnorderedLists-8 20000 79686 ns/op 107520 B/op 374 allocs/op -BenchmarkReferenceStrongAndEm-8 200000 10020 ns/op 17792 B/op 78 allocs/op -BenchmarkReferenceTabs-8 200000 12025 ns/op 18224 B/op 81 allocs/op -BenchmarkReferenceTidyness-8 200000 8985 ns/op 14432 B/op 71 allocs/op -PASS -ok github.com/gomarkdown/markdown 45.375s -``` - -After switching to using interface{} for Node.Data: -``` -BenchmarkEscapeHTML-8 2000000 929 ns/op 0 B/op 0 allocs/op -BenchmarkSmartDoubleQuotes-8 300000 5126 ns/op 9248 B/op 56 allocs/op -BenchmarkReferenceAmps-8 100000 19927 ns/op 17880 B/op 154 allocs/op -BenchmarkReferenceAutoLinks-8 100000 20732 ns/op 17360 B/op 141 allocs/op -BenchmarkReferenceBackslashEscapes-8 30000 50267 ns/op 38128 B/op 244 allocs/op -BenchmarkReferenceBlockquotesWithCodeBlocks-8 200000 8988 ns/op 10912 B/op 67 allocs/op -BenchmarkReferenceCodeBlocks-8 200000 8611 ns/op 12256 B/op 74 allocs/op -BenchmarkReferenceCodeSpans-8 200000 8256 ns/op 11248 B/op 69 allocs/op -BenchmarkReferenceHardWrappedPara-8 200000 6739 ns/op 9856 B/op 57 allocs/op -BenchmarkReferenceHorizontalRules-8 100000 15503 ns/op 15600 B/op 104 allocs/op -BenchmarkReferenceInlineHTMLAdvances-8 200000 6874 ns/op 10278 B/op 62 allocs/op -BenchmarkReferenceInlineHTMLSimple-8 100000 22271 ns/op 18552 B/op 121 allocs/op -BenchmarkReferenceInlineHTMLComments-8 200000 8315 ns/op 10736 B/op 64 allocs/op -BenchmarkReferenceLinksInline-8 100000 16155 ns/op 16912 B/op 152 allocs/op -BenchmarkReferenceLinksReference-8 30000 52387 ns/op 38192 B/op 445 allocs/op -BenchmarkReferenceLinksShortcut-8 100000 17111 ns/op 16592 B/op 167 allocs/op -BenchmarkReferenceLiterQuotesInTitles-8 200000 9164 ns/op 12048 B/op 97 allocs/op -BenchmarkReferenceMarkdownBasics-8 10000 129262 ns/op 87264 B/op 416 allocs/op -BenchmarkReferenceMarkdownSyntax-8 3000 496873 ns/op 293906 B/op 1559 allocs/op -BenchmarkReferenceNestedBlockquotes-8 200000 6854 ns/op 10192 B/op 64 allocs/op -BenchmarkReferenceOrderedAndUnorderedLists-8 20000 79633 ns/op 55024 B/op 447 allocs/op -BenchmarkReferenceStrongAndEm-8 200000 9637 ns/op 12176 B/op 78 allocs/op -BenchmarkReferenceTabs-8 100000 12164 ns/op 13776 B/op 87 allocs/op -BenchmarkReferenceTidyness-8 200000 8677 ns/op 11296 B/op 75 allocs/op -``` - -Not necessarily faster, but uses less bytes per op (but sometimes more allocs). - -After tweaking the API: -``` -$ ./s/run-bench.sh - -go test -bench=. -test.benchmem -goos: darwin -goarch: amd64 -pkg: github.com/gomarkdown/markdown -BenchmarkEscapeHTML-8 2000000 834 ns/op 0 B/op 0 allocs/op -BenchmarkSmartDoubleQuotes-8 300000 3486 ns/op 6160 B/op 27 allocs/op -BenchmarkReferenceAmps-8 100000 18158 ns/op 14792 B/op 125 allocs/op -BenchmarkReferenceAutoLinks-8 100000 16824 ns/op 14272 B/op 112 allocs/op -BenchmarkReferenceBackslashEscapes-8 30000 44066 ns/op 35040 B/op 215 allocs/op -BenchmarkReferenceBlockquotesWithCodeBlocks-8 200000 6868 ns/op 7824 B/op 38 allocs/op -BenchmarkReferenceCodeBlocks-8 200000 7157 ns/op 9168 B/op 45 allocs/op -BenchmarkReferenceCodeSpans-8 200000 6663 ns/op 8160 B/op 40 allocs/op -BenchmarkReferenceHardWrappedPara-8 300000 4821 ns/op 6768 B/op 28 allocs/op -BenchmarkReferenceHorizontalRules-8 100000 13033 ns/op 12512 B/op 75 allocs/op -BenchmarkReferenceInlineHTMLAdvances-8 300000 4998 ns/op 7190 B/op 33 allocs/op -BenchmarkReferenceInlineHTMLSimple-8 100000 17696 ns/op 15464 B/op 92 allocs/op -BenchmarkReferenceInlineHTMLComments-8 300000 5506 ns/op 7648 B/op 35 allocs/op -BenchmarkReferenceLinksInline-8 100000 14450 ns/op 13824 B/op 123 allocs/op -BenchmarkReferenceLinksReference-8 30000 52561 ns/op 35104 B/op 416 allocs/op -BenchmarkReferenceLinksShortcut-8 100000 15616 ns/op 13504 B/op 138 allocs/op -BenchmarkReferenceLiterQuotesInTitles-8 200000 7772 ns/op 8960 B/op 68 allocs/op -BenchmarkReferenceMarkdownBasics-8 10000 121436 ns/op 84176 B/op 387 allocs/op -BenchmarkReferenceMarkdownSyntax-8 3000 487404 ns/op 290818 B/op 1530 allocs/op -BenchmarkReferenceNestedBlockquotes-8 300000 5098 ns/op 7104 B/op 35 allocs/op -BenchmarkReferenceOrderedAndUnorderedLists-8 20000 74422 ns/op 51936 B/op 418 allocs/op -BenchmarkReferenceStrongAndEm-8 200000 7888 ns/op 9088 B/op 49 allocs/op -BenchmarkReferenceTabs-8 200000 10061 ns/op 10688 B/op 58 allocs/op -BenchmarkReferenceTidyness-8 200000 7152 ns/op 8208 B/op 46 allocs/op -ok github.com/gomarkdown/markdown 40.809s -``` - -After refactoring Renderer: -``` -BenchmarkEscapeHTML-8 2000000 883 ns/op 0 B/op 0 allocs/op -BenchmarkSmartDoubleQuotes-8 300000 3717 ns/op 6208 B/op 29 allocs/op -BenchmarkReferenceAmps-8 100000 19135 ns/op 14680 B/op 123 allocs/op -BenchmarkReferenceAutoLinks-8 100000 17142 ns/op 14176 B/op 110 allocs/op -BenchmarkReferenceBackslashEscapes-8 30000 54616 ns/op 35088 B/op 217 allocs/op -BenchmarkReferenceBlockquotesWithCodeBlocks-8 200000 7993 ns/op 7872 B/op 40 allocs/op -BenchmarkReferenceCodeBlocks-8 200000 8285 ns/op 9216 B/op 47 allocs/op -BenchmarkReferenceCodeSpans-8 200000 7684 ns/op 8208 B/op 42 allocs/op -BenchmarkReferenceHardWrappedPara-8 200000 5595 ns/op 6816 B/op 30 allocs/op -BenchmarkReferenceHorizontalRules-8 100000 16444 ns/op 12560 B/op 77 allocs/op -BenchmarkReferenceInlineHTMLAdvances-8 200000 5415 ns/op 7238 B/op 35 allocs/op -BenchmarkReferenceInlineHTMLSimple-8 100000 19867 ns/op 15512 B/op 94 allocs/op -BenchmarkReferenceInlineHTMLComments-8 200000 6026 ns/op 7696 B/op 37 allocs/op -BenchmarkReferenceLinksInline-8 100000 14864 ns/op 13664 B/op 120 allocs/op -BenchmarkReferenceLinksReference-8 30000 52479 ns/op 34816 B/op 401 allocs/op -BenchmarkReferenceLinksShortcut-8 100000 15812 ns/op 13472 B/op 135 allocs/op -BenchmarkReferenceLiterQuotesInTitles-8 200000 7767 ns/op 8880 B/op 68 allocs/op -BenchmarkReferenceMarkdownBasics-8 10000 131065 ns/op 84048 B/op 386 allocs/op -BenchmarkReferenceMarkdownSyntax-8 2000 515604 ns/op 289953 B/op 1501 allocs/op -BenchmarkReferenceNestedBlockquotes-8 200000 5655 ns/op 7152 B/op 37 allocs/op -BenchmarkReferenceOrderedAndUnorderedLists-8 20000 84188 ns/op 51984 B/op 420 allocs/op -BenchmarkReferenceStrongAndEm-8 200000 8664 ns/op 9136 B/op 51 allocs/op -BenchmarkReferenceTabs-8 100000 11110 ns/op 10736 B/op 60 allocs/op -BenchmarkReferenceTidyness-8 200000 7628 ns/op 8256 B/op 48 allocs/op -ok github.com/gomarkdown/markdown 40.841s -``` - -After Node refactor to have Children array: -``` -BenchmarkEscapeHTML-8 2000000 901 ns/op 0 B/op 0 allocs/op -BenchmarkSmartDoubleQuotes-8 300000 3905 ns/op 6224 B/op 31 allocs/op -BenchmarkReferenceAmps-8 100000 22216 ns/op 15560 B/op 157 allocs/op -BenchmarkReferenceAutoLinks-8 100000 20335 ns/op 14824 B/op 146 allocs/op -BenchmarkReferenceBackslashEscapes-8 20000 69174 ns/op 37392 B/op 316 allocs/op -BenchmarkReferenceBlockquotesWithCodeBlocks-8 200000 8443 ns/op 7968 B/op 48 allocs/op -BenchmarkReferenceCodeBlocks-8 200000 9250 ns/op 9392 B/op 58 allocs/op -BenchmarkReferenceCodeSpans-8 200000 8515 ns/op 8432 B/op 54 allocs/op -BenchmarkReferenceHardWrappedPara-8 200000 5738 ns/op 6856 B/op 34 allocs/op -BenchmarkReferenceHorizontalRules-8 100000 20864 ns/op 13648 B/op 93 allocs/op -BenchmarkReferenceInlineHTMLAdvances-8 200000 6187 ns/op 7310 B/op 40 allocs/op -BenchmarkReferenceInlineHTMLSimple-8 50000 23793 ns/op 16128 B/op 114 allocs/op -BenchmarkReferenceInlineHTMLComments-8 200000 7060 ns/op 7840 B/op 44 allocs/op -BenchmarkReferenceLinksInline-8 100000 18432 ns/op 14496 B/op 153 allocs/op -BenchmarkReferenceLinksReference-8 20000 67666 ns/op 37136 B/op 502 allocs/op -BenchmarkReferenceLinksShortcut-8 100000 19324 ns/op 13984 B/op 162 allocs/op -BenchmarkReferenceLiterQuotesInTitles-8 200000 8998 ns/op 9320 B/op 83 allocs/op -BenchmarkReferenceMarkdownBasics-8 10000 160908 ns/op 88152 B/op 518 allocs/op -BenchmarkReferenceMarkdownSyntax-8 2000 707160 ns/op 303801 B/op 2044 allocs/op -BenchmarkReferenceNestedBlockquotes-8 200000 6740 ns/op 7248 B/op 45 allocs/op -BenchmarkReferenceOrderedAndUnorderedLists-8 10000 115808 ns/op 55052 B/op 626 allocs/op -BenchmarkReferenceStrongAndEm-8 100000 10540 ns/op 9416 B/op 72 allocs/op -BenchmarkReferenceTabs-8 100000 13171 ns/op 10968 B/op 77 allocs/op -BenchmarkReferenceTidyness-8 200000 8903 ns/op 8404 B/op 62 allocs/op -PASS -ok github.com/gomarkdown/markdown 43.477s -``` -It's slower (but opens up possibilities for further improvements). - -After refactoring to make ast.Node a top-level thing. -``` -BenchmarkEscapeHTML-8 2000000 829 ns/op 0 B/op 0 allocs/op -BenchmarkSmartDoubleQuotes-8 300000 3998 ns/op 6192 B/op 31 allocs/op -BenchmarkReferenceAmps-8 50000 27389 ns/op 15480 B/op 153 allocs/op -BenchmarkReferenceAutoLinks-8 50000 23106 ns/op 14656 B/op 137 allocs/op -BenchmarkReferenceBackslashEscapes-8 10000 112435 ns/op 36696 B/op 315 allocs/op -BenchmarkReferenceBlockquotesWithCodeBlocks-8 200000 9227 ns/op 7856 B/op 46 allocs/op -BenchmarkReferenceCodeBlocks-8 200000 10469 ns/op 9248 B/op 54 allocs/op -BenchmarkReferenceCodeSpans-8 200000 10522 ns/op 8368 B/op 54 allocs/op -BenchmarkReferenceHardWrappedPara-8 200000 6354 ns/op 6784 B/op 34 allocs/op -BenchmarkReferenceHorizontalRules-8 50000 32393 ns/op 13952 B/op 87 allocs/op -BenchmarkReferenceInlineHTMLAdvances-8 200000 6894 ns/op 7238 B/op 40 allocs/op -BenchmarkReferenceInlineHTMLSimple-8 50000 32942 ns/op 15864 B/op 110 allocs/op -BenchmarkReferenceInlineHTMLComments-8 200000 8181 ns/op 7776 B/op 44 allocs/op -BenchmarkReferenceLinksInline-8 100000 21679 ns/op 14400 B/op 148 allocs/op -BenchmarkReferenceLinksReference-8 20000 83928 ns/op 36688 B/op 473 allocs/op -BenchmarkReferenceLinksShortcut-8 100000 22053 ns/op 13872 B/op 153 allocs/op -BenchmarkReferenceLiterQuotesInTitles-8 100000 10784 ns/op 9296 B/op 81 allocs/op -BenchmarkReferenceMarkdownBasics-8 5000 237097 ns/op 87760 B/op 480 allocs/op -BenchmarkReferenceMarkdownSyntax-8 1000 1465402 ns/op 300769 B/op 1896 allocs/op -BenchmarkReferenceNestedBlockquotes-8 200000 7461 ns/op 7152 B/op 45 allocs/op -BenchmarkReferenceOrderedAndUnorderedLists-8 5000 212256 ns/op 53724 B/op 553 allocs/op -BenchmarkReferenceStrongAndEm-8 100000 13018 ns/op 9264 B/op 72 allocs/op -BenchmarkReferenceTabs-8 100000 15005 ns/op 10752 B/op 71 allocs/op -BenchmarkReferenceTidyness-8 200000 10308 ns/op 8292 B/op 58 allocs/op -PASS -ok github.com/gomarkdown/markdown 42.176s -``` |