trst.nim 48 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921
  1. discard """
  2. output: '''
  3. [Suite] RST parsing
  4. [Suite] RST tables
  5. [Suite] RST indentation
  6. [Suite] Markdown indentation
  7. [Suite] Warnings
  8. [Suite] RST include directive
  9. [Suite] RST escaping
  10. [Suite] RST inline markup
  11. '''
  12. matrix: "--mm:refc; --mm:orc"
  13. """
  14. # tests for rst module
  15. import ../../lib/packages/docutils/[rstgen, rst, rstast]
  16. import unittest, strutils
  17. import std/private/miscdollars
  18. import os
  19. import std/[assertions, syncio]
  20. const preferMarkdown = {roPreferMarkdown, roSupportMarkdown, roNimFile, roSandboxDisabled}
  21. # legacy nimforum / old default mode:
  22. const preferRst = {roSupportMarkdown, roNimFile, roSandboxDisabled}
  23. const pureRst = {roNimFile, roSandboxDisabled}
  24. proc toAst(input: string,
  25. rstOptions: RstParseOptions = preferMarkdown,
  26. error: ref string = nil,
  27. warnings: ref seq[string] = nil): string =
  28. ## If `error` is nil then no errors should be generated.
  29. ## The same goes for `warnings`.
  30. proc testMsgHandler(filename: string, line, col: int, msgkind: MsgKind,
  31. arg: string) =
  32. let mc = msgkind.whichMsgClass
  33. let a = $msgkind % arg
  34. var message: string
  35. toLocation(message, filename, line, col + ColRstOffset)
  36. message.add " $1: $2" % [$mc, a]
  37. if mc == mcError:
  38. if error == nil:
  39. raise newException(EParseError, "[unexpected error] " & message)
  40. error[] = message
  41. # we check only first error because subsequent ones may be meaningless
  42. raise newException(EParseError, "")
  43. else:
  44. doAssert warnings != nil, "unexpected RST warning '" & message & "'"
  45. warnings[].add message
  46. try:
  47. const filen = "input"
  48. proc myFindFile(filename: string): string =
  49. # we don't find any files in online mode:
  50. result = ""
  51. var (rst, _, _) = rstParse(input, filen, line=LineRstInit, column=ColRstInit,
  52. rstOptions, myFindFile, nil, testMsgHandler)
  53. result = treeRepr(rst)
  54. except EParseError as e:
  55. if e.msg != "":
  56. result = e.msg
  57. suite "RST parsing":
  58. test "Standalone punctuation is not parsed as heading overlines":
  59. check(dedent"""
  60. Paragraph
  61. !""".toAst ==
  62. dedent"""
  63. rnInner
  64. rnParagraph
  65. rnLeaf 'Paragraph'
  66. rnParagraph
  67. rnLeaf '!'
  68. """)
  69. check(dedent"""
  70. Paragraph1
  71. ...
  72. Paragraph2""".toAst ==
  73. dedent"""
  74. rnInner
  75. rnParagraph
  76. rnLeaf 'Paragraph1'
  77. rnParagraph
  78. rnLeaf '...'
  79. rnParagraph
  80. rnLeaf 'Paragraph2'
  81. """)
  82. check(dedent"""
  83. ---
  84. Paragraph""".toAst ==
  85. dedent"""
  86. rnInner
  87. rnLeaf '---'
  88. rnLeaf ' '
  89. rnLeaf 'Paragraph'
  90. """)
  91. test "References are whitespace-neutral and case-insensitive":
  92. # refname is 'lexical-analysis', the same for all the 3 variants:
  93. check(dedent"""
  94. Lexical Analysis
  95. ================
  96. Ref. `Lexical Analysis`_ or `Lexical analysis`_ or `lexical analysis`_.
  97. """.toAst ==
  98. dedent"""
  99. rnInner
  100. rnHeadline level=1 anchor='lexical-analysis'
  101. rnLeaf 'Lexical'
  102. rnLeaf ' '
  103. rnLeaf 'Analysis'
  104. rnParagraph
  105. rnLeaf 'Ref'
  106. rnLeaf '.'
  107. rnLeaf ' '
  108. rnInternalRef
  109. rnInner
  110. rnLeaf 'Lexical'
  111. rnLeaf ' '
  112. rnLeaf 'Analysis'
  113. rnLeaf 'lexical-analysis'
  114. rnLeaf ' '
  115. rnLeaf 'or'
  116. rnLeaf ' '
  117. rnInternalRef
  118. rnInner
  119. rnLeaf 'Lexical'
  120. rnLeaf ' '
  121. rnLeaf 'analysis'
  122. rnLeaf 'lexical-analysis'
  123. rnLeaf ' '
  124. rnLeaf 'or'
  125. rnLeaf ' '
  126. rnInternalRef
  127. rnInner
  128. rnLeaf 'lexical'
  129. rnLeaf ' '
  130. rnLeaf 'analysis'
  131. rnLeaf 'lexical-analysis'
  132. rnLeaf '.'
  133. rnLeaf ' '
  134. """)
  135. test "RST quoted literal blocks":
  136. let expected =
  137. dedent"""
  138. rnInner
  139. rnLeaf 'Paragraph'
  140. rnLeaf ':'
  141. rnLiteralBlock
  142. rnLeaf '>x'
  143. """
  144. check(dedent"""
  145. Paragraph::
  146. >x""".toAst(rstOptions = preferRst) == expected)
  147. check(dedent"""
  148. Paragraph::
  149. >x""".toAst(rstOptions = preferRst) == expected)
  150. test "RST quoted literal blocks, :: at a separate line":
  151. let expected =
  152. dedent"""
  153. rnInner
  154. rnInner
  155. rnLeaf 'Paragraph'
  156. rnLiteralBlock
  157. rnLeaf '>x
  158. >>y'
  159. """
  160. check(dedent"""
  161. Paragraph
  162. ::
  163. >x
  164. >>y""".toAst(rstOptions = preferRst) == expected)
  165. check(dedent"""
  166. Paragraph
  167. ::
  168. >x
  169. >>y""".toAst(rstOptions = preferRst) == expected)
  170. test "Markdown quoted blocks":
  171. check(dedent"""
  172. Paragraph.
  173. >x""".toAst ==
  174. dedent"""
  175. rnInner
  176. rnLeaf 'Paragraph'
  177. rnLeaf '.'
  178. rnMarkdownBlockQuote
  179. rnMarkdownBlockQuoteItem quotationDepth=1
  180. rnLeaf 'x'
  181. """)
  182. # bug #17987
  183. check(dedent"""
  184. foo https://github.com/nim-lang/Nim/issues/8258
  185. > bar""".toAst ==
  186. dedent"""
  187. rnInner
  188. rnInner
  189. rnLeaf 'foo'
  190. rnLeaf ' '
  191. rnStandaloneHyperlink
  192. rnLeaf 'https://github.com/nim-lang/Nim/issues/8258'
  193. rnMarkdownBlockQuote
  194. rnMarkdownBlockQuoteItem quotationDepth=1
  195. rnLeaf 'bar'
  196. """)
  197. let expected = dedent"""
  198. rnInner
  199. rnLeaf 'Paragraph'
  200. rnLeaf '.'
  201. rnMarkdownBlockQuote
  202. rnMarkdownBlockQuoteItem quotationDepth=1
  203. rnInner
  204. rnLeaf 'x1'
  205. rnLeaf ' '
  206. rnLeaf 'x2'
  207. rnMarkdownBlockQuoteItem quotationDepth=2
  208. rnInner
  209. rnLeaf 'y1'
  210. rnLeaf ' '
  211. rnLeaf 'y2'
  212. rnMarkdownBlockQuoteItem quotationDepth=1
  213. rnLeaf 'z'
  214. """
  215. check(dedent"""
  216. Paragraph.
  217. >x1 x2
  218. >>y1 y2
  219. >z""".toAst == expected)
  220. check(dedent"""
  221. Paragraph.
  222. > x1 x2
  223. >> y1 y2
  224. > z""".toAst == expected)
  225. check(dedent"""
  226. >x
  227. >y
  228. >z""".toAst ==
  229. dedent"""
  230. rnMarkdownBlockQuote
  231. rnMarkdownBlockQuoteItem quotationDepth=1
  232. rnInner
  233. rnLeaf 'x'
  234. rnLeaf ' '
  235. rnLeaf 'y'
  236. rnLeaf ' '
  237. rnLeaf 'z'
  238. """)
  239. check(dedent"""
  240. > z
  241. > > >y
  242. """.toAst ==
  243. dedent"""
  244. rnMarkdownBlockQuote
  245. rnMarkdownBlockQuoteItem quotationDepth=1
  246. rnLeaf 'z'
  247. rnMarkdownBlockQuoteItem quotationDepth=3
  248. rnLeaf 'y'
  249. """)
  250. test "Markdown quoted blocks: lazy":
  251. let expected = dedent"""
  252. rnInner
  253. rnMarkdownBlockQuote
  254. rnMarkdownBlockQuoteItem quotationDepth=2
  255. rnInner
  256. rnLeaf 'x'
  257. rnLeaf ' '
  258. rnLeaf 'continuation1'
  259. rnLeaf ' '
  260. rnLeaf 'continuation2'
  261. rnParagraph
  262. rnLeaf 'newParagraph'
  263. """
  264. check(dedent"""
  265. >>x
  266. continuation1
  267. continuation2
  268. newParagraph""".toAst == expected)
  269. check(dedent"""
  270. >> x
  271. continuation1
  272. continuation2
  273. newParagraph""".toAst == expected)
  274. # however mixing more than 1 non-lazy line and lazy one(s) splits quote
  275. # in our parser, which appeared the easiest way to handle such cases:
  276. var warnings = new seq[string]
  277. check(dedent"""
  278. >> x
  279. >> continuation1
  280. continuation2
  281. newParagraph""".toAst(warnings=warnings) ==
  282. dedent"""
  283. rnInner
  284. rnMarkdownBlockQuote
  285. rnMarkdownBlockQuoteItem quotationDepth=2
  286. rnLeaf 'x'
  287. rnMarkdownBlockQuoteItem quotationDepth=2
  288. rnInner
  289. rnLeaf 'continuation1'
  290. rnLeaf ' '
  291. rnLeaf 'continuation2'
  292. rnParagraph
  293. rnLeaf 'newParagraph'
  294. """)
  295. check(warnings[] == @[
  296. "input(2, 1) Warning: RST style: two or more quoted lines " &
  297. "are followed by unquoted line 3"])
  298. test "Markdown quoted blocks: not lazy":
  299. # here is where we deviate from CommonMark specification: 'bar' below is
  300. # not considered as continuation of 2-level '>> foo' quote.
  301. check(dedent"""
  302. >>> foo
  303. > bar
  304. >> baz
  305. """.toAst() ==
  306. dedent"""
  307. rnMarkdownBlockQuote
  308. rnMarkdownBlockQuoteItem quotationDepth=3
  309. rnLeaf 'foo'
  310. rnMarkdownBlockQuoteItem quotationDepth=1
  311. rnLeaf 'bar'
  312. rnMarkdownBlockQuoteItem quotationDepth=2
  313. rnLeaf 'baz'
  314. """)
  315. test "Markdown quoted blocks: inline markup works":
  316. check(dedent"""
  317. > hi **bold** text
  318. """.toAst == dedent"""
  319. rnMarkdownBlockQuote
  320. rnMarkdownBlockQuoteItem quotationDepth=1
  321. rnInner
  322. rnLeaf 'hi'
  323. rnLeaf ' '
  324. rnStrongEmphasis
  325. rnLeaf 'bold'
  326. rnLeaf ' '
  327. rnLeaf 'text'
  328. """)
  329. test "Markdown quoted blocks: blank line separator":
  330. let expected = dedent"""
  331. rnInner
  332. rnMarkdownBlockQuote
  333. rnMarkdownBlockQuoteItem quotationDepth=1
  334. rnInner
  335. rnLeaf 'x'
  336. rnLeaf ' '
  337. rnLeaf 'y'
  338. rnMarkdownBlockQuote
  339. rnMarkdownBlockQuoteItem quotationDepth=1
  340. rnInner
  341. rnLeaf 'z'
  342. rnLeaf ' '
  343. rnLeaf 't'
  344. """
  345. check(dedent"""
  346. >x
  347. >y
  348. > z
  349. > t""".toAst == expected)
  350. check(dedent"""
  351. >x
  352. y
  353. > z
  354. t""".toAst == expected)
  355. test "Markdown quoted blocks: nested body blocks/elements work #1":
  356. let expected = dedent"""
  357. rnMarkdownBlockQuote
  358. rnMarkdownBlockQuoteItem quotationDepth=1
  359. rnBulletList
  360. rnBulletItem
  361. rnInner
  362. rnLeaf 'x'
  363. rnBulletItem
  364. rnInner
  365. rnLeaf 'y'
  366. """
  367. check(dedent"""
  368. > - x
  369. - y
  370. """.toAst == expected)
  371. # TODO: if bug #17340 point 28 is resolved then this may work:
  372. # check(dedent"""
  373. # > - x
  374. # - y
  375. # """.toAst == expected)
  376. check(dedent"""
  377. > - x
  378. > - y
  379. """.toAst == expected)
  380. check(dedent"""
  381. >
  382. > - x
  383. >
  384. > - y
  385. >
  386. """.toAst == expected)
  387. test "Markdown quoted blocks: nested body blocks/elements work #2":
  388. let expected = dedent"""
  389. rnAdmonition adType=note
  390. [nil]
  391. [nil]
  392. rnDefList
  393. rnDefItem
  394. rnDefName
  395. rnLeaf 'deflist'
  396. rnLeaf ':'
  397. rnDefBody
  398. rnMarkdownBlockQuote
  399. rnMarkdownBlockQuoteItem quotationDepth=2
  400. rnInner
  401. rnLeaf 'quote'
  402. rnLeaf ' '
  403. rnLeaf 'continuation'
  404. """
  405. check(dedent"""
  406. .. Note:: deflist:
  407. >> quote
  408. continuation
  409. """.toAst(rstOptions = preferRst) == expected)
  410. check(dedent"""
  411. .. Note::
  412. deflist:
  413. >> quote
  414. continuation
  415. """.toAst(rstOptions = preferRst) == expected)
  416. check(dedent"""
  417. .. Note::
  418. deflist:
  419. >> quote
  420. >> continuation
  421. """.toAst(rstOptions = preferRst) == expected)
  422. # spaces are not significant between `>`:
  423. check(dedent"""
  424. .. Note::
  425. deflist:
  426. > > quote
  427. > > continuation
  428. """.toAst(rstOptions = preferRst) == expected)
  429. test "Markdown quoted blocks: de-indent handled well":
  430. check(dedent"""
  431. >
  432. > - x
  433. > - y
  434. >
  435. > Paragraph.
  436. """.toAst(rstOptions = preferRst) == dedent"""
  437. rnMarkdownBlockQuote
  438. rnMarkdownBlockQuoteItem quotationDepth=1
  439. rnInner
  440. rnBlockQuote
  441. rnBulletList
  442. rnBulletItem
  443. rnInner
  444. rnLeaf 'x'
  445. rnBulletItem
  446. rnInner
  447. rnLeaf 'y'
  448. rnParagraph
  449. rnLeaf 'Paragraph'
  450. rnLeaf '.'
  451. """)
  452. let expectCodeBlock = dedent"""
  453. rnCodeBlock
  454. [nil]
  455. rnFieldList
  456. rnField
  457. rnFieldName
  458. rnLeaf 'default-language'
  459. rnFieldBody
  460. rnLeaf 'Nim'
  461. rnLiteralBlock
  462. rnLeaf '
  463. let a = 1
  464. ```'
  465. """
  466. test "Markdown code blocks with more > 3 backticks":
  467. check(dedent"""
  468. ````
  469. let a = 1
  470. ```
  471. ````""".toAst == expectCodeBlock)
  472. test "Markdown code blocks with ~~~":
  473. check(dedent"""
  474. ~~~
  475. let a = 1
  476. ```
  477. ~~~""".toAst == expectCodeBlock)
  478. check(dedent"""
  479. ~~~~~
  480. let a = 1
  481. ```
  482. ~~~~~""".toAst == expectCodeBlock)
  483. test "Markdown code blocks with Nim-specific arguments":
  484. check(dedent"""
  485. ```nim number-lines=1 test
  486. let a = 1
  487. ```""".toAst ==
  488. dedent"""
  489. rnCodeBlock
  490. rnDirArg
  491. rnLeaf 'nim'
  492. rnFieldList
  493. rnField
  494. rnFieldName
  495. rnLeaf 'number-lines'
  496. rnFieldBody
  497. rnLeaf '1'
  498. rnField
  499. rnFieldName
  500. rnLeaf 'test'
  501. rnFieldBody
  502. rnLiteralBlock
  503. rnLeaf '
  504. let a = 1'
  505. """)
  506. check(dedent"""
  507. ```nim test = "nim c $1" number-lines = 1
  508. let a = 1
  509. ```""".toAst ==
  510. dedent"""
  511. rnCodeBlock
  512. rnDirArg
  513. rnLeaf 'nim'
  514. rnFieldList
  515. rnField
  516. rnFieldName
  517. rnLeaf 'test'
  518. rnFieldBody
  519. rnLeaf '"nim c $1"'
  520. rnField
  521. rnFieldName
  522. rnLeaf 'number-lines'
  523. rnFieldBody
  524. rnLeaf '1'
  525. rnLiteralBlock
  526. rnLeaf '
  527. let a = 1'
  528. """)
  529. test "additional indentation < 4 spaces is handled fine":
  530. check(dedent"""
  531. Indentation
  532. ```nim
  533. let a = 1
  534. ```""".toAst ==
  535. dedent"""
  536. rnInner
  537. rnParagraph
  538. rnLeaf 'Indentation'
  539. rnParagraph
  540. rnCodeBlock
  541. rnDirArg
  542. rnLeaf 'nim'
  543. [nil]
  544. rnLiteralBlock
  545. rnLeaf '
  546. let a = 1'
  547. """)
  548. # | |
  549. # | \ indentation of exactly two spaces before 'let a = 1'
  550. test "no blank line is required before or after Markdown code block":
  551. let inputBacktick = dedent"""
  552. Some text
  553. ```
  554. CodeBlock()
  555. ```
  556. Other text"""
  557. let inputTilde = dedent"""
  558. Some text
  559. ~~~~~~~~~
  560. CodeBlock()
  561. ~~~~~~~~~
  562. Other text"""
  563. let expected = dedent"""
  564. rnInner
  565. rnParagraph
  566. rnLeaf 'Some'
  567. rnLeaf ' '
  568. rnLeaf 'text'
  569. rnParagraph
  570. rnCodeBlock
  571. [nil]
  572. rnFieldList
  573. rnField
  574. rnFieldName
  575. rnLeaf 'default-language'
  576. rnFieldBody
  577. rnLeaf 'Nim'
  578. rnLiteralBlock
  579. rnLeaf '
  580. CodeBlock()'
  581. rnLeaf ' '
  582. rnLeaf 'Other'
  583. rnLeaf ' '
  584. rnLeaf 'text'
  585. """
  586. check inputBacktick.toAst == expected
  587. check inputTilde.toAst == expected
  588. test "option list has priority over definition list":
  589. for opt in [preferMarkdown, preferRst]:
  590. check(dedent"""
  591. --defusages
  592. file
  593. -o set
  594. """.toAst(rstOptions = opt) ==
  595. dedent"""
  596. rnOptionList
  597. rnOptionListItem order=1
  598. rnOptionGroup
  599. rnLeaf '--'
  600. rnLeaf 'defusages'
  601. rnDescription
  602. rnInner
  603. rnLeaf 'file'
  604. rnOptionListItem order=2
  605. rnOptionGroup
  606. rnLeaf '-'
  607. rnLeaf 'o'
  608. rnDescription
  609. rnLeaf 'set'
  610. """)
  611. test "items of 1 option list can be separated by blank lines":
  612. check(dedent"""
  613. -a desc1
  614. -b desc2
  615. """.toAst ==
  616. dedent"""
  617. rnOptionList
  618. rnOptionListItem order=1
  619. rnOptionGroup
  620. rnLeaf '-'
  621. rnLeaf 'a'
  622. rnDescription
  623. rnLeaf 'desc1'
  624. rnOptionListItem order=2
  625. rnOptionGroup
  626. rnLeaf '-'
  627. rnLeaf 'b'
  628. rnDescription
  629. rnLeaf 'desc2'
  630. """)
  631. test "definition list does not gobble up the following blocks":
  632. check(dedent"""
  633. defName
  634. defBody
  635. -b desc2
  636. """.toAst(rstOptions = preferRst) ==
  637. dedent"""
  638. rnInner
  639. rnDefList
  640. rnDefItem
  641. rnDefName
  642. rnLeaf 'defName'
  643. rnDefBody
  644. rnInner
  645. rnLeaf 'defBody'
  646. rnOptionList
  647. rnOptionListItem order=1
  648. rnOptionGroup
  649. rnLeaf '-'
  650. rnLeaf 'b'
  651. rnDescription
  652. rnLeaf 'desc2'
  653. """)
  654. test "definition lists work correctly with additional indentation in Markdown":
  655. check(dedent"""
  656. Paragraph:
  657. -c desc1
  658. -b desc2
  659. """.toAst() ==
  660. dedent"""
  661. rnInner
  662. rnInner
  663. rnLeaf 'Paragraph'
  664. rnLeaf ':'
  665. rnOptionList
  666. rnOptionListItem order=1
  667. rnOptionGroup
  668. rnLeaf '-'
  669. rnLeaf 'c'
  670. rnDescription
  671. rnLeaf 'desc1'
  672. rnOptionListItem order=2
  673. rnOptionGroup
  674. rnLeaf '-'
  675. rnLeaf 'b'
  676. rnDescription
  677. rnLeaf 'desc2'
  678. """)
  679. test "RST comment":
  680. check(dedent"""
  681. .. comment1
  682. comment2
  683. someParagraph""".toAst ==
  684. dedent"""
  685. rnLeaf 'someParagraph'
  686. """)
  687. check(dedent"""
  688. ..
  689. comment1
  690. comment2
  691. someParagraph""".toAst ==
  692. dedent"""
  693. rnLeaf 'someParagraph'
  694. """)
  695. test "check that additional line right after .. ends comment":
  696. check(dedent"""
  697. ..
  698. notAcomment1
  699. notAcomment2
  700. someParagraph""".toAst(rstOptions = preferRst) ==
  701. dedent"""
  702. rnInner
  703. rnBlockQuote
  704. rnInner
  705. rnLeaf 'notAcomment1'
  706. rnLeaf ' '
  707. rnLeaf 'notAcomment2'
  708. rnParagraph
  709. rnLeaf 'someParagraph'
  710. """)
  711. test "check that additional line right after .. ends comment (Markdown mode)":
  712. # in Markdown small indentation does not matter so this should
  713. # just be split to 2 paragraphs.
  714. check(dedent"""
  715. ..
  716. notAcomment1
  717. notAcomment2
  718. someParagraph""".toAst ==
  719. dedent"""
  720. rnInner
  721. rnInner
  722. rnLeaf 'notAcomment1'
  723. rnLeaf ' '
  724. rnLeaf 'notAcomment2'
  725. rnParagraph
  726. rnLeaf 'someParagraph'
  727. """)
  728. test "but blank lines after 2nd non-empty line don't end the comment":
  729. check(dedent"""
  730. ..
  731. comment1
  732. comment2
  733. someParagraph""".toAst ==
  734. dedent"""
  735. rnLeaf 'someParagraph'
  736. """)
  737. test "using .. as separator b/w directives and block quotes":
  738. check(dedent"""
  739. .. note:: someNote
  740. ..
  741. someBlockQuote""".toAst(rstOptions = preferRst) ==
  742. dedent"""
  743. rnInner
  744. rnAdmonition adType=note
  745. [nil]
  746. [nil]
  747. rnLeaf 'someNote'
  748. rnBlockQuote
  749. rnInner
  750. rnLeaf 'someBlockQuote'
  751. """)
  752. test "no redundant blank lines in literal blocks":
  753. check(dedent"""
  754. Check::
  755. code
  756. """.toAst(rstOptions = preferRst) ==
  757. dedent"""
  758. rnInner
  759. rnLeaf 'Check'
  760. rnLeaf ':'
  761. rnLiteralBlock
  762. rnLeaf 'code'
  763. """)
  764. test "Markdown indented code blocks":
  765. check(dedent"""
  766. See
  767. some code""".toAst ==
  768. dedent"""
  769. rnInner
  770. rnInner
  771. rnLeaf 'See'
  772. rnLiteralBlock
  773. rnLeaf 'some code'
  774. """)
  775. # not a code block -- no blank line before:
  776. check(dedent"""
  777. See
  778. some code""".toAst ==
  779. dedent"""
  780. rnInner
  781. rnLeaf 'See'
  782. rnLeaf ' '
  783. rnLeaf 'some'
  784. rnLeaf ' '
  785. rnLeaf 'code'
  786. """)
  787. suite "RST tables":
  788. test "formatting in tables works":
  789. check(
  790. dedent"""
  791. ========= ===
  792. `build` `a`
  793. ========= ===
  794. """.toAst ==
  795. dedent"""
  796. rnTable colCount=2
  797. rnTableRow
  798. rnTableDataCell
  799. rnInlineCode
  800. rnDirArg
  801. rnLeaf 'nim'
  802. [nil]
  803. rnLiteralBlock
  804. rnLeaf 'build'
  805. rnTableDataCell
  806. rnInlineCode
  807. rnDirArg
  808. rnLeaf 'nim'
  809. [nil]
  810. rnLiteralBlock
  811. rnLeaf 'a'
  812. """)
  813. test "tables with slightly overflowed cells cause an error (1)":
  814. var error = new string
  815. check(
  816. dedent"""
  817. ====== ======
  818. Inputs Output
  819. ====== ======
  820. """.toAst(rstOptions = pureRst, error = error) == "")
  821. check(error[] == "input(2, 2) Error: Illformed table: " &
  822. "this word crosses table column from the right")
  823. # In nimforum compatibility mode & Markdown we raise a warning instead:
  824. let expected = dedent"""
  825. rnTable colCount=2
  826. rnTableRow
  827. rnTableDataCell
  828. rnLeaf 'Inputs'
  829. rnTableDataCell
  830. rnLeaf 'Output'
  831. """
  832. for opt in [preferRst, preferMarkdown]:
  833. var warnings = new seq[string]
  834. check(
  835. dedent"""
  836. ====== ======
  837. Inputs Output
  838. ====== ======
  839. """.toAst(rstOptions = opt, warnings = warnings) == expected)
  840. check(warnings[] == @[
  841. "input(2, 2) Warning: RST style: this word crosses table column from the right"])
  842. test "tables with slightly overflowed cells cause an error (2)":
  843. var error = new string
  844. check("" == dedent"""
  845. ===== ===== ======
  846. Input Output
  847. ===== ===== ======
  848. False False False
  849. ===== ===== ======
  850. """.toAst(rstOptions = pureRst, error = error))
  851. check(error[] == "input(2, 8) Error: Illformed table: " &
  852. "this word crosses table column from the right")
  853. test "tables with slightly underflowed cells cause an error":
  854. var error = new string
  855. check("" == dedent"""
  856. ===== ===== ======
  857. Input Output
  858. ===== ===== ======
  859. False False False
  860. ===== ===== ======
  861. """.toAst(rstOptions = pureRst, error = error))
  862. check(error[] == "input(2, 7) Error: Illformed table: " &
  863. "this word crosses table column from the left")
  864. test "tables with unequal underlines should be reported (1)":
  865. var error = new string
  866. error[] = "none"
  867. check("" == dedent"""
  868. ===== ======
  869. Input Output
  870. ===== ======
  871. False False
  872. ===== =======
  873. """.toAst(rstOptions = pureRst, error = error))
  874. check(error[] == "input(5, 14) Error: Illformed table: " &
  875. "end of table column #2 should end at position 13")
  876. test "tables with unequal underlines should be reported (2)":
  877. var error = new string
  878. check("" == dedent"""
  879. ===== ======
  880. Input Output
  881. ===== =======
  882. False False
  883. ===== ======
  884. """.toAst(rstOptions = pureRst, error = error))
  885. check(error[] == "input(3, 14) Error: Illformed table: " &
  886. "end of table column #2 should end at position 13")
  887. test "tables with empty first cells":
  888. check(
  889. dedent"""
  890. = = =
  891. x y z
  892. t
  893. = = =
  894. """.toAst ==
  895. dedent"""
  896. rnTable colCount=3
  897. rnTableRow
  898. rnTableDataCell
  899. rnLeaf 'x'
  900. rnTableDataCell
  901. rnInner
  902. rnLeaf 'y'
  903. rnLeaf ' '
  904. rnTableDataCell
  905. rnInner
  906. rnLeaf 'z'
  907. rnLeaf ' '
  908. rnLeaf 't'
  909. """)
  910. test "tables with spanning cells & separators":
  911. check(
  912. dedent"""
  913. ===== ===== ======
  914. Inputs Output
  915. ------------ ------
  916. A B A or B
  917. ===== ===== ======
  918. False False False
  919. True False True
  920. ----- ----- ------
  921. False True True
  922. True True True
  923. ===== ===== ======
  924. """.toAst ==
  925. dedent"""
  926. rnTable colCount=3
  927. rnTableRow
  928. rnTableHeaderCell span=2
  929. rnLeaf 'Inputs'
  930. rnTableHeaderCell span=1
  931. rnLeaf 'Output'
  932. rnTableRow endsHeader
  933. rnTableHeaderCell
  934. rnLeaf 'A'
  935. rnTableHeaderCell
  936. rnLeaf 'B'
  937. rnTableHeaderCell
  938. rnInner
  939. rnLeaf 'A'
  940. rnLeaf ' '
  941. rnLeaf 'or'
  942. rnLeaf ' '
  943. rnLeaf 'B'
  944. rnTableRow
  945. rnTableDataCell
  946. rnLeaf 'False'
  947. rnTableDataCell
  948. rnLeaf 'False'
  949. rnTableDataCell
  950. rnLeaf 'False'
  951. rnTableRow
  952. rnTableDataCell span=1
  953. rnLeaf 'True'
  954. rnTableDataCell span=1
  955. rnLeaf 'False'
  956. rnTableDataCell span=1
  957. rnLeaf 'True'
  958. rnTableRow
  959. rnTableDataCell
  960. rnLeaf 'False'
  961. rnTableDataCell
  962. rnLeaf 'True'
  963. rnTableDataCell
  964. rnLeaf 'True'
  965. rnTableRow
  966. rnTableDataCell
  967. rnLeaf 'True'
  968. rnTableDataCell
  969. rnLeaf 'True'
  970. rnTableDataCell
  971. rnLeaf 'True'
  972. """)
  973. test "tables with spanning cells with uneqal underlines cause an error":
  974. var error = new string
  975. check(
  976. dedent"""
  977. ===== ===== ======
  978. Inputs Output
  979. ------------- ------
  980. A B A or B
  981. ===== ===== ======
  982. """.toAst(error=error) == "")
  983. check(error[] == "input(3, 1) Error: Illformed table: " &
  984. "spanning underline does not match main table columns")
  985. let expTable = dedent"""
  986. rnTable colCount=2
  987. rnTableRow
  988. rnTableDataCell
  989. rnLeaf 'Inputs'
  990. rnTableDataCell
  991. rnLeaf 'Output'
  992. """
  993. test "only tables with `=` columns specs are allowed (1)":
  994. var warnings = new seq[string]
  995. check(
  996. dedent"""
  997. ------ ------
  998. Inputs Output
  999. ------ ------
  1000. """.toAst(warnings=warnings) ==
  1001. expTable)
  1002. check(warnings[] ==
  1003. @["input(1, 1) Warning: RST style: " &
  1004. "only tables with `=` columns specification are allowed",
  1005. "input(3, 1) Warning: RST style: " &
  1006. "only tables with `=` columns specification are allowed"])
  1007. test "only tables with `=` columns specs are allowed (2)":
  1008. var warnings = new seq[string]
  1009. check(
  1010. dedent"""
  1011. ====== ======
  1012. Inputs Output
  1013. ~~~~~~ ~~~~~~
  1014. """.toAst(warnings=warnings) ==
  1015. expTable)
  1016. check(warnings[] ==
  1017. @["input(3, 1) Warning: RST style: "&
  1018. "only tables with `=` columns specification are allowed"])
  1019. suite "RST indentation":
  1020. test "nested bullet lists":
  1021. let input = dedent """
  1022. * - bullet1
  1023. - bullet2
  1024. * - bullet3
  1025. - bullet4
  1026. """
  1027. let output = input.toAst
  1028. check(output == dedent"""
  1029. rnBulletList
  1030. rnBulletItem
  1031. rnBulletList
  1032. rnBulletItem
  1033. rnInner
  1034. rnLeaf 'bullet1'
  1035. rnBulletItem
  1036. rnInner
  1037. rnLeaf 'bullet2'
  1038. rnBulletItem
  1039. rnBulletList
  1040. rnBulletItem
  1041. rnInner
  1042. rnLeaf 'bullet3'
  1043. rnBulletItem
  1044. rnInner
  1045. rnLeaf 'bullet4'
  1046. """)
  1047. test "nested markup blocks":
  1048. let input = dedent"""
  1049. #) .. Hint:: .. Error:: none
  1050. #) .. Warning:: term0
  1051. Definition0
  1052. #) some
  1053. paragraph1
  1054. #) term1
  1055. Definition1
  1056. term2
  1057. Definition2
  1058. """
  1059. check(input.toAst(rstOptions = preferRst) == dedent"""
  1060. rnEnumList labelFmt=1)
  1061. rnEnumItem
  1062. rnAdmonition adType=hint
  1063. [nil]
  1064. [nil]
  1065. rnAdmonition adType=error
  1066. [nil]
  1067. [nil]
  1068. rnLeaf 'none'
  1069. rnEnumItem
  1070. rnAdmonition adType=warning
  1071. [nil]
  1072. [nil]
  1073. rnDefList
  1074. rnDefItem
  1075. rnDefName
  1076. rnLeaf 'term0'
  1077. rnDefBody
  1078. rnInner
  1079. rnLeaf 'Definition0'
  1080. rnEnumItem
  1081. rnInner
  1082. rnLeaf 'some'
  1083. rnLeaf ' '
  1084. rnLeaf 'paragraph1'
  1085. rnEnumItem
  1086. rnDefList
  1087. rnDefItem
  1088. rnDefName
  1089. rnLeaf 'term1'
  1090. rnDefBody
  1091. rnInner
  1092. rnLeaf 'Definition1'
  1093. rnDefItem
  1094. rnDefName
  1095. rnLeaf 'term2'
  1096. rnDefBody
  1097. rnInner
  1098. rnLeaf 'Definition2'
  1099. """)
  1100. test "code-block parsing":
  1101. let input1 = dedent"""
  1102. .. code-block:: nim
  1103. :test: "nim c $1"
  1104. template additive(typ: typedesc) =
  1105. discard
  1106. """
  1107. let input2 = dedent"""
  1108. .. code-block:: nim
  1109. :test: "nim c $1"
  1110. template additive(typ: typedesc) =
  1111. discard
  1112. """
  1113. let input3 = dedent"""
  1114. .. code-block:: nim
  1115. :test: "nim c $1"
  1116. template additive(typ: typedesc) =
  1117. discard
  1118. """
  1119. let inputWrong = dedent"""
  1120. .. code-block:: nim
  1121. :test: "nim c $1"
  1122. template additive(typ: typedesc) =
  1123. discard
  1124. """
  1125. let ast = dedent"""
  1126. rnCodeBlock
  1127. rnDirArg
  1128. rnLeaf 'nim'
  1129. rnFieldList
  1130. rnField
  1131. rnFieldName
  1132. rnLeaf 'test'
  1133. rnFieldBody
  1134. rnInner
  1135. rnLeaf '"'
  1136. rnLeaf 'nim'
  1137. rnLeaf ' '
  1138. rnLeaf 'c'
  1139. rnLeaf ' '
  1140. rnLeaf '$'
  1141. rnLeaf '1'
  1142. rnLeaf '"'
  1143. rnField
  1144. rnFieldName
  1145. rnLeaf 'default-language'
  1146. rnFieldBody
  1147. rnLeaf 'Nim'
  1148. rnLiteralBlock
  1149. rnLeaf 'template additive(typ: typedesc) =
  1150. discard'
  1151. """
  1152. check input1.toAst == ast
  1153. check input2.toAst == ast
  1154. check input3.toAst == ast
  1155. # "template..." should be parsed as a definition list attached to ":test:":
  1156. check inputWrong.toAst != ast
  1157. test "Markdown definition lists work in conjunction with bullet lists":
  1158. check(dedent"""
  1159. * some term
  1160. : the definition
  1161. Paragraph.""".toAst ==
  1162. dedent"""
  1163. rnInner
  1164. rnBulletList
  1165. rnBulletItem
  1166. rnMdDefList
  1167. rnDefItem
  1168. rnDefName
  1169. rnLeaf 'some'
  1170. rnLeaf ' '
  1171. rnLeaf 'term'
  1172. rnDefBody
  1173. rnInner
  1174. rnLeaf 'the'
  1175. rnLeaf ' '
  1176. rnLeaf 'definition'
  1177. rnParagraph
  1178. rnLeaf 'Paragraph'
  1179. rnLeaf '.'
  1180. """)
  1181. test "Markdown definition lists work with blank lines and extra paragraphs":
  1182. check(dedent"""
  1183. Term1
  1184. : Definition1
  1185. Term2 *inline markup*
  1186. : Definition2
  1187. Paragraph2
  1188. Term3
  1189. : * point1
  1190. * point2
  1191. : term3definition2
  1192. """.toAst == dedent"""
  1193. rnMdDefList
  1194. rnDefItem
  1195. rnDefName
  1196. rnLeaf 'Term1'
  1197. rnDefBody
  1198. rnInner
  1199. rnLeaf 'Definition1'
  1200. rnDefItem
  1201. rnDefName
  1202. rnLeaf 'Term2'
  1203. rnLeaf ' '
  1204. rnEmphasis
  1205. rnLeaf 'inline'
  1206. rnLeaf ' '
  1207. rnLeaf 'markup'
  1208. rnDefBody
  1209. rnParagraph
  1210. rnLeaf 'Definition2'
  1211. rnParagraph
  1212. rnLeaf 'Paragraph2'
  1213. rnDefItem
  1214. rnDefName
  1215. rnLeaf 'Term3'
  1216. rnDefBody
  1217. rnBulletList
  1218. rnBulletItem
  1219. rnInner
  1220. rnLeaf 'point1'
  1221. rnBulletItem
  1222. rnInner
  1223. rnLeaf 'point2'
  1224. rnDefBody
  1225. rnInner
  1226. rnLeaf 'term3definition2'
  1227. """)
  1228. suite "Markdown indentation":
  1229. test "Markdown paragraph indentation":
  1230. # Additional spaces (<=3) of indentation does not break the paragraph.
  1231. # TODO: in 2nd case de-indentation causes paragraph to break, this is
  1232. # reasonable but does not seem to conform the Markdown spec.
  1233. check(dedent"""
  1234. Start1
  1235. stop1
  1236. Start2
  1237. stop2
  1238. """.toAst ==
  1239. dedent"""
  1240. rnInner
  1241. rnParagraph
  1242. rnLeaf 'Start1'
  1243. rnLeaf ' '
  1244. rnLeaf 'stop1'
  1245. rnParagraph
  1246. rnLeaf 'Start2'
  1247. rnParagraph
  1248. rnLeaf 'stop2'
  1249. rnLeaf ' '
  1250. """)
  1251. suite "Warnings":
  1252. test "warnings for broken footnotes/links/substitutions":
  1253. let input = dedent"""
  1254. firstParagraph
  1255. footnoteRef [som]_
  1256. link `a broken Link`_
  1257. substitution |undefined subst|
  1258. link short.link_
  1259. lastParagraph
  1260. """
  1261. var warnings = new seq[string]
  1262. let output = input.toAst(rstOptions=preferRst, warnings=warnings)
  1263. check(warnings[] == @[
  1264. "input(3, 14) Warning: broken link 'citation-som'",
  1265. "input(5, 7) Warning: broken link 'a broken Link'",
  1266. "input(7, 15) Warning: unknown substitution 'undefined subst'",
  1267. "input(9, 6) Warning: broken link 'short.link'"
  1268. ])
  1269. test "Pandoc Markdown concise link warning points to target":
  1270. var warnings = new seq[string]
  1271. check(
  1272. "ref [here][target]".toAst(warnings=warnings) ==
  1273. dedent"""
  1274. rnInner
  1275. rnLeaf 'ref'
  1276. rnLeaf ' '
  1277. rnPandocRef
  1278. rnInner
  1279. rnLeaf 'here'
  1280. rnInner
  1281. rnLeaf 'target'
  1282. """)
  1283. check warnings[] == @["input(1, 12) Warning: broken link 'target'"]
  1284. test "With include directive and blank lines at the beginning":
  1285. "other.rst".writeFile(dedent"""
  1286. firstParagraph
  1287. here brokenLink_""")
  1288. let input = ".. include:: other.rst"
  1289. var warnings = new seq[string]
  1290. let output = input.toAst(warnings=warnings)
  1291. check warnings[] == @["other.rst(5, 6) Warning: broken link 'brokenLink'"]
  1292. check(output == dedent"""
  1293. rnInner
  1294. rnParagraph
  1295. rnLeaf 'firstParagraph'
  1296. rnParagraph
  1297. rnLeaf 'here'
  1298. rnLeaf ' '
  1299. rnRstRef
  1300. rnLeaf 'brokenLink'
  1301. """)
  1302. removeFile("other.rst")
  1303. test "warnings for ambiguous links (references + anchors)":
  1304. # Reference like `x`_ generates a link alias x that may clash with others
  1305. let input = dedent"""
  1306. Manual reference: `foo <#foo,string,string>`_
  1307. .. _foo:
  1308. Paragraph.
  1309. Ref foo_
  1310. """
  1311. var warnings = new seq[string]
  1312. let output = input.toAst(warnings=warnings)
  1313. check(warnings[] == @[
  1314. dedent """
  1315. input(7, 5) Warning: ambiguous doc link `foo`
  1316. clash:
  1317. (3, 8): (manual directive anchor)
  1318. (1, 45): (implicitly-generated hyperlink alias)"""
  1319. ])
  1320. # reference should be resolved to the manually set anchor:
  1321. check(output ==
  1322. dedent"""
  1323. rnInner
  1324. rnParagraph
  1325. rnLeaf 'Manual'
  1326. rnLeaf ' '
  1327. rnLeaf 'reference'
  1328. rnLeaf ':'
  1329. rnLeaf ' '
  1330. rnHyperlink
  1331. rnInner
  1332. rnLeaf 'foo'
  1333. rnInner
  1334. rnLeaf '#foo,string,string'
  1335. rnParagraph anchor='foo'
  1336. rnLeaf 'Paragraph'
  1337. rnLeaf '.'
  1338. rnParagraph
  1339. rnLeaf 'Ref'
  1340. rnLeaf ' '
  1341. rnInternalRef
  1342. rnInner
  1343. rnLeaf 'foo'
  1344. rnLeaf 'foo'
  1345. rnLeaf ' '
  1346. """)
  1347. suite "RST include directive":
  1348. test "Include whole":
  1349. "other.rst".writeFile("**test1**")
  1350. let input = ".. include:: other.rst"
  1351. doAssert "<strong>test1</strong>" == rstToHtml(input, {roSandboxDisabled}, defaultConfig())
  1352. removeFile("other.rst")
  1353. test "Include starting from":
  1354. "other.rst".writeFile("""
  1355. And this should **NOT** be visible in `docs.html`
  1356. OtherStart
  1357. *Visible*
  1358. """)
  1359. let input = """
  1360. .. include:: other.rst
  1361. :start-after: OtherStart
  1362. """
  1363. check "<em>Visible</em>" == rstToHtml(input, {roSandboxDisabled}, defaultConfig())
  1364. removeFile("other.rst")
  1365. test "Include everything before":
  1366. "other.rst".writeFile("""
  1367. *Visible*
  1368. OtherEnd
  1369. And this should **NOT** be visible in `docs.html`
  1370. """)
  1371. let input = """
  1372. .. include:: other.rst
  1373. :end-before: OtherEnd
  1374. """
  1375. doAssert "<em>Visible</em>" == rstToHtml(input, {roSandboxDisabled}, defaultConfig())
  1376. removeFile("other.rst")
  1377. test "Include everything between":
  1378. "other.rst".writeFile("""
  1379. And this should **NOT** be visible in `docs.html`
  1380. OtherStart
  1381. *Visible*
  1382. OtherEnd
  1383. And this should **NOT** be visible in `docs.html`
  1384. """)
  1385. let input = """
  1386. .. include:: other.rst
  1387. :start-after: OtherStart
  1388. :end-before: OtherEnd
  1389. """
  1390. check "<em>Visible</em>" == rstToHtml(input, {roSandboxDisabled}, defaultConfig())
  1391. removeFile("other.rst")
  1392. test "Ignore premature ending string":
  1393. "other.rst".writeFile("""
  1394. OtherEnd
  1395. And this should **NOT** be visible in `docs.html`
  1396. OtherStart
  1397. *Visible*
  1398. OtherEnd
  1399. And this should **NOT** be visible in `docs.html`
  1400. """)
  1401. let input = """
  1402. .. include:: other.rst
  1403. :start-after: OtherStart
  1404. :end-before: OtherEnd
  1405. """
  1406. doAssert "<em>Visible</em>" == rstToHtml(input, {roSandboxDisabled}, defaultConfig())
  1407. removeFile("other.rst")
  1408. suite "RST escaping":
  1409. test "backspaces":
  1410. check("""\ this""".toAst == dedent"""
  1411. rnLeaf 'this'
  1412. """)
  1413. check("""\\ this""".toAst == dedent"""
  1414. rnInner
  1415. rnLeaf '\'
  1416. rnLeaf ' '
  1417. rnLeaf 'this'
  1418. """)
  1419. check("""\\\ this""".toAst == dedent"""
  1420. rnInner
  1421. rnLeaf '\'
  1422. rnLeaf 'this'
  1423. """)
  1424. check("""\\\\ this""".toAst == dedent"""
  1425. rnInner
  1426. rnLeaf '\'
  1427. rnLeaf '\'
  1428. rnLeaf ' '
  1429. rnLeaf 'this'
  1430. """)
  1431. suite "RST inline markup":
  1432. test "* and ** surrounded by spaces are not inline markup":
  1433. check("a * b * c ** d ** e".toAst == dedent"""
  1434. rnInner
  1435. rnLeaf 'a'
  1436. rnLeaf ' '
  1437. rnLeaf '*'
  1438. rnLeaf ' '
  1439. rnLeaf 'b'
  1440. rnLeaf ' '
  1441. rnLeaf '*'
  1442. rnLeaf ' '
  1443. rnLeaf 'c'
  1444. rnLeaf ' '
  1445. rnLeaf '**'
  1446. rnLeaf ' '
  1447. rnLeaf 'd'
  1448. rnLeaf ' '
  1449. rnLeaf '**'
  1450. rnLeaf ' '
  1451. rnLeaf 'e'
  1452. """)
  1453. test "end-string has repeating symbols":
  1454. check("*emphasis content****".toAst == dedent"""
  1455. rnEmphasis
  1456. rnLeaf 'emphasis'
  1457. rnLeaf ' '
  1458. rnLeaf 'content'
  1459. rnLeaf '***'
  1460. """)
  1461. check("""*emphasis content\****""".toAst == dedent"""
  1462. rnEmphasis
  1463. rnLeaf 'emphasis'
  1464. rnLeaf ' '
  1465. rnLeaf 'content'
  1466. rnLeaf '*'
  1467. rnLeaf '**'
  1468. """) # exact configuration of leafs with * is not really essential,
  1469. # only total number of * is essential
  1470. check("**strong content****".toAst == dedent"""
  1471. rnStrongEmphasis
  1472. rnLeaf 'strong'
  1473. rnLeaf ' '
  1474. rnLeaf 'content'
  1475. rnLeaf '**'
  1476. """)
  1477. check("""**strong content*\****""".toAst == dedent"""
  1478. rnStrongEmphasis
  1479. rnLeaf 'strong'
  1480. rnLeaf ' '
  1481. rnLeaf 'content'
  1482. rnLeaf '*'
  1483. rnLeaf '*'
  1484. rnLeaf '*'
  1485. """)
  1486. check("``lit content`````".toAst == dedent"""
  1487. rnInlineLiteral
  1488. rnLeaf 'lit'
  1489. rnLeaf ' '
  1490. rnLeaf 'content'
  1491. rnLeaf '```'
  1492. """)
  1493. test "interpreted text parsing: code fragments":
  1494. check(dedent"""
  1495. .. default-role:: option
  1496. `--gc:refc`""".toAst ==
  1497. dedent"""
  1498. rnInner
  1499. rnDefaultRole
  1500. rnDirArg
  1501. rnLeaf 'option'
  1502. [nil]
  1503. [nil]
  1504. rnParagraph
  1505. rnCodeFragment
  1506. rnInner
  1507. rnLeaf '--'
  1508. rnLeaf 'gc'
  1509. rnLeaf ':'
  1510. rnLeaf 'refc'
  1511. rnLeaf 'option'
  1512. """)
  1513. test """interpreted text can be ended with \` """:
  1514. let output = (".. default-role:: literal\n" & """`\``""").toAst
  1515. check(output.endsWith """
  1516. rnParagraph
  1517. rnInlineLiteral
  1518. rnLeaf '`'""" & "\n")
  1519. let output2 = """`\``""".toAst
  1520. check(output2 == dedent"""
  1521. rnInlineCode
  1522. rnDirArg
  1523. rnLeaf 'nim'
  1524. [nil]
  1525. rnLiteralBlock
  1526. rnLeaf '`'
  1527. """)
  1528. let output3 = """`proc \`+\``""".toAst
  1529. check(output3 == dedent"""
  1530. rnInlineCode
  1531. rnDirArg
  1532. rnLeaf 'nim'
  1533. [nil]
  1534. rnLiteralBlock
  1535. rnLeaf 'proc `+`'
  1536. """)
  1537. check("""`\\`""".toAst ==
  1538. dedent"""
  1539. rnInlineCode
  1540. rnDirArg
  1541. rnLeaf 'nim'
  1542. [nil]
  1543. rnLiteralBlock
  1544. rnLeaf '\\'
  1545. """)
  1546. test "Markdown-style code/backtick":
  1547. # no whitespace is required before `
  1548. check("`try`...`except`".toAst ==
  1549. dedent"""
  1550. rnInner
  1551. rnInlineCode
  1552. rnDirArg
  1553. rnLeaf 'nim'
  1554. [nil]
  1555. rnLiteralBlock
  1556. rnLeaf 'try'
  1557. rnLeaf '...'
  1558. rnInlineCode
  1559. rnDirArg
  1560. rnLeaf 'nim'
  1561. [nil]
  1562. rnLiteralBlock
  1563. rnLeaf 'except'
  1564. """)
  1565. test """inline literals can contain \ anywhere""":
  1566. check("""``\``""".toAst == dedent"""
  1567. rnInlineLiteral
  1568. rnLeaf '\'
  1569. """)
  1570. check("""``\\``""".toAst == dedent"""
  1571. rnInlineLiteral
  1572. rnLeaf '\'
  1573. rnLeaf '\'
  1574. """)
  1575. check("""``\```""".toAst == dedent"""
  1576. rnInlineLiteral
  1577. rnLeaf '\'
  1578. rnLeaf '`'
  1579. """)
  1580. check("""``\\```""".toAst == dedent"""
  1581. rnInlineLiteral
  1582. rnLeaf '\'
  1583. rnLeaf '\'
  1584. rnLeaf '`'
  1585. """)
  1586. check("""``\````""".toAst == dedent"""
  1587. rnInlineLiteral
  1588. rnLeaf '\'
  1589. rnLeaf '`'
  1590. rnLeaf '`'
  1591. """)
  1592. test "references with _ at the end":
  1593. check(dedent"""
  1594. .. _lnk: https
  1595. lnk_""".toAst ==
  1596. dedent"""
  1597. rnHyperlink
  1598. rnInner
  1599. rnLeaf 'lnk'
  1600. rnInner
  1601. rnLeaf 'https'
  1602. """)
  1603. test "not a hyper link":
  1604. check(dedent"""
  1605. .. _lnk: https
  1606. lnk___""".toAst ==
  1607. dedent"""
  1608. rnInner
  1609. rnLeaf 'lnk'
  1610. rnLeaf '___'
  1611. """)
  1612. test "no punctuation in the end of a standalone URI is allowed":
  1613. check(dedent"""
  1614. [see (http://no.org)], end""".toAst(rstOptions = preferRst) ==
  1615. dedent"""
  1616. rnInner
  1617. rnLeaf '['
  1618. rnLeaf 'see'
  1619. rnLeaf ' '
  1620. rnLeaf '('
  1621. rnStandaloneHyperlink
  1622. rnLeaf 'http://no.org'
  1623. rnLeaf ')'
  1624. rnLeaf ']'
  1625. rnLeaf ','
  1626. rnLeaf ' '
  1627. rnLeaf 'end'
  1628. """)
  1629. # but `/` at the end is OK
  1630. check(
  1631. dedent"""
  1632. See http://no.org/ end""".toAst ==
  1633. dedent"""
  1634. rnInner
  1635. rnLeaf 'See'
  1636. rnLeaf ' '
  1637. rnStandaloneHyperlink
  1638. rnLeaf 'http://no.org/'
  1639. rnLeaf ' '
  1640. rnLeaf 'end'
  1641. """)
  1642. # a more complex URL with some made-up ending '&='.
  1643. # Github Markdown would include final &= and
  1644. # so would rst2html.py in contradiction with RST spec.
  1645. check(
  1646. dedent"""
  1647. See https://www.google.com/url?sa=t&source=web&cd=&cad=rja&url=https%3A%2F%2Fnim-lang.github.io%2FNim%2Frst.html%23features&usg=AO&= end""".toAst ==
  1648. dedent"""
  1649. rnInner
  1650. rnLeaf 'See'
  1651. rnLeaf ' '
  1652. rnStandaloneHyperlink
  1653. rnLeaf 'https://www.google.com/url?sa=t&source=web&cd=&cad=rja&url=https%3A%2F%2Fnim-lang.github.io%2FNim%2Frst.html%23features&usg=AO'
  1654. rnLeaf '&'
  1655. rnLeaf '='
  1656. rnLeaf ' '
  1657. rnLeaf 'end'
  1658. """)
  1659. test "Markdown-style link can be split to a few lines":
  1660. check(dedent"""
  1661. is [term-rewriting
  1662. macros](manual.html#term-rewriting-macros)""".toAst ==
  1663. dedent"""
  1664. rnInner
  1665. rnLeaf 'is'
  1666. rnLeaf ' '
  1667. rnHyperlink
  1668. rnLeaf 'term-rewriting macros'
  1669. rnLeaf 'manual.html#term-rewriting-macros'
  1670. """)
  1671. test "URL with balanced parentheses (Markdown rule)":
  1672. # 2 balanced parens, 1 unbalanced:
  1673. check(dedent"""
  1674. https://en.wikipedia.org/wiki/APL_((programming_language)))""".toAst ==
  1675. dedent"""
  1676. rnInner
  1677. rnStandaloneHyperlink
  1678. rnLeaf 'https://en.wikipedia.org/wiki/APL_((programming_language))'
  1679. rnLeaf ')'
  1680. """)
  1681. # the same for Markdown-style link:
  1682. check(dedent"""
  1683. [foo [bar]](https://en.wikipedia.org/wiki/APL_((programming_language))))""".toAst ==
  1684. dedent"""
  1685. rnInner
  1686. rnHyperlink
  1687. rnLeaf 'foo [bar]'
  1688. rnLeaf 'https://en.wikipedia.org/wiki/APL_((programming_language))'
  1689. rnLeaf ')'
  1690. """)
  1691. # unbalanced (here behavior is more RST-like actually):
  1692. check(dedent"""
  1693. https://en.wikipedia.org/wiki/APL_(programming_language(""".toAst ==
  1694. dedent"""
  1695. rnInner
  1696. rnStandaloneHyperlink
  1697. rnLeaf 'https://en.wikipedia.org/wiki/APL_(programming_language'
  1698. rnLeaf '('
  1699. """)
  1700. # unbalanced [, but still acceptable:
  1701. check(dedent"""
  1702. [my {link example](http://example.com/bracket_(symbol_[))""".toAst ==
  1703. dedent"""
  1704. rnHyperlink
  1705. rnLeaf 'my {link example'
  1706. rnLeaf 'http://example.com/bracket_(symbol_[)'
  1707. """)
  1708. test "not a Markdown link":
  1709. # bug #17340 (27) `f` will be considered as a protocol and blocked as unsafe
  1710. var warnings = new seq[string]
  1711. check("[T](f: var Foo)".toAst(warnings = warnings) ==
  1712. dedent"""
  1713. rnInner
  1714. rnLeaf '['
  1715. rnLeaf 'T'
  1716. rnLeaf ']'
  1717. rnLeaf '('
  1718. rnLeaf 'f'
  1719. rnLeaf ':'
  1720. rnLeaf ' '
  1721. rnLeaf 'var'
  1722. rnLeaf ' '
  1723. rnLeaf 'Foo'
  1724. rnLeaf ')'
  1725. """)
  1726. check(warnings[] == @["input(1, 5) Warning: broken link 'f'"])