summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAndrey Makarov <ph.makarov@gmail.com>2020-12-31 13:20:04 +0300
committerGitHub <noreply@github.com>2020-12-31 11:20:04 +0100
commit5984f7a7dda5e6fb3119cd5705d5758e1b8f3fc7 (patch)
tree1a6b36185ba46ee8f846eb5e985245fcd91b7b36
parent17992fca1dc0b3674dce123296b277551bbca1db (diff)
downloadNim-5984f7a7dda5e6fb3119cd5705d5758e1b8f3fc7.tar.gz
RST: improve line blocks (#16518)
-rw-r--r--lib/packages/docutils/rst.nim24
-rw-r--r--lib/packages/docutils/rstast.nim5
-rw-r--r--lib/packages/docutils/rstgen.nim16
-rw-r--r--nimdoc/rst2html/expected/rst_examples.html2
-rw-r--r--tests/stdlib/trstgen.nim38
5 files changed, 68 insertions, 17 deletions
diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim
index 698d76da1..8d16edc61 100644
--- a/lib/packages/docutils/rst.nim
+++ b/lib/packages/docutils/rst.nim
@@ -1147,7 +1147,8 @@ proc isAdornmentHeadline(p: RstParser, adornmentIdx: int): bool =
 proc isLineBlock(p: RstParser): bool =
   var j = tokenAfterNewline(p)
   result = currentTok(p).col == p.tok[j].col and p.tok[j].symbol == "|" or
-      p.tok[j].col > currentTok(p).col
+      p.tok[j].col > currentTok(p).col or
+      p.tok[j].symbol == "\n"
 
 proc predNL(p: RstParser): bool =
   result = true
@@ -1245,21 +1246,28 @@ proc whichSection(p: RstParser): RstNodeKind =
 
 proc parseLineBlock(p: var RstParser): PRstNode =
   result = nil
-  if nextTok(p).kind == tkWhite:
+  if nextTok(p).kind in {tkWhite, tkIndent}:
     var col = currentTok(p).col
     result = newRstNode(rnLineBlock)
-    pushInd(p, p.tok[p.idx + 2].col)
-    inc p.idx, 2
     while true:
       var item = newRstNode(rnLineBlockItem)
-      parseSection(p, item)
+      if nextTok(p).kind == tkWhite:
+        if nextTok(p).symbol.len > 1:  # pass additional indentation after '| '
+          item.text = nextTok(p).symbol
+        inc p.idx, 2
+        pushInd(p, p.tok[p.idx].col)
+        parseSection(p, item)
+        popInd(p)
+      else:  # tkIndent => add an empty line
+        item.text = "\n"
+        inc p.idx, 1
       result.add(item)
       if currentTok(p).kind == tkIndent and currentTok(p).ival == col and
-          nextTok(p).symbol == "|" and p.tok[p.idx + 2].kind == tkWhite:
-        inc p.idx, 3
+          nextTok(p).symbol == "|" and
+          p.tok[p.idx + 2].kind in {tkWhite, tkIndent}:
+        inc p.idx, 1
       else:
         break
-    popInd(p)
 
 proc parseParagraph(p: var RstParser, result: PRstNode) =
   while true:
diff --git a/lib/packages/docutils/rstast.nim b/lib/packages/docutils/rstast.nim
index f01bcada1..e4e192fa3 100644
--- a/lib/packages/docutils/rstast.nim
+++ b/lib/packages/docutils/rstast.nim
@@ -35,7 +35,8 @@ type
     rnOptionList, rnOptionListItem, rnOptionGroup, rnOption, rnOptionString,
     rnOptionArgument, rnDescription, rnLiteralBlock, rnQuotedLiteralBlock,
     rnLineBlock,              # the | thingie
-    rnLineBlockItem,          # sons of the | thing
+    rnLineBlockItem,          # a son of rnLineBlock - one line inside it.
+                              # When `RstNode` text="\n" the line's empty
     rnBlockQuote,             # text just indented
     rnTable, rnGridTable, rnMarkdownTable, rnTableRow, rnTableHeaderCell, rnTableDataCell,
     rnLabel,                  # used for footnotes and other things
@@ -73,7 +74,7 @@ type
     kind*: RstNodeKind       ## the node's kind
     text*: string             ## valid for leafs in the AST; and the title of
                               ## the document or the section; and rnEnumList
-                              ## and rnAdmonition
+                              ## and rnAdmonition; and rnLineBlockItem
     level*: int               ## valid for some node kinds
     sons*: RstNodeSeq        ## the node's sons
 
diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim
index 5aa2b03d4..52125b52c 100644
--- a/lib/packages/docutils/rstgen.nim
+++ b/lib/packages/docutils/rstgen.nim
@@ -1160,9 +1160,21 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) =
   of rnQuotedLiteralBlock:
     doAssert false, "renderRstToOut"
   of rnLineBlock:
-    renderAux(d, n, "<p>$1</p>", "$1\n\n", result)
+    if n.sons.len == 1 and n.sons[0].text == "\n":
+      # whole line block is one empty line, no need to add extra spacing
+      renderAux(d, n, "<p>$1</p> ", "\n\n$1", result)
+    else:  # add extra spacing around the line block for Latex
+      renderAux(d, n, "<p>$1</p>", "\n\\vspace{0.5em}\n$1\\vspace{0.5em}\n", result)
   of rnLineBlockItem:
-    renderAux(d, n, "$1<br />", "$1\\\\\n", result)
+    if n.text.len == 0:  # normal case - no additional indentation
+      renderAux(d, n, "$1<br/>", "\\noindent $1\n\n", result)
+    elif n.text == "\n":  # add one empty line
+      renderAux(d, n, "<br/>", "\\vspace{1em}\n", result)
+    else:  # additional indentation w.r.t. '| '
+      let indent = $(0.5 * (n.text.len - 1).toFloat) & "em"
+      renderAux(d, n,
+        "<span style=\"margin-left: " & indent & "\">$1</span><br/>",
+        "\\noindent\\hspace{" & indent & "}$1\n\n", result)
   of rnBlockQuote:
     renderAux(d, n, "<blockquote><p>$1</p></blockquote>\n",
                     "\\begin{quote}$1\\end{quote}\n", result)
diff --git a/nimdoc/rst2html/expected/rst_examples.html b/nimdoc/rst2html/expected/rst_examples.html
index a95fac0bd..23d192009 100644
--- a/nimdoc/rst2html/expected/rst_examples.html
+++ b/nimdoc/rst2html/expected/rst_examples.html
@@ -215,7 +215,7 @@ stmt = IND{&gt;} stmt ^+ IND{=} DED  # list of statements
 <p>Apart from built-in operations like array indexing, memory allocation, etc. the <tt class="docutils literal"><span class="pre">raise</span></tt> statement is the only way to raise an exception.</p>
 <p><tt class="docutils literal"><span class="pre">typedesc</span></tt> used as a parameter type also introduces an implicit generic. <tt class="docutils literal"><span class="pre">typedesc</span></tt> has its own set of rules:</p>
 <p>The <tt class="docutils literal"><span class="pre">!=</span></tt>, <tt class="docutils literal"><span class="pre">&gt;</span></tt>, <tt class="docutils literal"><span class="pre">&gt;=</span></tt>, <tt class="docutils literal"><span class="pre">in</span></tt>, <tt class="docutils literal"><span class="pre">notin</span></tt>, <tt class="docutils literal"><span class="pre">isnot</span></tt> operators are in fact templates:</p>
-<p><tt class="docutils literal"><span class="pre">a &gt; b</span></tt> is transformed into <tt class="docutils literal"><span class="pre">b &lt; a</span></tt>.<br /><tt class="docutils literal"><span class="pre">a in b</span></tt> is transformed into <tt class="docutils literal"><span class="pre">contains(b, a)</span></tt>.<br /><tt class="docutils literal"><span class="pre">notin</span></tt> and <tt class="docutils literal"><span class="pre">isnot</span></tt> have the obvious meanings.<br /></p><p>A template where every parameter is <tt class="docutils literal"><span class="pre">untyped</span></tt> is called an <span id="immediate_1">immediate</span> template. For historical reasons templates can be explicitly annotated with an <tt class="docutils literal"><span class="pre">immediate</span></tt> pragma and then these templates do not take part in overloading resolution and the parameters' types are <em>ignored</em> by the compiler. Explicit immediate templates are now deprecated.</p>
+<p><tt class="docutils literal"><span class="pre">a &gt; b</span></tt> is transformed into <tt class="docutils literal"><span class="pre">b &lt; a</span></tt>.<br/><tt class="docutils literal"><span class="pre">a in b</span></tt> is transformed into <tt class="docutils literal"><span class="pre">contains(b, a)</span></tt>.<br/><tt class="docutils literal"><span class="pre">notin</span></tt> and <tt class="docutils literal"><span class="pre">isnot</span></tt> have the obvious meanings.<br/></p><p>A template where every parameter is <tt class="docutils literal"><span class="pre">untyped</span></tt> is called an <span id="immediate_1">immediate</span> template. For historical reasons templates can be explicitly annotated with an <tt class="docutils literal"><span class="pre">immediate</span></tt> pragma and then these templates do not take part in overloading resolution and the parameters' types are <em>ignored</em> by the compiler. Explicit immediate templates are now deprecated.</p>
 
 <h2><a class="toc-backref" id="constants-and-constant-expressions-symbol-lookup-in-generics" href="#constants-and-constant-expressions-symbol-lookup-in-generics">Symbol lookup in generics</a></h2>
 <h3><a class="toc-backref" id="symbol-lookup-in-generics-open-and-closed-symbols" href="#symbol-lookup-in-generics-open-and-closed-symbols">Open and Closed symbols</a></h3><p>The symbol binding rules in generics are slightly subtle: There are &quot;open&quot; and &quot;closed&quot; symbols. A &quot;closed&quot; symbol cannot be re-bound in the instantiation context, an &quot;open&quot; symbol can. Per default overloaded symbols are open and every other symbol is closed.</p>
diff --git a/tests/stdlib/trstgen.nim b/tests/stdlib/trstgen.nim
index 54a3db202..7acb23c5b 100644
--- a/tests/stdlib/trstgen.nim
+++ b/tests/stdlib/trstgen.nim
@@ -355,11 +355,41 @@ Test1
     rstGenera.renderRstToOut(rstParse(input1, "", 1, 1, option, {}), output1)
     doAssert rstGenera.meta[metaTitle] == "Test1"
       # check that title was not overwritten to '|'
-    doAssert "line block<br />" in output1
-    doAssert "other line<br />" in output1
+    doAssert output1 == "<p><br/><br/>line block<br/>other line<br/></p>"
     let output1l = rstToLatex(input1, {})
-    doAssert "line block\\\\" in output1l
-    doAssert "other line\\\\" in output1l
+    doAssert "line block\n\n" in output1l
+    doAssert "other line\n\n" in output1l
+    doAssert output1l.count("\\vspace") == 2 + 2  # +2 surrounding paddings
+
+    let input2 = dedent"""
+      Paragraph1
+      
+      |
+
+      Paragraph2"""
+
+    let output2 = rstToHtml(input2, {roSupportMarkdown}, defaultConfig())
+    doAssert "Paragraph1<p><br/></p> <p>Paragraph2</p>\n" == output2
+
+    let input3 = dedent"""
+      | xxx
+      |   yyy
+      |     zzz"""
+
+    let output3 = rstToHtml(input3, {roSupportMarkdown}, defaultConfig())
+    doAssert "xxx<br/>" in output3
+    doAssert "<span style=\"margin-left: 1.0em\">yyy</span><br/>" in output3
+    doAssert "<span style=\"margin-left: 2.0em\">zzz</span><br/>" in output3
+
+    # check that '|   ' with a few spaces is still parsed as new line
+    let input4 = dedent"""
+      | xxx
+      |      
+      |     zzz"""
+
+    let output4 = rstToHtml(input4, {roSupportMarkdown}, defaultConfig())
+    doAssert "xxx<br/><br/>" in output4
+    doAssert "<span style=\"margin-left: 2.0em\">zzz</span><br/>" in output4
 
   test "RST enumerated lists":
     let input1 = dedent """