mirror of
https://github.com/nim-lang/Nim.git
synced 2026-06-05 19:34:12 +00:00
Don't throw errors on RST tables in Markdown and RstMarkdown modes (#22165)
* Don't throw errors on RST tables in Markdown and RstMarkdown modes Additions to RST simple tables (#19859) made their parsing more restrictive, which can introduce problems with of some old nimforum posts, which have tables with sloppily aligned columns (like this one: https://github.com/nim-lang/nimforum/issues/330#issuecomment-1376039966). Also this strictness contradicts to Markdown style of not getting in the way (ignoring errors). So this PR proposes a new strategy of dealing with errors: * In Markdown and legacy (old default) RstMarkdown we try to continue parsing, emitting only warnings * And only in pure RST mode we throw a error I expect that this strategy will be applied to more parts of markup code in the future. * Don't return anything in `checkColumns`
This commit is contained in:
@@ -585,6 +585,29 @@ proc rstMessage(p: RstParser, msgKind: MsgKind) =
|
||||
p.col + currentTok(p).col, msgKind,
|
||||
currentTok(p).symbol)
|
||||
|
||||
# Functions `isPureRst` & `stopOrWarn` address differences between
|
||||
# Markdown and RST:
|
||||
# * Markdown always tries to continue working. If it is really impossible
|
||||
# to parse a markup element, its proc just returns `nil` and parsing
|
||||
# continues for it as for normal text paragraph.
|
||||
# The downside is that real mistakes/typos are often silently ignored.
|
||||
# The same applies to legacy `RstMarkdown` mode for nimforum.
|
||||
# * RST really signals errors. The downside is that it's more intrusive -
|
||||
# the user must escape special syntax with \ explicitly.
|
||||
#
|
||||
# TODO: we need to apply this strategy to all markup elements eventually.
|
||||
|
||||
func isPureRst(p: RstParser): bool =
|
||||
roSupportMarkdown notin p.s.options
|
||||
|
||||
proc stopOrWarn(p: RstParser, errorType: MsgKind, arg: string) =
|
||||
let realMsgKind = if isPureRst(p): errorType else: mwRstStyle
|
||||
rstMessage(p, realMsgKind, arg)
|
||||
|
||||
proc stopOrWarn(p: RstParser, errorType: MsgKind, arg: string, line, col: int) =
|
||||
let realMsgKind = if isPureRst(p): errorType else: mwRstStyle
|
||||
rstMessage(p, realMsgKind, arg, line, col)
|
||||
|
||||
proc currInd(p: RstParser): int =
|
||||
result = p.indentStack[high(p.indentStack)]
|
||||
|
||||
@@ -2596,11 +2619,11 @@ proc getColumns(p: RstParser, cols: var RstCols, startIdx: int): int =
|
||||
proc checkColumns(p: RstParser, cols: RstCols) =
|
||||
var i = p.idx
|
||||
if p.tok[i].symbol[0] != '=':
|
||||
rstMessage(p, mwRstStyle,
|
||||
stopOrWarn(p, meIllformedTable,
|
||||
"only tables with `=` columns specification are allowed")
|
||||
for col in 0 ..< cols.len:
|
||||
if tokEnd(p, i) != cols[col].stop:
|
||||
rstMessage(p, meIllformedTable,
|
||||
stopOrWarn(p, meIllformedTable,
|
||||
"end of table column #$1 should end at position $2" % [
|
||||
$(col+1), $(cols[col].stop+ColRstOffset)],
|
||||
p.tok[i].line, tokEnd(p, i))
|
||||
@@ -2609,12 +2632,12 @@ proc checkColumns(p: RstParser, cols: RstCols) =
|
||||
if p.tok[i].kind == tkWhite:
|
||||
inc i
|
||||
if p.tok[i].kind notin {tkIndent, tkEof}:
|
||||
rstMessage(p, meIllformedTable, "extraneous column specification")
|
||||
stopOrWarn(p, meIllformedTable, "extraneous column specification")
|
||||
elif p.tok[i].kind == tkWhite:
|
||||
inc i
|
||||
else:
|
||||
rstMessage(p, meIllformedTable, "no enough table columns",
|
||||
p.tok[i].line, p.tok[i].col)
|
||||
stopOrWarn(p, meIllformedTable,
|
||||
"no enough table columns", p.tok[i].line, p.tok[i].col)
|
||||
|
||||
proc getSpans(p: RstParser, nextLine: int,
|
||||
cols: RstCols, unitedCols: RstCols): seq[int] =
|
||||
@@ -2669,17 +2692,18 @@ proc parseSimpleTableRow(p: var RstParser, cols: RstCols, colChar: char): PRstNo
|
||||
if tokEnd(p) <= colEnd(nCell):
|
||||
if tokStart(p) < colStart(nCell):
|
||||
if currentTok(p).kind != tkWhite:
|
||||
rstMessage(p, meIllformedTable,
|
||||
stopOrWarn(p, meIllformedTable,
|
||||
"this word crosses table column from the left")
|
||||
else:
|
||||
inc p.idx
|
||||
row[nCell].add(currentTok(p).symbol)
|
||||
else:
|
||||
row[nCell].add(currentTok(p).symbol)
|
||||
inc p.idx
|
||||
inc p.idx
|
||||
else:
|
||||
if tokStart(p) < colEnd(nCell) and currentTok(p).kind != tkWhite:
|
||||
rstMessage(p, meIllformedTable,
|
||||
stopOrWarn(p, meIllformedTable,
|
||||
"this word crosses table column from the right")
|
||||
row[nCell].add(currentTok(p).symbol)
|
||||
inc p.idx
|
||||
inc nCell
|
||||
if currentTok(p).kind == tkIndent: inc p.idx
|
||||
if tokEnd(p) <= colEnd(0): break
|
||||
|
||||
@@ -29,7 +29,9 @@ import os
|
||||
import std/[assertions, syncio]
|
||||
|
||||
const preferMarkdown = {roPreferMarkdown, roSupportMarkdown, roNimFile, roSandboxDisabled}
|
||||
# legacy nimforum / old default mode:
|
||||
const preferRst = {roSupportMarkdown, roNimFile, roSandboxDisabled}
|
||||
const pureRst = {roNimFile, roSandboxDisabled}
|
||||
|
||||
proc toAst(input: string,
|
||||
rstOptions: RstParseOptions = preferMarkdown,
|
||||
@@ -917,10 +919,31 @@ suite "RST tables":
|
||||
====== ======
|
||||
Inputs Output
|
||||
====== ======
|
||||
""".toAst(error=error) == "")
|
||||
""".toAst(rstOptions = pureRst, error = error) == "")
|
||||
check(error[] == "input(2, 2) Error: Illformed table: " &
|
||||
"this word crosses table column from the right")
|
||||
|
||||
# In nimforum compatibility mode & Markdown we raise a warning instead:
|
||||
let expected = dedent"""
|
||||
rnTable colCount=2
|
||||
rnTableRow
|
||||
rnTableDataCell
|
||||
rnLeaf 'Inputs'
|
||||
rnTableDataCell
|
||||
rnLeaf 'Output'
|
||||
"""
|
||||
for opt in [preferRst, preferMarkdown]:
|
||||
var warnings = new seq[string]
|
||||
|
||||
check(
|
||||
dedent"""
|
||||
====== ======
|
||||
Inputs Output
|
||||
====== ======
|
||||
""".toAst(rstOptions = opt, warnings = warnings) == expected)
|
||||
check(warnings[] == @[
|
||||
"input(2, 2) Warning: RST style: this word crosses table column from the right"])
|
||||
|
||||
test "tables with slightly overflowed cells cause an error (2)":
|
||||
var error = new string
|
||||
check("" == dedent"""
|
||||
@@ -929,7 +952,7 @@ suite "RST tables":
|
||||
===== ===== ======
|
||||
False False False
|
||||
===== ===== ======
|
||||
""".toAst(error=error))
|
||||
""".toAst(rstOptions = pureRst, error = error))
|
||||
check(error[] == "input(2, 8) Error: Illformed table: " &
|
||||
"this word crosses table column from the right")
|
||||
|
||||
@@ -941,7 +964,7 @@ suite "RST tables":
|
||||
===== ===== ======
|
||||
False False False
|
||||
===== ===== ======
|
||||
""".toAst(error=error))
|
||||
""".toAst(rstOptions = pureRst, error = error))
|
||||
check(error[] == "input(2, 7) Error: Illformed table: " &
|
||||
"this word crosses table column from the left")
|
||||
|
||||
@@ -954,7 +977,7 @@ suite "RST tables":
|
||||
===== ======
|
||||
False False
|
||||
===== =======
|
||||
""".toAst(error=error))
|
||||
""".toAst(rstOptions = pureRst, error = error))
|
||||
check(error[] == "input(5, 14) Error: Illformed table: " &
|
||||
"end of table column #2 should end at position 13")
|
||||
|
||||
@@ -966,7 +989,7 @@ suite "RST tables":
|
||||
===== =======
|
||||
False False
|
||||
===== ======
|
||||
""".toAst(error=error))
|
||||
""".toAst(rstOptions = pureRst, error = error))
|
||||
check(error[] == "input(3, 14) Error: Illformed table: " &
|
||||
"end of table column #2 should end at position 13")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user