gitdown 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (416) hide show
  1. data/AUTHORS +1 -0
  2. data/COPYING +24 -0
  3. data/GPL +674 -0
  4. data/README +43 -0
  5. data/Rakefile +370 -0
  6. data/VERSION +1 -0
  7. data/benchmark/benchmark.rb +34 -0
  8. data/benchmark/benchmark.sh +74 -0
  9. data/benchmark/generate_data.rb +119 -0
  10. data/benchmark/mdbasics.text +306 -0
  11. data/benchmark/mdsyntax.text +888 -0
  12. data/benchmark/testing.sh +9 -0
  13. data/benchmark/timing.sh +10 -0
  14. data/bin/kramdown +78 -0
  15. data/data/kramdown/document.html +18 -0
  16. data/data/kramdown/document.latex +43 -0
  17. data/doc/default.scss.css +530 -0
  18. data/doc/default.template +80 -0
  19. data/doc/documentation.page +71 -0
  20. data/doc/index.page +98 -0
  21. data/doc/installation.page +88 -0
  22. data/doc/links.markdown +6 -0
  23. data/doc/news.feed +10 -0
  24. data/doc/news.page +28 -0
  25. data/doc/quickref.page +585 -0
  26. data/doc/syntax.page +1644 -0
  27. data/doc/tests.page +52 -0
  28. data/doc/virtual +2 -0
  29. data/lib/kramdown.rb +23 -0
  30. data/lib/kramdown/compatibility.rb +35 -0
  31. data/lib/kramdown/converter.rb +41 -0
  32. data/lib/kramdown/converter/base.rb +169 -0
  33. data/lib/kramdown/converter/html.rb +410 -0
  34. data/lib/kramdown/converter/kramdown.rb +422 -0
  35. data/lib/kramdown/converter/latex.rb +607 -0
  36. data/lib/kramdown/converter/toc.rb +82 -0
  37. data/lib/kramdown/document.rb +117 -0
  38. data/lib/kramdown/element.rb +524 -0
  39. data/lib/kramdown/error.rb +30 -0
  40. data/lib/kramdown/options.rb +373 -0
  41. data/lib/kramdown/parser.rb +40 -0
  42. data/lib/kramdown/parser/base.rb +136 -0
  43. data/lib/kramdown/parser/github_markdown.rb +44 -0
  44. data/lib/kramdown/parser/github_markdown/github_codeblock.rb +44 -0
  45. data/lib/kramdown/parser/html.rb +570 -0
  46. data/lib/kramdown/parser/kramdown.rb +338 -0
  47. data/lib/kramdown/parser/kramdown/abbreviation.rb +71 -0
  48. data/lib/kramdown/parser/kramdown/autolink.rb +53 -0
  49. data/lib/kramdown/parser/kramdown/blank_line.rb +43 -0
  50. data/lib/kramdown/parser/kramdown/block_boundary.rb +46 -0
  51. data/lib/kramdown/parser/kramdown/blockquote.rb +51 -0
  52. data/lib/kramdown/parser/kramdown/codeblock.rb +63 -0
  53. data/lib/kramdown/parser/kramdown/codespan.rb +56 -0
  54. data/lib/kramdown/parser/kramdown/emphasis.rb +70 -0
  55. data/lib/kramdown/parser/kramdown/eob.rb +39 -0
  56. data/lib/kramdown/parser/kramdown/escaped_chars.rb +38 -0
  57. data/lib/kramdown/parser/kramdown/extensions.rb +204 -0
  58. data/lib/kramdown/parser/kramdown/footnote.rb +74 -0
  59. data/lib/kramdown/parser/kramdown/header.rb +68 -0
  60. data/lib/kramdown/parser/kramdown/horizontal_rule.rb +39 -0
  61. data/lib/kramdown/parser/kramdown/html.rb +169 -0
  62. data/lib/kramdown/parser/kramdown/html_entity.rb +44 -0
  63. data/lib/kramdown/parser/kramdown/line_break.rb +38 -0
  64. data/lib/kramdown/parser/kramdown/link.rb +148 -0
  65. data/lib/kramdown/parser/kramdown/list.rb +240 -0
  66. data/lib/kramdown/parser/kramdown/math.rb +64 -0
  67. data/lib/kramdown/parser/kramdown/paragraph.rb +63 -0
  68. data/lib/kramdown/parser/kramdown/smart_quotes.rb +214 -0
  69. data/lib/kramdown/parser/kramdown/table.rb +178 -0
  70. data/lib/kramdown/parser/kramdown/typographic_symbol.rb +52 -0
  71. data/lib/kramdown/parser/markdown.rb +69 -0
  72. data/lib/kramdown/utils.rb +37 -0
  73. data/lib/kramdown/utils/entities.rb +348 -0
  74. data/lib/kramdown/utils/html.rb +85 -0
  75. data/lib/kramdown/utils/ordered_hash.rb +100 -0
  76. data/lib/kramdown/version.rb +28 -0
  77. data/setup.rb +1585 -0
  78. data/test/run_tests.rb +59 -0
  79. data/test/test_files.rb +197 -0
  80. data/test/testcases/block/01_blank_line/spaces.html +1 -0
  81. data/test/testcases/block/01_blank_line/spaces.text +3 -0
  82. data/test/testcases/block/01_blank_line/tabs.html +1 -0
  83. data/test/testcases/block/01_blank_line/tabs.text +6 -0
  84. data/test/testcases/block/02_eob/beginning.html +1 -0
  85. data/test/testcases/block/02_eob/beginning.text +3 -0
  86. data/test/testcases/block/02_eob/end.html +1 -0
  87. data/test/testcases/block/02_eob/end.text +3 -0
  88. data/test/testcases/block/02_eob/middle.html +1 -0
  89. data/test/testcases/block/02_eob/middle.text +5 -0
  90. data/test/testcases/block/03_paragraph/indented.html +18 -0
  91. data/test/testcases/block/03_paragraph/indented.text +19 -0
  92. data/test/testcases/block/03_paragraph/no_newline_at_end.html +5 -0
  93. data/test/testcases/block/03_paragraph/no_newline_at_end.text +5 -0
  94. data/test/testcases/block/03_paragraph/one_para.html +1 -0
  95. data/test/testcases/block/03_paragraph/one_para.text +1 -0
  96. data/test/testcases/block/03_paragraph/two_para.html +4 -0
  97. data/test/testcases/block/03_paragraph/two_para.text +4 -0
  98. data/test/testcases/block/04_header/atx_header.html +37 -0
  99. data/test/testcases/block/04_header/atx_header.text +34 -0
  100. data/test/testcases/block/04_header/atx_header_no_newline_at_end.html +1 -0
  101. data/test/testcases/block/04_header/atx_header_no_newline_at_end.text +1 -0
  102. data/test/testcases/block/04_header/setext_header.html +30 -0
  103. data/test/testcases/block/04_header/setext_header.html.19 +30 -0
  104. data/test/testcases/block/04_header/setext_header.text +36 -0
  105. data/test/testcases/block/04_header/setext_header_no_newline_at_end.html +1 -0
  106. data/test/testcases/block/04_header/setext_header_no_newline_at_end.text +2 -0
  107. data/test/testcases/block/04_header/with_auto_id_prefix.html +3 -0
  108. data/test/testcases/block/04_header/with_auto_id_prefix.options +2 -0
  109. data/test/testcases/block/04_header/with_auto_id_prefix.text +3 -0
  110. data/test/testcases/block/04_header/with_auto_ids.html +17 -0
  111. data/test/testcases/block/04_header/with_auto_ids.options +1 -0
  112. data/test/testcases/block/04_header/with_auto_ids.text +19 -0
  113. data/test/testcases/block/05_blockquote/indented.html +25 -0
  114. data/test/testcases/block/05_blockquote/indented.text +14 -0
  115. data/test/testcases/block/05_blockquote/lazy.html +34 -0
  116. data/test/testcases/block/05_blockquote/lazy.text +20 -0
  117. data/test/testcases/block/05_blockquote/nested.html +10 -0
  118. data/test/testcases/block/05_blockquote/nested.text +6 -0
  119. data/test/testcases/block/05_blockquote/no_newline_at_end.html +4 -0
  120. data/test/testcases/block/05_blockquote/no_newline_at_end.text +2 -0
  121. data/test/testcases/block/05_blockquote/very_long_line.html +3 -0
  122. data/test/testcases/block/05_blockquote/very_long_line.text +1 -0
  123. data/test/testcases/block/05_blockquote/with_code_blocks.html +15 -0
  124. data/test/testcases/block/05_blockquote/with_code_blocks.text +11 -0
  125. data/test/testcases/block/06_codeblock/error.html +4 -0
  126. data/test/testcases/block/06_codeblock/error.text +4 -0
  127. data/test/testcases/block/06_codeblock/lazy.html +4 -0
  128. data/test/testcases/block/06_codeblock/lazy.text +5 -0
  129. data/test/testcases/block/06_codeblock/no_newline_at_end.html +2 -0
  130. data/test/testcases/block/06_codeblock/no_newline_at_end.text +1 -0
  131. data/test/testcases/block/06_codeblock/no_newline_at_end_1.html +2 -0
  132. data/test/testcases/block/06_codeblock/no_newline_at_end_1.text +2 -0
  133. data/test/testcases/block/06_codeblock/normal.html +13 -0
  134. data/test/testcases/block/06_codeblock/normal.text +10 -0
  135. data/test/testcases/block/06_codeblock/tilde_syntax.html +7 -0
  136. data/test/testcases/block/06_codeblock/tilde_syntax.text +9 -0
  137. data/test/testcases/block/06_codeblock/whitespace.html +3 -0
  138. data/test/testcases/block/06_codeblock/whitespace.text +3 -0
  139. data/test/testcases/block/06_codeblock/with_blank_line.html +13 -0
  140. data/test/testcases/block/06_codeblock/with_blank_line.text +12 -0
  141. data/test/testcases/block/06_codeblock/with_eob_marker.html +6 -0
  142. data/test/testcases/block/06_codeblock/with_eob_marker.text +5 -0
  143. data/test/testcases/block/06_codeblock/with_ial.html +6 -0
  144. data/test/testcases/block/06_codeblock/with_ial.text +5 -0
  145. data/test/testcases/block/07_horizontal_rule/error.html +7 -0
  146. data/test/testcases/block/07_horizontal_rule/error.html.19 +7 -0
  147. data/test/testcases/block/07_horizontal_rule/error.text +7 -0
  148. data/test/testcases/block/07_horizontal_rule/normal.html +17 -0
  149. data/test/testcases/block/07_horizontal_rule/normal.text +17 -0
  150. data/test/testcases/block/07_horizontal_rule/sepspaces.html +3 -0
  151. data/test/testcases/block/07_horizontal_rule/sepspaces.text +3 -0
  152. data/test/testcases/block/07_horizontal_rule/septabs.html +3 -0
  153. data/test/testcases/block/07_horizontal_rule/septabs.text +3 -0
  154. data/test/testcases/block/08_list/escaping.html +17 -0
  155. data/test/testcases/block/08_list/escaping.text +17 -0
  156. data/test/testcases/block/08_list/item_ial.html +10 -0
  157. data/test/testcases/block/08_list/item_ial.text +8 -0
  158. data/test/testcases/block/08_list/lazy.html +39 -0
  159. data/test/testcases/block/08_list/lazy.text +29 -0
  160. data/test/testcases/block/08_list/list_and_hr.html +9 -0
  161. data/test/testcases/block/08_list/list_and_hr.text +5 -0
  162. data/test/testcases/block/08_list/list_and_others.html +40 -0
  163. data/test/testcases/block/08_list/list_and_others.text +26 -0
  164. data/test/testcases/block/08_list/mixed.html +117 -0
  165. data/test/testcases/block/08_list/mixed.text +66 -0
  166. data/test/testcases/block/08_list/nested.html +17 -0
  167. data/test/testcases/block/08_list/nested.text +7 -0
  168. data/test/testcases/block/08_list/other_first_element.html +39 -0
  169. data/test/testcases/block/08_list/other_first_element.text +18 -0
  170. data/test/testcases/block/08_list/simple_ol.html +19 -0
  171. data/test/testcases/block/08_list/simple_ol.text +13 -0
  172. data/test/testcases/block/08_list/simple_ul.html +48 -0
  173. data/test/testcases/block/08_list/simple_ul.text +36 -0
  174. data/test/testcases/block/08_list/single_item.html +3 -0
  175. data/test/testcases/block/08_list/single_item.text +1 -0
  176. data/test/testcases/block/08_list/special_cases.html +55 -0
  177. data/test/testcases/block/08_list/special_cases.text +35 -0
  178. data/test/testcases/block/09_html/comment.html +18 -0
  179. data/test/testcases/block/09_html/comment.text +15 -0
  180. data/test/testcases/block/09_html/content_model/deflists.html +6 -0
  181. data/test/testcases/block/09_html/content_model/deflists.options +1 -0
  182. data/test/testcases/block/09_html/content_model/deflists.text +6 -0
  183. data/test/testcases/block/09_html/content_model/tables.html +14 -0
  184. data/test/testcases/block/09_html/content_model/tables.options +1 -0
  185. data/test/testcases/block/09_html/content_model/tables.text +14 -0
  186. data/test/testcases/block/09_html/html_and_codeblocks.html +15 -0
  187. data/test/testcases/block/09_html/html_and_codeblocks.options +1 -0
  188. data/test/testcases/block/09_html/html_and_codeblocks.text +13 -0
  189. data/test/testcases/block/09_html/html_and_headers.html +5 -0
  190. data/test/testcases/block/09_html/html_and_headers.text +6 -0
  191. data/test/testcases/block/09_html/html_to_native/code.html +10 -0
  192. data/test/testcases/block/09_html/html_to_native/code.text +9 -0
  193. data/test/testcases/block/09_html/html_to_native/comment.html +7 -0
  194. data/test/testcases/block/09_html/html_to_native/comment.text +8 -0
  195. data/test/testcases/block/09_html/html_to_native/emphasis.html +6 -0
  196. data/test/testcases/block/09_html/html_to_native/emphasis.text +6 -0
  197. data/test/testcases/block/09_html/html_to_native/entity.html +1 -0
  198. data/test/testcases/block/09_html/html_to_native/entity.text +1 -0
  199. data/test/testcases/block/09_html/html_to_native/header.html +6 -0
  200. data/test/testcases/block/09_html/html_to_native/header.options +2 -0
  201. data/test/testcases/block/09_html/html_to_native/header.text +6 -0
  202. data/test/testcases/block/09_html/html_to_native/list_dl.html +8 -0
  203. data/test/testcases/block/09_html/html_to_native/list_dl.text +8 -0
  204. data/test/testcases/block/09_html/html_to_native/list_ol.html +15 -0
  205. data/test/testcases/block/09_html/html_to_native/list_ol.text +17 -0
  206. data/test/testcases/block/09_html/html_to_native/list_ul.html +19 -0
  207. data/test/testcases/block/09_html/html_to_native/list_ul.text +22 -0
  208. data/test/testcases/block/09_html/html_to_native/options +1 -0
  209. data/test/testcases/block/09_html/html_to_native/paragraph.html +3 -0
  210. data/test/testcases/block/09_html/html_to_native/paragraph.text +4 -0
  211. data/test/testcases/block/09_html/html_to_native/table_normal.html +12 -0
  212. data/test/testcases/block/09_html/html_to_native/table_normal.text +12 -0
  213. data/test/testcases/block/09_html/html_to_native/table_simple.html +48 -0
  214. data/test/testcases/block/09_html/html_to_native/table_simple.text +56 -0
  215. data/test/testcases/block/09_html/html_to_native/typography.html +1 -0
  216. data/test/testcases/block/09_html/html_to_native/typography.html.19 +1 -0
  217. data/test/testcases/block/09_html/html_to_native/typography.text +1 -0
  218. data/test/testcases/block/09_html/invalid_html_1.html +5 -0
  219. data/test/testcases/block/09_html/invalid_html_1.text +5 -0
  220. data/test/testcases/block/09_html/invalid_html_2.html +5 -0
  221. data/test/testcases/block/09_html/invalid_html_2.text +5 -0
  222. data/test/testcases/block/09_html/markdown_attr.html +38 -0
  223. data/test/testcases/block/09_html/markdown_attr.text +38 -0
  224. data/test/testcases/block/09_html/not_parsed.html +24 -0
  225. data/test/testcases/block/09_html/not_parsed.text +24 -0
  226. data/test/testcases/block/09_html/parse_as_raw.html +35 -0
  227. data/test/testcases/block/09_html/parse_as_raw.htmlinput +34 -0
  228. data/test/testcases/block/09_html/parse_as_raw.options +1 -0
  229. data/test/testcases/block/09_html/parse_as_raw.text +33 -0
  230. data/test/testcases/block/09_html/parse_as_span.html +12 -0
  231. data/test/testcases/block/09_html/parse_as_span.htmlinput +12 -0
  232. data/test/testcases/block/09_html/parse_as_span.options +1 -0
  233. data/test/testcases/block/09_html/parse_as_span.text +9 -0
  234. data/test/testcases/block/09_html/parse_block_html.html +21 -0
  235. data/test/testcases/block/09_html/parse_block_html.options +1 -0
  236. data/test/testcases/block/09_html/parse_block_html.text +17 -0
  237. data/test/testcases/block/09_html/processing_instruction.html +13 -0
  238. data/test/testcases/block/09_html/processing_instruction.text +12 -0
  239. data/test/testcases/block/09_html/simple.html +64 -0
  240. data/test/testcases/block/09_html/simple.html.19 +64 -0
  241. data/test/testcases/block/09_html/simple.options +1 -0
  242. data/test/testcases/block/09_html/simple.text +59 -0
  243. data/test/testcases/block/10_ald/simple.html +2 -0
  244. data/test/testcases/block/10_ald/simple.text +8 -0
  245. data/test/testcases/block/11_ial/auto_id_and_ial.html +1 -0
  246. data/test/testcases/block/11_ial/auto_id_and_ial.options +1 -0
  247. data/test/testcases/block/11_ial/auto_id_and_ial.text +2 -0
  248. data/test/testcases/block/11_ial/nested.html +11 -0
  249. data/test/testcases/block/11_ial/nested.text +15 -0
  250. data/test/testcases/block/11_ial/simple.html +25 -0
  251. data/test/testcases/block/11_ial/simple.text +34 -0
  252. data/test/testcases/block/12_extension/comment.html +8 -0
  253. data/test/testcases/block/12_extension/comment.text +12 -0
  254. data/test/testcases/block/12_extension/ignored.html +8 -0
  255. data/test/testcases/block/12_extension/ignored.text +8 -0
  256. data/test/testcases/block/12_extension/nomarkdown.html +10 -0
  257. data/test/testcases/block/12_extension/nomarkdown.kramdown +20 -0
  258. data/test/testcases/block/12_extension/nomarkdown.latex +13 -0
  259. data/test/testcases/block/12_extension/nomarkdown.text +21 -0
  260. data/test/testcases/block/12_extension/options.html +21 -0
  261. data/test/testcases/block/12_extension/options.text +21 -0
  262. data/test/testcases/block/12_extension/options2.html +10 -0
  263. data/test/testcases/block/12_extension/options2.text +5 -0
  264. data/test/testcases/block/12_extension/options3.html +7 -0
  265. data/test/testcases/block/12_extension/options3.text +7 -0
  266. data/test/testcases/block/13_definition_list/definition_at_beginning.html +1 -0
  267. data/test/testcases/block/13_definition_list/definition_at_beginning.text +1 -0
  268. data/test/testcases/block/13_definition_list/item_ial.html +12 -0
  269. data/test/testcases/block/13_definition_list/item_ial.text +8 -0
  270. data/test/testcases/block/13_definition_list/multiple_terms.html +13 -0
  271. data/test/testcases/block/13_definition_list/multiple_terms.text +10 -0
  272. data/test/testcases/block/13_definition_list/no_def_list.html +2 -0
  273. data/test/testcases/block/13_definition_list/no_def_list.text +2 -0
  274. data/test/testcases/block/13_definition_list/para_wrapping.html +10 -0
  275. data/test/testcases/block/13_definition_list/para_wrapping.text +6 -0
  276. data/test/testcases/block/13_definition_list/separated_by_eob.html +8 -0
  277. data/test/testcases/block/13_definition_list/separated_by_eob.text +5 -0
  278. data/test/testcases/block/13_definition_list/simple.html +8 -0
  279. data/test/testcases/block/13_definition_list/simple.text +7 -0
  280. data/test/testcases/block/13_definition_list/styled_terms.html +4 -0
  281. data/test/testcases/block/13_definition_list/styled_terms.text +2 -0
  282. data/test/testcases/block/13_definition_list/too_much_space.html +3 -0
  283. data/test/testcases/block/13_definition_list/too_much_space.text +4 -0
  284. data/test/testcases/block/13_definition_list/with_blocks.html +38 -0
  285. data/test/testcases/block/13_definition_list/with_blocks.text +24 -0
  286. data/test/testcases/block/14_table/errors.html +8 -0
  287. data/test/testcases/block/14_table/errors.text +9 -0
  288. data/test/testcases/block/14_table/escaping.html +52 -0
  289. data/test/testcases/block/14_table/escaping.text +19 -0
  290. data/test/testcases/block/14_table/footer.html +65 -0
  291. data/test/testcases/block/14_table/footer.text +25 -0
  292. data/test/testcases/block/14_table/header.html +96 -0
  293. data/test/testcases/block/14_table/header.text +32 -0
  294. data/test/testcases/block/14_table/no_table.html +3 -0
  295. data/test/testcases/block/14_table/no_table.text +3 -0
  296. data/test/testcases/block/14_table/simple.html +177 -0
  297. data/test/testcases/block/14_table/simple.html.19 +177 -0
  298. data/test/testcases/block/14_table/simple.text +49 -0
  299. data/test/testcases/block/14_table/table_with_footnote.html +25 -0
  300. data/test/testcases/block/14_table/table_with_footnote.latex +11 -0
  301. data/test/testcases/block/14_table/table_with_footnote.text +6 -0
  302. data/test/testcases/block/15_math/normal.html +26 -0
  303. data/test/testcases/block/15_math/normal.text +28 -0
  304. data/test/testcases/block/16_toc/no_toc.html +33 -0
  305. data/test/testcases/block/16_toc/no_toc.options +1 -0
  306. data/test/testcases/block/16_toc/no_toc.text +16 -0
  307. data/test/testcases/block/16_toc/toc_levels.html +24 -0
  308. data/test/testcases/block/16_toc/toc_levels.options +1 -0
  309. data/test/testcases/block/16_toc/toc_levels.text +16 -0
  310. data/test/testcases/block/17_github_codeblock/backtick_syntax.html +7 -0
  311. data/test/testcases/block/17_github_codeblock/backtick_syntax.text +9 -0
  312. data/test/testcases/block/17_github_codeblock/error.html +4 -0
  313. data/test/testcases/block/17_github_codeblock/error.text +4 -0
  314. data/test/testcases/block/17_github_codeblock/no_newline_at_end.html +2 -0
  315. data/test/testcases/block/17_github_codeblock/no_newline_at_end.text +3 -0
  316. data/test/testcases/encoding.html +46 -0
  317. data/test/testcases/encoding.text +28 -0
  318. data/test/testcases/span/01_link/empty.html +5 -0
  319. data/test/testcases/span/01_link/empty.text +5 -0
  320. data/test/testcases/span/01_link/image_in_a.html +5 -0
  321. data/test/testcases/span/01_link/image_in_a.text +5 -0
  322. data/test/testcases/span/01_link/imagelinks.html +14 -0
  323. data/test/testcases/span/01_link/imagelinks.text +16 -0
  324. data/test/testcases/span/01_link/inline.html +46 -0
  325. data/test/testcases/span/01_link/inline.html.19 +46 -0
  326. data/test/testcases/span/01_link/inline.text +48 -0
  327. data/test/testcases/span/01_link/link_defs.html +9 -0
  328. data/test/testcases/span/01_link/link_defs.text +26 -0
  329. data/test/testcases/span/01_link/links_with_angle_brackets.html +3 -0
  330. data/test/testcases/span/01_link/links_with_angle_brackets.text +3 -0
  331. data/test/testcases/span/01_link/reference.html +36 -0
  332. data/test/testcases/span/01_link/reference.html.19 +36 -0
  333. data/test/testcases/span/01_link/reference.text +50 -0
  334. data/test/testcases/span/02_emphasis/empty.html +3 -0
  335. data/test/testcases/span/02_emphasis/empty.text +3 -0
  336. data/test/testcases/span/02_emphasis/errors.html +9 -0
  337. data/test/testcases/span/02_emphasis/errors.text +9 -0
  338. data/test/testcases/span/02_emphasis/nesting.html +38 -0
  339. data/test/testcases/span/02_emphasis/nesting.text +33 -0
  340. data/test/testcases/span/02_emphasis/normal.html +46 -0
  341. data/test/testcases/span/02_emphasis/normal.text +46 -0
  342. data/test/testcases/span/03_codespan/empty.html +5 -0
  343. data/test/testcases/span/03_codespan/empty.text +5 -0
  344. data/test/testcases/span/03_codespan/errors.html +1 -0
  345. data/test/testcases/span/03_codespan/errors.text +1 -0
  346. data/test/testcases/span/03_codespan/highlighting.html +1 -0
  347. data/test/testcases/span/03_codespan/highlighting.text +1 -0
  348. data/test/testcases/span/03_codespan/normal.html +16 -0
  349. data/test/testcases/span/03_codespan/normal.text +16 -0
  350. data/test/testcases/span/04_footnote/definitions.html +17 -0
  351. data/test/testcases/span/04_footnote/definitions.latex +17 -0
  352. data/test/testcases/span/04_footnote/definitions.text +24 -0
  353. data/test/testcases/span/04_footnote/footnote_nr.html +12 -0
  354. data/test/testcases/span/04_footnote/footnote_nr.latex +2 -0
  355. data/test/testcases/span/04_footnote/footnote_nr.options +1 -0
  356. data/test/testcases/span/04_footnote/footnote_nr.text +4 -0
  357. data/test/testcases/span/04_footnote/markers.html +46 -0
  358. data/test/testcases/span/04_footnote/markers.latex +23 -0
  359. data/test/testcases/span/04_footnote/markers.text +26 -0
  360. data/test/testcases/span/05_html/across_lines.html +1 -0
  361. data/test/testcases/span/05_html/across_lines.text +2 -0
  362. data/test/testcases/span/05_html/invalid.html +1 -0
  363. data/test/testcases/span/05_html/invalid.text +1 -0
  364. data/test/testcases/span/05_html/link_with_mailto.html +1 -0
  365. data/test/testcases/span/05_html/link_with_mailto.text +1 -0
  366. data/test/testcases/span/05_html/markdown_attr.html +6 -0
  367. data/test/testcases/span/05_html/markdown_attr.text +6 -0
  368. data/test/testcases/span/05_html/normal.html +34 -0
  369. data/test/testcases/span/05_html/normal.text +34 -0
  370. data/test/testcases/span/abbreviations/abbrev.html +8 -0
  371. data/test/testcases/span/abbreviations/abbrev.text +15 -0
  372. data/test/testcases/span/abbreviations/abbrev_defs.html +2 -0
  373. data/test/testcases/span/abbreviations/abbrev_defs.text +5 -0
  374. data/test/testcases/span/autolinks/url_links.html +12 -0
  375. data/test/testcases/span/autolinks/url_links.text +12 -0
  376. data/test/testcases/span/escaped_chars/normal.html +47 -0
  377. data/test/testcases/span/escaped_chars/normal.text +47 -0
  378. data/test/testcases/span/extension/comment.html +6 -0
  379. data/test/testcases/span/extension/comment.text +6 -0
  380. data/test/testcases/span/extension/ignored.html +1 -0
  381. data/test/testcases/span/extension/ignored.text +1 -0
  382. data/test/testcases/span/extension/nomarkdown.html +1 -0
  383. data/test/testcases/span/extension/nomarkdown.text +1 -0
  384. data/test/testcases/span/extension/options.html +1 -0
  385. data/test/testcases/span/extension/options.text +1 -0
  386. data/test/testcases/span/ial/simple.html +6 -0
  387. data/test/testcases/span/ial/simple.text +6 -0
  388. data/test/testcases/span/line_breaks/normal.html +11 -0
  389. data/test/testcases/span/line_breaks/normal.latex +12 -0
  390. data/test/testcases/span/line_breaks/normal.text +11 -0
  391. data/test/testcases/span/math/normal.html +5 -0
  392. data/test/testcases/span/math/normal.text +5 -0
  393. data/test/testcases/span/text_substitutions/entities.html +6 -0
  394. data/test/testcases/span/text_substitutions/entities.options +1 -0
  395. data/test/testcases/span/text_substitutions/entities.text +6 -0
  396. data/test/testcases/span/text_substitutions/entities_as_char.html +1 -0
  397. data/test/testcases/span/text_substitutions/entities_as_char.html.19 +1 -0
  398. data/test/testcases/span/text_substitutions/entities_as_char.options +1 -0
  399. data/test/testcases/span/text_substitutions/entities_as_char.text +1 -0
  400. data/test/testcases/span/text_substitutions/entities_as_input.html +1 -0
  401. data/test/testcases/span/text_substitutions/entities_as_input.options +1 -0
  402. data/test/testcases/span/text_substitutions/entities_as_input.text +1 -0
  403. data/test/testcases/span/text_substitutions/entities_numeric.html +1 -0
  404. data/test/testcases/span/text_substitutions/entities_numeric.options +1 -0
  405. data/test/testcases/span/text_substitutions/entities_numeric.text +1 -0
  406. data/test/testcases/span/text_substitutions/entities_symbolic.html +1 -0
  407. data/test/testcases/span/text_substitutions/entities_symbolic.options +1 -0
  408. data/test/testcases/span/text_substitutions/entities_symbolic.text +1 -0
  409. data/test/testcases/span/text_substitutions/greaterthan.html +1 -0
  410. data/test/testcases/span/text_substitutions/greaterthan.text +1 -0
  411. data/test/testcases/span/text_substitutions/lowerthan.html +1 -0
  412. data/test/testcases/span/text_substitutions/lowerthan.text +1 -0
  413. data/test/testcases/span/text_substitutions/typography.html +18 -0
  414. data/test/testcases/span/text_substitutions/typography.html.19 +18 -0
  415. data/test/testcases/span/text_substitutions/typography.text +18 -0
  416. metadata +817 -0
data/doc/tests.page ADDED
@@ -0,0 +1,52 @@
1
+ ---
2
+ title: Tests and Benchmark
3
+ ---
4
+
5
+ # Tests
6
+
7
+ There exist several test suites for testing the correctness of a Markdown implementation. The
8
+ original [Markdown Test Suite] is the standard which one needs to test against. The [PHP Markdown
9
+ suite][MDTest] contains the original test suite and several more tests (some specifically geared
10
+ towards the extension of the PHP Markdown Extra package). I have used the latter test tool to
11
+ roughly verify that kramdown is able to parse standard Markdown. However, since the syntax used by
12
+ kramdown varies slightly from standard Markdown most of the tests fail - which is fine. When looking
13
+ at the differences one can see that the failures result from these differences.
14
+
15
+ Besides using the above mentioned test suite kramdown comes with its own set of tests which is used
16
+ to verify that the implementation matches the kramdown specification.
17
+
18
+ If you believe you have found a bug in the implementation, please follow these steps:
19
+
20
+ * Check the syntax page and see if the behaviour is not intended.
21
+
22
+ * If the behaviour is not intended and it seems that kramdown should parse some text in another
23
+ fashion, please open a bug report and attach two files: one with the text and one with the HTML
24
+ conversion you think is correct.
25
+
26
+
27
+ # Benchmark
28
+
29
+ kramdown comes with a small benchmark to test how fast it is in regard to four other Ruby Markdown
30
+ implementations: Maruku, BlueFeather, BlueCloth and RDiscount. The first two are written using only
31
+ Ruby, the latter two use the C discount library for the actual hard work (which makes them really
32
+ fast but they do not provide additional syntax elements). As one can see below, kramdown is
33
+ currently (November 2010) ~3-4x faster than Maruku, ~4-5x faster than BlueFeather but ~30x slower
34
+ than BlueCloth and rdiscount:
35
+
36
+ <pre><code>
37
+ {execute_cmd: {command: "ruby -Ilib -rubygems benchmark/benchmark.rb", process_output: false, escape_html: true}}
38
+ </code>
39
+ </pre>
40
+
41
+ And here are some graphs which show the execution times of the various kramdown releases on
42
+ different Ruby interpreters:
43
+
44
+ ![ruby 1.8.5p231]({relocatable: img/graph-ruby-1.8.5-231.png})
45
+ ![ruby 1.8.6p399]({relocatable: img/graph-ruby-1.8.6-399.png})
46
+ ![ruby 1.8.7p249]({relocatable: img/graph-ruby-1.8.7-249.png})
47
+ ![ruby 1.8.7p302]({relocatable: img/graph-ruby-1.8.7-302.png})
48
+ ![ruby 1.9.2p136]({relocatable: img/graph-ruby-1.9.2p136-136.png})
49
+ ![ruby 1.9.3p0]({relocatable: img/graph-ruby-1.9.3p0-0.png})
50
+
51
+ [Markdown Test Suite]: http://daringfireball.net/projects/downloads/MarkdownTest_1.0.zip
52
+ [MDTest]: http://www.michelf.com/docs/projets/mdtest-1.0.zip
data/doc/virtual ADDED
@@ -0,0 +1,2 @@
1
+ rdoc/index.html:
2
+ title: API Documentation
data/lib/kramdown.rb ADDED
@@ -0,0 +1,23 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ #--
4
+ # Copyright (C) 2009-2010 Thomas Leitner <t_leitner@gmx.at>
5
+ #
6
+ # This file is part of kramdown.
7
+ #
8
+ # kramdown is free software: you can redistribute it and/or modify
9
+ # it under the terms of the GNU General Public License as published by
10
+ # the Free Software Foundation, either version 3 of the License, or
11
+ # (at your option) any later version.
12
+ #
13
+ # This program is distributed in the hope that it will be useful,
14
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ # GNU General Public License for more details.
17
+ #
18
+ # You should have received a copy of the GNU General Public License
19
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
20
+ #++
21
+ #
22
+
23
+ require 'kramdown/document'
@@ -0,0 +1,35 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ #--
4
+ # Copyright (C) 2009-2010 Thomas Leitner <t_leitner@gmx.at>
5
+ #
6
+ # This file is part of kramdown.
7
+ #
8
+ # kramdown is free software: you can redistribute it and/or modify
9
+ # it under the terms of the GNU General Public License as published by
10
+ # the Free Software Foundation, either version 3 of the License, or
11
+ # (at your option) any later version.
12
+ #
13
+ # This program is distributed in the hope that it will be useful,
14
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ # GNU General Public License for more details.
17
+ #
18
+ # You should have received a copy of the GNU General Public License
19
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
20
+ #++
21
+ #
22
+ # All the code in this file is backported from Ruby 1.8.7 sothat kramdown works under 1.8.5
23
+ #
24
+ # :stopdoc:
25
+
26
+ if RUBY_VERSION == '1.8.5'
27
+ require 'rexml/parsers/baseparser'
28
+ module REXML
29
+ module Parsers
30
+ class BaseParser
31
+ UNAME_STR= "(?:#{NCNAME_STR}:)?#{NCNAME_STR}"
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,41 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ #--
4
+ # Copyright (C) 2009-2010 Thomas Leitner <t_leitner@gmx.at>
5
+ #
6
+ # This file is part of kramdown.
7
+ #
8
+ # kramdown is free software: you can redistribute it and/or modify
9
+ # it under the terms of the GNU General Public License as published by
10
+ # the Free Software Foundation, either version 3 of the License, or
11
+ # (at your option) any later version.
12
+ #
13
+ # This program is distributed in the hope that it will be useful,
14
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ # GNU General Public License for more details.
17
+ #
18
+ # You should have received a copy of the GNU General Public License
19
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
20
+ #++
21
+ #
22
+
23
+ module Kramdown
24
+
25
+ # This module contains all available converters, i.e. classes that take a root Element and convert
26
+ # it to a specific output format. The result is normally a string. For example, the
27
+ # Converter::Html module converts an element tree into valid HTML.
28
+ #
29
+ # Converters use the Base class for common functionality (like applying a template to the output)
30
+ # \- see its API documentation for how to create a custom converter class.
31
+ module Converter
32
+
33
+ autoload :Base, 'kramdown/converter/base'
34
+ autoload :Html, 'kramdown/converter/html'
35
+ autoload :Latex, 'kramdown/converter/latex'
36
+ autoload :Kramdown, 'kramdown/converter/kramdown'
37
+ autoload :Toc, 'kramdown/converter/toc'
38
+
39
+ end
40
+
41
+ end
@@ -0,0 +1,169 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ #--
4
+ # Copyright (C) 2009-2010 Thomas Leitner <t_leitner@gmx.at>
5
+ #
6
+ # This file is part of kramdown.
7
+ #
8
+ # kramdown is free software: you can redistribute it and/or modify
9
+ # it under the terms of the GNU General Public License as published by
10
+ # the Free Software Foundation, either version 3 of the License, or
11
+ # (at your option) any later version.
12
+ #
13
+ # This program is distributed in the hope that it will be useful,
14
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ # GNU General Public License for more details.
17
+ #
18
+ # You should have received a copy of the GNU General Public License
19
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
20
+ #++
21
+ #
22
+
23
+ require 'erb'
24
+
25
+ module Kramdown
26
+
27
+ module Converter
28
+
29
+ # == \Base class for converters
30
+ #
31
+ # This class serves as base class for all converters. It provides methods that can/should be
32
+ # used by all converters (like #generate_id) as well as common functionality that is
33
+ # automatically applied to the result (for example, embedding the output into a template).
34
+ #
35
+ # A converter object is used as a throw-away object, i.e. it is only used for storing the needed
36
+ # state information during conversion. Therefore one can't instantiate a converter object
37
+ # directly but only use the Base::convert method.
38
+ #
39
+ # == Implementing a converter
40
+ #
41
+ # Implementing a new converter is rather easy: just derive a new class from this class and put
42
+ # it in the Kramdown::Converter module (the latter is only needed if auto-detection should work
43
+ # properly). Then you need to implement the #convert method which has to contain the conversion
44
+ # code for converting an element and has to return the conversion result.
45
+ #
46
+ # The actual transformation of the document tree can be done in any way. However, writing one
47
+ # method per element type is a straight forward way to do it - this is how the Html and Latex
48
+ # converters do the transformation.
49
+ #
50
+ # Have a look at the Base::convert method for additional information!
51
+ class Base
52
+
53
+ # Can be used by a converter for storing arbitrary information during the conversion process.
54
+ attr_reader :data
55
+
56
+ # The hash with the conversion options.
57
+ attr_reader :options
58
+
59
+ # The root element that is converted.
60
+ attr_reader :root
61
+
62
+ # The warnings array.
63
+ attr_reader :warnings
64
+
65
+ # Initialize the converter with the given +root+ element and +options+ hash.
66
+ def initialize(root, options)
67
+ @options = options
68
+ @root = root
69
+ @data = {}
70
+ @warnings = []
71
+ end
72
+ private_class_method(:new, :allocate)
73
+
74
+ # Convert the element tree +tree+ and return the resulting conversion object (normally a
75
+ # string) and an array with warning messages. The parameter +options+ specifies the conversion
76
+ # options that should be used.
77
+ #
78
+ # Initializes a new instance of the calling class and then calls the #convert method with
79
+ # +tree+ as parameter. If the +template+ option is specified and non-empty, the result is
80
+ # rendered into the specified template. The template resolution is done in the following way:
81
+ #
82
+ # 1. Look in the current working directory for the template.
83
+ #
84
+ # 2. Append +.convertername+ (e.g. +.html+) to the template name and look for the resulting
85
+ # file in the current working directory.
86
+ #
87
+ # 3. Append +.convertername+ to the template name and look for it in the kramdown data
88
+ # directory.
89
+ def self.convert(tree, options = {})
90
+ converter = new(tree, ::Kramdown::Options.merge(options.merge(tree.options[:options] || {})))
91
+ result = converter.convert(tree)
92
+ result = apply_template(converter, result) if !converter.options[:template].empty?
93
+ [result, converter.warnings]
94
+ end
95
+
96
+ # Convert the element +el+ and return the resulting object.
97
+ #
98
+ # This is the only method that has to be implemented by sub-classes!
99
+ def convert(el)
100
+ raise NotImplementedError
101
+ end
102
+
103
+ # Apply the +template+ using +body+ as the body string.
104
+ def self.apply_template(converter, body) # :nodoc:
105
+ erb = ERB.new(get_template(converter.options[:template]))
106
+ obj = Object.new
107
+ obj.instance_variable_set(:@converter, converter)
108
+ obj.instance_variable_set(:@body, body)
109
+ erb.result(obj.instance_eval{binding})
110
+ end
111
+
112
+ # Return the template specified by +template+.
113
+ def self.get_template(template) # :nodoc:
114
+ format_ext = '.' + self.name.split(/::/).last.downcase
115
+ shipped = File.join(::Kramdown.data_dir, template + format_ext)
116
+ if File.exist?(template)
117
+ File.read(template)
118
+ elsif File.exist?(template + format_ext)
119
+ File.read(template + format_ext)
120
+ elsif File.exist?(shipped)
121
+ File.read(shipped)
122
+ else
123
+ raise "The specified template file #{template} does not exist"
124
+ end
125
+ end
126
+
127
+ # Add the given warning +text+ to the warning array.
128
+ def warning(text)
129
+ @warnings << text
130
+ end
131
+
132
+ # Return +true+ if the header element +el+ should be used for the table of contents (as
133
+ # specified by the +toc_levels+ option).
134
+ def in_toc?(el)
135
+ @options[:toc_levels].include?(el.options[:level])
136
+ end
137
+
138
+ # Generate an unique alpha-numeric ID from the the string +str+ for use as a header ID.
139
+ #
140
+ # Uses the option +auto_id_prefix+: the value of this option is prepended to every generated
141
+ # ID.
142
+ def generate_id(str)
143
+ gen_id = str.gsub(/^[^a-zA-Z]+/, '')
144
+ gen_id.tr!('^a-zA-Z0-9 -', '')
145
+ gen_id.tr!(' ', '-')
146
+ gen_id.downcase!
147
+ gen_id = 'section' if gen_id.length == 0
148
+ @used_ids ||= {}
149
+ if @used_ids.has_key?(gen_id)
150
+ gen_id += '-' << (@used_ids[gen_id] += 1).to_s
151
+ else
152
+ @used_ids[gen_id] = 0
153
+ end
154
+ @options[:auto_id_prefix] + gen_id
155
+ end
156
+
157
+ SMART_QUOTE_INDICES = {:lsquo => 0, :rsquo => 1, :ldquo => 2, :rdquo => 3} # :nodoc:
158
+
159
+ # Return the entity that represents the given smart_quote element.
160
+ def smart_quote_entity(el)
161
+ res = @options[:smart_quotes][SMART_QUOTE_INDICES[el.value]]
162
+ ::Kramdown::Utils::Entities.entity(res)
163
+ end
164
+
165
+ end
166
+
167
+ end
168
+
169
+ end
@@ -0,0 +1,410 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ #--
4
+ # Copyright (C) 2009-2010 Thomas Leitner <t_leitner@gmx.at>
5
+ #
6
+ # This file is part of kramdown.
7
+ #
8
+ # kramdown is free software: you can redistribute it and/or modify
9
+ # it under the terms of the GNU General Public License as published by
10
+ # the Free Software Foundation, either version 3 of the License, or
11
+ # (at your option) any later version.
12
+ #
13
+ # This program is distributed in the hope that it will be useful,
14
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ # GNU General Public License for more details.
17
+ #
18
+ # You should have received a copy of the GNU General Public License
19
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
20
+ #++
21
+ #
22
+
23
+ require 'rexml/parsers/baseparser'
24
+
25
+ module Kramdown
26
+
27
+ module Converter
28
+
29
+ # Converts a Kramdown::Document to HTML.
30
+ #
31
+ # You can customize the HTML converter by sub-classing it and overriding the +convert_NAME+
32
+ # methods. Each such method takes the following parameters:
33
+ #
34
+ # [+el+] The element of type +NAME+ to be converted.
35
+ #
36
+ # [+indent+] A number representing the current amount of spaces for indent (only used for
37
+ # block-level elements).
38
+ #
39
+ # The return value of such a method has to be a string containing the element +el+ formatted as
40
+ # HTML element.
41
+ class Html < Base
42
+
43
+ begin
44
+ require 'coderay'
45
+
46
+ # Highlighting via coderay is available if this constant is +true+.
47
+ HIGHLIGHTING_AVAILABLE = true
48
+ rescue LoadError
49
+ HIGHLIGHTING_AVAILABLE = false # :nodoc:
50
+ end
51
+
52
+ include ::Kramdown::Utils::Html
53
+
54
+
55
+ # The amount of indentation used when nesting HTML tags.
56
+ attr_accessor :indent
57
+
58
+ # Initialize the HTML converter with the given Kramdown document +doc+.
59
+ def initialize(root, options)
60
+ super
61
+ @footnote_counter = @footnote_start = @options[:footnote_nr]
62
+ @footnotes = []
63
+ @toc = []
64
+ @toc_code = nil
65
+ @indent = 2
66
+ @stack = []
67
+ end
68
+
69
+ # The mapping of element type to conversion method.
70
+ DISPATCHER = Hash.new {|h,k| h[k] = "convert_#{k}"}
71
+
72
+ # Dispatch the conversion of the element +el+ to a +convert_TYPE+ method using the +type+ of
73
+ # the element.
74
+ def convert(el, indent = -@indent)
75
+ send(DISPATCHER[el.type], el, indent)
76
+ end
77
+
78
+ # Return the converted content of the children of +el+ as a string. The parameter +indent+ has
79
+ # to be the amount of indentation used for the element +el+.
80
+ #
81
+ # Pushes +el+ onto the @stack before converting the child elements and pops it from the stack
82
+ # afterwards.
83
+ def inner(el, indent)
84
+ result = ''
85
+ indent += @indent
86
+ @stack.push(el)
87
+ el.children.each do |inner_el|
88
+ result << send(DISPATCHER[inner_el.type], inner_el, indent)
89
+ end
90
+ @stack.pop
91
+ result
92
+ end
93
+
94
+ def convert_blank(el, indent)
95
+ "\n"
96
+ end
97
+
98
+ def convert_text(el, indent)
99
+ escape_html(el.value, :text)
100
+ end
101
+
102
+ def convert_p(el, indent)
103
+ if el.options[:transparent]
104
+ inner(el, indent)
105
+ else
106
+ "#{' '*indent}<p#{html_attributes(el.attr)}>#{inner(el, indent)}</p>\n"
107
+ end
108
+ end
109
+
110
+ def convert_codeblock(el, indent)
111
+ if el.attr['lang'] && HIGHLIGHTING_AVAILABLE
112
+ attr = el.attr.dup
113
+ opts = {:wrap => @options[:coderay_wrap], :line_numbers => @options[:coderay_line_numbers],
114
+ :line_number_start => @options[:coderay_line_number_start], :tab_width => @options[:coderay_tab_width],
115
+ :bold_every => @options[:coderay_bold_every], :css => @options[:coderay_css]}
116
+ result = CodeRay.scan(el.value, attr.delete('lang').to_sym).html(opts).chomp << "\n"
117
+ "#{' '*indent}<div#{html_attributes(attr)}>#{result}#{' '*indent}</div>\n"
118
+ else
119
+ result = escape_html(el.value)
120
+ result.chomp!
121
+ if el.attr['class'].to_s =~ /\bshow-whitespaces\b/
122
+ result.gsub!(/(?:(^[ \t]+)|([ \t]+$)|([ \t]+))/) do |m|
123
+ suffix = ($1 ? '-l' : ($2 ? '-r' : ''))
124
+ m.scan(/./).map do |c|
125
+ case c
126
+ when "\t" then "<span class=\"ws-tab#{suffix}\">\t</span>"
127
+ when " " then "<span class=\"ws-space#{suffix}\">&#8901;</span>"
128
+ end
129
+ end.join('')
130
+ end
131
+ end
132
+ "#{' '*indent}<pre#{html_attributes(el.attr)}><code>#{result}\n</code></pre>\n"
133
+ end
134
+ end
135
+
136
+ def convert_blockquote(el, indent)
137
+ "#{' '*indent}<blockquote#{html_attributes(el.attr)}>\n#{inner(el, indent)}#{' '*indent}</blockquote>\n"
138
+ end
139
+
140
+ def convert_header(el, indent)
141
+ attr = el.attr.dup
142
+ if @options[:auto_ids] && !attr['id']
143
+ attr['id'] = generate_id(el.options[:raw_text])
144
+ end
145
+ @toc << [el.options[:level], attr['id'], el.children] if attr['id'] && in_toc?(el)
146
+ "#{' '*indent}<h#{el.options[:level]}#{html_attributes(attr)}>#{inner(el, indent)}</h#{el.options[:level]}>\n"
147
+ end
148
+
149
+ def convert_hr(el, indent)
150
+ "#{' '*indent}<hr />\n"
151
+ end
152
+
153
+ def convert_ul(el, indent)
154
+ if !@toc_code && (el.options[:ial][:refs].include?('toc') rescue nil) && (el.type == :ul || el.type == :ol)
155
+ @toc_code = [el.type, el.attr, (0..128).to_a.map{|a| rand(36).to_s(36)}.join]
156
+ @toc_code.last
157
+ else
158
+ "#{' '*indent}<#{el.type}#{html_attributes(el.attr)}>\n#{inner(el, indent)}#{' '*indent}</#{el.type}>\n"
159
+ end
160
+ end
161
+ alias :convert_ol :convert_ul
162
+ alias :convert_dl :convert_ul
163
+
164
+ def convert_li(el, indent)
165
+ output = ' '*indent << "<#{el.type}" << html_attributes(el.attr) << ">"
166
+ res = inner(el, indent)
167
+ if el.children.empty? || (el.children.first.type == :p && el.children.first.options[:transparent])
168
+ output << res << (res =~ /\n\Z/ ? ' '*indent : '')
169
+ else
170
+ output << "\n" << res << ' '*indent
171
+ end
172
+ output << "</#{el.type}>\n"
173
+ end
174
+ alias :convert_dd :convert_li
175
+
176
+ def convert_dt(el, indent)
177
+ "#{' '*indent}<dt#{html_attributes(el.attr)}>#{inner(el, indent)}</dt>\n"
178
+ end
179
+
180
+ # A list of all HTML tags that need to have a body (even if the body is empty).
181
+ HTML_TAGS_WITH_BODY=['div', 'span', 'script', 'iframe', 'textarea', 'a'] # :nodoc:
182
+
183
+ def convert_html_element(el, indent)
184
+ res = inner(el, indent)
185
+ if el.options[:category] == :span
186
+ "<#{el.value}#{html_attributes(el.attr)}" << (!res.empty? || HTML_TAGS_WITH_BODY.include?(el.value) ? ">#{res}</#{el.value}>" : " />")
187
+ else
188
+ output = ''
189
+ output << ' '*indent if @stack.last.type != :html_element || @stack.last.options[:content_model] != :raw
190
+ output << "<#{el.value}#{html_attributes(el.attr)}"
191
+ if !res.empty? && el.options[:content_model] != :block
192
+ output << ">#{res}</#{el.value}>"
193
+ elsif !res.empty?
194
+ output << ">\n#{res.chomp}\n" << ' '*indent << "</#{el.value}>"
195
+ elsif HTML_TAGS_WITH_BODY.include?(el.value)
196
+ output << "></#{el.value}>"
197
+ else
198
+ output << " />"
199
+ end
200
+ output << "\n" if @stack.last.type != :html_element || @stack.last.options[:content_model] != :raw
201
+ output
202
+ end
203
+ end
204
+
205
+ def convert_xml_comment(el, indent)
206
+ if el.options[:category] == :block && (@stack.last.type != :html_element || @stack.last.options[:content_model] != :raw)
207
+ ' '*indent << el.value << "\n"
208
+ else
209
+ el.value
210
+ end
211
+ end
212
+ alias :convert_xml_pi :convert_xml_comment
213
+
214
+ def convert_table(el, indent)
215
+ "#{' '*indent}<table#{html_attributes(el.attr)}>\n#{inner(el, indent)}#{' '*indent}</table>\n"
216
+ end
217
+
218
+ def convert_thead(el, indent)
219
+ "#{' '*indent}<#{el.type}#{html_attributes(el.attr)}>\n#{inner(el, indent)}#{' '*indent}</#{el.type}>\n"
220
+ end
221
+ alias :convert_tbody :convert_thead
222
+ alias :convert_tfoot :convert_thead
223
+ alias :convert_tr :convert_thead
224
+
225
+ ENTITY_NBSP = ::Kramdown::Utils::Entities.entity('nbsp') # :nodoc:
226
+
227
+ def convert_td(el, indent)
228
+ res = inner(el, indent)
229
+ type = (@stack[-2].type == :thead ? :th : :td)
230
+ attr = el.attr
231
+ alignment = @stack[-3].options[:alignment][@stack.last.children.index(el)]
232
+ if alignment != :default
233
+ attr = el.attr.dup
234
+ attr['style'] = (attr.has_key?('style') ? "#{attr['style']}; ": '') << "text-align: #{alignment}"
235
+ end
236
+ "#{' '*indent}<#{type}#{html_attributes(attr)}>#{res.empty? ? entity_to_str(ENTITY_NBSP) : res}</#{type}>\n"
237
+ end
238
+
239
+ def convert_comment(el, indent)
240
+ if el.options[:category] == :block
241
+ "#{' '*indent}<!-- #{el.value} -->\n"
242
+ else
243
+ "<!-- #{el.value} -->"
244
+ end
245
+ end
246
+
247
+ def convert_br(el, indent)
248
+ "<br />"
249
+ end
250
+
251
+ def convert_a(el, indent)
252
+ res = inner(el, indent)
253
+ attr = el.attr.dup
254
+ if attr['href'] =~ /^mailto:/
255
+ attr['href'] = obfuscate('mailto') << ":" << obfuscate(attr['href'].sub(/^mailto:/, ''))
256
+ res = obfuscate(res)
257
+ end
258
+ "<a#{html_attributes(attr)}>#{res}</a>"
259
+ end
260
+
261
+ def convert_img(el, indent)
262
+ "<img#{html_attributes(el.attr)} />"
263
+ end
264
+
265
+ def convert_codespan(el, indent)
266
+ if el.attr['lang'] && HIGHLIGHTING_AVAILABLE
267
+ attr = el.attr.dup
268
+ result = CodeRay.scan(el.value, attr.delete('lang').to_sym).html(:wrap => :span, :css => @options[:coderay_css]).chomp
269
+ "<code#{html_attributes(attr)}>#{result}</code>"
270
+ else
271
+ "<code#{html_attributes(el.attr)}>#{escape_html(el.value)}</code>"
272
+ end
273
+ end
274
+
275
+ def convert_footnote(el, indent)
276
+ number = @footnote_counter
277
+ @footnote_counter += 1
278
+ @footnotes << [el.options[:name], el.value]
279
+ "<sup id=\"fnref:#{el.options[:name]}\"><a href=\"#fn:#{el.options[:name]}\" rel=\"footnote\">#{number}</a></sup>"
280
+ end
281
+
282
+ def convert_raw(el, indent)
283
+ if !el.options[:type] || el.options[:type].empty? || el.options[:type].include?('html')
284
+ el.value + (el.options[:category] == :block ? "\n" : '')
285
+ else
286
+ ''
287
+ end
288
+ end
289
+
290
+ def convert_em(el, indent)
291
+ "<#{el.type}#{html_attributes(el.attr)}>#{inner(el, indent)}</#{el.type}>"
292
+ end
293
+ alias :convert_strong :convert_em
294
+
295
+ def convert_entity(el, indent)
296
+ entity_to_str(el.value, el.options[:original])
297
+ end
298
+
299
+ TYPOGRAPHIC_SYMS = {
300
+ :mdash => [::Kramdown::Utils::Entities.entity('mdash')],
301
+ :ndash => [::Kramdown::Utils::Entities.entity('ndash')],
302
+ :hellip => [::Kramdown::Utils::Entities.entity('hellip')],
303
+ :laquo_space => [::Kramdown::Utils::Entities.entity('laquo'), ::Kramdown::Utils::Entities.entity('nbsp')],
304
+ :raquo_space => [::Kramdown::Utils::Entities.entity('nbsp'), ::Kramdown::Utils::Entities.entity('raquo')],
305
+ :laquo => [::Kramdown::Utils::Entities.entity('laquo')],
306
+ :raquo => [::Kramdown::Utils::Entities.entity('raquo')]
307
+ } # :nodoc:
308
+ def convert_typographic_sym(el, indent)
309
+ TYPOGRAPHIC_SYMS[el.value].map {|e| entity_to_str(e)}.join('')
310
+ end
311
+
312
+ def convert_smart_quote(el, indent)
313
+ entity_to_str(smart_quote_entity(el))
314
+ end
315
+
316
+ def convert_math(el, indent)
317
+ block = (el.options[:category] == :block)
318
+ "<script type=\"math/tex#{block ? '; mode=display' : ''}\">#{el.value}</script>#{block ? "\n" : ''}"
319
+ end
320
+
321
+ def convert_abbreviation(el, indent)
322
+ title = @root.options[:abbrev_defs][el.value]
323
+ "<abbr#{!title.empty? ? " title=\"#{title}\"" : ''}>#{el.value}</abbr>"
324
+ end
325
+
326
+ def convert_root(el, indent)
327
+ result = inner(el, indent)
328
+ result << footnote_content
329
+ if @toc_code
330
+ toc_tree = generate_toc_tree(@toc, @toc_code[0], @toc_code[1] || {})
331
+ text = if toc_tree.children.size > 0
332
+ convert(toc_tree, 0)
333
+ else
334
+ ''
335
+ end
336
+ result.sub!(/#{@toc_code.last}/, text)
337
+ end
338
+ result
339
+ end
340
+
341
+ # Generate and return an element tree for the table of contents.
342
+ def generate_toc_tree(toc, type, attr)
343
+ sections = Element.new(type, nil, attr)
344
+ sections.attr['id'] ||= 'markdown-toc'
345
+ stack = []
346
+ toc.each do |level, id, children|
347
+ li = Element.new(:li, nil, nil, {:level => level})
348
+ li.children << Element.new(:p, nil, nil, {:transparent => true})
349
+ a = Element.new(:a, nil, {'href' => "##{id}"})
350
+ a.children.concat(children)
351
+ li.children.last.children << a
352
+ li.children << Element.new(type)
353
+
354
+ success = false
355
+ while !success
356
+ if stack.empty?
357
+ sections.children << li
358
+ stack << li
359
+ success = true
360
+ elsif stack.last.options[:level] < li.options[:level]
361
+ stack.last.children.last.children << li
362
+ stack << li
363
+ success = true
364
+ else
365
+ item = stack.pop
366
+ item.children.pop unless item.children.last.children.size > 0
367
+ end
368
+ end
369
+ end
370
+ while !stack.empty?
371
+ item = stack.pop
372
+ item.children.pop unless item.children.last.children.size > 0
373
+ end
374
+ sections
375
+ end
376
+
377
+ # Obfuscate the +text+ by using HTML entities.
378
+ def obfuscate(text)
379
+ result = ""
380
+ text.each_byte do |b|
381
+ result << (b > 128 ? b.chr : "&#%03d;" % b)
382
+ end
383
+ result.force_encoding(text.encoding) if RUBY_VERSION >= '1.9'
384
+ result
385
+ end
386
+
387
+ # Return a HTML ordered list with the footnote content for the used footnotes.
388
+ def footnote_content
389
+ ol = Element.new(:ol)
390
+ ol.attr['start'] = @footnote_start if @footnote_start != 1
391
+ @footnotes.each do |name, data|
392
+ li = Element.new(:li, nil, {'id' => "fn:#{name}"})
393
+ li.children = Marshal.load(Marshal.dump(data.children))
394
+ ol.children << li
395
+
396
+ ref = Element.new(:raw, "<a href=\"#fnref:#{name}\" rel=\"reference\">&#8617;</a>")
397
+ if li.children.last.type == :p
398
+ para = li.children.last
399
+ else
400
+ li.children << (para = Element.new(:p))
401
+ end
402
+ para.children << ref
403
+ end
404
+ (ol.children.empty? ? '' : "<div class=\"footnotes\">\n#{convert(ol, 2)}</div>\n")
405
+ end
406
+
407
+ end
408
+
409
+ end
410
+ end