summary refs log tree commit diff stats
path: root/lib
diff options
context:
space:
mode:
authorMiran <narimiran@disroot.org>2020-11-10 09:41:26 +0100
committerGitHub <noreply@github.com>2020-11-10 09:41:26 +0100
commitee78d7610853f4866c9b3d1e81d523b7ef339da0 (patch)
tree48fb70888df2e0dde545e9b40a25d39ad302d1a0 /lib
parentd8e7caf5dd4ab70b7429896c1587cde992e7855a (diff)
downloadNim-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.nim73
-rw-r--r--lib/packages/docutils/rstast.nim2
-rw-r--r--lib/packages/docutils/rstgen.nim2
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}{" &