trst.nim 49 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983
  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 'let a = 1
  463. ```'
  464. """
  465. test "Markdown footnotes":
  466. # Testing also 1) correct order of manually-numbered and automatically-
  467. # numbered footnotes; 2) no spaces between references (html & 3 below):
  468. check(dedent"""
  469. Paragraph [^1] [^html-hyphen][^3] and [^latex]
  470. [^1]: footnote1
  471. [^html-hyphen]: footnote2
  472. continuation2
  473. [^latex]: footnote4
  474. [^3]: footnote3
  475. continuation3
  476. """.toAst ==
  477. dedent"""
  478. rnInner
  479. rnInner
  480. rnLeaf 'Paragraph'
  481. rnLeaf ' '
  482. rnFootnoteRef
  483. rnInner
  484. rnLeaf '1'
  485. rnLeaf 'footnote-1'
  486. rnLeaf ' '
  487. rnFootnoteRef
  488. rnInner
  489. rnLeaf '2'
  490. rnLeaf 'footnote-htmlminushyphen'
  491. rnFootnoteRef
  492. rnInner
  493. rnLeaf '3'
  494. rnLeaf 'footnote-3'
  495. rnLeaf ' '
  496. rnLeaf 'and'
  497. rnLeaf ' '
  498. rnFootnoteRef
  499. rnInner
  500. rnLeaf '4'
  501. rnLeaf 'footnote-latex'
  502. rnFootnoteGroup
  503. rnFootnote anchor='footnote-1'
  504. rnInner
  505. rnLeaf '1'
  506. rnLeaf 'footnote1'
  507. rnFootnote anchor='footnote-htmlminushyphen'
  508. rnInner
  509. rnLeaf '2'
  510. rnInner
  511. rnLeaf 'footnote2'
  512. rnLeaf ' '
  513. rnLeaf 'continuation2'
  514. rnFootnote anchor='footnote-latex'
  515. rnInner
  516. rnLeaf '4'
  517. rnLeaf 'footnote4'
  518. rnFootnote anchor='footnote-3'
  519. rnInner
  520. rnLeaf '3'
  521. rnInner
  522. rnLeaf 'footnote3'
  523. rnLeaf ' '
  524. rnLeaf 'continuation3'
  525. """)
  526. test "Markdown code blocks with more > 3 backticks":
  527. check(dedent"""
  528. ````
  529. let a = 1
  530. ```
  531. ````""".toAst == expectCodeBlock)
  532. test "Markdown code blocks with ~~~":
  533. check(dedent"""
  534. ~~~
  535. let a = 1
  536. ```
  537. ~~~""".toAst == expectCodeBlock)
  538. check(dedent"""
  539. ~~~~~
  540. let a = 1
  541. ```
  542. ~~~~~""".toAst == expectCodeBlock)
  543. test "Markdown code blocks with Nim-specific arguments":
  544. check(dedent"""
  545. ```nim number-lines=1 test
  546. let a = 1
  547. ```""".toAst ==
  548. dedent"""
  549. rnCodeBlock
  550. rnDirArg
  551. rnLeaf 'nim'
  552. rnFieldList
  553. rnField
  554. rnFieldName
  555. rnLeaf 'number-lines'
  556. rnFieldBody
  557. rnLeaf '1'
  558. rnField
  559. rnFieldName
  560. rnLeaf 'test'
  561. rnFieldBody
  562. rnLiteralBlock
  563. rnLeaf 'let a = 1'
  564. """)
  565. check(dedent"""
  566. ```nim test = "nim c $1" number-lines = 1
  567. let a = 1
  568. ```""".toAst ==
  569. dedent"""
  570. rnCodeBlock
  571. rnDirArg
  572. rnLeaf 'nim'
  573. rnFieldList
  574. rnField
  575. rnFieldName
  576. rnLeaf 'test'
  577. rnFieldBody
  578. rnLeaf '"nim c $1"'
  579. rnField
  580. rnFieldName
  581. rnLeaf 'number-lines'
  582. rnFieldBody
  583. rnLeaf '1'
  584. rnLiteralBlock
  585. rnLeaf 'let a = 1'
  586. """)
  587. test "additional indentation < 4 spaces is handled fine":
  588. check(dedent"""
  589. Indentation
  590. ```nim
  591. let a = 1
  592. ```""".toAst ==
  593. dedent"""
  594. rnInner
  595. rnParagraph
  596. rnLeaf 'Indentation'
  597. rnParagraph
  598. rnCodeBlock
  599. rnDirArg
  600. rnLeaf 'nim'
  601. [nil]
  602. rnLiteralBlock
  603. rnLeaf ' let a = 1'
  604. """)
  605. # | |
  606. # | \ indentation of exactly two spaces before 'let a = 1'
  607. test "no blank line is required before or after Markdown code block":
  608. let inputBacktick = dedent"""
  609. Some text
  610. ```
  611. CodeBlock()
  612. ```
  613. Other text"""
  614. let inputTilde = dedent"""
  615. Some text
  616. ~~~~~~~~~
  617. CodeBlock()
  618. ~~~~~~~~~
  619. Other text"""
  620. let expected = dedent"""
  621. rnInner
  622. rnParagraph
  623. rnLeaf 'Some'
  624. rnLeaf ' '
  625. rnLeaf 'text'
  626. rnParagraph
  627. rnCodeBlock
  628. [nil]
  629. rnFieldList
  630. rnField
  631. rnFieldName
  632. rnLeaf 'default-language'
  633. rnFieldBody
  634. rnLeaf 'Nim'
  635. rnLiteralBlock
  636. rnLeaf 'CodeBlock()'
  637. rnLeaf ' '
  638. rnLeaf 'Other'
  639. rnLeaf ' '
  640. rnLeaf 'text'
  641. """
  642. check inputBacktick.toAst == expected
  643. check inputTilde.toAst == expected
  644. test "option list has priority over definition list":
  645. for opt in [preferMarkdown, preferRst]:
  646. check(dedent"""
  647. --defusages
  648. file
  649. -o set
  650. """.toAst(rstOptions = opt) ==
  651. dedent"""
  652. rnOptionList
  653. rnOptionListItem order=1
  654. rnOptionGroup
  655. rnLeaf '--'
  656. rnLeaf 'defusages'
  657. rnDescription
  658. rnInner
  659. rnLeaf 'file'
  660. rnOptionListItem order=2
  661. rnOptionGroup
  662. rnLeaf '-'
  663. rnLeaf 'o'
  664. rnDescription
  665. rnLeaf 'set'
  666. """)
  667. test "items of 1 option list can be separated by blank lines":
  668. check(dedent"""
  669. -a desc1
  670. -b desc2
  671. """.toAst ==
  672. dedent"""
  673. rnOptionList
  674. rnOptionListItem order=1
  675. rnOptionGroup
  676. rnLeaf '-'
  677. rnLeaf 'a'
  678. rnDescription
  679. rnLeaf 'desc1'
  680. rnOptionListItem order=2
  681. rnOptionGroup
  682. rnLeaf '-'
  683. rnLeaf 'b'
  684. rnDescription
  685. rnLeaf 'desc2'
  686. """)
  687. test "definition list does not gobble up the following blocks":
  688. check(dedent"""
  689. defName
  690. defBody
  691. -b desc2
  692. """.toAst(rstOptions = preferRst) ==
  693. dedent"""
  694. rnInner
  695. rnDefList
  696. rnDefItem
  697. rnDefName
  698. rnLeaf 'defName'
  699. rnDefBody
  700. rnInner
  701. rnLeaf 'defBody'
  702. rnOptionList
  703. rnOptionListItem order=1
  704. rnOptionGroup
  705. rnLeaf '-'
  706. rnLeaf 'b'
  707. rnDescription
  708. rnLeaf 'desc2'
  709. """)
  710. test "definition lists work correctly with additional indentation in Markdown":
  711. check(dedent"""
  712. Paragraph:
  713. -c desc1
  714. -b desc2
  715. """.toAst() ==
  716. dedent"""
  717. rnInner
  718. rnInner
  719. rnLeaf 'Paragraph'
  720. rnLeaf ':'
  721. rnOptionList
  722. rnOptionListItem order=1
  723. rnOptionGroup
  724. rnLeaf '-'
  725. rnLeaf 'c'
  726. rnDescription
  727. rnLeaf 'desc1'
  728. rnOptionListItem order=2
  729. rnOptionGroup
  730. rnLeaf '-'
  731. rnLeaf 'b'
  732. rnDescription
  733. rnLeaf 'desc2'
  734. """)
  735. test "RST comment":
  736. check(dedent"""
  737. .. comment1
  738. comment2
  739. someParagraph""".toAst ==
  740. dedent"""
  741. rnLeaf 'someParagraph'
  742. """)
  743. check(dedent"""
  744. ..
  745. comment1
  746. comment2
  747. someParagraph""".toAst ==
  748. dedent"""
  749. rnLeaf 'someParagraph'
  750. """)
  751. test "check that additional line right after .. ends comment":
  752. check(dedent"""
  753. ..
  754. notAcomment1
  755. notAcomment2
  756. someParagraph""".toAst(rstOptions = preferRst) ==
  757. dedent"""
  758. rnInner
  759. rnBlockQuote
  760. rnInner
  761. rnLeaf 'notAcomment1'
  762. rnLeaf ' '
  763. rnLeaf 'notAcomment2'
  764. rnParagraph
  765. rnLeaf 'someParagraph'
  766. """)
  767. test "check that additional line right after .. ends comment (Markdown mode)":
  768. # in Markdown small indentation does not matter so this should
  769. # just be split to 2 paragraphs.
  770. check(dedent"""
  771. ..
  772. notAcomment1
  773. notAcomment2
  774. someParagraph""".toAst ==
  775. dedent"""
  776. rnInner
  777. rnInner
  778. rnLeaf 'notAcomment1'
  779. rnLeaf ' '
  780. rnLeaf 'notAcomment2'
  781. rnParagraph
  782. rnLeaf 'someParagraph'
  783. """)
  784. test "but blank lines after 2nd non-empty line don't end the comment":
  785. check(dedent"""
  786. ..
  787. comment1
  788. comment2
  789. someParagraph""".toAst ==
  790. dedent"""
  791. rnLeaf 'someParagraph'
  792. """)
  793. test "using .. as separator b/w directives and block quotes":
  794. check(dedent"""
  795. .. note:: someNote
  796. ..
  797. someBlockQuote""".toAst(rstOptions = preferRst) ==
  798. dedent"""
  799. rnInner
  800. rnAdmonition adType=note
  801. [nil]
  802. [nil]
  803. rnLeaf 'someNote'
  804. rnBlockQuote
  805. rnInner
  806. rnLeaf 'someBlockQuote'
  807. """)
  808. test "no redundant blank lines in literal blocks":
  809. check(dedent"""
  810. Check::
  811. code
  812. """.toAst(rstOptions = preferRst) ==
  813. dedent"""
  814. rnInner
  815. rnLeaf 'Check'
  816. rnLeaf ':'
  817. rnLiteralBlock
  818. rnLeaf 'code'
  819. """)
  820. test "Markdown indented code blocks":
  821. check(dedent"""
  822. See
  823. some code""".toAst ==
  824. dedent"""
  825. rnInner
  826. rnInner
  827. rnLeaf 'See'
  828. rnLiteralBlock
  829. rnLeaf 'some code'
  830. """)
  831. # not a code block -- no blank line before:
  832. check(dedent"""
  833. See
  834. some code""".toAst ==
  835. dedent"""
  836. rnInner
  837. rnLeaf 'See'
  838. rnLeaf ' '
  839. rnLeaf 'some'
  840. rnLeaf ' '
  841. rnLeaf 'code'
  842. """)
  843. suite "RST tables":
  844. test "formatting in tables works":
  845. check(
  846. dedent"""
  847. ========= ===
  848. `build` `a`
  849. ========= ===
  850. """.toAst ==
  851. dedent"""
  852. rnTable colCount=2
  853. rnTableRow
  854. rnTableDataCell
  855. rnInlineCode
  856. rnDirArg
  857. rnLeaf 'nim'
  858. [nil]
  859. rnLiteralBlock
  860. rnLeaf 'build'
  861. rnTableDataCell
  862. rnInlineCode
  863. rnDirArg
  864. rnLeaf 'nim'
  865. [nil]
  866. rnLiteralBlock
  867. rnLeaf 'a'
  868. """)
  869. test "tables with slightly overflowed cells cause an error (1)":
  870. var error = new string
  871. check(
  872. dedent"""
  873. ====== ======
  874. Inputs Output
  875. ====== ======
  876. """.toAst(rstOptions = pureRst, error = error) == "")
  877. check(error[] == "input(2, 2) Error: Illformed table: " &
  878. "this word crosses table column from the right")
  879. # In nimforum compatibility mode & Markdown we raise a warning instead:
  880. let expected = dedent"""
  881. rnTable colCount=2
  882. rnTableRow
  883. rnTableDataCell
  884. rnLeaf 'Inputs'
  885. rnTableDataCell
  886. rnLeaf 'Output'
  887. """
  888. for opt in [preferRst, preferMarkdown]:
  889. var warnings = new seq[string]
  890. check(
  891. dedent"""
  892. ====== ======
  893. Inputs Output
  894. ====== ======
  895. """.toAst(rstOptions = opt, warnings = warnings) == expected)
  896. check(warnings[] == @[
  897. "input(2, 2) Warning: RST style: this word crosses table column from the right"])
  898. test "tables with slightly overflowed cells cause an error (2)":
  899. var error = new string
  900. check("" == dedent"""
  901. ===== ===== ======
  902. Input Output
  903. ===== ===== ======
  904. False False False
  905. ===== ===== ======
  906. """.toAst(rstOptions = pureRst, error = error))
  907. check(error[] == "input(2, 8) Error: Illformed table: " &
  908. "this word crosses table column from the right")
  909. test "tables with slightly underflowed cells cause an error":
  910. var error = new string
  911. check("" == dedent"""
  912. ===== ===== ======
  913. Input Output
  914. ===== ===== ======
  915. False False False
  916. ===== ===== ======
  917. """.toAst(rstOptions = pureRst, error = error))
  918. check(error[] == "input(2, 7) Error: Illformed table: " &
  919. "this word crosses table column from the left")
  920. test "tables with unequal underlines should be reported (1)":
  921. var error = new string
  922. error[] = "none"
  923. check("" == dedent"""
  924. ===== ======
  925. Input Output
  926. ===== ======
  927. False False
  928. ===== =======
  929. """.toAst(rstOptions = pureRst, error = error))
  930. check(error[] == "input(5, 14) Error: Illformed table: " &
  931. "end of table column #2 should end at position 13")
  932. test "tables with unequal underlines should be reported (2)":
  933. var error = new string
  934. check("" == dedent"""
  935. ===== ======
  936. Input Output
  937. ===== =======
  938. False False
  939. ===== ======
  940. """.toAst(rstOptions = pureRst, error = error))
  941. check(error[] == "input(3, 14) Error: Illformed table: " &
  942. "end of table column #2 should end at position 13")
  943. test "tables with empty first cells":
  944. check(
  945. dedent"""
  946. = = =
  947. x y z
  948. t
  949. = = =
  950. """.toAst ==
  951. dedent"""
  952. rnTable colCount=3
  953. rnTableRow
  954. rnTableDataCell
  955. rnLeaf 'x'
  956. rnTableDataCell
  957. rnInner
  958. rnLeaf 'y'
  959. rnLeaf ' '
  960. rnTableDataCell
  961. rnInner
  962. rnLeaf 'z'
  963. rnLeaf ' '
  964. rnLeaf 't'
  965. """)
  966. test "tables with spanning cells & separators":
  967. check(
  968. dedent"""
  969. ===== ===== ======
  970. Inputs Output
  971. ------------ ------
  972. A B A or B
  973. ===== ===== ======
  974. False False False
  975. True False True
  976. ----- ----- ------
  977. False True True
  978. True True True
  979. ===== ===== ======
  980. """.toAst ==
  981. dedent"""
  982. rnTable colCount=3
  983. rnTableRow
  984. rnTableHeaderCell span=2
  985. rnLeaf 'Inputs'
  986. rnTableHeaderCell span=1
  987. rnLeaf 'Output'
  988. rnTableRow endsHeader
  989. rnTableHeaderCell
  990. rnLeaf 'A'
  991. rnTableHeaderCell
  992. rnLeaf 'B'
  993. rnTableHeaderCell
  994. rnInner
  995. rnLeaf 'A'
  996. rnLeaf ' '
  997. rnLeaf 'or'
  998. rnLeaf ' '
  999. rnLeaf 'B'
  1000. rnTableRow
  1001. rnTableDataCell
  1002. rnLeaf 'False'
  1003. rnTableDataCell
  1004. rnLeaf 'False'
  1005. rnTableDataCell
  1006. rnLeaf 'False'
  1007. rnTableRow
  1008. rnTableDataCell span=1
  1009. rnLeaf 'True'
  1010. rnTableDataCell span=1
  1011. rnLeaf 'False'
  1012. rnTableDataCell span=1
  1013. rnLeaf 'True'
  1014. rnTableRow
  1015. rnTableDataCell
  1016. rnLeaf 'False'
  1017. rnTableDataCell
  1018. rnLeaf 'True'
  1019. rnTableDataCell
  1020. rnLeaf 'True'
  1021. rnTableRow
  1022. rnTableDataCell
  1023. rnLeaf 'True'
  1024. rnTableDataCell
  1025. rnLeaf 'True'
  1026. rnTableDataCell
  1027. rnLeaf 'True'
  1028. """)
  1029. test "tables with spanning cells with uneqal underlines cause an error":
  1030. var error = new string
  1031. check(
  1032. dedent"""
  1033. ===== ===== ======
  1034. Inputs Output
  1035. ------------- ------
  1036. A B A or B
  1037. ===== ===== ======
  1038. """.toAst(error=error) == "")
  1039. check(error[] == "input(3, 1) Error: Illformed table: " &
  1040. "spanning underline does not match main table columns")
  1041. let expTable = dedent"""
  1042. rnTable colCount=2
  1043. rnTableRow
  1044. rnTableDataCell
  1045. rnLeaf 'Inputs'
  1046. rnTableDataCell
  1047. rnLeaf 'Output'
  1048. """
  1049. test "only tables with `=` columns specs are allowed (1)":
  1050. var warnings = new seq[string]
  1051. check(
  1052. dedent"""
  1053. ------ ------
  1054. Inputs Output
  1055. ------ ------
  1056. """.toAst(warnings=warnings) ==
  1057. expTable)
  1058. check(warnings[] ==
  1059. @["input(1, 1) Warning: RST style: " &
  1060. "only tables with `=` columns specification are allowed",
  1061. "input(3, 1) Warning: RST style: " &
  1062. "only tables with `=` columns specification are allowed"])
  1063. test "only tables with `=` columns specs are allowed (2)":
  1064. var warnings = new seq[string]
  1065. check(
  1066. dedent"""
  1067. ====== ======
  1068. Inputs Output
  1069. ~~~~~~ ~~~~~~
  1070. """.toAst(warnings=warnings) ==
  1071. expTable)
  1072. check(warnings[] ==
  1073. @["input(3, 1) Warning: RST style: "&
  1074. "only tables with `=` columns specification are allowed"])
  1075. suite "RST indentation":
  1076. test "nested bullet lists":
  1077. let input = dedent """
  1078. * - bullet1
  1079. - bullet2
  1080. * - bullet3
  1081. - bullet4
  1082. """
  1083. let output = input.toAst
  1084. check(output == dedent"""
  1085. rnBulletList
  1086. rnBulletItem
  1087. rnBulletList
  1088. rnBulletItem
  1089. rnInner
  1090. rnLeaf 'bullet1'
  1091. rnBulletItem
  1092. rnInner
  1093. rnLeaf 'bullet2'
  1094. rnBulletItem
  1095. rnBulletList
  1096. rnBulletItem
  1097. rnInner
  1098. rnLeaf 'bullet3'
  1099. rnBulletItem
  1100. rnInner
  1101. rnLeaf 'bullet4'
  1102. """)
  1103. test "nested markup blocks":
  1104. let input = dedent"""
  1105. #) .. Hint:: .. Error:: none
  1106. #) .. Warning:: term0
  1107. Definition0
  1108. #) some
  1109. paragraph1
  1110. #) term1
  1111. Definition1
  1112. term2
  1113. Definition2
  1114. """
  1115. check(input.toAst(rstOptions = preferRst) == dedent"""
  1116. rnEnumList labelFmt=1)
  1117. rnEnumItem
  1118. rnAdmonition adType=hint
  1119. [nil]
  1120. [nil]
  1121. rnAdmonition adType=error
  1122. [nil]
  1123. [nil]
  1124. rnLeaf 'none'
  1125. rnEnumItem
  1126. rnAdmonition adType=warning
  1127. [nil]
  1128. [nil]
  1129. rnDefList
  1130. rnDefItem
  1131. rnDefName
  1132. rnLeaf 'term0'
  1133. rnDefBody
  1134. rnInner
  1135. rnLeaf 'Definition0'
  1136. rnEnumItem
  1137. rnInner
  1138. rnLeaf 'some'
  1139. rnLeaf ' '
  1140. rnLeaf 'paragraph1'
  1141. rnEnumItem
  1142. rnDefList
  1143. rnDefItem
  1144. rnDefName
  1145. rnLeaf 'term1'
  1146. rnDefBody
  1147. rnInner
  1148. rnLeaf 'Definition1'
  1149. rnDefItem
  1150. rnDefName
  1151. rnLeaf 'term2'
  1152. rnDefBody
  1153. rnInner
  1154. rnLeaf 'Definition2'
  1155. """)
  1156. test "code-block parsing":
  1157. let input1 = dedent"""
  1158. .. code-block:: nim
  1159. :test: "nim c $1"
  1160. template additive(typ: typedesc) =
  1161. discard
  1162. """
  1163. let input2 = dedent"""
  1164. .. code-block:: nim
  1165. :test: "nim c $1"
  1166. template additive(typ: typedesc) =
  1167. discard
  1168. """
  1169. let input3 = dedent"""
  1170. .. code-block:: nim
  1171. :test: "nim c $1"
  1172. template additive(typ: typedesc) =
  1173. discard
  1174. """
  1175. let inputWrong = dedent"""
  1176. .. code-block:: nim
  1177. :test: "nim c $1"
  1178. template additive(typ: typedesc) =
  1179. discard
  1180. """
  1181. let ast = dedent"""
  1182. rnCodeBlock
  1183. rnDirArg
  1184. rnLeaf 'nim'
  1185. rnFieldList
  1186. rnField
  1187. rnFieldName
  1188. rnLeaf 'test'
  1189. rnFieldBody
  1190. rnInner
  1191. rnLeaf '"'
  1192. rnLeaf 'nim'
  1193. rnLeaf ' '
  1194. rnLeaf 'c'
  1195. rnLeaf ' '
  1196. rnLeaf '$'
  1197. rnLeaf '1'
  1198. rnLeaf '"'
  1199. rnField
  1200. rnFieldName
  1201. rnLeaf 'default-language'
  1202. rnFieldBody
  1203. rnLeaf 'Nim'
  1204. rnLiteralBlock
  1205. rnLeaf 'template additive(typ: typedesc) =
  1206. discard'
  1207. """
  1208. check input1.toAst == ast
  1209. check input2.toAst == ast
  1210. check input3.toAst == ast
  1211. # "template..." should be parsed as a definition list attached to ":test:":
  1212. check inputWrong.toAst != ast
  1213. test "Markdown definition lists work in conjunction with bullet lists":
  1214. check(dedent"""
  1215. * some term
  1216. : the definition
  1217. Paragraph.""".toAst ==
  1218. dedent"""
  1219. rnInner
  1220. rnBulletList
  1221. rnBulletItem
  1222. rnMdDefList
  1223. rnDefItem
  1224. rnDefName
  1225. rnLeaf 'some'
  1226. rnLeaf ' '
  1227. rnLeaf 'term'
  1228. rnDefBody
  1229. rnInner
  1230. rnLeaf 'the'
  1231. rnLeaf ' '
  1232. rnLeaf 'definition'
  1233. rnParagraph
  1234. rnLeaf 'Paragraph'
  1235. rnLeaf '.'
  1236. """)
  1237. test "Markdown definition lists work with blank lines and extra paragraphs":
  1238. check(dedent"""
  1239. Term1
  1240. : Definition1
  1241. Term2 *inline markup*
  1242. : Definition2
  1243. Paragraph2
  1244. Term3
  1245. : * point1
  1246. * point2
  1247. : term3definition2
  1248. """.toAst == dedent"""
  1249. rnMdDefList
  1250. rnDefItem
  1251. rnDefName
  1252. rnLeaf 'Term1'
  1253. rnDefBody
  1254. rnInner
  1255. rnLeaf 'Definition1'
  1256. rnDefItem
  1257. rnDefName
  1258. rnLeaf 'Term2'
  1259. rnLeaf ' '
  1260. rnEmphasis
  1261. rnLeaf 'inline'
  1262. rnLeaf ' '
  1263. rnLeaf 'markup'
  1264. rnDefBody
  1265. rnParagraph
  1266. rnLeaf 'Definition2'
  1267. rnParagraph
  1268. rnLeaf 'Paragraph2'
  1269. rnDefItem
  1270. rnDefName
  1271. rnLeaf 'Term3'
  1272. rnDefBody
  1273. rnBulletList
  1274. rnBulletItem
  1275. rnInner
  1276. rnLeaf 'point1'
  1277. rnBulletItem
  1278. rnInner
  1279. rnLeaf 'point2'
  1280. rnDefBody
  1281. rnInner
  1282. rnLeaf 'term3definition2'
  1283. """)
  1284. suite "Markdown indentation":
  1285. test "Markdown paragraph indentation":
  1286. # Additional spaces (<=3) of indentation does not break the paragraph.
  1287. # TODO: in 2nd case de-indentation causes paragraph to break, this is
  1288. # reasonable but does not seem to conform the Markdown spec.
  1289. check(dedent"""
  1290. Start1
  1291. stop1
  1292. Start2
  1293. stop2
  1294. """.toAst ==
  1295. dedent"""
  1296. rnInner
  1297. rnParagraph
  1298. rnLeaf 'Start1'
  1299. rnLeaf ' '
  1300. rnLeaf 'stop1'
  1301. rnParagraph
  1302. rnLeaf 'Start2'
  1303. rnParagraph
  1304. rnLeaf 'stop2'
  1305. rnLeaf ' '
  1306. """)
  1307. suite "Warnings":
  1308. test "warnings for broken footnotes/links/substitutions":
  1309. let input = dedent"""
  1310. firstParagraph
  1311. footnoteRef [som]_
  1312. link `a broken Link`_
  1313. substitution |undefined subst|
  1314. link short.link_
  1315. lastParagraph
  1316. """
  1317. var warnings = new seq[string]
  1318. let output = input.toAst(rstOptions=preferRst, warnings=warnings)
  1319. check(warnings[] == @[
  1320. "input(3, 14) Warning: broken link 'citation-som'",
  1321. "input(5, 7) Warning: broken link 'a broken Link'",
  1322. "input(7, 15) Warning: unknown substitution 'undefined subst'",
  1323. "input(9, 6) Warning: broken link 'short.link'"
  1324. ])
  1325. test "Pandoc Markdown concise link warning points to target":
  1326. var warnings = new seq[string]
  1327. check(
  1328. "ref [here][target]".toAst(warnings=warnings) ==
  1329. dedent"""
  1330. rnInner
  1331. rnLeaf 'ref'
  1332. rnLeaf ' '
  1333. rnPandocRef
  1334. rnInner
  1335. rnLeaf 'here'
  1336. rnInner
  1337. rnLeaf 'target'
  1338. """)
  1339. check warnings[] == @["input(1, 12) Warning: broken link 'target'"]
  1340. test "With include directive and blank lines at the beginning":
  1341. "other.rst".writeFile(dedent"""
  1342. firstParagraph
  1343. here brokenLink_""")
  1344. let input = ".. include:: other.rst"
  1345. var warnings = new seq[string]
  1346. let output = input.toAst(warnings=warnings)
  1347. check warnings[] == @["other.rst(5, 6) Warning: broken link 'brokenLink'"]
  1348. check(output == dedent"""
  1349. rnInner
  1350. rnParagraph
  1351. rnLeaf 'firstParagraph'
  1352. rnParagraph
  1353. rnLeaf 'here'
  1354. rnLeaf ' '
  1355. rnRstRef
  1356. rnLeaf 'brokenLink'
  1357. """)
  1358. removeFile("other.rst")
  1359. test "warnings for ambiguous links (references + anchors)":
  1360. # Reference like `x`_ generates a link alias x that may clash with others
  1361. let input = dedent"""
  1362. Manual reference: `foo <#foo,string,string>`_
  1363. .. _foo:
  1364. Paragraph.
  1365. Ref foo_
  1366. """
  1367. var warnings = new seq[string]
  1368. let output = input.toAst(warnings=warnings)
  1369. check(warnings[] == @[
  1370. dedent """
  1371. input(7, 5) Warning: ambiguous doc link `foo`
  1372. clash:
  1373. (3, 8): (manual directive anchor)
  1374. (1, 45): (implicitly-generated hyperlink alias)"""
  1375. ])
  1376. # reference should be resolved to the manually set anchor:
  1377. check(output ==
  1378. dedent"""
  1379. rnInner
  1380. rnParagraph
  1381. rnLeaf 'Manual'
  1382. rnLeaf ' '
  1383. rnLeaf 'reference'
  1384. rnLeaf ':'
  1385. rnLeaf ' '
  1386. rnHyperlink
  1387. rnInner
  1388. rnLeaf 'foo'
  1389. rnInner
  1390. rnLeaf '#foo,string,string'
  1391. rnParagraph anchor='foo'
  1392. rnLeaf 'Paragraph'
  1393. rnLeaf '.'
  1394. rnParagraph
  1395. rnLeaf 'Ref'
  1396. rnLeaf ' '
  1397. rnInternalRef
  1398. rnInner
  1399. rnLeaf 'foo'
  1400. rnLeaf 'foo'
  1401. rnLeaf ' '
  1402. """)
  1403. suite "RST include directive":
  1404. test "Include whole":
  1405. "other.rst".writeFile("**test1**")
  1406. let input = ".. include:: other.rst"
  1407. doAssert "<strong>test1</strong>" == rstToHtml(input, {roSandboxDisabled}, defaultConfig())
  1408. removeFile("other.rst")
  1409. test "Include starting from":
  1410. "other.rst".writeFile("""
  1411. And this should **NOT** be visible in `docs.html`
  1412. OtherStart
  1413. *Visible*
  1414. """)
  1415. let input = """
  1416. .. include:: other.rst
  1417. :start-after: OtherStart
  1418. """
  1419. check "<em>Visible</em>" == rstToHtml(input, {roSandboxDisabled}, defaultConfig())
  1420. removeFile("other.rst")
  1421. test "Include everything before":
  1422. "other.rst".writeFile("""
  1423. *Visible*
  1424. OtherEnd
  1425. And this should **NOT** be visible in `docs.html`
  1426. """)
  1427. let input = """
  1428. .. include:: other.rst
  1429. :end-before: OtherEnd
  1430. """
  1431. doAssert "<em>Visible</em>" == rstToHtml(input, {roSandboxDisabled}, defaultConfig())
  1432. removeFile("other.rst")
  1433. test "Include everything between":
  1434. "other.rst".writeFile("""
  1435. And this should **NOT** be visible in `docs.html`
  1436. OtherStart
  1437. *Visible*
  1438. OtherEnd
  1439. And this should **NOT** be visible in `docs.html`
  1440. """)
  1441. let input = """
  1442. .. include:: other.rst
  1443. :start-after: OtherStart
  1444. :end-before: OtherEnd
  1445. """
  1446. check "<em>Visible</em>" == rstToHtml(input, {roSandboxDisabled}, defaultConfig())
  1447. removeFile("other.rst")
  1448. test "Ignore premature ending string":
  1449. "other.rst".writeFile("""
  1450. OtherEnd
  1451. And this should **NOT** be visible in `docs.html`
  1452. OtherStart
  1453. *Visible*
  1454. OtherEnd
  1455. And this should **NOT** be visible in `docs.html`
  1456. """)
  1457. let input = """
  1458. .. include:: other.rst
  1459. :start-after: OtherStart
  1460. :end-before: OtherEnd
  1461. """
  1462. doAssert "<em>Visible</em>" == rstToHtml(input, {roSandboxDisabled}, defaultConfig())
  1463. removeFile("other.rst")
  1464. suite "RST escaping":
  1465. test "backspaces":
  1466. check("""\ this""".toAst == dedent"""
  1467. rnLeaf 'this'
  1468. """)
  1469. check("""\\ this""".toAst == dedent"""
  1470. rnInner
  1471. rnLeaf '\'
  1472. rnLeaf ' '
  1473. rnLeaf 'this'
  1474. """)
  1475. check("""\\\ this""".toAst == dedent"""
  1476. rnInner
  1477. rnLeaf '\'
  1478. rnLeaf 'this'
  1479. """)
  1480. check("""\\\\ this""".toAst == dedent"""
  1481. rnInner
  1482. rnLeaf '\'
  1483. rnLeaf '\'
  1484. rnLeaf ' '
  1485. rnLeaf 'this'
  1486. """)
  1487. suite "RST inline markup":
  1488. test "* and ** surrounded by spaces are not inline markup":
  1489. check("a * b * c ** d ** e".toAst == dedent"""
  1490. rnInner
  1491. rnLeaf 'a'
  1492. rnLeaf ' '
  1493. rnLeaf '*'
  1494. rnLeaf ' '
  1495. rnLeaf 'b'
  1496. rnLeaf ' '
  1497. rnLeaf '*'
  1498. rnLeaf ' '
  1499. rnLeaf 'c'
  1500. rnLeaf ' '
  1501. rnLeaf '**'
  1502. rnLeaf ' '
  1503. rnLeaf 'd'
  1504. rnLeaf ' '
  1505. rnLeaf '**'
  1506. rnLeaf ' '
  1507. rnLeaf 'e'
  1508. """)
  1509. test "end-string has repeating symbols":
  1510. check("*emphasis content****".toAst == dedent"""
  1511. rnEmphasis
  1512. rnLeaf 'emphasis'
  1513. rnLeaf ' '
  1514. rnLeaf 'content'
  1515. rnLeaf '***'
  1516. """)
  1517. check("""*emphasis content\****""".toAst == dedent"""
  1518. rnEmphasis
  1519. rnLeaf 'emphasis'
  1520. rnLeaf ' '
  1521. rnLeaf 'content'
  1522. rnLeaf '*'
  1523. rnLeaf '**'
  1524. """) # exact configuration of leafs with * is not really essential,
  1525. # only total number of * is essential
  1526. check("**strong content****".toAst == dedent"""
  1527. rnStrongEmphasis
  1528. rnLeaf 'strong'
  1529. rnLeaf ' '
  1530. rnLeaf 'content'
  1531. rnLeaf '**'
  1532. """)
  1533. check("""**strong content*\****""".toAst == dedent"""
  1534. rnStrongEmphasis
  1535. rnLeaf 'strong'
  1536. rnLeaf ' '
  1537. rnLeaf 'content'
  1538. rnLeaf '*'
  1539. rnLeaf '*'
  1540. rnLeaf '*'
  1541. """)
  1542. check("``lit content`````".toAst == dedent"""
  1543. rnInlineLiteral
  1544. rnLeaf 'lit'
  1545. rnLeaf ' '
  1546. rnLeaf 'content'
  1547. rnLeaf '```'
  1548. """)
  1549. test "interpreted text parsing: code fragments":
  1550. check(dedent"""
  1551. .. default-role:: option
  1552. `--gc:refc`""".toAst ==
  1553. dedent"""
  1554. rnInner
  1555. rnDefaultRole
  1556. rnDirArg
  1557. rnLeaf 'option'
  1558. [nil]
  1559. [nil]
  1560. rnParagraph
  1561. rnCodeFragment
  1562. rnInner
  1563. rnLeaf '--'
  1564. rnLeaf 'gc'
  1565. rnLeaf ':'
  1566. rnLeaf 'refc'
  1567. rnLeaf 'option'
  1568. """)
  1569. test """interpreted text can be ended with \` """:
  1570. let output = (".. default-role:: literal\n" & """`\``""").toAst
  1571. check(output.endsWith """
  1572. rnParagraph
  1573. rnInlineLiteral
  1574. rnLeaf '`'""" & "\n")
  1575. let output2 = """`\``""".toAst
  1576. check(output2 == dedent"""
  1577. rnInlineCode
  1578. rnDirArg
  1579. rnLeaf 'nim'
  1580. [nil]
  1581. rnLiteralBlock
  1582. rnLeaf '`'
  1583. """)
  1584. let output3 = """`proc \`+\``""".toAst
  1585. check(output3 == dedent"""
  1586. rnInlineCode
  1587. rnDirArg
  1588. rnLeaf 'nim'
  1589. [nil]
  1590. rnLiteralBlock
  1591. rnLeaf 'proc `+`'
  1592. """)
  1593. check("""`\\`""".toAst ==
  1594. dedent"""
  1595. rnInlineCode
  1596. rnDirArg
  1597. rnLeaf 'nim'
  1598. [nil]
  1599. rnLiteralBlock
  1600. rnLeaf '\\'
  1601. """)
  1602. test "Markdown-style code/backtick":
  1603. # no whitespace is required before `
  1604. check("`try`...`except`".toAst ==
  1605. dedent"""
  1606. rnInner
  1607. rnInlineCode
  1608. rnDirArg
  1609. rnLeaf 'nim'
  1610. [nil]
  1611. rnLiteralBlock
  1612. rnLeaf 'try'
  1613. rnLeaf '...'
  1614. rnInlineCode
  1615. rnDirArg
  1616. rnLeaf 'nim'
  1617. [nil]
  1618. rnLiteralBlock
  1619. rnLeaf 'except'
  1620. """)
  1621. test """inline literals can contain \ anywhere""":
  1622. check("""``\``""".toAst == dedent"""
  1623. rnInlineLiteral
  1624. rnLeaf '\'
  1625. """)
  1626. check("""``\\``""".toAst == dedent"""
  1627. rnInlineLiteral
  1628. rnLeaf '\'
  1629. rnLeaf '\'
  1630. """)
  1631. check("""``\```""".toAst == dedent"""
  1632. rnInlineLiteral
  1633. rnLeaf '\'
  1634. rnLeaf '`'
  1635. """)
  1636. check("""``\\```""".toAst == dedent"""
  1637. rnInlineLiteral
  1638. rnLeaf '\'
  1639. rnLeaf '\'
  1640. rnLeaf '`'
  1641. """)
  1642. check("""``\````""".toAst == dedent"""
  1643. rnInlineLiteral
  1644. rnLeaf '\'
  1645. rnLeaf '`'
  1646. rnLeaf '`'
  1647. """)
  1648. test "references with _ at the end":
  1649. check(dedent"""
  1650. .. _lnk: https
  1651. lnk_""".toAst ==
  1652. dedent"""
  1653. rnHyperlink
  1654. rnInner
  1655. rnLeaf 'lnk'
  1656. rnInner
  1657. rnLeaf 'https'
  1658. """)
  1659. test "not a hyper link":
  1660. check(dedent"""
  1661. .. _lnk: https
  1662. lnk___""".toAst ==
  1663. dedent"""
  1664. rnInner
  1665. rnLeaf 'lnk'
  1666. rnLeaf '___'
  1667. """)
  1668. test "no punctuation in the end of a standalone URI is allowed":
  1669. check(dedent"""
  1670. [see (http://no.org)], end""".toAst(rstOptions = preferRst) ==
  1671. dedent"""
  1672. rnInner
  1673. rnLeaf '['
  1674. rnLeaf 'see'
  1675. rnLeaf ' '
  1676. rnLeaf '('
  1677. rnStandaloneHyperlink
  1678. rnLeaf 'http://no.org'
  1679. rnLeaf ')'
  1680. rnLeaf ']'
  1681. rnLeaf ','
  1682. rnLeaf ' '
  1683. rnLeaf 'end'
  1684. """)
  1685. # but `/` at the end is OK
  1686. check(
  1687. dedent"""
  1688. See http://no.org/ end""".toAst ==
  1689. dedent"""
  1690. rnInner
  1691. rnLeaf 'See'
  1692. rnLeaf ' '
  1693. rnStandaloneHyperlink
  1694. rnLeaf 'http://no.org/'
  1695. rnLeaf ' '
  1696. rnLeaf 'end'
  1697. """)
  1698. # a more complex URL with some made-up ending '&='.
  1699. # Github Markdown would include final &= and
  1700. # so would rst2html.py in contradiction with RST spec.
  1701. check(
  1702. dedent"""
  1703. 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 ==
  1704. dedent"""
  1705. rnInner
  1706. rnLeaf 'See'
  1707. rnLeaf ' '
  1708. rnStandaloneHyperlink
  1709. 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'
  1710. rnLeaf '&'
  1711. rnLeaf '='
  1712. rnLeaf ' '
  1713. rnLeaf 'end'
  1714. """)
  1715. test "Markdown-style link can be split to a few lines":
  1716. check(dedent"""
  1717. is [term-rewriting
  1718. macros](manual.html#term-rewriting-macros)""".toAst ==
  1719. dedent"""
  1720. rnInner
  1721. rnLeaf 'is'
  1722. rnLeaf ' '
  1723. rnHyperlink
  1724. rnLeaf 'term-rewriting macros'
  1725. rnLeaf 'manual.html#term-rewriting-macros'
  1726. """)
  1727. test "URL with balanced parentheses (Markdown rule)":
  1728. # 2 balanced parens, 1 unbalanced:
  1729. check(dedent"""
  1730. https://en.wikipedia.org/wiki/APL_((programming_language)))""".toAst ==
  1731. dedent"""
  1732. rnInner
  1733. rnStandaloneHyperlink
  1734. rnLeaf 'https://en.wikipedia.org/wiki/APL_((programming_language))'
  1735. rnLeaf ')'
  1736. """)
  1737. # the same for Markdown-style link:
  1738. check(dedent"""
  1739. [foo [bar]](https://en.wikipedia.org/wiki/APL_((programming_language))))""".toAst ==
  1740. dedent"""
  1741. rnInner
  1742. rnHyperlink
  1743. rnLeaf 'foo [bar]'
  1744. rnLeaf 'https://en.wikipedia.org/wiki/APL_((programming_language))'
  1745. rnLeaf ')'
  1746. """)
  1747. # unbalanced (here behavior is more RST-like actually):
  1748. check(dedent"""
  1749. https://en.wikipedia.org/wiki/APL_(programming_language(""".toAst ==
  1750. dedent"""
  1751. rnInner
  1752. rnStandaloneHyperlink
  1753. rnLeaf 'https://en.wikipedia.org/wiki/APL_(programming_language'
  1754. rnLeaf '('
  1755. """)
  1756. # unbalanced [, but still acceptable:
  1757. check(dedent"""
  1758. [my {link example](http://example.com/bracket_(symbol_[))""".toAst ==
  1759. dedent"""
  1760. rnHyperlink
  1761. rnLeaf 'my {link example'
  1762. rnLeaf 'http://example.com/bracket_(symbol_[)'
  1763. """)
  1764. test "not a Markdown link":
  1765. # bug #17340 (27) `f` will be considered as a protocol and blocked as unsafe
  1766. var warnings = new seq[string]
  1767. check("[T](f: var Foo)".toAst(warnings = warnings) ==
  1768. dedent"""
  1769. rnInner
  1770. rnLeaf '['
  1771. rnLeaf 'T'
  1772. rnLeaf ']'
  1773. rnLeaf '('
  1774. rnLeaf 'f'
  1775. rnLeaf ':'
  1776. rnLeaf ' '
  1777. rnLeaf 'var'
  1778. rnLeaf ' '
  1779. rnLeaf 'Foo'
  1780. rnLeaf ')'
  1781. """)
  1782. check(warnings[] == @["input(1, 5) Warning: broken link 'f'"])