trst.nim 50 KB

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