diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index ea0c079daa93d..d83d07cf88483 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -146,7 +146,7 @@ ## .. _Sphinx directives: https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html import - os, strutils, rstast, algorithm, lists, sequtils + os, strutils, rstast, std/enumutils, algorithm, lists, sequtils type RstParseOption* = enum ## options for the RST parser @@ -487,7 +487,7 @@ template nextTok(p: RstParser): Token = p.tok[p.idx + 1] proc whichMsgClass*(k: MsgKind): MsgClass = ## returns which message class `k` belongs to. - case ($k)[1] + case k.symbolName[1] of 'e', 'E': result = mcError of 'w', 'W': result = mcWarning of 'h', 'H': result = mcHint diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim index f72ff9e8f0ba9..c52a0fdccd144 100644 --- a/lib/packages/docutils/rstgen.nim +++ b/lib/packages/docutils/rstgen.nim @@ -1476,7 +1476,8 @@ $content # ---------- forum --------------------------------------------------------- proc rstToHtml*(s: string, options: RstParseOptions, - config: StringTableRef): string = + config: StringTableRef, + msgHandler: MsgHandler = rst.defaultMsgHandler): string = ## Converts an input rst string into embeddable HTML. ## ## This convenience proc parses any input string using rst markup (it doesn't @@ -1503,11 +1504,10 @@ proc rstToHtml*(s: string, options: RstParseOptions, const filen = "input" var d: RstGenerator - initRstGenerator(d, outHtml, config, filen, options, myFindFile, - rst.defaultMsgHandler) + initRstGenerator(d, outHtml, config, filen, options, myFindFile, msgHandler) var dummyHasToc = false var rst = rstParse(s, filen, line=LineRstInit, column=ColRstInit, - dummyHasToc, options) + dummyHasToc, options, myFindFile, msgHandler) result = "" renderRstToOut(d, rst, result) diff --git a/tests/stdlib/trstgen.nim b/tests/stdlib/trstgen.nim index 7d5c0e28f2c27..4d0f0678144ba 100644 --- a/tests/stdlib/trstgen.nim +++ b/tests/stdlib/trstgen.nim @@ -8,8 +8,37 @@ import ../../lib/packages/docutils/rstgen import ../../lib/packages/docutils/rst import unittest, strutils, strtabs -proc toHtml(input: string): string = - rstToHtml(input, {roSupportMarkdown}, defaultConfig()) +proc toHtml(input: string, + rstOptions: RstParseOptions = {roSupportMarkdown}, + expectError: string = "", + expectWarnings: seq[string] = @[]): string = + var warnings: seq[string] + var error: string + proc testMsgHandler(filename: string, line, col: int, msgkind: MsgKind, + arg: string) = + let mc = msgkind.whichMsgClass + let a = $msgkind % arg + let message = "$1($2, $3) $4: $5" % [$filename, $line, $col, $mc, a] + if mc == mcError: + error = message + # we check only first error because subsequent ones may be meaningless + raise newException(EParseError, message) + else: + warnings.add message + try: + result = rstToHtml(input, rstOptions, defaultConfig(), testMsgHandler) + except EParseError: + discard + template assertEqual(s1, s2: untyped) = + let result = s1 == s2 + if not result: + echo "assert failed, Expected:" + echo s1 + echo "got:" + echo s2 + doAssert result + assertEqual(expectError, error) + assertEqual(expectWarnings, warnings) suite "YAML syntax highlighting": test "Basics": @@ -24,7 +53,7 @@ suite "YAML syntax highlighting": ? key : value ...""" - let output = rstTohtml(input, {}, defaultConfig()) + let output = input.toHtml({}) doAssert output == """
%YAML 1.2
 ---
 a string: string
@@ -50,7 +79,7 @@ suite "YAML syntax highlighting":
     another literal block scalar:
       |+ # comment after header
      allowed, since more indented than parent"""
-    let output = rstToHtml(input, {}, defaultConfig())
+    let output = input.toHtml({})
     doAssert output == """
a literal block scalar: |
   some text
   # not a comment
@@ -76,7 +105,7 @@ suite "YAML syntax highlighting":
     % not a directive
     ...
     %TAG ! !foo:"""
-    let output = rstToHtml(input, {}, defaultConfig())
+    let output = input.toHtml({})
     doAssert output == """
%YAML 1.2
 ---
 %not a directive
@@ -97,7 +126,7 @@ suite "YAML syntax highlighting":
       more numbers: [-783, 11e78],
       not numbers: [ 42e, 0023, +32.37, 8 ball]
     }"""
-    let output = rstToHtml(input, {}, defaultConfig())
+    let output = input.toHtml({})
     doAssert output == """
{
   "quoted string": 42,
   'single quoted string': false,
@@ -114,7 +143,7 @@ suite "YAML syntax highlighting":
     : !localtag foo
     alias: *anchor
     """
-    let output = rstToHtml(input, {}, defaultConfig())
+    let output = input.toHtml({})
     doAssert output == """
--- !!map
 !!str string: !<tag:yaml.org,2002:int> 42
 ? &anchor !!seq []:
@@ -134,7 +163,7 @@ suite "YAML syntax highlighting":
     example.com/not/a#comment:
       ?not a map key
     """
-    let output = rstToHtml(input, {}, defaultConfig())
+    let output = input.toHtml({})
     doAssert output == """
...
  %a string:
   a:string:not:a:map
@@ -155,9 +184,9 @@ suite "RST/Markdown general":
 
   test "Markdown links":
     let
-      a = rstToHtml("(( [Nim](https://nim-lang.org/) ))", {roSupportMarkdown}, defaultConfig())
-      b = rstToHtml("(([Nim](https://nim-lang.org/)))", {roSupportMarkdown}, defaultConfig())
-      c = rstToHtml("[[Nim](https://nim-lang.org/)]", {roSupportMarkdown}, defaultConfig())
+      a = "(( [Nim](https://nim-lang.org/) ))".toHtml
+      b = "(([Nim](https://nim-lang.org/)))".toHtml
+      c = "[[Nim](https://nim-lang.org/)]".toHtml
 
     doAssert a == """(( Nim ))"""
     doAssert b == """((Nim))"""
@@ -172,7 +201,7 @@ suite "RST/Markdown general":
 | E1 \| text   |
 |              | F2 without pipe
 not in table"""
-    let output1 = rstToHtml(input1, {roSupportMarkdown}, defaultConfig())
+    let output1 = input1.toHtml
     doAssert output1 == """
@@ -183,7 +212,7 @@ not in table"""
     let input2 = """
 | A1 header | A2 |
 | --- | --- |"""
-    let output2 = rstToHtml(input2, {roSupportMarkdown}, defaultConfig())
+    let output2 = input2.toHtml
     doAssert output2 == """
A1 headerA2 | not fooled
C1C2 bold
D1 code |D2
A1 headerA2
""" @@ -225,7 +254,7 @@ A0 A1 X let input1 = """ Check that a few punctuation symbols are not parsed as adornments: :word1: word2 .... word3 """ - let output1 = rstToHtml(input1, {roSupportMarkdown}, defaultConfig()) + let output1 = input1.toHtml discard output1 test "RST sections": @@ -233,7 +262,7 @@ Check that a few punctuation symbols are not parsed as adornments: Long chapter name ''''''''''''''''''' """ - let output1 = rstToHtml(input1, {roSupportMarkdown}, defaultConfig()) + let output1 = input1.toHtml doAssert "Long chapter name" in output1 and "Some chapter" in output6 # check that overline and underline match @@ -287,16 +317,19 @@ Some chapter Some chapter ----------- """ - expect(EParseError): - let output7 = rstToHtml(input7, {roSupportMarkdown}, defaultConfig()) + let output7 = input7.toHtml( + expectError = "input(1, 0) Error: new section expected (underline " & + "\'-----------\' does not match overline \'------------\')") let input8 = dedent """ ----------- Overflow ----------- """ - expect(EParseError): - let output8 = rstToHtml(input8, {roSupportMarkdown}, defaultConfig()) + # TODO: too many errors + let output8 = input8.toHtml( + expectError = "input(1, 0) Error: new section expected (overline " & + "\'-----------\' is too short)") # check that hierarchy of title styles works let input9good = dedent """ @@ -319,7 +352,7 @@ Some chapter ~~~~~ """ - let output9good = rstToHtml(input9good, {roSupportMarkdown}, defaultConfig()) + let output9good = input9good.toHtml doAssert "

Level1

" in output9good doAssert "

Level2

" in output9good doAssert "

Level3

" in output9good @@ -348,8 +381,11 @@ Some chapter ------- """ - expect(EParseError): - let output9Bad = rstToHtml(input9Bad, {roSupportMarkdown}, defaultConfig()) + let output9Bad = input9bad.toHtml( + expectError = "input(15, 0) Error: new section expected (section " & + "level inconsistent: underline ~~~~~ unexpectedly found, while " & + "the following intermediate section level(s) are missing on " & + "lines 12..15: underline -----)") # the same as input9good but with overline headings # first overline heading has a special meaning: document title @@ -464,7 +500,7 @@ Some chapter Want to learn about `my favorite programming language`_? .. _my favorite programming language: https://nim-lang.org""" - let output1 = rstToHtml(input1, {roSupportMarkdown}, defaultConfig()) + let output1 = input1.toHtml doAssert "" in output1 test "Markdown code block": @@ -503,7 +540,7 @@ Test literal block ``` let x = 1 ``` """ - let output1 = rstToHtml(input1, {roSupportMarkdown}, defaultConfig()) + let output1 = input1.toHtml doAssert "

Paragraph2

\n" == output2 let input3 = dedent""" @@ -563,7 +600,7 @@ Test1 | yyy | zzz""" - let output3 = rstToHtml(input3, {roSupportMarkdown}, defaultConfig()) + let output3 = input3.toHtml doAssert "xxx
" in output3 doAssert "yyy
" in output3 doAssert "zzz
" in output3 @@ -574,7 +611,7 @@ Test1 | | zzz""" - let output4 = rstToHtml(input4, {roSupportMarkdown}, defaultConfig()) + let output4 = input4.toHtml doAssert "xxx

" in output4 doAssert "zzz
" in output4 @@ -597,7 +634,7 @@ Test1 5. line5 5 """ - let output1 = rstToHtml(input1, {roSupportMarkdown}, defaultConfig()) + let output1 = input1.toHtml for i in 1..5: doAssert ($i & ". line" & $i) notin output1 doAssert ("
  • line" & $i & " " & $i & "
  • ") in output1 @@ -619,7 +656,7 @@ Test1 8. line8 """ - let output2 = rstToHtml(input2, {roSupportMarkdown}, defaultConfig()) + let output2 = input2.toHtml for i in [3, 4, 5, 7, 8]: doAssert ($i & ". line" & $i) notin output2 doAssert ("
  • line" & $i & "
  • ") in output2 @@ -629,7 +666,7 @@ Test1 1. a) string1 2. string2 """ - let output3 = rstToHtml(input3, {roSupportMarkdown}, defaultConfig()) + let output3 = input3.toHtml doAssert count(output3, "
      ") == 2 doAssert "
    1. string1
    2. " in output3 and "
    3. string2
    4. " in output3 @@ -645,7 +682,7 @@ Test1 c) string5 e) string6 """ - let output4 = rstToHtml(input4, {roSupportMarkdown}, defaultConfig()) + let output4 = input4.toHtml doAssert count(output4, "
        ") == 4 for enumerator in [9, 12]: @@ -665,7 +702,7 @@ Test1 #) string5 #) string6 """ - let output5 = rstToHtml(input5, {roSupportMarkdown}, defaultConfig()) + let output5 = input5.toHtml doAssert count(output5, "
          ") == 2 doAssert count(output5, "
        1. ") == 5 @@ -677,7 +714,7 @@ Test1 #. string2 #. string3 """ - let output5a = rstToHtml(input5a, {roSupportMarkdown}, defaultConfig()) + let output5a = input5a.toHtml doAssert count(output5a, "
            ") == 1 doAssert count(output5a, "
          1. ") == 3 @@ -689,7 +726,7 @@ Test1 #. string2 #. string3 """ - let output6 = rstToHtml(input6, {roSupportMarkdown}, defaultConfig()) + let output6 = input6.toHtml doAssert count(output6, "
              ") == 1 doAssert count(output6, "
            1. ") == 3 @@ -702,7 +739,7 @@ Test1 #. string2 #. string3 """ - let output7 = rstToHtml(input7, {roSupportMarkdown}, defaultConfig()) + let output7 = input7.toHtml doAssert count(output7, "
                ") == 1 doAssert count(output7, "
              1. ") == 3 @@ -710,12 +747,19 @@ Test1 # check that it's not recognized as enum.list without indentation on 2nd line let input8 = dedent """ + Paragraph. + A. string1 string2 """ - # TODO: find out hot to catch warning here instead of throwing a defect - expect(AssertionDefect): - let output8 = input8.toHtml + let output8 = input8.toHtml( + expectWarnings = @["input(3, 0) Warning: RST style: \n" & + """ + not enough indentation on line 4 + (if it's continuation of enumeration list), + or no blank line after line 3 (if it should be the next paragraph), + or no escaping \ at the beginning of line 3 + (if lines 3..4 are a normal paragraph, not enum. list)""".unindent(10)]) test "Markdown enumerated lists": let input1 = dedent """ @@ -729,7 +773,7 @@ Test1 #. lineA """ - let output1 = rstToHtml(input1, {roSupportMarkdown}, defaultConfig()) + let output1 = input1.toHtml for i in 1..5: doAssert ($i & ". line" & $i) notin output1 doAssert ("
              2. line" & $i & "
              3. ") in output1 @@ -755,7 +799,7 @@ Test1 * line5 5 """ - let output1 = rstToHtml(input1, {roSupportMarkdown}, defaultConfig()) + let output1 = input1.toHtml for i in 1..5: doAssert ("
              4. line" & $i & " " & $i & "
              5. ") in output1 doAssert count(output1, "
                  Paragraph1

                  " in output0 test "RST admonitions": @@ -983,7 +1031,7 @@ Test1 .. tip:: endOf tip .. warning:: endOf warning """ - let output0 = rstToHtml(input0, {roSupportMarkdown}, defaultConfig()) + let output0 = input0.toHtml for a in ["admonition", "attention", "caution", "danger", "error", "hint", "important", "note", "tip", "warning" ]: doAssert "endOf " & a & "" in output0 @@ -994,7 +1042,7 @@ Test1 Test paragraph. """ - let output1 = rstToHtml(input1, {roSupportMarkdown}, defaultConfig()) + let output1 = input1.toHtml doAssert "endOfError" in output1 doAssert "

                  Test paragraph.

                  " in output1 doAssert "class=\"admonition admonition-error\"" in output1 @@ -1006,7 +1054,7 @@ Test1 Test paragraph. """ - let output2 = rstToHtml(input2, {roSupportMarkdown}, defaultConfig()) + let output2 = input2.toHtml doAssert "endOfError Test2p." in output2 doAssert "

                  Test paragraph.

                  " in output2 doAssert "class=\"admonition admonition-error\"" in output2 @@ -1014,7 +1062,7 @@ Test1 let input3 = dedent """ .. note:: endOfNote """ - let output3 = rstToHtml(input3, {roSupportMarkdown}, defaultConfig()) + let output3 = input3.toHtml doAssert "endOfNote" in output3 doAssert "class=\"admonition admonition-info\"" in output3 @@ -1099,7 +1147,7 @@ Test1 That was a transition. """ - let output1 = rstToHtml(input1, {roSupportMarkdown}, defaultConfig()) + let output1 = input1.toHtml doAssert "

                  some definition" in output1 doAssert "Ref.