diff options
author | Miran <narimiran@disroot.org> | 2020-11-10 09:41:26 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-11-10 09:41:26 +0100 |
commit | ee78d7610853f4866c9b3d1e81d523b7ef339da0 (patch) | |
tree | 48fb70888df2e0dde545e9b40a25d39ad302d1a0 /lib | |
parent | d8e7caf5dd4ab70b7429896c1587cde992e7855a (diff) | |
download | Nim-ee78d7610853f4866c9b3d1e81d523b7ef339da0.tar.gz |
rst: add support for markdown tables (#15854)
* rst: add support for markdown tables * change template into proc * don't create unnecessary `seq[string]`
Diffstat (limited to 'lib')
-rw-r--r-- | lib/packages/docutils/rst.nim | 73 | ||||
-rw-r--r-- | lib/packages/docutils/rstast.nim | 2 | ||||
-rw-r--r-- | lib/packages/docutils/rstgen.nim | 2 |
3 files changed, 75 insertions, 2 deletions
diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index 56bfe580b..c04a6e07c 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -36,6 +36,7 @@ type meCannotOpenFile, meExpected, meGridTableNotImplemented, + meMarkdownIllformedTable, meNewSectionExpected, meGeneralParseError, meInvalidDirective, @@ -53,6 +54,7 @@ const meCannotOpenFile: "cannot open '$1'", meExpected: "'$1' expected", meGridTableNotImplemented: "grid table is not implemented", + meMarkdownIllformedTable: "illformed delimiter row of a markdown table", meNewSectionExpected: "new section expected", meGeneralParseError: "general parse error", meInvalidDirective: "invalid directive: '$1'", @@ -1091,6 +1093,13 @@ proc isMarkdownHeadline(p: RstParser): bool = if p.tok[p.idx+2].kind in {tkWord, tkOther, tkPunct}: result = true +proc findPipe(p: RstParser, start: int): bool = + var i = start + while true: + if p.tok[i].symbol == "|": return true + if p.tok[i].kind in {tkIndent, tkEof}: return false + inc i + proc whichSection(p: RstParser): RstNodeKind = case p.tok[p.idx].kind of tkAdornment: @@ -1104,6 +1113,9 @@ proc whichSection(p: RstParser): RstNodeKind = of tkPunct: if isMarkdownHeadline(p): result = rnHeadline + elif roSupportMarkdown in p.s.options and predNL(p) and + match(p, p.idx, "| w") and findPipe(p, p.idx+3): + result = rnMarkdownTable elif p.tok[p.idx].symbol == "```": result = rnCodeBlock elif match(p, tokenAfterNewline(p), "ai"): @@ -1206,6 +1218,9 @@ proc parseHeadline(p: var RstParser): PRstNode = type IntSeq = seq[int] + ColumnLimits = tuple + first, last: int + ColSeq = seq[ColumnLimits] proc tokEnd(p: RstParser): int = result = p.tok[p.idx].col + len(p.tok[p.idx].symbol) - 1 @@ -1280,6 +1295,63 @@ proc parseSimpleTable(p: var RstParser): PRstNode = add(a, b) add(result, a) +proc readTableRow(p: var RstParser): ColSeq = + if p.tok[p.idx].symbol == "|": inc p.idx + while p.tok[p.idx].kind notin {tkIndent, tkEof}: + var limits: ColumnLimits + limits.first = p.idx + while p.tok[p.idx].kind notin {tkIndent, tkEof}: + if p.tok[p.idx].symbol == "|" and p.tok[p.idx-1].symbol != "\\": break + inc p.idx + limits.last = p.idx + result.add(limits) + if p.tok[p.idx].kind in {tkIndent, tkEof}: break + inc p.idx + p.idx = tokenAfterNewline(p) + +proc getColContents(p: var RstParser, colLim: ColumnLimits): string = + for i in colLim.first ..< colLim.last: + result.add(p.tok[i].symbol) + result.strip + +proc isValidDelimiterRow(p: var RstParser, colNum: int): bool = + let row = readTableRow(p) + if row.len != colNum: return false + for limits in row: + let content = getColContents(p, limits) + if content.len < 3 or not (content.startsWith("--") or content.startsWith(":-")): + return false + return true + +proc parseMarkdownTable(p: var RstParser): PRstNode = + var + row: ColSeq + colNum: int + a, b: PRstNode + q: RstParser + result = newRstNode(rnMarkdownTable) + + proc parseRow(p: var RstParser, cellKind: RstNodeKind, result: PRstNode) = + row = readTableRow(p) + if colNum == 0: colNum = row.len # table header + elif row.len < colNum: row.setLen(colNum) + a = newRstNode(rnTableRow) + for j in 0 ..< colNum: + b = newRstNode(cellKind) + initParser(q, p.s) + q.col = p.col + q.line = p.tok[p.idx].line - 1 + q.filename = p.filename + q.col += getTokens(getColContents(p, row[j]), false, q.tok) + b.add(parseDoc(q)) + a.add(b) + result.add(a) + + parseRow(p, rnTableHeaderCell, result) + if not isValidDelimiterRow(p, colNum): rstMessage(p, meMarkdownIllformedTable) + while predNL(p) and p.tok[p.idx].symbol == "|": + parseRow(p, rnTableDataCell, result) + proc parseTransition(p: var RstParser): PRstNode = result = newRstNode(rnTransition) inc(p.idx) @@ -1461,6 +1533,7 @@ proc parseSection(p: var RstParser, result: PRstNode) = of rnHeadline: a = parseHeadline(p) of rnOverline: a = parseOverline(p) of rnTable: a = parseSimpleTable(p) + of rnMarkdownTable: a = parseMarkdownTable(p) of rnOptionList: a = parseOptionList(p) else: #InternalError("rst.parseSection()") diff --git a/lib/packages/docutils/rstast.nim b/lib/packages/docutils/rstast.nim index 044ea2c14..8b2159aeb 100644 --- a/lib/packages/docutils/rstast.nim +++ b/lib/packages/docutils/rstast.nim @@ -37,7 +37,7 @@ type rnLineBlock, # the | thingie rnLineBlockItem, # sons of the | thing rnBlockQuote, # text just indented - rnTable, rnGridTable, rnTableRow, rnTableHeaderCell, rnTableDataCell, + rnTable, rnGridTable, rnMarkdownTable, rnTableRow, rnTableHeaderCell, rnTableDataCell, rnLabel, # used for footnotes and other things rnFootnote, # a footnote rnCitation, # similar to footnote diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim index c70998edb..604cc3ca9 100644 --- a/lib/packages/docutils/rstgen.nim +++ b/lib/packages/docutils/rstgen.nim @@ -1094,7 +1094,7 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) = of rnBlockQuote: renderAux(d, n, "<blockquote><p>$1</p></blockquote>\n", "\\begin{quote}$1\\end{quote}\n", result) - of rnTable, rnGridTable: + of rnTable, rnGridTable, rnMarkdownTable: renderAux(d, n, "<table border=\"1\" class=\"docutils\">$1</table>", "\\begin{table}\\begin{rsttab}{" & |