summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAndrey Makarov <ph.makarov@gmail.com>2021-03-17 20:08:13 +0300
committerGitHub <noreply@github.com>2021-03-17 18:08:13 +0100
commit144e338abb33debfa6ec6abdf3a110aade779485 (patch)
tree172c716e7165d1b34cceffd01522ff8dbd8523b4
parente9b5543bd503ffebbd7fc4b5328d8a9c69419908 (diff)
downloadNim-144e338abb33debfa6ec6abdf3a110aade779485.tar.gz
allow short-style rst references with symbols (#17372)
-rw-r--r--lib/packages/docutils/rst.nim41
-rw-r--r--tests/stdlib/trstgen.nim25
2 files changed, 55 insertions, 11 deletions
diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim
index ea0c079da..d54d7fa27 100644
--- a/lib/packages/docutils/rst.nim
+++ b/lib/packages/docutils/rst.nim
@@ -1011,14 +1011,21 @@ proc parseSmiley(p: var RstParser): PRstNode =
       result.text = val
       return
 
+proc validRefnamePunct(x: string): bool =
+  ## https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#reference-names
+  x.len == 1 and x[0] in {'-', '_', '.', ':', '+'}
+
 proc isUrl(p: RstParser, i: int): bool =
   result = p.tok[i+1].symbol == ":" and p.tok[i+2].symbol == "//" and
     p.tok[i+3].kind == tkWord and
     p.tok[i].symbol in ["http", "https", "ftp", "telnet", "file"]
 
-proc parseWordOrUrl(p: var RstParser, father: PRstNode) =
-  #if currentTok(p).symbol[strStart] == '<':
-  if isUrl(p, p.idx):
+proc parseWordOrRef(p: var RstParser, father: PRstNode) =
+  ## Parses a normal word or may be a reference or URL.
+  if nextTok(p).kind != tkPunct:  # <- main path, a normal word
+    father.add newLeaf(p)
+    inc p.idx
+  elif isUrl(p, p.idx):           # URL http://something
     var n = newRstNode(rnStandaloneHyperlink)
     while true:
       case currentTok(p).kind
@@ -1031,10 +1038,26 @@ proc parseWordOrUrl(p: var RstParser, father: PRstNode) =
       inc p.idx
     father.add(n)
   else:
-    var n = newLeaf(p)
+    # check for reference (probably, long one like some.ref.with.dots_ )
+    var saveIdx = p.idx
+    var isRef = false
     inc p.idx
-    if currentTok(p).symbol == "_": n = parsePostfix(p, n)
-    father.add(n)
+    while currentTok(p).kind in {tkWord, tkPunct}:
+      if currentTok(p).kind == tkPunct:
+        if isInlineMarkupEnd(p, "_"):
+          isRef = true
+          break
+        if not validRefnamePunct(currentTok(p).symbol):
+          break
+      inc p.idx
+    if isRef:
+      let r = newRstNode(rnRef)
+      for i in saveIdx..p.idx-1: r.add newLeaf(p.tok[i].symbol)
+      father.add r
+      inc p.idx  # skip final _
+    else:  # 1 normal word
+      father.add newLeaf(p.tok[saveIdx].symbol)
+      p.idx = saveIdx + 1
 
 proc parseBackslash(p: var RstParser, father: PRstNode) =
   assert(currentTok(p).kind == tkPunct)
@@ -1154,10 +1177,6 @@ proc getFootnoteType(label: PRstNode): (FootnoteType, int) =
   else:
     result = (fnCitation, -1)
 
-proc validRefnamePunct(x: string): bool =
-  ## https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#reference-names
-  x.len == 1 and x[0] in {'-', '_', '.', ':', '+'}
-
 proc parseFootnoteName(p: var RstParser, reference: bool): PRstNode =
   ## parse footnote/citation label. Precondition: start at `[`.
   ## Label text should be valid ref. name symbol, otherwise nil is returned.
@@ -1258,7 +1277,7 @@ proc parseInline(p: var RstParser, father: PRstNode) =
       if n != nil:
         father.add(n)
         return
-    parseWordOrUrl(p, father)
+    parseWordOrRef(p, father)
   of tkAdornment, tkOther, tkWhite:
     if roSupportMarkdown in p.s.options and currentTok(p).symbol == "```":
       inc p.idx
diff --git a/tests/stdlib/trstgen.nim b/tests/stdlib/trstgen.nim
index 7d5c0e28f..61e4d44e7 100644
--- a/tests/stdlib/trstgen.nim
+++ b/tests/stdlib/trstgen.nim
@@ -1184,6 +1184,31 @@ Test1
     doAssert "Ref. <a class=\"reference internal\" " &
         "href=\"#some-definition\">some definition</a>" in output1
 
+  test "RST references (additional symbols)":
+    # check that ., _, -, +, : are allowed symbols in references without ` `
+    let input1 = dedent """
+      sec.1
+      -----
+
+      2-other:sec+c_2
+      ^^^^^^^^^^^^^^^
+
+      .. _link.1_2021:
+
+      Paragraph
+
+      Ref. sec.1_! and 2-other:sec+c_2_;and link.1_2021_.
+    """
+    let output1 = input1.toHtml
+    doAssert "id=\"secdot1\"" in output1
+    doAssert "id=\"Z2minusothercolonsecplusc-2\"" in output1
+    doAssert "id=\"linkdot1-2021\"" in output1
+    let ref1 = "<a class=\"reference internal\" href=\"#secdot1\">sec.1</a>"
+    let ref2 = "<a class=\"reference internal\" href=\"#Z2minusothercolonsecplusc-2\">2-other:sec+c_2</a>"
+    let ref3 = "<a class=\"reference internal\" href=\"#linkdot1-2021\">link.1_2021</a>"
+    let refline = "Ref. " & ref1 & "! and " & ref2 & ";and " & ref3 & "."
+    doAssert refline in output1
+
 suite "RST/Code highlight":
   test "Basic Python code highlight":
     let pythonCode = """