From ea617e4e266ccdfbe916b92e8c0a70369e41c4e3 Mon Sep 17 00:00:00 2001 From: Andrey Makarov Date: Wed, 17 Mar 2021 20:08:13 +0300 Subject: [PATCH] allow short-style rst references with symbols (#17372) --- lib/packages/docutils/rst.nim | 41 +++++++++++++++++++++++++---------- tests/stdlib/trstgen.nim | 25 +++++++++++++++++++++ 2 files changed, 55 insertions(+), 11 deletions(-) diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index ea0c079daa93d..d54d7fa27aaca 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 7d5c0e28f2c27..61e4d44e76c51 100644 --- a/tests/stdlib/trstgen.nim +++ b/tests/stdlib/trstgen.nim @@ -1184,6 +1184,31 @@ Test1 doAssert "Ref. some definition" 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 = "sec.1" + let ref2 = "2-other:sec+c_2" + let ref3 = "link.1_2021" + let refline = "Ref. " & ref1 & "! and " & ref2 & ";and " & ref3 & "." + doAssert refline in output1 + suite "RST/Code highlight": test "Basic Python code highlight": let pythonCode = """