From 9a5aaadda82c5e33d481097c9c15b9c8e54e34c5 Mon Sep 17 00:00:00 2001 From: Kamanji Date: Sun, 5 Jan 2020 12:01:21 +0300 Subject: [PATCH] Rst parser respect `:start-after:` and `:end-before:` in `include` directive (#12972) * [FEATURE] rst parser respect :start-after: in include Rst parser now respects `:start-after:` and `:end-before:` attributes for `include` directive. * [DOC] include directive parsing proc update * [TEST] Added unit tests for include rst directive in `rst` module --- lib/packages/docutils/rst.nim | 49 +++++++++++++++++----- tests/stdlib/trst.nim | 79 +++++++++++++++++++++++++++++++++++ 2 files changed, 118 insertions(+), 10 deletions(-) create mode 100644 tests/stdlib/trst.nim diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index eaefc7265d0cc..50b8556629b53 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -1558,15 +1558,20 @@ proc parseDirBody(p: var RstParser, contentParser: SectionParser): PRstNode = popInd(p) proc dirInclude(p: var RstParser): PRstNode = - # - #The following options are recognized: - # - #start-after : text to find in the external data file - # Only the content after the first occurrence of the specified text will - # be included. - #end-before : text to find in the external data file - # Only the content before the first occurrence of the specified text - # (but after any after text) will be included. + ## + ## The following options are recognized: + ## + ## :start-after: text to find in the external data file + ## + ## Only the content after the first occurrence of the specified + ## text will be included. If text is not found inclusion will + ## start from beginning of the file + ## + ## :end-before: text to find in the external data file + ## + ## Only the content before the first occurrence of the specified + ## text (but after any after text) will be included. If text is + ## not found inclusion will happen until the end of the file. #literal : flag (empty) # The entire included text is inserted into the document as a single # literal block (useful for program listings). @@ -1586,10 +1591,34 @@ proc dirInclude(p: var RstParser): PRstNode = result = newRstNode(rnLiteralBlock) add(result, newRstNode(rnLeaf, readFile(path))) else: + let inputString = readFile(path).string() + let startPosition = + block: + let searchFor = n.getFieldValue("start-after").strip() + if searchFor != "": + let pos = inputString.find(searchFor) + if pos != -1: pos + searchFor.len() + else: 0 + else: + 0 + + let endPosition = + block: + let searchFor = n.getFieldValue("end-before").strip() + if searchFor != "": + let pos = inputString.find(searchFor, start = startPosition) + if pos != -1: pos - 1 + else: 0 + else: + inputString.len - 1 + var q: RstParser initParser(q, p.s) q.filename = path - q.col += getTokens(readFile(path), false, q.tok) + q.col += getTokens( + inputString[startPosition..endPosition].strip(), + false, + q.tok) # workaround a GCC bug; more like the interior pointer bug? #if find(q.tok[high(q.tok)].symbol, "\0\x01\x02") > 0: # InternalError("Too many binary zeros in include file") diff --git a/tests/stdlib/trst.nim b/tests/stdlib/trst.nim new file mode 100644 index 0000000000000..6b1bd6897cc15 --- /dev/null +++ b/tests/stdlib/trst.nim @@ -0,0 +1,79 @@ +# tests for rst module + +import ../../lib/packages/docutils/rstgen +import ../../lib/packages/docutils/rst +import unittest +import os + +suite "RST include directive": + test "Include whole": + "other.rst".writeFile("**test1**") + let input = ".. include:: other.rst" + assert "test1" == rstTohtml(input, {}, defaultConfig()) + removeFile("other.rst") + + test "Include starting from": + "other.rst".writeFile(""" +And this should **NOT** be visible in `docs.html` +OtherStart +*Visible* +""") + + let input = """ +.. include:: other.rst + :start-after: OtherStart +""" + assert "Visible" == rstTohtml(input, {}, defaultConfig()) + removeFile("other.rst") + + test "Include everything before": + "other.rst".writeFile(""" +*Visible* +OtherEnd +And this should **NOT** be visible in `docs.html` +""") + + let input = """ +.. include:: other.rst + :end-before: OtherEnd +""" + assert "Visible" == rstTohtml(input, {}, defaultConfig()) + removeFile("other.rst") + + + test "Include everything between": + "other.rst".writeFile(""" +And this should **NOT** be visible in `docs.html` +OtherStart +*Visible* +OtherEnd +And this should **NOT** be visible in `docs.html` +""") + + let input = """ +.. include:: other.rst + :start-after: OtherStart + :end-before: OtherEnd +""" + assert "Visible" == rstTohtml(input, {}, defaultConfig()) + removeFile("other.rst") + + + test "Ignore premature ending string": + "other.rst".writeFile(""" + +OtherEnd +And this should **NOT** be visible in `docs.html` +OtherStart +*Visible* +OtherEnd +And this should **NOT** be visible in `docs.html` +""") + + let input = """ +.. include:: other.rst + :start-after: OtherStart + :end-before: OtherEnd +""" + assert "Visible" == rstTohtml(input, {}, defaultConfig()) + removeFile("other.rst")