stricter checks for RST headlines (#17089)
This commit is contained in:
parent
0fcf1af765
commit
d1fec552d0
9 changed files with 72 additions and 17 deletions
|
|
@ -142,6 +142,7 @@ template declareClosures =
|
||||||
of mwUnknownSubstitution: k = warnUnknownSubstitutionX
|
of mwUnknownSubstitution: k = warnUnknownSubstitutionX
|
||||||
of mwUnsupportedLanguage: k = warnLanguageXNotSupported
|
of mwUnsupportedLanguage: k = warnLanguageXNotSupported
|
||||||
of mwUnsupportedField: k = warnFieldXNotSupported
|
of mwUnsupportedField: k = warnFieldXNotSupported
|
||||||
|
of mwRstStyle: k = warnRstStyle
|
||||||
{.gcsafe.}:
|
{.gcsafe.}:
|
||||||
globalError(conf, newLineInfo(conf, AbsoluteFile filename, line, col), k, arg)
|
globalError(conf, newLineInfo(conf, AbsoluteFile filename, line, col), k, arg)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -44,8 +44,10 @@ type
|
||||||
warnDeprecated = "Deprecated", warnConfigDeprecated = "ConfigDeprecated",
|
warnDeprecated = "Deprecated", warnConfigDeprecated = "ConfigDeprecated",
|
||||||
warnSmallLshouldNotBeUsed = "SmallLshouldNotBeUsed", warnUnknownMagic = "UnknownMagic",
|
warnSmallLshouldNotBeUsed = "SmallLshouldNotBeUsed", warnUnknownMagic = "UnknownMagic",
|
||||||
warnRedefinitionOfLabel = "RedefinitionOfLabel", warnUnknownSubstitutionX = "UnknownSubstitutionX",
|
warnRedefinitionOfLabel = "RedefinitionOfLabel", warnUnknownSubstitutionX = "UnknownSubstitutionX",
|
||||||
warnLanguageXNotSupported = "LanguageXNotSupported", warnFieldXNotSupported = "FieldXNotSupported",
|
warnLanguageXNotSupported = "LanguageXNotSupported",
|
||||||
warnCommentXIgnored = "CommentXIgnored", warnTypelessParam = "TypelessParam",
|
warnFieldXNotSupported = "FieldXNotSupported",
|
||||||
|
warnRstStyle = "warnRstStyle", warnCommentXIgnored = "CommentXIgnored",
|
||||||
|
warnTypelessParam = "TypelessParam",
|
||||||
warnUseBase = "UseBase", warnWriteToForeignHeap = "WriteToForeignHeap",
|
warnUseBase = "UseBase", warnWriteToForeignHeap = "WriteToForeignHeap",
|
||||||
warnUnsafeCode = "UnsafeCode", warnUnusedImportX = "UnusedImport",
|
warnUnsafeCode = "UnsafeCode", warnUnusedImportX = "UnusedImport",
|
||||||
warnInheritFromException = "InheritFromException", warnEachIdentIsTuple = "EachIdentIsTuple",
|
warnInheritFromException = "InheritFromException", warnEachIdentIsTuple = "EachIdentIsTuple",
|
||||||
|
|
@ -83,7 +85,7 @@ const
|
||||||
errGridTableNotImplemented: "grid table is not implemented",
|
errGridTableNotImplemented: "grid table is not implemented",
|
||||||
errMarkdownIllformedTable: "illformed delimiter row of a markdown table",
|
errMarkdownIllformedTable: "illformed delimiter row of a markdown table",
|
||||||
errGeneralParseError: "general parse error",
|
errGeneralParseError: "general parse error",
|
||||||
errNewSectionExpected: "new section expected",
|
errNewSectionExpected: "new section expected $1",
|
||||||
errInvalidDirectiveX: "invalid directive: '$1'",
|
errInvalidDirectiveX: "invalid directive: '$1'",
|
||||||
errFootnoteMismatch: "number of footnotes and their references don't match: $1",
|
errFootnoteMismatch: "number of footnotes and their references don't match: $1",
|
||||||
errProveInit: "Cannot prove that '$1' is initialized.", # deadcode
|
errProveInit: "Cannot prove that '$1' is initialized.", # deadcode
|
||||||
|
|
@ -101,6 +103,7 @@ const
|
||||||
warnUnknownSubstitutionX: "unknown substitution '$1'",
|
warnUnknownSubstitutionX: "unknown substitution '$1'",
|
||||||
warnLanguageXNotSupported: "language '$1' not supported",
|
warnLanguageXNotSupported: "language '$1' not supported",
|
||||||
warnFieldXNotSupported: "field '$1' not supported",
|
warnFieldXNotSupported: "field '$1' not supported",
|
||||||
|
warnRstStyle: "RST style: $1",
|
||||||
warnCommentXIgnored: "comment '$1' ignored",
|
warnCommentXIgnored: "comment '$1' ignored",
|
||||||
warnTypelessParam: "'$1' has no type. Typeless parameters are deprecated; only allowed for 'template'",
|
warnTypelessParam: "'$1' has no type. Typeless parameters are deprecated; only allowed for 'template'",
|
||||||
warnUseBase: "use {.base.} for base methods; baseless methods are deprecated",
|
warnUseBase: "use {.base.} for base methods; baseless methods are deprecated",
|
||||||
|
|
|
||||||
|
|
@ -261,6 +261,10 @@ proc mainCommand*(graph: ModuleGraph) =
|
||||||
if optGenIndex in conf.globalOptions and optWholeProject in conf.globalOptions:
|
if optGenIndex in conf.globalOptions and optWholeProject in conf.globalOptions:
|
||||||
commandBuildIndex(conf, $conf.outDir)
|
commandBuildIndex(conf, $conf.outDir)
|
||||||
of cmdRst2html:
|
of cmdRst2html:
|
||||||
|
# XXX: why are warnings disabled by default for rst2html and rst2tex?
|
||||||
|
for warn in [warnUnknownSubstitutionX, warnLanguageXNotSupported,
|
||||||
|
warnFieldXNotSupported, warnRstStyle]:
|
||||||
|
conf.setNoteDefaults(warn, true)
|
||||||
conf.setNoteDefaults(warnRedefinitionOfLabel, false) # similar to issue #13218
|
conf.setNoteDefaults(warnRedefinitionOfLabel, false) # similar to issue #13218
|
||||||
when defined(leanCompiler):
|
when defined(leanCompiler):
|
||||||
quit "compiler wasn't built with documentation generator"
|
quit "compiler wasn't built with documentation generator"
|
||||||
|
|
@ -268,6 +272,10 @@ proc mainCommand*(graph: ModuleGraph) =
|
||||||
loadConfigs(DocConfig, cache, conf, graph.idgen)
|
loadConfigs(DocConfig, cache, conf, graph.idgen)
|
||||||
commandRst2Html(cache, conf)
|
commandRst2Html(cache, conf)
|
||||||
of cmdRst2tex:
|
of cmdRst2tex:
|
||||||
|
for warn in [warnRedefinitionOfLabel, warnUnknownSubstitutionX,
|
||||||
|
warnLanguageXNotSupported,
|
||||||
|
warnFieldXNotSupported, warnRstStyle]:
|
||||||
|
conf.setNoteDefaults(warn, true)
|
||||||
when defined(leanCompiler):
|
when defined(leanCompiler):
|
||||||
quit "compiler wasn't built with documentation generator"
|
quit "compiler wasn't built with documentation generator"
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,7 @@ the garbage collector with ``GC_enableMarkAndSweep`` and ``GC_disableMarkAndSwee
|
||||||
|
|
||||||
|
|
||||||
Soft real-time support
|
Soft real-time support
|
||||||
---------------------
|
----------------------
|
||||||
|
|
||||||
To enable real-time support, the symbol `useRealtimeGC`:idx: needs to be
|
To enable real-time support, the symbol `useRealtimeGC`:idx: needs to be
|
||||||
defined via ``--define:useRealtimeGC`` (you can put this into your config
|
defined via ``--define:useRealtimeGC`` (you can put this into your config
|
||||||
|
|
|
||||||
|
|
@ -183,7 +183,7 @@ Usually we just track the result of an expression: probably this should apply fo
|
||||||
Also related to tracking initialization of expressions/fields.
|
Also related to tracking initialization of expressions/fields.
|
||||||
|
|
||||||
unstructured control flow rules
|
unstructured control flow rules
|
||||||
-------------------------
|
-------------------------------
|
||||||
|
|
||||||
Unstructured control flow keywords as ``return``, ``break``, ``continue``, ``raise`` mean that we jump from a branch out.
|
Unstructured control flow keywords as ``return``, ``break``, ``continue``, ``raise`` mean that we jump from a branch out.
|
||||||
This means that if there is code after the finishing of the branch, it would be ran if one hasn't hit the direct parent branch of those: so it is similar to an ``else``. In those cases we should use the reverse nilabilities for the local to the condition expressions. E.g.
|
This means that if there is code after the finishing of the branch, it would be ran if one hasn't hit the direct parent branch of those: so it is similar to an ``else``. In those cases we should use the reverse nilabilities for the local to the condition expressions. E.g.
|
||||||
|
|
|
||||||
|
|
@ -154,7 +154,7 @@ but does nothing else. Here is an example of such a tree representation:
|
||||||
|
|
||||||
|
|
||||||
Custom Semantic Checking
|
Custom Semantic Checking
|
||||||
-----------------------
|
------------------------
|
||||||
|
|
||||||
The first thing that a macro should do with its arguments is to check
|
The first thing that a macro should do with its arguments is to check
|
||||||
if the argument is in the correct form. Not every type of wrong input
|
if the argument is in the correct form. Not every type of wrong input
|
||||||
|
|
|
||||||
|
|
@ -165,14 +165,15 @@ type
|
||||||
meExpected = "'$1' expected",
|
meExpected = "'$1' expected",
|
||||||
meGridTableNotImplemented = "grid table is not implemented",
|
meGridTableNotImplemented = "grid table is not implemented",
|
||||||
meMarkdownIllformedTable = "illformed delimiter row of a Markdown table",
|
meMarkdownIllformedTable = "illformed delimiter row of a Markdown table",
|
||||||
meNewSectionExpected = "new section expected",
|
meNewSectionExpected = "new section expected $1",
|
||||||
meGeneralParseError = "general parse error",
|
meGeneralParseError = "general parse error",
|
||||||
meInvalidDirective = "invalid directive: '$1'",
|
meInvalidDirective = "invalid directive: '$1'",
|
||||||
meFootnoteMismatch = "mismatch in number of footnotes and their refs: $1",
|
meFootnoteMismatch = "mismatch in number of footnotes and their refs: $1",
|
||||||
mwRedefinitionOfLabel = "redefinition of label '$1'",
|
mwRedefinitionOfLabel = "redefinition of label '$1'",
|
||||||
mwUnknownSubstitution = "unknown substitution '$1'",
|
mwUnknownSubstitution = "unknown substitution '$1'",
|
||||||
mwUnsupportedLanguage = "language '$1' not supported",
|
mwUnsupportedLanguage = "language '$1' not supported",
|
||||||
mwUnsupportedField = "field '$1' not supported"
|
mwUnsupportedField = "field '$1' not supported",
|
||||||
|
mwRstStyle = "RST style: $1"
|
||||||
|
|
||||||
MsgHandler* = proc (filename: string, line, col: int, msgKind: MsgKind,
|
MsgHandler* = proc (filename: string, line, col: int, msgKind: MsgKind,
|
||||||
arg: string) {.closure, gcsafe.} ## what to do in case of an error
|
arg: string) {.closure, gcsafe.} ## what to do in case of an error
|
||||||
|
|
@ -1420,16 +1421,42 @@ proc tokenAfterNewline(p: RstParser): int =
|
||||||
else: inc result
|
else: inc result
|
||||||
|
|
||||||
proc isAdornmentHeadline(p: RstParser, adornmentIdx: int): bool =
|
proc isAdornmentHeadline(p: RstParser, adornmentIdx: int): bool =
|
||||||
|
## check that underline/overline length is enough for the heading.
|
||||||
|
## No support for Unicode.
|
||||||
|
if p.tok[adornmentIdx].symbol in ["::", "..", "|"]:
|
||||||
|
return false
|
||||||
var headlineLen = 0
|
var headlineLen = 0
|
||||||
if p.idx < adornmentIdx: # underline
|
var failure = ""
|
||||||
|
if p.idx < adornmentIdx: # check for underline
|
||||||
|
if p.idx > 0:
|
||||||
|
headlineLen = currentTok(p).col - p.tok[adornmentIdx].col
|
||||||
|
if headlineLen > 0:
|
||||||
|
rstMessage(p, mwRstStyle, "indentation of heading text allowed" &
|
||||||
|
" only for overline titles")
|
||||||
for i in p.idx ..< adornmentIdx-1: # adornmentIdx-1 is a linebreak
|
for i in p.idx ..< adornmentIdx-1: # adornmentIdx-1 is a linebreak
|
||||||
headlineLen += p.tok[i].symbol.len
|
headlineLen += p.tok[i].symbol.len
|
||||||
else: # overline
|
result = p.tok[adornmentIdx].symbol.len >= headlineLen and headlineLen != 0
|
||||||
|
if not result:
|
||||||
|
failure = "(underline '" & p.tok[adornmentIdx].symbol & "' is too short)"
|
||||||
|
else: # p.idx == adornmentIdx, at overline. Check overline and underline
|
||||||
var i = p.idx + 2
|
var i = p.idx + 2
|
||||||
|
headlineLen = p.tok[i].col - p.tok[adornmentIdx].col
|
||||||
while p.tok[i].kind notin {tkEof, tkIndent}:
|
while p.tok[i].kind notin {tkEof, tkIndent}:
|
||||||
headlineLen += p.tok[i].symbol.len
|
headlineLen += p.tok[i].symbol.len
|
||||||
inc i
|
inc i
|
||||||
return p.tok[adornmentIdx].symbol.len >= headlineLen
|
result = p.tok[adornmentIdx].symbol.len >= headlineLen and
|
||||||
|
headlineLen != 0
|
||||||
|
if result:
|
||||||
|
result = result and p.tok[i].kind == tkIndent and
|
||||||
|
p.tok[i+1].kind == tkAdornment and
|
||||||
|
p.tok[i+1].symbol == p.tok[adornmentIdx].symbol
|
||||||
|
if not result:
|
||||||
|
failure = "(underline '" & p.tok[i+1].symbol & "' does not match " &
|
||||||
|
"overline '" & p.tok[adornmentIdx].symbol & "')"
|
||||||
|
else:
|
||||||
|
failure = "(overline '" & p.tok[adornmentIdx].symbol & "' is too short)"
|
||||||
|
if not result:
|
||||||
|
rstMessage(p, meNewSectionExpected, failure)
|
||||||
|
|
||||||
proc isLineBlock(p: RstParser): bool =
|
proc isLineBlock(p: RstParser): bool =
|
||||||
var j = tokenAfterNewline(p)
|
var j = tokenAfterNewline(p)
|
||||||
|
|
@ -1941,7 +1968,7 @@ proc parseSection(p: var RstParser, result: PRstNode) =
|
||||||
of rnLineBlock: a = parseLineBlock(p)
|
of rnLineBlock: a = parseLineBlock(p)
|
||||||
of rnDirective: a = parseDotDot(p)
|
of rnDirective: a = parseDotDot(p)
|
||||||
of rnEnumList: a = parseEnumList(p)
|
of rnEnumList: a = parseEnumList(p)
|
||||||
of rnLeaf: rstMessage(p, meNewSectionExpected)
|
of rnLeaf: rstMessage(p, meNewSectionExpected, "(syntax error)")
|
||||||
of rnParagraph: discard
|
of rnParagraph: discard
|
||||||
of rnDefList: a = parseDefinitionList(p)
|
of rnDefList: a = parseDefinitionList(p)
|
||||||
of rnFieldList:
|
of rnFieldList:
|
||||||
|
|
|
||||||
|
|
@ -101,7 +101,7 @@
|
||||||
## Another message
|
## Another message
|
||||||
##
|
##
|
||||||
## Passing Channels Safely
|
## Passing Channels Safely
|
||||||
## ----------------------
|
## -----------------------
|
||||||
## Note that when passing objects to procedures on another thread by pointer
|
## Note that when passing objects to procedures on another thread by pointer
|
||||||
## (for example through a thread's argument), objects created using the default
|
## (for example through a thread's argument), objects created using the default
|
||||||
## allocator will use thread-local, GC-managed memory. Thus it is generally
|
## allocator will use thread-local, GC-managed memory. Thus it is generally
|
||||||
|
|
|
||||||
|
|
@ -261,8 +261,8 @@ Wrong chapter
|
||||||
------------
|
------------
|
||||||
|
|
||||||
"""
|
"""
|
||||||
let output4 = rstToHtml(input4, {roSupportMarkdown}, defaultConfig())
|
expect(EParseError):
|
||||||
doAssert "Wrong chapter" in output4 and "<h1" notin output4
|
let output4 = rstToHtml(input4, {roSupportMarkdown}, defaultConfig())
|
||||||
|
|
||||||
let input5 = """
|
let input5 = """
|
||||||
Check that punctuation after adornment and indent are not detected as adornment.
|
Check that punctuation after adornment and indent are not detected as adornment.
|
||||||
|
|
@ -281,6 +281,22 @@ Some chapter
|
||||||
let output6 = rstToHtml(input6, {roSupportMarkdown}, defaultConfig())
|
let output6 = rstToHtml(input6, {roSupportMarkdown}, defaultConfig())
|
||||||
doAssert "<h1 id=\"some-chapter\">Some chapter</h1>" in output6
|
doAssert "<h1 id=\"some-chapter\">Some chapter</h1>" in output6
|
||||||
|
|
||||||
|
# check that overline and underline match
|
||||||
|
let input7 = dedent """
|
||||||
|
------------
|
||||||
|
Some chapter
|
||||||
|
-----------
|
||||||
|
"""
|
||||||
|
expect(EParseError):
|
||||||
|
let output7 = rstToHtml(input7, {roSupportMarkdown}, defaultConfig())
|
||||||
|
|
||||||
|
let input8 = dedent """
|
||||||
|
-----------
|
||||||
|
Overflow
|
||||||
|
-----------
|
||||||
|
"""
|
||||||
|
expect(EParseError):
|
||||||
|
let output8 = rstToHtml(input8, {roSupportMarkdown}, defaultConfig())
|
||||||
|
|
||||||
test "RST links":
|
test "RST links":
|
||||||
let input1 = """
|
let input1 = """
|
||||||
|
|
@ -308,8 +324,8 @@ This is too short to be a transition:
|
||||||
|
|
||||||
context2
|
context2
|
||||||
"""
|
"""
|
||||||
let output2 = rstToHtml(input2, {roSupportMarkdown}, defaultConfig())
|
expect(EParseError):
|
||||||
doAssert "<hr" notin output2
|
let output2 = rstToHtml(input2, {roSupportMarkdown}, defaultConfig())
|
||||||
|
|
||||||
test "RST literal block":
|
test "RST literal block":
|
||||||
let input1 = """
|
let input1 = """
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue