summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/gomarkdown/markdown/parser/block_table.go
diff options
context:
space:
mode:
authorWim <wim@42.be>2021-10-17 00:47:22 +0200
committerGitHub <noreply@github.com>2021-10-17 00:47:22 +0200
commit4dd8bae5c91fa4aef09d865d8fef1acd84f90925 (patch)
treeffad9b242daccaf8c86d1c1fbd59032302bd3be9 /vendor/github.com/gomarkdown/markdown/parser/block_table.go
parent7ae45c42e712bd0e66c101f3f714c05aa1dc2104 (diff)
downloadmatterbridge-msglm-4dd8bae5c91fa4aef09d865d8fef1acd84f90925.tar.gz
matterbridge-msglm-4dd8bae5c91fa4aef09d865d8fef1acd84f90925.tar.bz2
matterbridge-msglm-4dd8bae5c91fa4aef09d865d8fef1acd84f90925.zip
Update dependencies (#1610)
* Update dependencies * Update module to go 1.17
Diffstat (limited to 'vendor/github.com/gomarkdown/markdown/parser/block_table.go')
-rw-r--r--vendor/github.com/gomarkdown/markdown/parser/block_table.go311
1 files changed, 311 insertions, 0 deletions
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
+}