kramdown 0.14.2 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of kramdown might be problematic. Click here for more details.

Files changed (323) hide show
  1. checksums.yaml +7 -0
  2. data/CONTRIBUTERS +63 -1
  3. data/COPYING +17 -11
  4. data/README.md +35 -14
  5. data/VERSION +1 -1
  6. data/bin/kramdown +92 -40
  7. data/data/kramdown/document.html +4 -0
  8. data/data/kramdown/document.latex +7 -0
  9. data/lib/kramdown.rb +3 -16
  10. data/lib/kramdown/converter.rb +42 -16
  11. data/lib/kramdown/converter/base.rb +102 -38
  12. data/lib/kramdown/converter/hash_ast.rb +38 -0
  13. data/lib/kramdown/converter/html.rb +232 -141
  14. data/lib/kramdown/converter/kramdown.rb +122 -104
  15. data/lib/kramdown/converter/latex.rb +95 -78
  16. data/lib/kramdown/converter/man.rb +300 -0
  17. data/lib/kramdown/converter/math_engine/mathjax.rb +32 -0
  18. data/lib/kramdown/converter/remove_html_tags.rb +8 -17
  19. data/lib/kramdown/converter/syntax_highlighter.rb +56 -0
  20. data/lib/kramdown/converter/syntax_highlighter/minted.rb +35 -0
  21. data/lib/kramdown/converter/syntax_highlighter/rouge.rb +85 -0
  22. data/lib/kramdown/converter/toc.rb +7 -20
  23. data/lib/kramdown/document.rb +30 -37
  24. data/lib/kramdown/element.rb +54 -27
  25. data/lib/kramdown/error.rb +3 -16
  26. data/lib/kramdown/options.rb +392 -247
  27. data/lib/kramdown/parser.rb +3 -16
  28. data/lib/kramdown/parser/base.rb +28 -33
  29. data/lib/kramdown/parser/html.rb +151 -119
  30. data/lib/kramdown/parser/kramdown.rb +87 -50
  31. data/lib/kramdown/parser/kramdown/abbreviation.rb +33 -27
  32. data/lib/kramdown/parser/kramdown/autolink.rb +7 -25
  33. data/lib/kramdown/parser/kramdown/blank_line.rb +6 -19
  34. data/lib/kramdown/parser/kramdown/block_boundary.rb +6 -18
  35. data/lib/kramdown/parser/kramdown/blockquote.rb +6 -19
  36. data/lib/kramdown/parser/kramdown/codeblock.rb +15 -24
  37. data/lib/kramdown/parser/kramdown/codespan.rb +20 -22
  38. data/lib/kramdown/parser/kramdown/emphasis.rb +15 -24
  39. data/lib/kramdown/parser/kramdown/eob.rb +3 -16
  40. data/lib/kramdown/parser/kramdown/escaped_chars.rb +3 -16
  41. data/lib/kramdown/parser/kramdown/extensions.rb +66 -56
  42. data/lib/kramdown/parser/kramdown/footnote.rb +21 -31
  43. data/lib/kramdown/parser/kramdown/header.rb +37 -37
  44. data/lib/kramdown/parser/kramdown/horizontal_rule.rb +5 -17
  45. data/lib/kramdown/parser/kramdown/html.rb +47 -56
  46. data/lib/kramdown/parser/kramdown/html_entity.rb +9 -19
  47. data/lib/kramdown/parser/kramdown/line_break.rb +4 -17
  48. data/lib/kramdown/parser/kramdown/link.rb +39 -38
  49. data/lib/kramdown/parser/kramdown/list.rb +124 -82
  50. data/lib/kramdown/parser/kramdown/math.rb +12 -24
  51. data/lib/kramdown/parser/kramdown/paragraph.rb +23 -24
  52. data/lib/kramdown/parser/kramdown/smart_quotes.rb +26 -66
  53. data/lib/kramdown/parser/kramdown/table.rb +41 -48
  54. data/lib/kramdown/parser/kramdown/typographic_symbol.rb +14 -22
  55. data/lib/kramdown/parser/markdown.rb +11 -23
  56. data/lib/kramdown/utils.rb +21 -18
  57. data/lib/kramdown/utils/configurable.rb +45 -0
  58. data/lib/kramdown/utils/entities.rb +287 -292
  59. data/lib/kramdown/utils/html.rb +27 -30
  60. data/lib/kramdown/utils/lru_cache.rb +41 -0
  61. data/lib/kramdown/utils/string_scanner.rb +81 -0
  62. data/lib/kramdown/utils/unidecoder.rb +50 -0
  63. data/lib/kramdown/version.rb +4 -17
  64. data/man/man1/kramdown.1 +340 -347
  65. data/test/run_tests.rb +7 -20
  66. data/test/test_files.rb +188 -100
  67. data/test/test_location.rb +216 -0
  68. data/test/test_string_scanner_kramdown.rb +27 -0
  69. data/test/testcases/block/03_paragraph/indented.html.gfm +18 -0
  70. data/test/testcases/block/03_paragraph/line_break_last_line.html +9 -0
  71. data/test/testcases/block/03_paragraph/line_break_last_line.text +9 -0
  72. data/test/testcases/block/03_paragraph/standalone_image.html +8 -0
  73. data/test/testcases/block/03_paragraph/standalone_image.text +6 -0
  74. data/test/testcases/block/03_paragraph/with_html_to_native.html +1 -0
  75. data/test/testcases/block/03_paragraph/with_html_to_native.options +1 -0
  76. data/test/testcases/block/03_paragraph/with_html_to_native.text +1 -0
  77. data/test/testcases/block/04_header/atx_header.html +15 -1
  78. data/test/testcases/block/04_header/atx_header.text +14 -1
  79. data/test/testcases/block/04_header/setext_header.html +3 -1
  80. data/test/testcases/block/04_header/setext_header.text +4 -1
  81. data/test/testcases/block/04_header/with_auto_id_stripping.html +1 -0
  82. data/test/testcases/block/04_header/with_auto_id_stripping.options +1 -0
  83. data/test/testcases/block/04_header/with_auto_id_stripping.text +1 -0
  84. data/test/testcases/block/04_header/with_auto_ids.html +2 -0
  85. data/test/testcases/block/04_header/with_auto_ids.options +1 -0
  86. data/test/testcases/block/04_header/with_auto_ids.text +2 -0
  87. data/test/testcases/block/06_codeblock/guess_lang_css_class.html +15 -0
  88. data/test/testcases/block/06_codeblock/guess_lang_css_class.options +2 -0
  89. data/test/testcases/block/06_codeblock/guess_lang_css_class.text +13 -0
  90. data/test/testcases/block/06_codeblock/highlighting-minted-with-opts.latex +9 -0
  91. data/test/testcases/block/06_codeblock/highlighting-minted-with-opts.options +4 -0
  92. data/test/testcases/block/06_codeblock/highlighting-minted-with-opts.text +5 -0
  93. data/test/testcases/block/06_codeblock/highlighting-minted.latex +8 -0
  94. data/test/testcases/block/06_codeblock/highlighting-minted.options +3 -0
  95. data/test/testcases/block/06_codeblock/highlighting-minted.text +4 -0
  96. data/test/testcases/block/06_codeblock/highlighting-opts.html +6 -0
  97. data/test/testcases/block/06_codeblock/highlighting-opts.options +7 -0
  98. data/test/testcases/block/06_codeblock/highlighting-opts.text +4 -0
  99. data/test/testcases/block/06_codeblock/highlighting.html +5 -6
  100. data/test/testcases/block/06_codeblock/issue_gh45.html +164 -0
  101. data/test/testcases/block/06_codeblock/issue_gh45.test +188 -0
  102. data/test/testcases/block/06_codeblock/rouge/disabled.html +2 -0
  103. data/test/testcases/block/06_codeblock/rouge/disabled.options +4 -0
  104. data/test/testcases/block/06_codeblock/rouge/disabled.text +1 -0
  105. data/test/testcases/block/06_codeblock/rouge/multiple.html +11 -0
  106. data/test/testcases/block/06_codeblock/rouge/multiple.options +4 -0
  107. data/test/testcases/block/06_codeblock/rouge/multiple.text +11 -0
  108. data/test/testcases/block/06_codeblock/rouge/simple.html +10 -0
  109. data/test/testcases/block/06_codeblock/rouge/simple.options +3 -0
  110. data/test/testcases/block/06_codeblock/rouge/simple.text +9 -0
  111. data/test/testcases/block/06_codeblock/with_lang_in_fenced_block.options +1 -1
  112. data/test/testcases/block/06_codeblock/with_lang_in_fenced_block_any_char.html +8 -0
  113. data/test/testcases/block/06_codeblock/with_lang_in_fenced_block_any_char.options +2 -0
  114. data/test/testcases/block/06_codeblock/with_lang_in_fenced_block_any_char.text +11 -0
  115. data/test/testcases/block/06_codeblock/with_lang_in_fenced_block_name_with_dash.html +3 -0
  116. data/test/testcases/block/06_codeblock/with_lang_in_fenced_block_name_with_dash.options +2 -0
  117. data/test/testcases/block/06_codeblock/with_lang_in_fenced_block_name_with_dash.text +4 -0
  118. data/test/testcases/block/07_horizontal_rule/error.html +2 -2
  119. data/test/testcases/block/07_horizontal_rule/normal.html +2 -0
  120. data/test/testcases/block/07_horizontal_rule/normal.text +3 -0
  121. data/test/testcases/block/08_list/brackets_in_item.latex +3 -0
  122. data/test/testcases/block/08_list/brackets_in_item.text +1 -0
  123. data/test/testcases/block/08_list/lazy_and_nested.html +9 -0
  124. data/test/testcases/block/08_list/lazy_and_nested.text +4 -0
  125. data/test/testcases/block/09_html/html5_attributes.html +2 -0
  126. data/test/testcases/block/09_html/html5_attributes.text +2 -0
  127. data/test/testcases/block/09_html/html_after_block.html +7 -0
  128. data/test/testcases/block/09_html/html_after_block.text +5 -0
  129. data/test/testcases/block/09_html/html_to_native/table_simple.html +13 -0
  130. data/test/testcases/block/09_html/html_to_native/table_simple.text +15 -0
  131. data/test/testcases/block/09_html/html_to_native/typography.html +1 -1
  132. data/test/testcases/block/09_html/not_parsed.html +1 -1
  133. data/test/testcases/block/09_html/processing_instruction.html +5 -6
  134. data/test/testcases/block/09_html/simple.html +1 -5
  135. data/test/testcases/block/09_html/simple.text +1 -5
  136. data/test/testcases/block/09_html/standalone_image_in_div.htmlinput +7 -0
  137. data/test/testcases/block/09_html/standalone_image_in_div.text +8 -0
  138. data/test/testcases/block/09_html/textarea.html +8 -0
  139. data/test/testcases/block/09_html/textarea.text +8 -0
  140. data/test/testcases/block/09_html/xml.html +8 -0
  141. data/test/testcases/block/09_html/xml.text +7 -0
  142. data/test/testcases/block/11_ial/simple.html +5 -1
  143. data/test/testcases/block/11_ial/simple.text +8 -1
  144. data/test/testcases/block/12_extension/options.html +4 -4
  145. data/test/testcases/block/12_extension/options.text +2 -0
  146. data/test/testcases/block/12_extension/options2.html +4 -4
  147. data/test/testcases/block/12_extension/options3.html +7 -6
  148. data/test/testcases/block/12_extension/options3.text +2 -2
  149. data/test/testcases/block/13_definition_list/auto_ids.html +15 -0
  150. data/test/testcases/block/13_definition_list/auto_ids.text +18 -0
  151. data/test/testcases/block/13_definition_list/item_ial.html +5 -0
  152. data/test/testcases/block/13_definition_list/item_ial.text +8 -0
  153. data/test/testcases/block/14_table/empty_tag_in_cell.html +8 -0
  154. data/test/testcases/block/14_table/empty_tag_in_cell.options +1 -0
  155. data/test/testcases/block/14_table/empty_tag_in_cell.text +1 -0
  156. data/test/testcases/block/14_table/errors.html +4 -0
  157. data/test/testcases/block/14_table/errors.text +4 -0
  158. data/test/testcases/block/14_table/header.html +21 -0
  159. data/test/testcases/block/14_table/header.text +7 -0
  160. data/test/testcases/block/14_table/simple.html +22 -7
  161. data/test/testcases/block/14_table/simple.text +4 -0
  162. data/test/testcases/block/14_table/table_with_footnote.html +4 -4
  163. data/test/testcases/block/15_math/gh_128.html +1 -0
  164. data/test/testcases/block/15_math/gh_128.text +1 -0
  165. data/test/testcases/block/15_math/no_engine.html +3 -0
  166. data/test/testcases/block/15_math/no_engine.options +1 -0
  167. data/test/testcases/block/15_math/no_engine.text +2 -0
  168. data/test/testcases/block/15_math/normal.html +17 -14
  169. data/test/testcases/block/15_math/normal.text +2 -0
  170. data/test/testcases/block/16_toc/toc_exclude.html +7 -7
  171. data/test/testcases/block/16_toc/toc_levels.html +5 -5
  172. data/test/testcases/block/16_toc/toc_levels.text +1 -1
  173. data/test/testcases/block/16_toc/toc_with_footnotes.html +5 -5
  174. data/test/testcases/block/16_toc/toc_with_links.html +8 -0
  175. data/test/testcases/block/16_toc/toc_with_links.options +2 -0
  176. data/test/testcases/block/16_toc/toc_with_links.text +8 -0
  177. data/test/testcases/cjk-line-break.html +4 -0
  178. data/test/testcases/cjk-line-break.options +1 -0
  179. data/test/testcases/cjk-line-break.text +12 -0
  180. data/test/testcases/man/example.man +123 -0
  181. data/test/testcases/man/example.text +85 -0
  182. data/test/testcases/man/heading-name-dash-description.man +4 -0
  183. data/test/testcases/man/heading-name-dash-description.text +1 -0
  184. data/test/testcases/man/heading-name-description.man +4 -0
  185. data/test/testcases/man/heading-name-description.text +2 -0
  186. data/test/testcases/man/heading-name-section-description.man +4 -0
  187. data/test/testcases/man/heading-name-section-description.text +1 -0
  188. data/test/testcases/man/heading-name-section.man +2 -0
  189. data/test/testcases/man/heading-name-section.text +1 -0
  190. data/test/testcases/man/heading-name.man +2 -0
  191. data/test/testcases/man/heading-name.text +1 -0
  192. data/test/testcases/man/sections.man +4 -0
  193. data/test/testcases/man/sections.text +11 -0
  194. data/test/testcases/man/text-escaping.man +8 -0
  195. data/test/testcases/man/text-escaping.text +7 -0
  196. data/test/testcases/span/01_link/empty.html +1 -1
  197. data/test/testcases/span/01_link/empty_title.htmlinput +3 -0
  198. data/test/testcases/span/01_link/empty_title.text +7 -0
  199. data/test/testcases/span/01_link/imagelinks.html +1 -0
  200. data/test/testcases/span/01_link/imagelinks.text +2 -0
  201. data/test/testcases/span/01_link/inline.html +1 -1
  202. data/test/testcases/span/01_link/latex_escaping.latex +6 -0
  203. data/test/testcases/span/01_link/latex_escaping.text +5 -0
  204. data/test/testcases/span/01_link/link_defs.html +1 -1
  205. data/test/testcases/span/01_link/link_defs.text +2 -1
  206. data/test/testcases/span/01_link/link_defs_with_ial.html +4 -0
  207. data/test/testcases/span/01_link/link_defs_with_ial.text +16 -0
  208. data/test/testcases/span/01_link/reference.html +3 -3
  209. data/test/testcases/span/02_emphasis/nesting.html +3 -0
  210. data/test/testcases/span/02_emphasis/nesting.text +4 -1
  211. data/test/testcases/span/02_emphasis/normal.html +19 -0
  212. data/test/testcases/span/02_emphasis/normal.options +1 -0
  213. data/test/testcases/span/02_emphasis/normal.text +17 -0
  214. data/test/testcases/span/03_codespan/highlighting-minted.latex +2 -0
  215. data/test/testcases/span/03_codespan/highlighting-minted.options +1 -0
  216. data/test/testcases/span/03_codespan/highlighting-minted.text +1 -0
  217. data/test/testcases/span/03_codespan/highlighting.html +1 -1
  218. data/test/testcases/span/03_codespan/normal-css-class.html +1 -0
  219. data/test/testcases/span/03_codespan/normal-css-class.options +2 -0
  220. data/test/testcases/span/03_codespan/normal-css-class.text +1 -0
  221. data/test/testcases/span/03_codespan/rouge/disabled.html +1 -0
  222. data/test/testcases/span/03_codespan/rouge/disabled.options +4 -0
  223. data/test/testcases/span/03_codespan/rouge/disabled.text +1 -0
  224. data/test/testcases/span/03_codespan/rouge/simple.html +1 -0
  225. data/test/testcases/span/03_codespan/rouge/simple.options +1 -0
  226. data/test/testcases/span/03_codespan/rouge/simple.text +1 -0
  227. data/test/testcases/span/04_footnote/backlink_inline.html +79 -0
  228. data/test/testcases/span/04_footnote/backlink_inline.options +1 -0
  229. data/test/testcases/span/04_footnote/backlink_inline.text +38 -0
  230. data/test/testcases/span/04_footnote/backlink_text.html +9 -0
  231. data/test/testcases/span/04_footnote/backlink_text.options +1 -0
  232. data/test/testcases/span/04_footnote/backlink_text.text +3 -0
  233. data/test/testcases/span/04_footnote/definitions.latex +2 -2
  234. data/test/testcases/span/04_footnote/footnote_nr.html +6 -6
  235. data/test/testcases/span/04_footnote/footnote_prefix.html +12 -0
  236. data/test/testcases/span/04_footnote/footnote_prefix.options +1 -0
  237. data/test/testcases/span/04_footnote/footnote_prefix.text +4 -0
  238. data/test/testcases/span/04_footnote/inside_footnote.html +17 -0
  239. data/test/testcases/span/04_footnote/inside_footnote.text +9 -0
  240. data/test/testcases/span/04_footnote/markers.html +16 -16
  241. data/test/testcases/span/04_footnote/markers.latex +3 -3
  242. data/test/testcases/span/04_footnote/markers.options +2 -0
  243. data/test/testcases/span/04_footnote/markers.text +2 -1
  244. data/test/testcases/span/04_footnote/placement.html +11 -0
  245. data/test/testcases/span/04_footnote/placement.options +1 -0
  246. data/test/testcases/span/04_footnote/placement.text +8 -0
  247. data/test/testcases/span/04_footnote/regexp_problem.html +14 -0
  248. data/test/testcases/span/04_footnote/regexp_problem.options +2 -0
  249. data/test/testcases/span/04_footnote/regexp_problem.text +52 -0
  250. data/test/testcases/span/04_footnote/without_backlink.html +9 -0
  251. data/test/testcases/span/04_footnote/without_backlink.options +1 -0
  252. data/test/testcases/span/04_footnote/without_backlink.text +3 -0
  253. data/test/testcases/span/05_html/button.html +7 -0
  254. data/test/testcases/span/05_html/button.text +7 -0
  255. data/test/testcases/span/05_html/mark_element.html +3 -0
  256. data/test/testcases/span/05_html/mark_element.text +3 -0
  257. data/test/testcases/span/05_html/normal.html +10 -1
  258. data/test/testcases/span/05_html/normal.text +9 -0
  259. data/test/testcases/span/05_html/raw_span_elements.html +2 -0
  260. data/test/testcases/span/05_html/raw_span_elements.text +2 -0
  261. data/test/testcases/span/05_html/xml.html +5 -0
  262. data/test/testcases/span/05_html/xml.text +5 -0
  263. data/test/testcases/span/abbreviations/abbrev.html +14 -1
  264. data/test/testcases/span/abbreviations/abbrev.text +18 -2
  265. data/test/testcases/span/abbreviations/in_footnote.html +9 -0
  266. data/test/testcases/span/abbreviations/in_footnote.text +5 -0
  267. data/test/testcases/span/autolinks/url_links.html +5 -4
  268. data/test/testcases/span/autolinks/url_links.text +1 -0
  269. data/test/testcases/span/line_breaks/normal.html +2 -2
  270. data/test/testcases/span/line_breaks/normal.latex +2 -2
  271. data/test/testcases/span/math/no_engine.html +1 -0
  272. data/test/testcases/span/math/no_engine.options +1 -0
  273. data/test/testcases/span/math/no_engine.text +1 -0
  274. data/test/testcases/span/math/normal.html +4 -3
  275. data/test/testcases/span/math/normal.text +2 -1
  276. data/test/testcases/span/text_substitutions/entities_as_char.html +1 -1
  277. data/test/testcases/span/text_substitutions/entities_as_char.options +1 -0
  278. data/test/testcases/span/text_substitutions/entities_as_char.text +1 -1
  279. data/test/testcases/span/text_substitutions/typography.html +22 -0
  280. data/test/testcases/span/text_substitutions/typography.text +22 -0
  281. data/test/testcases/span/text_substitutions/typography_subst.html +3 -0
  282. data/test/testcases/span/text_substitutions/typography_subst.latex +4 -0
  283. data/test/testcases/span/text_substitutions/typography_subst.options +8 -0
  284. data/test/testcases/span/text_substitutions/typography_subst.text +3 -0
  285. metadata +218 -67
  286. data/ChangeLog +0 -7436
  287. data/GPL +0 -674
  288. data/Rakefile +0 -306
  289. data/benchmark/benchmark.rb +0 -36
  290. data/benchmark/benchmark.sh +0 -74
  291. data/benchmark/generate_data.rb +0 -119
  292. data/benchmark/mdbasics.text +0 -306
  293. data/benchmark/mdsyntax.text +0 -888
  294. data/benchmark/testing.sh +0 -9
  295. data/benchmark/timing.sh +0 -10
  296. data/doc/bg.png +0 -0
  297. data/doc/default.scss.css +0 -181
  298. data/doc/default.template +0 -68
  299. data/doc/design.scss.css +0 -441
  300. data/doc/documentation.page +0 -84
  301. data/doc/documentation.template +0 -20
  302. data/doc/index.page +0 -94
  303. data/doc/installation.page +0 -88
  304. data/doc/links.markdown +0 -6
  305. data/doc/metainfo +0 -3
  306. data/doc/news.feed +0 -10
  307. data/doc/news.page +0 -29
  308. data/doc/options.page +0 -10
  309. data/doc/quickref.page +0 -598
  310. data/doc/sidebar.template +0 -21
  311. data/doc/syntax.page +0 -1700
  312. data/doc/tests.page +0 -91
  313. data/doc/virtual +0 -2
  314. data/lib/kramdown/compatibility.rb +0 -49
  315. data/lib/kramdown/utils/ordered_hash.rb +0 -100
  316. data/setup.rb +0 -1585
  317. data/test/testcases/block/07_horizontal_rule/error.html.19 +0 -7
  318. data/test/testcases/block/09_html/html_to_native/typography.html.19 +0 -1
  319. data/test/testcases/block/09_html/simple.html.19 +0 -64
  320. data/test/testcases/block/14_table/simple.html.19 +0 -177
  321. data/test/testcases/span/01_link/inline.html.19 +0 -46
  322. data/test/testcases/span/01_link/reference.html.19 +0 -37
  323. data/test/testcases/span/text_substitutions/entities_as_char.html.19 +0 -1
@@ -1,26 +1,14 @@
1
- # -*- coding: utf-8 -*-
1
+ # -*- coding: utf-8; frozen_string_literal: true -*-
2
2
  #
3
3
  #--
4
- # Copyright (C) 2009-2012 Thomas Leitner <t_leitner@gmx.at>
4
+ # Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at>
5
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/>.
6
+ # This file is part of kramdown which is licensed under the MIT.
20
7
  #++
21
8
  #
22
9
 
23
10
  require 'set'
11
+ require 'kramdown/converter'
24
12
 
25
13
  module Kramdown
26
14
 
@@ -45,8 +33,6 @@ module Kramdown
45
33
  # Initialize the LaTeX converter with the +root+ element and the conversion +options+.
46
34
  def initialize(root, options)
47
35
  super
48
- #TODO: set the footnote counter at the beginning of the document
49
- @options[:footnote_nr]
50
36
  @data[:packages] = Set.new
51
37
  end
52
38
 
@@ -58,8 +44,8 @@ module Kramdown
58
44
 
59
45
  # Return the converted content of the children of +el+ as a string.
60
46
  def inner(el, opts)
61
- result = ''
62
- options = opts.dup.merge(:parent => el)
47
+ result = +''
48
+ options = opts.dup.merge(parent: el)
63
49
  el.children.each_with_index do |inner_el, index|
64
50
  options[:index] = index
65
51
  options[:result] = result
@@ -72,16 +58,17 @@ module Kramdown
72
58
  inner(el, opts)
73
59
  end
74
60
 
75
- def convert_blank(el, opts)
61
+ def convert_blank(_el, opts)
76
62
  opts[:result] =~ /\n\n\Z|\A\Z/ ? "" : "\n"
77
63
  end
78
64
 
79
- def convert_text(el, opts)
65
+ def convert_text(el, _opts)
80
66
  escape(el.value)
81
67
  end
82
68
 
83
69
  def convert_p(el, opts)
84
- if el.children.size == 1 && el.children.first.type == :img && !(img = convert_img(el.children.first, opts)).empty?
70
+ if el.children.size == 1 && el.children.first.type == :img &&
71
+ !(img = convert_img(el.children.first, opts)).empty?
85
72
  convert_standalone_image(el, opts, img)
86
73
  else
87
74
  "#{latex_link_target(el)}#{inner(el, opts)}\n\n"
@@ -90,23 +77,31 @@ module Kramdown
90
77
 
91
78
  # Helper method used by +convert_p+ to convert a paragraph that only contains a single :img
92
79
  # element.
93
- def convert_standalone_image(el, opts, img)
80
+ def convert_standalone_image(el, _opts, img)
94
81
  attrs = attribute_list(el)
95
- "\\begin{figure}#{attrs}\n\\begin{center}\n#{img}\n\\end{center}\n\\caption{#{escape(el.children.first.attr['alt'])}}\n#{latex_link_target(el, true)}\n\\end{figure}#{attrs}\n"
82
+ "\\begin{figure}#{attrs}\n\\begin{center}\n#{img}\n\\end{center}\n" \
83
+ "\\caption{#{escape(el.children.first.attr['alt'])}}\n" \
84
+ "#{latex_link_target(el, true)}\n\\end{figure}#{attrs}\n"
96
85
  end
97
86
 
98
- def convert_codeblock(el, opts)
87
+ def convert_codeblock(el, _opts)
99
88
  show_whitespace = el.attr['class'].to_s =~ /\bshow-whitespaces\b/
100
89
  lang = extract_code_language(el.attr)
101
- if show_whitespace || lang
90
+
91
+ if @options[:syntax_highlighter] == :minted &&
92
+ (highlighted_code = highlight_code(el.value, lang, :block))
93
+ @data[:packages] << 'minted'
94
+ "#{latex_link_target(el)}#{highlighted_code}\n"
95
+ elsif show_whitespace || lang
102
96
  options = []
103
- options << "showspaces=%s,showtabs=%s" % (show_whitespace ? ['true', 'true'] : ['false', 'false'])
97
+ options << (show_whitespace ? "showspaces=true,showtabs=true" : "showspaces=false,showtabs=false")
104
98
  options << "language=#{lang}" if lang
105
99
  options << "basicstyle=\\ttfamily\\footnotesize,columns=fixed,frame=tlbr"
106
100
  id = el.attr['id']
107
101
  options << "label=#{id}" if id
108
102
  attrs = attribute_list(el)
109
- "#{latex_link_target(el)}\\begin{lstlisting}[#{options.join(',')}]\n#{el.value}\n\\end{lstlisting}#{attrs}\n"
103
+ "#{latex_link_target(el)}\\begin{lstlisting}[#{options.join(',')}]\n" \
104
+ "#{el.value}\n\\end{lstlisting}#{attrs}\n"
110
105
  else
111
106
  "#{latex_link_target(el)}\\begin{verbatim}#{el.value}\\end{verbatim}\n"
112
107
  end
@@ -126,27 +121,27 @@ module Kramdown
126
121
  end
127
122
  end
128
123
 
129
- def convert_hr(el, opts)
124
+ def convert_hr(el, _opts)
130
125
  attrs = attribute_list(el)
131
126
  "#{latex_link_target(el)}\\begin{center}#{attrs}\n\\rule{3in}{0.4pt}\n\\end{center}#{attrs}\n"
132
127
  end
133
128
 
134
129
  def convert_ul(el, opts)
135
- if !@data[:has_toc] && (el.options[:ial][:refs].include?('toc') rescue nil)
130
+ if !@data[:has_toc] && el.options.dig(:ial, :refs)&.include?('toc')
136
131
  @data[:has_toc] = true
137
132
  '\tableofcontents'
138
133
  else
139
134
  latex_environment(el.type == :ul ? 'itemize' : 'enumerate', el, inner(el, opts))
140
135
  end
141
136
  end
142
- alias :convert_ol :convert_ul
137
+ alias convert_ol convert_ul
143
138
 
144
139
  def convert_dl(el, opts)
145
140
  latex_environment('description', el, inner(el, opts))
146
141
  end
147
142
 
148
143
  def convert_li(el, opts)
149
- "\\item #{latex_link_target(el, true)}#{inner(el, opts).sub(/\n+\Z/, '')}\n"
144
+ "\\item{} #{latex_link_target(el, true)}#{inner(el, opts).sub(/\n+\Z/, '')}\n"
150
145
  end
151
146
 
152
147
  def convert_dt(el, opts)
@@ -158,32 +153,33 @@ module Kramdown
158
153
  end
159
154
 
160
155
  def convert_html_element(el, opts)
161
- if el.value == 'i'
162
- "\\emph{#{inner(el, opts)}}"
163
- elsif el.value == 'b'
156
+ if el.value == 'i' || el.value == 'em'
164
157
  "\\emph{#{inner(el, opts)}}"
158
+ elsif el.value == 'b' || el.value == 'strong'
159
+ "\\textbf{#{inner(el, opts)}}"
165
160
  else
166
161
  warning("Can't convert HTML element")
167
162
  ''
168
163
  end
169
164
  end
170
165
 
171
- def convert_xml_comment(el, opts)
172
- el.value.split(/\n/).map {|l| "% #{l}"}.join("\n") + "\n"
166
+ def convert_xml_comment(el, _opts)
167
+ el.value.split(/\n/).map {|l| "% #{l}" }.join("\n") + "\n"
173
168
  end
174
169
 
175
- def convert_xml_pi(el, opts)
170
+ def convert_xml_pi(_el, _opts)
176
171
  warning("Can't convert XML PI")
177
172
  ''
178
173
  end
179
174
 
180
- TABLE_ALIGNMENT_CHAR = {:default => 'l', :left => 'l', :center => 'c', :right => 'r'} # :nodoc:
175
+ TABLE_ALIGNMENT_CHAR = {default: 'l', left: 'l', center: 'c', right: 'r'} # :nodoc:
181
176
 
182
177
  def convert_table(el, opts)
183
178
  @data[:packages] << 'longtable'
184
- align = el.options[:alignment].map {|a| TABLE_ALIGNMENT_CHAR[a]}.join('|')
179
+ align = el.options[:alignment].map {|a| TABLE_ALIGNMENT_CHAR[a] }.join('|')
185
180
  attrs = attribute_list(el)
186
- "#{latex_link_target(el)}\\begin{longtable}{|#{align}|}#{attrs}\n\\hline\n#{inner(el, opts)}\\hline\n\\end{longtable}#{attrs}\n\n"
181
+ "#{latex_link_target(el)}\\begin{longtable}{|#{align}|}#{attrs}\n" \
182
+ "\\hline\n#{inner(el, opts)}\\hline\n\\end{longtable}#{attrs}\n\n"
187
183
  end
188
184
 
189
185
  def convert_thead(el, opts)
@@ -199,47 +195,56 @@ module Kramdown
199
195
  end
200
196
 
201
197
  def convert_tr(el, opts)
202
- el.children.map {|c| send("convert_#{c.type}", c, opts)}.join(' & ') + "\\\\\n"
198
+ el.children.map {|c| send("convert_#{c.type}", c, opts) }.join(' & ') << "\\\\\n"
203
199
  end
204
200
 
205
201
  def convert_td(el, opts)
206
202
  inner(el, opts)
207
203
  end
208
204
 
209
- def convert_comment(el, opts)
210
- el.value.split(/\n/).map {|l| "% #{l}"}.join("\n") + "\n"
205
+ def convert_comment(el, _opts)
206
+ el.value.split(/\n/).map {|l| "% #{l}" }.join("\n") << "\n"
211
207
  end
212
208
 
213
- def convert_br(el, opts)
214
- res = "\\newline"
215
- res << "\n" if (c = opts[:parent].children[opts[:index]+1]) && (c.type != :text || c.value !~ /^\s*\n/)
209
+ def convert_br(_el, opts)
210
+ res = +"\\newline"
211
+ res << "\n" if (c = opts[:parent].children[opts[:index] + 1]) &&
212
+ (c.type != :text || c.value !~ /^\s*\n/)
216
213
  res
217
214
  end
218
215
 
219
216
  def convert_a(el, opts)
220
217
  url = el.attr['href']
221
- if url =~ /^#/
222
- "\\hyperlink{#{url[1..-1]}}{#{inner(el, opts)}}"
218
+ if url.start_with?('#')
219
+ "\\hyperlink{#{url[1..-1].gsub('%', '\\%')}}{#{inner(el, opts)}}"
223
220
  else
224
- "\\href{#{url}}{#{inner(el, opts)}}"
221
+ "\\href{#{url.gsub('%', '\\%')}}{#{inner(el, opts)}}"
225
222
  end
226
223
  end
227
224
 
228
- def convert_img(el, opts)
225
+ def convert_img(el, _opts)
226
+ line = el.options[:location]
229
227
  if el.attr['src'] =~ /^(https?|ftps?):\/\//
230
- warning("Cannot include non-local image")
228
+ warning("Cannot include non-local image#{line ? " (line #{line})" : ''}")
231
229
  ''
232
230
  elsif !el.attr['src'].empty?
233
231
  @data[:packages] << 'graphicx'
234
232
  "#{latex_link_target(el)}\\includegraphics{#{el.attr['src']}}"
235
233
  else
236
- warning("Cannot include image with empty path")
234
+ warning("Cannot include image with empty path#{line ? " (line #{line})" : ''}")
237
235
  ''
238
236
  end
239
237
  end
240
238
 
241
- def convert_codespan(el, opts)
242
- "{\\tt #{latex_link_target(el)}#{escape(el.value)}}"
239
+ def convert_codespan(el, _opts)
240
+ lang = extract_code_language(el.attr)
241
+ if @options[:syntax_highlighter] == :minted &&
242
+ (highlighted_code = highlight_code(el.value, lang, :span))
243
+ @data[:packages] << 'minted'
244
+ "#{latex_link_target(el)}#{highlighted_code}"
245
+ else
246
+ "\\texttt{#{latex_link_target(el)}#{escape(el.value)}}"
247
+ end
243
248
  end
244
249
 
245
250
  def convert_footnote(el, opts)
@@ -247,7 +252,7 @@ module Kramdown
247
252
  "\\footnote{#{inner(el.value, opts).rstrip}}"
248
253
  end
249
254
 
250
- def convert_raw(el, opts)
255
+ def convert_raw(el, _opts)
251
256
  if !el.options[:type] || el.options[:type].empty? || el.options[:type].include?('latex')
252
257
  el.value + (el.options[:category] == :block ? "\n" : '')
253
258
  else
@@ -356,8 +361,8 @@ module Kramdown
356
361
  8736 => ['$\angle$'],
357
362
  8743 => ['$\wedge$'],
358
363
  8744 => ['$\vee$'],
359
- 8745 => ['$\cup$'],
360
- 8746 => ['$\cap$'],
364
+ 8745 => ['$\cap$'],
365
+ 8746 => ['$\cup$'],
361
366
  8747 => ['$\int$'],
362
367
  8756 => ['$\therefore$', 'amssymb'],
363
368
  8764 => ['$\sim$'],
@@ -417,7 +422,7 @@ module Kramdown
417
422
  402 => ['\textflorin', 'mathcomp'],
418
423
  381 => ['\v{Z}'],
419
424
  382 => ['\v{z}'],
420
- 160 => ['\nolinebreak'],
425
+ 160 => ['~'],
421
426
  161 => ['\textexclamdown'],
422
427
  163 => ['\pounds'],
423
428
  164 => ['\currency', 'wasysym'],
@@ -512,7 +517,7 @@ module Kramdown
512
517
  8194 => ['\hskip .5em\relax'],
513
518
  8195 => ['\quad'],
514
519
  } # :nodoc:
515
- ENTITY_CONV_TABLE.each {|k,v| ENTITY_CONV_TABLE[k][0].insert(-1, '{}')}
520
+ ENTITY_CONV_TABLE.each_value {|v| v[0] = "{}#{v[0]}" }
516
521
 
517
522
  def entity_to_latex(entity)
518
523
  text, package = ENTITY_CONV_TABLE[entity.code_point]
@@ -525,26 +530,30 @@ module Kramdown
525
530
  end
526
531
  end
527
532
 
528
- def convert_entity(el, opts)
533
+ def convert_entity(el, _opts)
529
534
  entity_to_latex(el.value)
530
535
  end
531
536
 
532
537
  TYPOGRAPHIC_SYMS = {
533
- :mdash => '---', :ndash => '--', :hellip => '\ldots{}',
534
- :laquo_space => '\guillemotleft{}~', :raquo_space => '~\guillemotright{}',
535
- :laquo => '\guillemotleft{}', :raquo => '\guillemotright{}'
538
+ mdash: '---', ndash: '--', hellip: '\ldots{}',
539
+ laquo_space: '\guillemotleft{}~', raquo_space: '~\guillemotright{}',
540
+ laquo: '\guillemotleft{}', raquo: '\guillemotright{}'
536
541
  } # :nodoc:
537
- def convert_typographic_sym(el, opts)
538
- TYPOGRAPHIC_SYMS[el.value]
542
+ def convert_typographic_sym(el, _opts)
543
+ if (result = @options[:typographic_symbols][el.value])
544
+ escape(result)
545
+ else
546
+ TYPOGRAPHIC_SYMS[el.value]
547
+ end
539
548
  end
540
549
 
541
550
  def convert_smart_quote(el, opts)
542
551
  res = entity_to_latex(smart_quote_entity(el)).chomp('{}')
543
- res << "{}" if ((nel = opts[:parent].children[opts[:index]+1]) && nel.type == :smart_quote) || res =~ /\w$/
552
+ res << "{}" if ((nel = opts[:parent].children[opts[:index] + 1]) && nel.type == :smart_quote) || res =~ /\w$/
544
553
  res
545
554
  end
546
555
 
547
- def convert_math(el, opts)
556
+ def convert_math(el, _opts)
548
557
  @data[:packages] += %w[amssymb amsmath amsthm amsfonts]
549
558
  if el.options[:category] == :block
550
559
  if el.value =~ /\A\s*\\begin\{/
@@ -557,8 +566,14 @@ module Kramdown
557
566
  end
558
567
  end
559
568
 
560
- def convert_abbreviation(el, opts)
561
- el.value
569
+ def convert_abbreviation(el, _opts)
570
+ @data[:packages] += %w[acronym]
571
+ "\\ac{#{normalize_abbreviation_key(el.value)}}"
572
+ end
573
+
574
+ # Normalize the abbreviation key so that it only contains allowed ASCII character
575
+ def normalize_abbreviation_key(key)
576
+ key.gsub(/\W/) {|m| m.unpack('H*').first }
562
577
  end
563
578
 
564
579
  # Wrap the +text+ inside a LaTeX environment of type +type+. The element +el+ is passed on to
@@ -574,7 +589,7 @@ module Kramdown
574
589
  # additionally to the \hypertarget command.
575
590
  def latex_link_target(el, add_label = false)
576
591
  if (id = el.attr['id'])
577
- "\\hypertarget{#{id}}{}" << (add_label ? "\\label{#{id}}" : '')
592
+ "\\hypertarget{#{id}}{}#{add_label ? "\\label{#{id}}" : ''}"
578
593
  else
579
594
  nil
580
595
  end
@@ -582,8 +597,8 @@ module Kramdown
582
597
 
583
598
  # Return a LaTeX comment containing all attributes as 'key="value"' pairs.
584
599
  def attribute_list(el)
585
- attrs = el.attr.map {|k,v| v.nil? ? '' : " #{k}=\"#{v.to_s}\""}.compact.sort.join('')
586
- attrs = " % #{attrs}" if !attrs.empty?
600
+ attrs = el.attr.map {|k, v| v.nil? ? '' : " #{k}=\"#{v}\"" }.compact.sort.join('')
601
+ attrs = " % #{attrs}" unless attrs.empty?
587
602
  attrs
588
603
  end
589
604
 
@@ -593,13 +608,15 @@ module Kramdown
593
608
  "~" => "\\ensuremath{\\sim}",
594
609
  "|" => "\\textbar{}",
595
610
  "<" => "\\textless{}",
596
- ">" => "\\textgreater{}"
597
- }.merge(Hash[*("{}$%&_#".scan(/./).map {|c| [c, "\\#{c}"]}.flatten)]) # :nodoc:
598
- ESCAPE_RE = Regexp.union(*ESCAPE_MAP.collect {|k,v| k}) # :nodoc:
611
+ ">" => "\\textgreater{}",
612
+ "[" => "{[}",
613
+ "]" => "{]}",
614
+ }.merge(Hash[*("{}$%&_#".each_char.map {|c| [c, "\\#{c}"] }.flatten)]) # :nodoc:
615
+ ESCAPE_RE = Regexp.union(*ESCAPE_MAP.collect {|k, _v| k }) # :nodoc:
599
616
 
600
617
  # Escape the special LaTeX characters in the string +str+.
601
618
  def escape(str)
602
- str.gsub(ESCAPE_RE) {|m| ESCAPE_MAP[m]}
619
+ str.gsub(ESCAPE_RE) {|m| ESCAPE_MAP[m] }
603
620
  end
604
621
 
605
622
  end
@@ -0,0 +1,300 @@
1
+ # -*- coding: utf-8; frozen_string_literal: true -*-
2
+ #
3
+ #--
4
+ # Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at>
5
+ #
6
+ # This file is part of kramdown which is licensed under the MIT.
7
+ #++
8
+ #
9
+
10
+ require 'kramdown/converter'
11
+
12
+ module Kramdown
13
+
14
+ module Converter
15
+
16
+ # Converts a Kramdown::Document to a manpage in groff format. See man(7), groff_man(7) and
17
+ # man-pages(7) for information regarding the output.
18
+ class Man < Base
19
+
20
+ def convert(el, opts = {indent: 0, result: +''}) #:nodoc:
21
+ send("convert_#{el.type}", el, opts)
22
+ end
23
+
24
+ private
25
+
26
+ def inner(el, opts, use = :all)
27
+ arr = el.children.reject {|e| e.type == :blank }
28
+ arr.each_with_index do |inner_el, index|
29
+ next if use == :rest && index == 0
30
+ break if use == :first && index > 0
31
+ options = opts.dup
32
+ options[:parent] = el
33
+ options[:index] = index
34
+ options[:prev] = (index == 0 ? nil : arr[index - 1])
35
+ options[:next] = (index == arr.length - 1 ? nil : arr[index + 1])
36
+ convert(inner_el, options)
37
+ end
38
+ end
39
+
40
+ def convert_root(el, opts)
41
+ @title_done = false
42
+ opts[:result] = +".\\\" generated by kramdown\n"
43
+ inner(el, opts)
44
+ opts[:result]
45
+ end
46
+
47
+ def convert_blank(*)
48
+ end
49
+ alias convert_hr convert_blank
50
+ alias convert_xml_pi convert_blank
51
+
52
+ def convert_p(el, opts)
53
+ if (opts[:index] != 0 && opts[:prev].type != :header) ||
54
+ (opts[:parent].type == :blockquote && opts[:index] == 0)
55
+ opts[:result] << macro("P")
56
+ end
57
+ inner(el, opts)
58
+ newline(opts[:result])
59
+ end
60
+
61
+ def convert_header(el, opts)
62
+ return unless opts[:parent].type == :root
63
+ case el.options[:level]
64
+ when 1
65
+ unless @title_done
66
+ @title_done = true
67
+ data = el.options[:raw_text].scan(/([^(]+)\s*\((\d\w*)\)(?:\s*-+\s*(.*))?/).first ||
68
+ el.options[:raw_text].scan(/([^\s]+)\s*(?:-*\s+)?()(.*)/).first
69
+ return unless data && data[0]
70
+ name = data[0]
71
+ section = (data[1].to_s.empty? ? el.attr['data-section'] || '7' : data[1])
72
+ description = (data[2].to_s.empty? ? nil : " - #{data[2]}")
73
+ date = el.attr['data-date'] ? quote(el.attr['data-date']) : nil
74
+ extra = (el.attr['data-extra'] ? quote(escape(el.attr['data-extra'].to_s)) : nil)
75
+ opts[:result] << macro("TH", quote(escape(name.upcase)), quote(section), date, extra)
76
+ if description
77
+ opts[:result] << macro("SH", "NAME") << escape("#{name}#{description}") << "\n"
78
+ end
79
+ end
80
+ when 2
81
+ opts[:result] << macro("SH", quote(escape(el.options[:raw_text])))
82
+ when 3
83
+ opts[:result] << macro("SS", quote(escape(el.options[:raw_text])))
84
+ else
85
+ warning("Header levels greater than three are not supported")
86
+ end
87
+ end
88
+
89
+ def convert_codeblock(el, opts)
90
+ opts[:result] << macro("sp") << macro("RS", 4) << macro("EX")
91
+ opts[:result] << newline(escape(el.value, true))
92
+ opts[:result] << macro("EE") << macro("RE")
93
+ end
94
+
95
+ def convert_blockquote(el, opts)
96
+ opts[:result] << macro("RS")
97
+ inner(el, opts)
98
+ opts[:result] << macro("RE")
99
+ end
100
+
101
+ def convert_ul(el, opts)
102
+ compact = (el.attr['class'] =~ /\bcompact\b/)
103
+ opts[:result] << macro("sp") << macro("PD", 0) if compact
104
+ inner(el, opts)
105
+ opts[:result] << macro("PD") if compact
106
+ end
107
+ alias convert_dl convert_ul
108
+ alias convert_ol convert_ul
109
+
110
+ def convert_li(el, opts)
111
+ sym = (opts[:parent].type == :ul ? '\(bu' : "#{opts[:index] + 1}.")
112
+ opts[:result] << macro("IP", sym, 4)
113
+ inner(el, opts, :first)
114
+ if el.children.size > 1
115
+ opts[:result] << macro("RS")
116
+ inner(el, opts, :rest)
117
+ opts[:result] << macro("RE")
118
+ end
119
+ end
120
+
121
+ def convert_dt(el, opts)
122
+ opts[:result] << macro(opts[:prev] && opts[:prev].type == :dt ? "TQ" : "TP")
123
+ inner(el, opts)
124
+ opts[:result] << "\n"
125
+ end
126
+
127
+ def convert_dd(el, opts)
128
+ inner(el, opts, :first)
129
+ if el.children.size > 1
130
+ opts[:result] << macro("RS")
131
+ inner(el, opts, :rest)
132
+ opts[:result] << macro("RE")
133
+ end
134
+ opts[:result] << macro("sp") if opts[:next] && opts[:next].type == :dd
135
+ end
136
+
137
+ TABLE_CELL_ALIGNMENT = {left: 'l', center: 'c', right: 'r', default: 'l'}
138
+
139
+ def convert_table(el, opts)
140
+ opts[:alignment] = el.options[:alignment].map {|a| TABLE_CELL_ALIGNMENT[a] }
141
+ table_options = ["box"]
142
+ table_options << "center" if el.attr['class'] =~ /\bcenter\b/
143
+ opts[:result] << macro("TS") << "#{table_options.join(' ')} ;\n"
144
+ inner(el, opts)
145
+ opts[:result] << macro("TE") << macro("sp")
146
+ end
147
+
148
+ def convert_thead(el, opts)
149
+ opts[:result] << opts[:alignment].map {|a| "#{a}b" }.join(' ') << " .\n"
150
+ inner(el, opts)
151
+ opts[:result] << "=\n"
152
+ end
153
+
154
+ def convert_tbody(el, opts)
155
+ opts[:result] << ".T&\n" if opts[:index] != 0
156
+ opts[:result] << opts[:alignment].join(' ') << " .\n"
157
+ inner(el, opts)
158
+ opts[:result] << (opts[:next].type == :tfoot ? "=\n" : "_\n") if opts[:next]
159
+ end
160
+
161
+ def convert_tfoot(el, opts)
162
+ inner(el, opts)
163
+ end
164
+
165
+ def convert_tr(el, opts)
166
+ inner(el, opts)
167
+ opts[:result] << "\n"
168
+ end
169
+
170
+ def convert_td(el, opts)
171
+ result = opts[:result]
172
+ opts[:result] = +''
173
+ inner(el, opts)
174
+ if opts[:result] =~ /\n/
175
+ warning("Table cells using links are not supported")
176
+ result << "\t"
177
+ else
178
+ result << opts[:result] << "\t"
179
+ end
180
+ end
181
+
182
+ def convert_html_element(*)
183
+ warning("HTML elements are not supported")
184
+ end
185
+
186
+ def convert_xml_comment(el, opts)
187
+ newline(opts[:result]) << ".\"#{escape(el.value, true).rstrip.gsub(/\n/, "\n.\"")}\n"
188
+ end
189
+ alias convert_comment convert_xml_comment
190
+
191
+ def convert_a(el, opts)
192
+ if el.children.size == 1 && el.children[0].type == :text &&
193
+ el.attr['href'] == el.children[0].value
194
+ newline(opts[:result]) << macro("UR", escape(el.attr['href'])) << macro("UE")
195
+ elsif el.attr['href'].start_with?('mailto:')
196
+ newline(opts[:result]) << macro("MT", escape(el.attr['href'].sub(/^mailto:/, ''))) <<
197
+ macro("UE")
198
+ else
199
+ newline(opts[:result]) << macro("UR", escape(el.attr['href']))
200
+ inner(el, opts)
201
+ newline(opts[:result]) << macro("UE")
202
+ end
203
+ end
204
+
205
+ def convert_img(_el, _opts)
206
+ warning("Images are not supported")
207
+ end
208
+
209
+ def convert_em(el, opts)
210
+ opts[:result] << '\fI'
211
+ inner(el, opts)
212
+ opts[:result] << '\fP'
213
+ end
214
+
215
+ def convert_strong(el, opts)
216
+ opts[:result] << '\fB'
217
+ inner(el, opts)
218
+ opts[:result] << '\fP'
219
+ end
220
+
221
+ def convert_codespan(el, opts)
222
+ opts[:result] << "\\fB#{escape(el.value)}\\fP"
223
+ end
224
+
225
+ def convert_br(_el, opts)
226
+ newline(opts[:result]) << macro("br")
227
+ end
228
+
229
+ def convert_abbreviation(el, opts)
230
+ opts[:result] << escape(el.value)
231
+ end
232
+
233
+ def convert_math(el, opts)
234
+ if el.options[:category] == :block
235
+ convert_codeblock(el, opts)
236
+ else
237
+ convert_codespan(el, opts)
238
+ end
239
+ end
240
+
241
+ def convert_footnote(*)
242
+ warning("Footnotes are not supported")
243
+ end
244
+
245
+ def convert_raw(*)
246
+ warning("Raw content is not supported")
247
+ end
248
+
249
+ def convert_text(el, opts)
250
+ text = escape(el.value)
251
+ text.lstrip! if opts[:result][-1] == "\n"
252
+ opts[:result] << text
253
+ end
254
+
255
+ def convert_entity(el, opts)
256
+ opts[:result] << unicode_char(el.value.code_point)
257
+ end
258
+
259
+ def convert_smart_quote(el, opts)
260
+ opts[:result] << unicode_char(::Kramdown::Utils::Entities.entity(el.value.to_s).code_point)
261
+ end
262
+
263
+ TYPOGRAPHIC_SYMS_MAP = {
264
+ mdash: '\(em', ndash: '\(em', hellip: '\.\.\.',
265
+ laquo_space: '\[Fo]', raquo_space: '\[Fc]', laquo: '\[Fo]', raquo: '\[Fc]'
266
+ }
267
+
268
+ def convert_typographic_sym(el, opts)
269
+ opts[:result] << TYPOGRAPHIC_SYMS_MAP[el.value]
270
+ end
271
+
272
+ def macro(name, *args)
273
+ ".#{[name, *args].compact.join(' ')}\n"
274
+ end
275
+
276
+ def newline(text)
277
+ text << "\n" unless text[-1] == "\n"
278
+ text
279
+ end
280
+
281
+ def quote(text)
282
+ "\"#{text.gsub(/"/, '\\"')}\""
283
+ end
284
+
285
+ def escape(text, preserve_whitespace = false)
286
+ text = (preserve_whitespace ? text.dup : text.gsub(/\s+/, ' '))
287
+ text.gsub!('\\', "\\e")
288
+ text.gsub!(/^\./, '\\\\&.')
289
+ text.gsub!(/[.'-]/) {|m| "\\#{m}" }
290
+ text
291
+ end
292
+
293
+ def unicode_char(codepoint)
294
+ "\\[u#{codepoint.to_s(16).rjust(4, '0')}]"
295
+ end
296
+
297
+ end
298
+
299
+ end
300
+ end