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.
- checksums.yaml +7 -0
- data/CONTRIBUTERS +63 -1
- data/COPYING +17 -11
- data/README.md +35 -14
- data/VERSION +1 -1
- data/bin/kramdown +92 -40
- data/data/kramdown/document.html +4 -0
- data/data/kramdown/document.latex +7 -0
- data/lib/kramdown.rb +3 -16
- data/lib/kramdown/converter.rb +42 -16
- data/lib/kramdown/converter/base.rb +102 -38
- data/lib/kramdown/converter/hash_ast.rb +38 -0
- data/lib/kramdown/converter/html.rb +232 -141
- data/lib/kramdown/converter/kramdown.rb +122 -104
- data/lib/kramdown/converter/latex.rb +95 -78
- data/lib/kramdown/converter/man.rb +300 -0
- data/lib/kramdown/converter/math_engine/mathjax.rb +32 -0
- data/lib/kramdown/converter/remove_html_tags.rb +8 -17
- data/lib/kramdown/converter/syntax_highlighter.rb +56 -0
- data/lib/kramdown/converter/syntax_highlighter/minted.rb +35 -0
- data/lib/kramdown/converter/syntax_highlighter/rouge.rb +85 -0
- data/lib/kramdown/converter/toc.rb +7 -20
- data/lib/kramdown/document.rb +30 -37
- data/lib/kramdown/element.rb +54 -27
- data/lib/kramdown/error.rb +3 -16
- data/lib/kramdown/options.rb +392 -247
- data/lib/kramdown/parser.rb +3 -16
- data/lib/kramdown/parser/base.rb +28 -33
- data/lib/kramdown/parser/html.rb +151 -119
- data/lib/kramdown/parser/kramdown.rb +87 -50
- data/lib/kramdown/parser/kramdown/abbreviation.rb +33 -27
- data/lib/kramdown/parser/kramdown/autolink.rb +7 -25
- data/lib/kramdown/parser/kramdown/blank_line.rb +6 -19
- data/lib/kramdown/parser/kramdown/block_boundary.rb +6 -18
- data/lib/kramdown/parser/kramdown/blockquote.rb +6 -19
- data/lib/kramdown/parser/kramdown/codeblock.rb +15 -24
- data/lib/kramdown/parser/kramdown/codespan.rb +20 -22
- data/lib/kramdown/parser/kramdown/emphasis.rb +15 -24
- data/lib/kramdown/parser/kramdown/eob.rb +3 -16
- data/lib/kramdown/parser/kramdown/escaped_chars.rb +3 -16
- data/lib/kramdown/parser/kramdown/extensions.rb +66 -56
- data/lib/kramdown/parser/kramdown/footnote.rb +21 -31
- data/lib/kramdown/parser/kramdown/header.rb +37 -37
- data/lib/kramdown/parser/kramdown/horizontal_rule.rb +5 -17
- data/lib/kramdown/parser/kramdown/html.rb +47 -56
- data/lib/kramdown/parser/kramdown/html_entity.rb +9 -19
- data/lib/kramdown/parser/kramdown/line_break.rb +4 -17
- data/lib/kramdown/parser/kramdown/link.rb +39 -38
- data/lib/kramdown/parser/kramdown/list.rb +124 -82
- data/lib/kramdown/parser/kramdown/math.rb +12 -24
- data/lib/kramdown/parser/kramdown/paragraph.rb +23 -24
- data/lib/kramdown/parser/kramdown/smart_quotes.rb +26 -66
- data/lib/kramdown/parser/kramdown/table.rb +41 -48
- data/lib/kramdown/parser/kramdown/typographic_symbol.rb +14 -22
- data/lib/kramdown/parser/markdown.rb +11 -23
- data/lib/kramdown/utils.rb +21 -18
- data/lib/kramdown/utils/configurable.rb +45 -0
- data/lib/kramdown/utils/entities.rb +287 -292
- data/lib/kramdown/utils/html.rb +27 -30
- data/lib/kramdown/utils/lru_cache.rb +41 -0
- data/lib/kramdown/utils/string_scanner.rb +81 -0
- data/lib/kramdown/utils/unidecoder.rb +50 -0
- data/lib/kramdown/version.rb +4 -17
- data/man/man1/kramdown.1 +340 -347
- data/test/run_tests.rb +7 -20
- data/test/test_files.rb +188 -100
- data/test/test_location.rb +216 -0
- data/test/test_string_scanner_kramdown.rb +27 -0
- data/test/testcases/block/03_paragraph/indented.html.gfm +18 -0
- data/test/testcases/block/03_paragraph/line_break_last_line.html +9 -0
- data/test/testcases/block/03_paragraph/line_break_last_line.text +9 -0
- data/test/testcases/block/03_paragraph/standalone_image.html +8 -0
- data/test/testcases/block/03_paragraph/standalone_image.text +6 -0
- data/test/testcases/block/03_paragraph/with_html_to_native.html +1 -0
- data/test/testcases/block/03_paragraph/with_html_to_native.options +1 -0
- data/test/testcases/block/03_paragraph/with_html_to_native.text +1 -0
- data/test/testcases/block/04_header/atx_header.html +15 -1
- data/test/testcases/block/04_header/atx_header.text +14 -1
- data/test/testcases/block/04_header/setext_header.html +3 -1
- data/test/testcases/block/04_header/setext_header.text +4 -1
- data/test/testcases/block/04_header/with_auto_id_stripping.html +1 -0
- data/test/testcases/block/04_header/with_auto_id_stripping.options +1 -0
- data/test/testcases/block/04_header/with_auto_id_stripping.text +1 -0
- data/test/testcases/block/04_header/with_auto_ids.html +2 -0
- data/test/testcases/block/04_header/with_auto_ids.options +1 -0
- data/test/testcases/block/04_header/with_auto_ids.text +2 -0
- data/test/testcases/block/06_codeblock/guess_lang_css_class.html +15 -0
- data/test/testcases/block/06_codeblock/guess_lang_css_class.options +2 -0
- data/test/testcases/block/06_codeblock/guess_lang_css_class.text +13 -0
- data/test/testcases/block/06_codeblock/highlighting-minted-with-opts.latex +9 -0
- data/test/testcases/block/06_codeblock/highlighting-minted-with-opts.options +4 -0
- data/test/testcases/block/06_codeblock/highlighting-minted-with-opts.text +5 -0
- data/test/testcases/block/06_codeblock/highlighting-minted.latex +8 -0
- data/test/testcases/block/06_codeblock/highlighting-minted.options +3 -0
- data/test/testcases/block/06_codeblock/highlighting-minted.text +4 -0
- data/test/testcases/block/06_codeblock/highlighting-opts.html +6 -0
- data/test/testcases/block/06_codeblock/highlighting-opts.options +7 -0
- data/test/testcases/block/06_codeblock/highlighting-opts.text +4 -0
- data/test/testcases/block/06_codeblock/highlighting.html +5 -6
- data/test/testcases/block/06_codeblock/issue_gh45.html +164 -0
- data/test/testcases/block/06_codeblock/issue_gh45.test +188 -0
- data/test/testcases/block/06_codeblock/rouge/disabled.html +2 -0
- data/test/testcases/block/06_codeblock/rouge/disabled.options +4 -0
- data/test/testcases/block/06_codeblock/rouge/disabled.text +1 -0
- data/test/testcases/block/06_codeblock/rouge/multiple.html +11 -0
- data/test/testcases/block/06_codeblock/rouge/multiple.options +4 -0
- data/test/testcases/block/06_codeblock/rouge/multiple.text +11 -0
- data/test/testcases/block/06_codeblock/rouge/simple.html +10 -0
- data/test/testcases/block/06_codeblock/rouge/simple.options +3 -0
- data/test/testcases/block/06_codeblock/rouge/simple.text +9 -0
- data/test/testcases/block/06_codeblock/with_lang_in_fenced_block.options +1 -1
- data/test/testcases/block/06_codeblock/with_lang_in_fenced_block_any_char.html +8 -0
- data/test/testcases/block/06_codeblock/with_lang_in_fenced_block_any_char.options +2 -0
- data/test/testcases/block/06_codeblock/with_lang_in_fenced_block_any_char.text +11 -0
- data/test/testcases/block/06_codeblock/with_lang_in_fenced_block_name_with_dash.html +3 -0
- data/test/testcases/block/06_codeblock/with_lang_in_fenced_block_name_with_dash.options +2 -0
- data/test/testcases/block/06_codeblock/with_lang_in_fenced_block_name_with_dash.text +4 -0
- data/test/testcases/block/07_horizontal_rule/error.html +2 -2
- data/test/testcases/block/07_horizontal_rule/normal.html +2 -0
- data/test/testcases/block/07_horizontal_rule/normal.text +3 -0
- data/test/testcases/block/08_list/brackets_in_item.latex +3 -0
- data/test/testcases/block/08_list/brackets_in_item.text +1 -0
- data/test/testcases/block/08_list/lazy_and_nested.html +9 -0
- data/test/testcases/block/08_list/lazy_and_nested.text +4 -0
- data/test/testcases/block/09_html/html5_attributes.html +2 -0
- data/test/testcases/block/09_html/html5_attributes.text +2 -0
- data/test/testcases/block/09_html/html_after_block.html +7 -0
- data/test/testcases/block/09_html/html_after_block.text +5 -0
- data/test/testcases/block/09_html/html_to_native/table_simple.html +13 -0
- data/test/testcases/block/09_html/html_to_native/table_simple.text +15 -0
- data/test/testcases/block/09_html/html_to_native/typography.html +1 -1
- data/test/testcases/block/09_html/not_parsed.html +1 -1
- data/test/testcases/block/09_html/processing_instruction.html +5 -6
- data/test/testcases/block/09_html/simple.html +1 -5
- data/test/testcases/block/09_html/simple.text +1 -5
- data/test/testcases/block/09_html/standalone_image_in_div.htmlinput +7 -0
- data/test/testcases/block/09_html/standalone_image_in_div.text +8 -0
- data/test/testcases/block/09_html/textarea.html +8 -0
- data/test/testcases/block/09_html/textarea.text +8 -0
- data/test/testcases/block/09_html/xml.html +8 -0
- data/test/testcases/block/09_html/xml.text +7 -0
- data/test/testcases/block/11_ial/simple.html +5 -1
- data/test/testcases/block/11_ial/simple.text +8 -1
- data/test/testcases/block/12_extension/options.html +4 -4
- data/test/testcases/block/12_extension/options.text +2 -0
- data/test/testcases/block/12_extension/options2.html +4 -4
- data/test/testcases/block/12_extension/options3.html +7 -6
- data/test/testcases/block/12_extension/options3.text +2 -2
- data/test/testcases/block/13_definition_list/auto_ids.html +15 -0
- data/test/testcases/block/13_definition_list/auto_ids.text +18 -0
- data/test/testcases/block/13_definition_list/item_ial.html +5 -0
- data/test/testcases/block/13_definition_list/item_ial.text +8 -0
- data/test/testcases/block/14_table/empty_tag_in_cell.html +8 -0
- data/test/testcases/block/14_table/empty_tag_in_cell.options +1 -0
- data/test/testcases/block/14_table/empty_tag_in_cell.text +1 -0
- data/test/testcases/block/14_table/errors.html +4 -0
- data/test/testcases/block/14_table/errors.text +4 -0
- data/test/testcases/block/14_table/header.html +21 -0
- data/test/testcases/block/14_table/header.text +7 -0
- data/test/testcases/block/14_table/simple.html +22 -7
- data/test/testcases/block/14_table/simple.text +4 -0
- data/test/testcases/block/14_table/table_with_footnote.html +4 -4
- data/test/testcases/block/15_math/gh_128.html +1 -0
- data/test/testcases/block/15_math/gh_128.text +1 -0
- data/test/testcases/block/15_math/no_engine.html +3 -0
- data/test/testcases/block/15_math/no_engine.options +1 -0
- data/test/testcases/block/15_math/no_engine.text +2 -0
- data/test/testcases/block/15_math/normal.html +17 -14
- data/test/testcases/block/15_math/normal.text +2 -0
- data/test/testcases/block/16_toc/toc_exclude.html +7 -7
- data/test/testcases/block/16_toc/toc_levels.html +5 -5
- data/test/testcases/block/16_toc/toc_levels.text +1 -1
- data/test/testcases/block/16_toc/toc_with_footnotes.html +5 -5
- data/test/testcases/block/16_toc/toc_with_links.html +8 -0
- data/test/testcases/block/16_toc/toc_with_links.options +2 -0
- data/test/testcases/block/16_toc/toc_with_links.text +8 -0
- data/test/testcases/cjk-line-break.html +4 -0
- data/test/testcases/cjk-line-break.options +1 -0
- data/test/testcases/cjk-line-break.text +12 -0
- data/test/testcases/man/example.man +123 -0
- data/test/testcases/man/example.text +85 -0
- data/test/testcases/man/heading-name-dash-description.man +4 -0
- data/test/testcases/man/heading-name-dash-description.text +1 -0
- data/test/testcases/man/heading-name-description.man +4 -0
- data/test/testcases/man/heading-name-description.text +2 -0
- data/test/testcases/man/heading-name-section-description.man +4 -0
- data/test/testcases/man/heading-name-section-description.text +1 -0
- data/test/testcases/man/heading-name-section.man +2 -0
- data/test/testcases/man/heading-name-section.text +1 -0
- data/test/testcases/man/heading-name.man +2 -0
- data/test/testcases/man/heading-name.text +1 -0
- data/test/testcases/man/sections.man +4 -0
- data/test/testcases/man/sections.text +11 -0
- data/test/testcases/man/text-escaping.man +8 -0
- data/test/testcases/man/text-escaping.text +7 -0
- data/test/testcases/span/01_link/empty.html +1 -1
- data/test/testcases/span/01_link/empty_title.htmlinput +3 -0
- data/test/testcases/span/01_link/empty_title.text +7 -0
- data/test/testcases/span/01_link/imagelinks.html +1 -0
- data/test/testcases/span/01_link/imagelinks.text +2 -0
- data/test/testcases/span/01_link/inline.html +1 -1
- data/test/testcases/span/01_link/latex_escaping.latex +6 -0
- data/test/testcases/span/01_link/latex_escaping.text +5 -0
- data/test/testcases/span/01_link/link_defs.html +1 -1
- data/test/testcases/span/01_link/link_defs.text +2 -1
- data/test/testcases/span/01_link/link_defs_with_ial.html +4 -0
- data/test/testcases/span/01_link/link_defs_with_ial.text +16 -0
- data/test/testcases/span/01_link/reference.html +3 -3
- data/test/testcases/span/02_emphasis/nesting.html +3 -0
- data/test/testcases/span/02_emphasis/nesting.text +4 -1
- data/test/testcases/span/02_emphasis/normal.html +19 -0
- data/test/testcases/span/02_emphasis/normal.options +1 -0
- data/test/testcases/span/02_emphasis/normal.text +17 -0
- data/test/testcases/span/03_codespan/highlighting-minted.latex +2 -0
- data/test/testcases/span/03_codespan/highlighting-minted.options +1 -0
- data/test/testcases/span/03_codespan/highlighting-minted.text +1 -0
- data/test/testcases/span/03_codespan/highlighting.html +1 -1
- data/test/testcases/span/03_codespan/normal-css-class.html +1 -0
- data/test/testcases/span/03_codespan/normal-css-class.options +2 -0
- data/test/testcases/span/03_codespan/normal-css-class.text +1 -0
- data/test/testcases/span/03_codespan/rouge/disabled.html +1 -0
- data/test/testcases/span/03_codespan/rouge/disabled.options +4 -0
- data/test/testcases/span/03_codespan/rouge/disabled.text +1 -0
- data/test/testcases/span/03_codespan/rouge/simple.html +1 -0
- data/test/testcases/span/03_codespan/rouge/simple.options +1 -0
- data/test/testcases/span/03_codespan/rouge/simple.text +1 -0
- data/test/testcases/span/04_footnote/backlink_inline.html +79 -0
- data/test/testcases/span/04_footnote/backlink_inline.options +1 -0
- data/test/testcases/span/04_footnote/backlink_inline.text +38 -0
- data/test/testcases/span/04_footnote/backlink_text.html +9 -0
- data/test/testcases/span/04_footnote/backlink_text.options +1 -0
- data/test/testcases/span/04_footnote/backlink_text.text +3 -0
- data/test/testcases/span/04_footnote/definitions.latex +2 -2
- data/test/testcases/span/04_footnote/footnote_nr.html +6 -6
- data/test/testcases/span/04_footnote/footnote_prefix.html +12 -0
- data/test/testcases/span/04_footnote/footnote_prefix.options +1 -0
- data/test/testcases/span/04_footnote/footnote_prefix.text +4 -0
- data/test/testcases/span/04_footnote/inside_footnote.html +17 -0
- data/test/testcases/span/04_footnote/inside_footnote.text +9 -0
- data/test/testcases/span/04_footnote/markers.html +16 -16
- data/test/testcases/span/04_footnote/markers.latex +3 -3
- data/test/testcases/span/04_footnote/markers.options +2 -0
- data/test/testcases/span/04_footnote/markers.text +2 -1
- data/test/testcases/span/04_footnote/placement.html +11 -0
- data/test/testcases/span/04_footnote/placement.options +1 -0
- data/test/testcases/span/04_footnote/placement.text +8 -0
- data/test/testcases/span/04_footnote/regexp_problem.html +14 -0
- data/test/testcases/span/04_footnote/regexp_problem.options +2 -0
- data/test/testcases/span/04_footnote/regexp_problem.text +52 -0
- data/test/testcases/span/04_footnote/without_backlink.html +9 -0
- data/test/testcases/span/04_footnote/without_backlink.options +1 -0
- data/test/testcases/span/04_footnote/without_backlink.text +3 -0
- data/test/testcases/span/05_html/button.html +7 -0
- data/test/testcases/span/05_html/button.text +7 -0
- data/test/testcases/span/05_html/mark_element.html +3 -0
- data/test/testcases/span/05_html/mark_element.text +3 -0
- data/test/testcases/span/05_html/normal.html +10 -1
- data/test/testcases/span/05_html/normal.text +9 -0
- data/test/testcases/span/05_html/raw_span_elements.html +2 -0
- data/test/testcases/span/05_html/raw_span_elements.text +2 -0
- data/test/testcases/span/05_html/xml.html +5 -0
- data/test/testcases/span/05_html/xml.text +5 -0
- data/test/testcases/span/abbreviations/abbrev.html +14 -1
- data/test/testcases/span/abbreviations/abbrev.text +18 -2
- data/test/testcases/span/abbreviations/in_footnote.html +9 -0
- data/test/testcases/span/abbreviations/in_footnote.text +5 -0
- data/test/testcases/span/autolinks/url_links.html +5 -4
- data/test/testcases/span/autolinks/url_links.text +1 -0
- data/test/testcases/span/line_breaks/normal.html +2 -2
- data/test/testcases/span/line_breaks/normal.latex +2 -2
- data/test/testcases/span/math/no_engine.html +1 -0
- data/test/testcases/span/math/no_engine.options +1 -0
- data/test/testcases/span/math/no_engine.text +1 -0
- data/test/testcases/span/math/normal.html +4 -3
- data/test/testcases/span/math/normal.text +2 -1
- data/test/testcases/span/text_substitutions/entities_as_char.html +1 -1
- data/test/testcases/span/text_substitutions/entities_as_char.options +1 -0
- data/test/testcases/span/text_substitutions/entities_as_char.text +1 -1
- data/test/testcases/span/text_substitutions/typography.html +22 -0
- data/test/testcases/span/text_substitutions/typography.text +22 -0
- data/test/testcases/span/text_substitutions/typography_subst.html +3 -0
- data/test/testcases/span/text_substitutions/typography_subst.latex +4 -0
- data/test/testcases/span/text_substitutions/typography_subst.options +8 -0
- data/test/testcases/span/text_substitutions/typography_subst.text +3 -0
- metadata +218 -67
- data/ChangeLog +0 -7436
- data/GPL +0 -674
- data/Rakefile +0 -306
- data/benchmark/benchmark.rb +0 -36
- data/benchmark/benchmark.sh +0 -74
- data/benchmark/generate_data.rb +0 -119
- data/benchmark/mdbasics.text +0 -306
- data/benchmark/mdsyntax.text +0 -888
- data/benchmark/testing.sh +0 -9
- data/benchmark/timing.sh +0 -10
- data/doc/bg.png +0 -0
- data/doc/default.scss.css +0 -181
- data/doc/default.template +0 -68
- data/doc/design.scss.css +0 -441
- data/doc/documentation.page +0 -84
- data/doc/documentation.template +0 -20
- data/doc/index.page +0 -94
- data/doc/installation.page +0 -88
- data/doc/links.markdown +0 -6
- data/doc/metainfo +0 -3
- data/doc/news.feed +0 -10
- data/doc/news.page +0 -29
- data/doc/options.page +0 -10
- data/doc/quickref.page +0 -598
- data/doc/sidebar.template +0 -21
- data/doc/syntax.page +0 -1700
- data/doc/tests.page +0 -91
- data/doc/virtual +0 -2
- data/lib/kramdown/compatibility.rb +0 -49
- data/lib/kramdown/utils/ordered_hash.rb +0 -100
- data/setup.rb +0 -1585
- data/test/testcases/block/07_horizontal_rule/error.html.19 +0 -7
- data/test/testcases/block/09_html/html_to_native/typography.html.19 +0 -1
- data/test/testcases/block/09_html/simple.html.19 +0 -64
- data/test/testcases/block/14_table/simple.html.19 +0 -177
- data/test/testcases/span/01_link/inline.html.19 +0 -46
- data/test/testcases/span/01_link/reference.html.19 +0 -37
- data/test/testcases/span/text_substitutions/entities_as_char.html.19 +0 -1
@@ -1,26 +1,15 @@
|
|
1
|
-
# -*- coding: utf-8 -*-
|
1
|
+
# -*- coding: utf-8; frozen_string_literal: true -*-
|
2
2
|
#
|
3
3
|
#--
|
4
|
-
# Copyright (C) 2009-
|
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 'erb'
|
11
|
+
require 'kramdown/utils'
|
12
|
+
require 'kramdown/document'
|
24
13
|
|
25
14
|
module Kramdown
|
26
15
|
|
@@ -71,47 +60,84 @@ module Kramdown
|
|
71
60
|
end
|
72
61
|
private_class_method(:new, :allocate)
|
73
62
|
|
63
|
+
# Returns whether the template should be applied before the conversion of the tree.
|
64
|
+
#
|
65
|
+
# Defaults to false.
|
66
|
+
def apply_template_before?
|
67
|
+
false
|
68
|
+
end
|
69
|
+
|
70
|
+
# Returns whether the template should be applied after the conversion of the tree.
|
71
|
+
#
|
72
|
+
# Defaults to true.
|
73
|
+
def apply_template_after?
|
74
|
+
true
|
75
|
+
end
|
76
|
+
|
74
77
|
# Convert the element tree +tree+ and return the resulting conversion object (normally a
|
75
78
|
# string) and an array with warning messages. The parameter +options+ specifies the conversion
|
76
79
|
# options that should be used.
|
77
80
|
#
|
78
81
|
# Initializes a new instance of the calling class and then calls the #convert method with
|
79
|
-
# +tree+ as parameter.
|
80
|
-
#
|
82
|
+
# +tree+ as parameter.
|
83
|
+
#
|
84
|
+
# If the +template+ option is specified and non-empty, the template is evaluate with ERB
|
85
|
+
# before and/or after the tree conversion depending on the result of #apply_template_before?
|
86
|
+
# and #apply_template_after?. If the template is evaluated before, an empty string is used for
|
87
|
+
# the body; if evaluated after, the result is used as body. See ::apply_template.
|
88
|
+
#
|
89
|
+
# The template resolution is done in the following way (for the converter ConverterName):
|
81
90
|
#
|
82
91
|
# 1. Look in the current working directory for the template.
|
83
92
|
#
|
84
|
-
# 2. Append +.
|
85
|
-
# file in the current working directory.
|
93
|
+
# 2. Append +.converter_name+ (e.g. +.html+) to the template name and look for the resulting
|
94
|
+
# file in the current working directory (the form +.convertername+ is deprecated).
|
95
|
+
#
|
96
|
+
# 3. Append +.converter_name+ to the template name and look for it in the kramdown data
|
97
|
+
# directory (the form +.convertername+ is deprecated).
|
86
98
|
#
|
87
|
-
#
|
88
|
-
#
|
99
|
+
# 4. Check if the template name starts with 'string://' and if so, strip this prefix away and
|
100
|
+
# use the rest as template.
|
89
101
|
def self.convert(tree, options = {})
|
90
102
|
converter = new(tree, ::Kramdown::Options.merge(options.merge(tree.options[:options] || {})))
|
103
|
+
|
104
|
+
if !converter.options[:template].empty? && converter.apply_template_before?
|
105
|
+
apply_template(converter, '')
|
106
|
+
end
|
91
107
|
result = converter.convert(tree)
|
92
|
-
result
|
108
|
+
if result.respond_to?(:encode!) && result.encoding != Encoding::BINARY
|
109
|
+
result.encode!(tree.options[:encoding] ||
|
110
|
+
(raise ::Kramdown::Error, "Missing encoding option on root element"))
|
111
|
+
end
|
112
|
+
if !converter.options[:template].empty? && converter.apply_template_after?
|
113
|
+
result = apply_template(converter, result)
|
114
|
+
end
|
115
|
+
|
93
116
|
[result, converter.warnings]
|
94
117
|
end
|
95
118
|
|
96
119
|
# Convert the element +el+ and return the resulting object.
|
97
120
|
#
|
98
121
|
# This is the only method that has to be implemented by sub-classes!
|
99
|
-
def convert(
|
122
|
+
def convert(_el)
|
100
123
|
raise NotImplementedError
|
101
124
|
end
|
102
125
|
|
103
126
|
# Apply the +template+ using +body+ as the body string.
|
127
|
+
#
|
128
|
+
# The template is evaluated using ERB and the body is available in the @body instance variable
|
129
|
+
# and the converter object in the @converter instance variable.
|
104
130
|
def self.apply_template(converter, body) # :nodoc:
|
105
131
|
erb = ERB.new(get_template(converter.options[:template]))
|
106
132
|
obj = Object.new
|
107
133
|
obj.instance_variable_set(:@converter, converter)
|
108
134
|
obj.instance_variable_set(:@body, body)
|
109
|
-
erb.result(obj.instance_eval{binding})
|
135
|
+
erb.result(obj.instance_eval { binding })
|
110
136
|
end
|
111
137
|
|
112
138
|
# Return the template specified by +template+.
|
113
139
|
def self.get_template(template) # :nodoc:
|
114
|
-
format_ext = '.' + self.name.split(/::/).last
|
140
|
+
format_ext = '.' + ::Kramdown::Utils.snake_case(self.name.split(/::/).last)
|
115
141
|
shipped = File.join(::Kramdown.data_dir, template + format_ext)
|
116
142
|
if File.exist?(template)
|
117
143
|
File.read(template)
|
@@ -119,6 +145,8 @@ module Kramdown
|
|
119
145
|
File.read(template + format_ext)
|
120
146
|
elsif File.exist?(shipped)
|
121
147
|
File.read(shipped)
|
148
|
+
elsif template.start_with?('string://')
|
149
|
+
template.sub(/\Astring:\/\//, '')
|
122
150
|
else
|
123
151
|
raise "The specified template file #{template} does not exist"
|
124
152
|
end
|
@@ -132,7 +160,7 @@ module Kramdown
|
|
132
160
|
# Return +true+ if the header element +el+ should be used for the table of contents (as
|
133
161
|
# specified by the +toc_levels+ option).
|
134
162
|
def in_toc?(el)
|
135
|
-
@options[:toc_levels].include?(el.options[:level])
|
163
|
+
@options[:toc_levels].include?(el.options[:level]) && (el.attr['class'] || '') !~ /\bno_toc\b/
|
136
164
|
end
|
137
165
|
|
138
166
|
# Return the output header level given a level.
|
@@ -144,8 +172,8 @@ module Kramdown
|
|
144
172
|
|
145
173
|
# Extract the code block/span language from the attributes.
|
146
174
|
def extract_code_language(attr)
|
147
|
-
if attr['class'] && attr['class'] =~ /\blanguage-\
|
148
|
-
attr['class'].scan(/\blanguage-(\
|
175
|
+
if attr['class'] && attr['class'] =~ /\blanguage-\S+/
|
176
|
+
attr['class'].scan(/\blanguage-(\S+)/).first.first
|
149
177
|
end
|
150
178
|
end
|
151
179
|
|
@@ -154,31 +182,67 @@ module Kramdown
|
|
154
182
|
# *Warning*: This version will modify the given attributes if a language is present.
|
155
183
|
def extract_code_language!(attr)
|
156
184
|
lang = extract_code_language(attr)
|
157
|
-
attr['class'] = attr['class'].sub(/\blanguage-\
|
185
|
+
attr['class'] = attr['class'].sub(/\blanguage-\S+/, '').strip if lang
|
158
186
|
attr.delete('class') if lang && attr['class'].empty?
|
159
187
|
lang
|
160
188
|
end
|
161
189
|
|
190
|
+
# Highlight the given +text+ in the language +lang+ with the syntax highlighter configured
|
191
|
+
# through the option 'syntax_highlighter'.
|
192
|
+
def highlight_code(text, lang, type, opts = {})
|
193
|
+
return nil unless @options[:syntax_highlighter]
|
194
|
+
|
195
|
+
highlighter = ::Kramdown::Converter.syntax_highlighter(@options[:syntax_highlighter])
|
196
|
+
if highlighter
|
197
|
+
highlighter.call(self, text, lang, type, opts)
|
198
|
+
else
|
199
|
+
warning("The configured syntax highlighter #{@options[:syntax_highlighter]} is not available.")
|
200
|
+
nil
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
# Format the given math element with the math engine configured through the option
|
205
|
+
# 'math_engine'.
|
206
|
+
def format_math(el, opts = {})
|
207
|
+
return nil unless @options[:math_engine]
|
208
|
+
|
209
|
+
engine = ::Kramdown::Converter.math_engine(@options[:math_engine])
|
210
|
+
if engine
|
211
|
+
engine.call(self, el, opts)
|
212
|
+
else
|
213
|
+
warning("The configured math engine #{@options[:math_engine]} is not available.")
|
214
|
+
nil
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
162
218
|
# Generate an unique alpha-numeric ID from the the string +str+ for use as a header ID.
|
163
219
|
#
|
164
220
|
# Uses the option +auto_id_prefix+: the value of this option is prepended to every generated
|
165
221
|
# ID.
|
166
222
|
def generate_id(str)
|
167
|
-
|
168
|
-
gen_id
|
169
|
-
gen_id
|
170
|
-
gen_id.downcase!
|
171
|
-
gen_id = 'section' if gen_id.length == 0
|
223
|
+
str = ::Kramdown::Utils::Unidecoder.decode(str) if @options[:transliterated_header_ids]
|
224
|
+
gen_id = basic_generate_id(str)
|
225
|
+
gen_id = 'section' if gen_id.empty?
|
172
226
|
@used_ids ||= {}
|
173
|
-
if @used_ids.
|
174
|
-
gen_id +=
|
227
|
+
if @used_ids.key?(gen_id)
|
228
|
+
gen_id += "-#{@used_ids[gen_id] += 1}"
|
175
229
|
else
|
176
230
|
@used_ids[gen_id] = 0
|
177
231
|
end
|
178
232
|
@options[:auto_id_prefix] + gen_id
|
179
233
|
end
|
180
234
|
|
181
|
-
|
235
|
+
# The basic version of the ID generator, without any special provisions for empty or unique
|
236
|
+
# IDs.
|
237
|
+
def basic_generate_id(str)
|
238
|
+
gen_id = str.gsub(/^[^a-zA-Z]+/, '')
|
239
|
+
gen_id.tr!('^a-zA-Z0-9 -', '')
|
240
|
+
gen_id.tr!(' ', '-')
|
241
|
+
gen_id.downcase!
|
242
|
+
gen_id
|
243
|
+
end
|
244
|
+
|
245
|
+
SMART_QUOTE_INDICES = {lsquo: 0, rsquo: 1, ldquo: 2, rdquo: 3} # :nodoc:
|
182
246
|
|
183
247
|
# Return the entity that represents the given smart_quote element.
|
184
248
|
def smart_quote_entity(el)
|
@@ -0,0 +1,38 @@
|
|
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/parser'
|
11
|
+
require 'kramdown/converter'
|
12
|
+
require 'kramdown/utils'
|
13
|
+
|
14
|
+
module Kramdown
|
15
|
+
|
16
|
+
module Converter
|
17
|
+
|
18
|
+
# Converts a Kramdown::Document to a nested hash for further processing or debug output.
|
19
|
+
class HashAST < Base
|
20
|
+
|
21
|
+
def convert(el)
|
22
|
+
hash = {type: el.type}
|
23
|
+
hash[:attr] = el.attr unless el.attr.empty?
|
24
|
+
hash[:value] = el.value unless el.value.nil?
|
25
|
+
hash[:options] = el.options unless el.options.empty?
|
26
|
+
unless el.children.empty?
|
27
|
+
hash[:children] = []
|
28
|
+
el.children.each {|child| hash[:children] << convert(child) }
|
29
|
+
end
|
30
|
+
hash
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
HashAst = HashAST
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
@@ -1,27 +1,15 @@
|
|
1
|
-
# -*- coding: utf-8 -*-
|
1
|
+
# -*- coding: utf-8; frozen_string_literal: true -*-
|
2
2
|
#
|
3
3
|
#--
|
4
|
-
# Copyright (C) 2009-
|
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
|
-
require '
|
24
|
-
require 'kramdown/
|
10
|
+
require 'kramdown/parser'
|
11
|
+
require 'kramdown/converter'
|
12
|
+
require 'kramdown/utils'
|
25
13
|
|
26
14
|
module Kramdown
|
27
15
|
|
@@ -41,15 +29,6 @@ module Kramdown
|
|
41
29
|
# HTML element.
|
42
30
|
class Html < Base
|
43
31
|
|
44
|
-
begin
|
45
|
-
require 'coderay'
|
46
|
-
|
47
|
-
# Highlighting via coderay is available if this constant is +true+.
|
48
|
-
HIGHLIGHTING_AVAILABLE = true
|
49
|
-
rescue LoadError
|
50
|
-
HIGHLIGHTING_AVAILABLE = false # :nodoc:
|
51
|
-
end
|
52
|
-
|
53
32
|
include ::Kramdown::Utils::Html
|
54
33
|
include ::Kramdown::Parser::Html::Constants
|
55
34
|
|
@@ -61,20 +40,22 @@ module Kramdown
|
|
61
40
|
super
|
62
41
|
@footnote_counter = @footnote_start = @options[:footnote_nr]
|
63
42
|
@footnotes = []
|
43
|
+
@footnotes_by_name = {}
|
44
|
+
@footnote_location = nil
|
64
45
|
@toc = []
|
65
46
|
@toc_code = nil
|
66
47
|
@indent = 2
|
67
48
|
@stack = []
|
68
|
-
@coderay_enabled = @options[:enable_coderay] && HIGHLIGHTING_AVAILABLE
|
69
|
-
end
|
70
49
|
|
71
|
-
|
72
|
-
|
50
|
+
# stash string representation of symbol to avoid allocations from multiple interpolations.
|
51
|
+
@highlighter_class = " highlighter-#{options[:syntax_highlighter]}"
|
52
|
+
@dispatcher = Hash.new {|h, k| h[k] = :"convert_#{k}" }
|
53
|
+
end
|
73
54
|
|
74
55
|
# Dispatch the conversion of the element +el+ to a +convert_TYPE+ method using the +type+ of
|
75
56
|
# the element.
|
76
57
|
def convert(el, indent = -@indent)
|
77
|
-
send(
|
58
|
+
send(@dispatcher[el.type], el, indent)
|
78
59
|
end
|
79
60
|
|
80
61
|
# Return the converted content of the children of +el+ as a string. The parameter +indent+ has
|
@@ -83,42 +64,57 @@ module Kramdown
|
|
83
64
|
# Pushes +el+ onto the @stack before converting the child elements and pops it from the stack
|
84
65
|
# afterwards.
|
85
66
|
def inner(el, indent)
|
86
|
-
result = ''
|
67
|
+
result = +''
|
87
68
|
indent += @indent
|
88
69
|
@stack.push(el)
|
89
70
|
el.children.each do |inner_el|
|
90
|
-
result << send(
|
71
|
+
result << send(@dispatcher[inner_el.type], inner_el, indent)
|
91
72
|
end
|
92
73
|
@stack.pop
|
93
74
|
result
|
94
75
|
end
|
95
76
|
|
96
|
-
def convert_blank(
|
77
|
+
def convert_blank(_el, _indent)
|
97
78
|
"\n"
|
98
79
|
end
|
99
80
|
|
100
|
-
def convert_text(el,
|
101
|
-
escape_html(el.value, :text)
|
81
|
+
def convert_text(el, _indent)
|
82
|
+
escaped = escape_html(el.value, :text)
|
83
|
+
@options[:remove_line_breaks_for_cjk] ? fix_cjk_line_break(escaped) : escaped
|
102
84
|
end
|
103
85
|
|
104
86
|
def convert_p(el, indent)
|
105
87
|
if el.options[:transparent]
|
106
88
|
inner(el, indent)
|
89
|
+
elsif el.children.size == 1 && el.children.first.type == :img &&
|
90
|
+
el.children.first.options[:ial]&.[](:refs)&.include?('standalone')
|
91
|
+
convert_standalone_image(el.children.first, indent)
|
107
92
|
else
|
108
|
-
format_as_block_html(
|
93
|
+
format_as_block_html("p", el.attr, inner(el, indent), indent)
|
109
94
|
end
|
110
95
|
end
|
111
96
|
|
97
|
+
# Helper method used by +convert_p+ to convert a paragraph that only contains a single :img
|
98
|
+
# element.
|
99
|
+
def convert_standalone_image(el, indent)
|
100
|
+
attr = el.attr.dup
|
101
|
+
figure_attr = {}
|
102
|
+
figure_attr['class'] = attr.delete('class') if attr.key?('class')
|
103
|
+
figure_attr['id'] = attr.delete('id') if attr.key?('id')
|
104
|
+
body = "#{' ' * (indent + @indent)}<img#{html_attributes(attr)} />\n" \
|
105
|
+
"#{' ' * (indent + @indent)}<figcaption>#{attr['alt']}</figcaption>\n"
|
106
|
+
format_as_indented_block_html("figure", figure_attr, body, indent)
|
107
|
+
end
|
108
|
+
|
112
109
|
def convert_codeblock(el, indent)
|
113
110
|
attr = el.attr.dup
|
114
111
|
lang = extract_code_language!(attr)
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
"#{' '*indent}<div#{html_attributes(attr)}>#{result}#{' '*indent}</div>\n"
|
112
|
+
hl_opts = {}
|
113
|
+
highlighted_code = highlight_code(el.value, el.options[:lang] || lang, :block, hl_opts)
|
114
|
+
|
115
|
+
if highlighted_code
|
116
|
+
add_syntax_highlighter_to_class_attr(attr, lang || hl_opts[:default_lang])
|
117
|
+
"#{' ' * indent}<div#{html_attributes(attr)}>#{highlighted_code}#{' ' * indent}</div>\n"
|
122
118
|
else
|
123
119
|
result = escape_html(el.value)
|
124
120
|
result.chomp!
|
@@ -135,12 +131,13 @@ module Kramdown
|
|
135
131
|
end
|
136
132
|
code_attr = {}
|
137
133
|
code_attr['class'] = "language-#{lang}" if lang
|
138
|
-
"#{' '*indent}<pre#{html_attributes(attr)}
|
134
|
+
"#{' ' * indent}<pre#{html_attributes(attr)}>" \
|
135
|
+
"<code#{html_attributes(code_attr)}>#{result}\n</code></pre>\n"
|
139
136
|
end
|
140
137
|
end
|
141
138
|
|
142
139
|
def convert_blockquote(el, indent)
|
143
|
-
format_as_indented_block_html(
|
140
|
+
format_as_indented_block_html("blockquote", el.attr, inner(el, indent), indent)
|
144
141
|
end
|
145
142
|
|
146
143
|
def convert_header(el, indent)
|
@@ -154,50 +151,68 @@ module Kramdown
|
|
154
151
|
end
|
155
152
|
|
156
153
|
def convert_hr(el, indent)
|
157
|
-
"#{' '*indent}<hr />\n"
|
154
|
+
"#{' ' * indent}<hr#{html_attributes(el.attr)} />\n"
|
158
155
|
end
|
159
156
|
|
157
|
+
ZERO_TO_ONETWENTYEIGHT = (0..128).to_a.freeze
|
158
|
+
private_constant :ZERO_TO_ONETWENTYEIGHT
|
159
|
+
|
160
160
|
def convert_ul(el, indent)
|
161
|
-
if !@toc_code &&
|
162
|
-
@toc_code = [el.type, el.attr,
|
161
|
+
if !@toc_code && el.options.dig(:ial, :refs)&.include?('toc')
|
162
|
+
@toc_code = [el.type, el.attr, ZERO_TO_ONETWENTYEIGHT.map { rand(36).to_s(36) }.join]
|
163
163
|
@toc_code.last
|
164
|
+
elsif !@footnote_location && el.options.dig(:ial, :refs)&.include?('footnotes')
|
165
|
+
@footnote_location = ZERO_TO_ONETWENTYEIGHT.map { rand(36).to_s(36) }.join
|
164
166
|
else
|
165
167
|
format_as_indented_block_html(el.type, el.attr, inner(el, indent), indent)
|
166
168
|
end
|
167
169
|
end
|
168
|
-
alias
|
169
|
-
|
170
|
+
alias convert_ol convert_ul
|
171
|
+
|
172
|
+
def convert_dl(el, indent)
|
173
|
+
format_as_indented_block_html("dl", el.attr, inner(el, indent), indent)
|
174
|
+
end
|
170
175
|
|
171
176
|
def convert_li(el, indent)
|
172
|
-
output = ' '*indent << "<#{el.type}" << html_attributes(el.attr) << ">"
|
177
|
+
output = ' ' * indent << "<#{el.type}" << html_attributes(el.attr) << ">"
|
173
178
|
res = inner(el, indent)
|
174
179
|
if el.children.empty? || (el.children.first.type == :p && el.children.first.options[:transparent])
|
175
|
-
output << res << (res =~ /\n\Z/ ? ' '*indent : '')
|
180
|
+
output << res << (res =~ /\n\Z/ ? ' ' * indent : '')
|
176
181
|
else
|
177
|
-
output << "\n" << res << ' '*indent
|
182
|
+
output << "\n" << res << ' ' * indent
|
178
183
|
end
|
179
184
|
output << "</#{el.type}>\n"
|
180
185
|
end
|
181
|
-
alias
|
186
|
+
alias convert_dd convert_li
|
182
187
|
|
183
188
|
def convert_dt(el, indent)
|
184
|
-
|
189
|
+
attr = el.attr.dup
|
190
|
+
@stack.last.options[:ial][:refs].each do |ref|
|
191
|
+
if ref =~ /\Aauto_ids(?:-([\w-]+))?/
|
192
|
+
attr['id'] = "#{$1}#{basic_generate_id(el.options[:raw_text])}".lstrip
|
193
|
+
break
|
194
|
+
end
|
195
|
+
end if !attr['id'] && @stack.last.options[:ial] && @stack.last.options[:ial][:refs]
|
196
|
+
format_as_block_html("dt", attr, inner(el, indent), indent)
|
185
197
|
end
|
186
198
|
|
187
199
|
def convert_html_element(el, indent)
|
188
200
|
res = inner(el, indent)
|
189
201
|
if el.options[:category] == :span
|
190
|
-
"<#{el.value}#{html_attributes(el.attr)}"
|
202
|
+
"<#{el.value}#{html_attributes(el.attr)}" + \
|
203
|
+
(res.empty? && HTML_ELEMENTS_WITHOUT_BODY.include?(el.value) ? " />" : ">#{res}</#{el.value}>")
|
191
204
|
else
|
192
|
-
output = ''
|
193
|
-
|
205
|
+
output = +''
|
206
|
+
if @stack.last.type != :html_element || @stack.last.options[:content_model] != :raw
|
207
|
+
output << ' ' * indent
|
208
|
+
end
|
194
209
|
output << "<#{el.value}#{html_attributes(el.attr)}"
|
195
210
|
if el.options[:is_closed] && el.options[:content_model] == :raw
|
196
211
|
output << " />"
|
197
212
|
elsif !res.empty? && el.options[:content_model] != :block
|
198
213
|
output << ">#{res}</#{el.value}>"
|
199
214
|
elsif !res.empty?
|
200
|
-
output << ">\n#{res.chomp}\n"
|
215
|
+
output << ">\n#{res.chomp}\n" << ' ' * indent << "</#{el.value}>"
|
201
216
|
elsif HTML_ELEMENTS_WITHOUT_BODY.include?(el.value)
|
202
217
|
output << " />"
|
203
218
|
else
|
@@ -209,21 +224,22 @@ module Kramdown
|
|
209
224
|
end
|
210
225
|
|
211
226
|
def convert_xml_comment(el, indent)
|
212
|
-
if el.options[:category] == :block &&
|
213
|
-
|
227
|
+
if el.options[:category] == :block &&
|
228
|
+
(@stack.last.type != :html_element || @stack.last.options[:content_model] != :raw)
|
229
|
+
' ' * indent << el.value << "\n"
|
214
230
|
else
|
215
231
|
el.value
|
216
232
|
end
|
217
233
|
end
|
218
|
-
alias
|
234
|
+
alias convert_xml_pi convert_xml_comment
|
219
235
|
|
220
236
|
def convert_table(el, indent)
|
221
237
|
format_as_indented_block_html(el.type, el.attr, inner(el, indent), indent)
|
222
238
|
end
|
223
|
-
alias
|
224
|
-
alias
|
225
|
-
alias
|
226
|
-
alias
|
239
|
+
alias convert_thead convert_table
|
240
|
+
alias convert_tbody convert_table
|
241
|
+
alias convert_tfoot convert_table
|
242
|
+
alias convert_tr convert_table
|
227
243
|
|
228
244
|
ENTITY_NBSP = ::Kramdown::Utils::Entities.entity('nbsp') # :nodoc:
|
229
245
|
|
@@ -234,56 +250,63 @@ module Kramdown
|
|
234
250
|
alignment = @stack[-3].options[:alignment][@stack.last.children.index(el)]
|
235
251
|
if alignment != :default
|
236
252
|
attr = el.attr.dup
|
237
|
-
attr['style'] = (attr.
|
253
|
+
attr['style'] = (attr.key?('style') ? "#{attr['style']}; " : '') + "text-align: #{alignment}"
|
238
254
|
end
|
239
255
|
format_as_block_html(type, attr, res.empty? ? entity_to_str(ENTITY_NBSP) : res, indent)
|
240
256
|
end
|
241
257
|
|
242
258
|
def convert_comment(el, indent)
|
243
259
|
if el.options[:category] == :block
|
244
|
-
"#{' '*indent}<!-- #{el.value} -->\n"
|
260
|
+
"#{' ' * indent}<!-- #{el.value} -->\n"
|
245
261
|
else
|
246
262
|
"<!-- #{el.value} -->"
|
247
263
|
end
|
248
264
|
end
|
249
265
|
|
250
|
-
def convert_br(
|
266
|
+
def convert_br(_el, _indent)
|
251
267
|
"<br />"
|
252
268
|
end
|
253
269
|
|
254
270
|
def convert_a(el, indent)
|
255
|
-
|
256
|
-
attr = el.attr.dup
|
257
|
-
if attr['href'] =~ /^mailto:/
|
258
|
-
mail_addr = attr['href'].sub(/^mailto:/, '')
|
259
|
-
attr['href'] = obfuscate('mailto') << ":" << obfuscate(mail_addr)
|
260
|
-
res = obfuscate(res) if res == mail_addr
|
261
|
-
end
|
262
|
-
format_as_span_html(el.type, attr, res)
|
271
|
+
format_as_span_html("a", el.attr, inner(el, indent))
|
263
272
|
end
|
264
273
|
|
265
|
-
def convert_img(el,
|
274
|
+
def convert_img(el, _indent)
|
266
275
|
"<img#{html_attributes(el.attr)} />"
|
267
276
|
end
|
268
277
|
|
269
|
-
def convert_codespan(el,
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
278
|
+
def convert_codespan(el, _indent)
|
279
|
+
attr = el.attr.dup
|
280
|
+
lang = extract_code_language(attr)
|
281
|
+
hl_opts = {}
|
282
|
+
result = highlight_code(el.value, lang, :span, hl_opts)
|
283
|
+
if result
|
284
|
+
add_syntax_highlighter_to_class_attr(attr, hl_opts[:default_lang])
|
285
|
+
else
|
286
|
+
result = escape_html(el.value)
|
287
|
+
end
|
288
|
+
|
289
|
+
format_as_span_html('code', attr, result)
|
277
290
|
end
|
278
291
|
|
279
|
-
def convert_footnote(el,
|
280
|
-
|
281
|
-
@
|
282
|
-
|
283
|
-
|
292
|
+
def convert_footnote(el, _indent)
|
293
|
+
repeat = ''
|
294
|
+
name = @options[:footnote_prefix] + el.options[:name]
|
295
|
+
if (footnote = @footnotes_by_name[name])
|
296
|
+
number = footnote[2]
|
297
|
+
repeat = ":#{footnote[3] += 1}"
|
298
|
+
else
|
299
|
+
number = @footnote_counter
|
300
|
+
@footnote_counter += 1
|
301
|
+
@footnotes << [name, el.value, number, 0]
|
302
|
+
@footnotes_by_name[name] = @footnotes.last
|
303
|
+
end
|
304
|
+
"<sup id=\"fnref:#{name}#{repeat}\" role=\"doc-noteref\">" \
|
305
|
+
"<a href=\"#fn:#{name}\" class=\"footnote\">" \
|
306
|
+
"#{number}</a></sup>"
|
284
307
|
end
|
285
308
|
|
286
|
-
def convert_raw(el,
|
309
|
+
def convert_raw(el, _indent)
|
287
310
|
if !el.options[:type] || el.options[:type].empty? || el.options[:type].include?('html')
|
288
311
|
el.value + (el.options[:category] == :block ? "\n" : '')
|
289
312
|
else
|
@@ -294,56 +317,71 @@ module Kramdown
|
|
294
317
|
def convert_em(el, indent)
|
295
318
|
format_as_span_html(el.type, el.attr, inner(el, indent))
|
296
319
|
end
|
297
|
-
alias
|
320
|
+
alias convert_strong convert_em
|
298
321
|
|
299
|
-
def convert_entity(el,
|
322
|
+
def convert_entity(el, _indent)
|
300
323
|
entity_to_str(el.value, el.options[:original])
|
301
324
|
end
|
302
325
|
|
303
326
|
TYPOGRAPHIC_SYMS = {
|
304
|
-
:
|
305
|
-
:
|
306
|
-
:
|
307
|
-
:
|
308
|
-
|
309
|
-
:
|
310
|
-
|
327
|
+
mdash: [::Kramdown::Utils::Entities.entity('mdash')],
|
328
|
+
ndash: [::Kramdown::Utils::Entities.entity('ndash')],
|
329
|
+
hellip: [::Kramdown::Utils::Entities.entity('hellip')],
|
330
|
+
laquo_space: [::Kramdown::Utils::Entities.entity('laquo'),
|
331
|
+
::Kramdown::Utils::Entities.entity('nbsp')],
|
332
|
+
raquo_space: [::Kramdown::Utils::Entities.entity('nbsp'),
|
333
|
+
::Kramdown::Utils::Entities.entity('raquo')],
|
334
|
+
laquo: [::Kramdown::Utils::Entities.entity('laquo')],
|
335
|
+
raquo: [::Kramdown::Utils::Entities.entity('raquo')],
|
311
336
|
} # :nodoc:
|
312
|
-
def convert_typographic_sym(el,
|
313
|
-
|
337
|
+
def convert_typographic_sym(el, _indent)
|
338
|
+
if (result = @options[:typographic_symbols][el.value])
|
339
|
+
escape_html(result, :text)
|
340
|
+
else
|
341
|
+
TYPOGRAPHIC_SYMS[el.value].map {|e| entity_to_str(e) }.join('')
|
342
|
+
end
|
314
343
|
end
|
315
344
|
|
316
|
-
def convert_smart_quote(el,
|
345
|
+
def convert_smart_quote(el, _indent)
|
317
346
|
entity_to_str(smart_quote_entity(el))
|
318
347
|
end
|
319
348
|
|
320
349
|
def convert_math(el, indent)
|
321
|
-
|
322
|
-
|
323
|
-
type = {:type => "math/tex#{block ? '; mode=display' : ''}"}
|
324
|
-
if block
|
325
|
-
format_as_block_html('script', type, value, indent)
|
350
|
+
if (result = format_math(el, indent: indent))
|
351
|
+
result
|
326
352
|
else
|
327
|
-
|
353
|
+
attr = el.attr.dup
|
354
|
+
attr['class'] = "#{attr['class']} kdmath".lstrip
|
355
|
+
if el.options[:category] == :block
|
356
|
+
format_as_block_html('div', attr, "$$\n#{el.value}\n$$", indent)
|
357
|
+
else
|
358
|
+
format_as_span_html('span', attr, "$#{el.value}$")
|
359
|
+
end
|
328
360
|
end
|
329
361
|
end
|
330
362
|
|
331
|
-
def convert_abbreviation(el,
|
363
|
+
def convert_abbreviation(el, _indent)
|
332
364
|
title = @root.options[:abbrev_defs][el.value]
|
333
|
-
|
365
|
+
attr = @root.options[:abbrev_attr][el.value].dup
|
366
|
+
attr['title'] = title unless title.empty?
|
367
|
+
format_as_span_html("abbr", attr, el.value)
|
334
368
|
end
|
335
369
|
|
336
370
|
def convert_root(el, indent)
|
337
371
|
result = inner(el, indent)
|
338
|
-
|
372
|
+
if @footnote_location
|
373
|
+
result.sub!(/#{@footnote_location}/, footnote_content.gsub(/\\/, "\\\\\\\\"))
|
374
|
+
else
|
375
|
+
result << footnote_content
|
376
|
+
end
|
339
377
|
if @toc_code
|
340
378
|
toc_tree = generate_toc_tree(@toc, @toc_code[0], @toc_code[1] || {})
|
341
|
-
text = if toc_tree.children.
|
379
|
+
text = if !toc_tree.children.empty?
|
342
380
|
convert(toc_tree, 0)
|
343
381
|
else
|
344
382
|
''
|
345
383
|
end
|
346
|
-
result.sub!(/#{@toc_code.last}/, text)
|
384
|
+
result.sub!(/#{@toc_code.last}/, text.gsub(/\\/, "\\\\\\\\"))
|
347
385
|
end
|
348
386
|
result
|
349
387
|
end
|
@@ -355,30 +393,39 @@ module Kramdown
|
|
355
393
|
|
356
394
|
# Format the given element as block HTML.
|
357
395
|
def format_as_block_html(name, attr, body, indent)
|
358
|
-
"#{' '*indent}<#{name}#{html_attributes(attr)}>#{body}</#{name}>\n"
|
396
|
+
"#{' ' * indent}<#{name}#{html_attributes(attr)}>#{body}</#{name}>\n"
|
359
397
|
end
|
360
398
|
|
361
399
|
# Format the given element as block HTML with a newline after the start tag and indentation
|
362
400
|
# before the end tag.
|
363
401
|
def format_as_indented_block_html(name, attr, body, indent)
|
364
|
-
"#{' '*indent}<#{name}#{html_attributes(attr)}>\n#{body}#{' '*indent}</#{name}>\n"
|
402
|
+
"#{' ' * indent}<#{name}#{html_attributes(attr)}>\n#{body}#{' ' * indent}</#{name}>\n"
|
403
|
+
end
|
404
|
+
|
405
|
+
# Add the syntax highlighter name to the 'class' attribute of the given attribute hash. And
|
406
|
+
# overwrites or add a "language-LANG" part using the +lang+ parameter if +lang+ is not nil.
|
407
|
+
def add_syntax_highlighter_to_class_attr(attr, lang = nil)
|
408
|
+
(attr['class'] = (attr['class'] || '') + @highlighter_class).lstrip!
|
409
|
+
attr['class'].sub!(/\blanguage-\S+|(^)/) { "language-#{lang}#{$1 ? ' ' : ''}" } if lang
|
365
410
|
end
|
366
411
|
|
367
412
|
# Generate and return an element tree for the table of contents.
|
368
413
|
def generate_toc_tree(toc, type, attr)
|
369
|
-
sections = Element.new(type, nil, attr)
|
414
|
+
sections = Element.new(type, nil, attr.dup)
|
370
415
|
sections.attr['id'] ||= 'markdown-toc'
|
371
416
|
stack = []
|
372
417
|
toc.each do |level, id, children|
|
373
|
-
li = Element.new(:li, nil, nil,
|
374
|
-
li.children << Element.new(:p, nil, nil,
|
375
|
-
a = Element.new(:a, nil
|
376
|
-
a.
|
418
|
+
li = Element.new(:li, nil, nil, level: level)
|
419
|
+
li.children << Element.new(:p, nil, nil, transparent: true)
|
420
|
+
a = Element.new(:a, nil)
|
421
|
+
a.attr['href'] = "##{id}"
|
422
|
+
a.attr['id'] = "#{sections.attr['id']}-#{id}"
|
423
|
+
a.children.concat(fix_for_toc_entry(Marshal.load(Marshal.dump(children))))
|
377
424
|
li.children.last.children << a
|
378
425
|
li.children << Element.new(type)
|
379
426
|
|
380
427
|
success = false
|
381
|
-
|
428
|
+
until success
|
382
429
|
if stack.empty?
|
383
430
|
sections.children << li
|
384
431
|
stack << li
|
@@ -389,17 +436,32 @@ module Kramdown
|
|
389
436
|
success = true
|
390
437
|
else
|
391
438
|
item = stack.pop
|
392
|
-
item.children.pop
|
439
|
+
item.children.pop if item.children.last.children.empty?
|
393
440
|
end
|
394
441
|
end
|
395
442
|
end
|
396
|
-
|
443
|
+
until stack.empty?
|
397
444
|
item = stack.pop
|
398
|
-
item.children.pop
|
445
|
+
item.children.pop if item.children.last.children.empty?
|
399
446
|
end
|
400
447
|
sections
|
401
448
|
end
|
402
449
|
|
450
|
+
# Fixes the elements for use in a TOC entry.
|
451
|
+
def fix_for_toc_entry(elements)
|
452
|
+
remove_footnotes(elements)
|
453
|
+
unwrap_links(elements)
|
454
|
+
elements
|
455
|
+
end
|
456
|
+
|
457
|
+
# Remove all link elements by unwrapping them.
|
458
|
+
def unwrap_links(elements)
|
459
|
+
elements.map! do |c|
|
460
|
+
unwrap_links(c.children)
|
461
|
+
c.type == :a ? c.children : c
|
462
|
+
end.flatten!
|
463
|
+
end
|
464
|
+
|
403
465
|
# Remove all footnotes from the given elements.
|
404
466
|
def remove_footnotes(elements)
|
405
467
|
elements.delete_if do |c|
|
@@ -410,32 +472,61 @@ module Kramdown
|
|
410
472
|
|
411
473
|
# Obfuscate the +text+ by using HTML entities.
|
412
474
|
def obfuscate(text)
|
413
|
-
result =
|
475
|
+
result = +''
|
414
476
|
text.each_byte do |b|
|
415
|
-
result << (b > 128 ? b.chr : "&#%03d;"
|
477
|
+
result << (b > 128 ? b.chr : sprintf("&#%03d;", b))
|
416
478
|
end
|
417
|
-
result.force_encoding(text.encoding)
|
479
|
+
result.force_encoding(text.encoding)
|
418
480
|
result
|
419
481
|
end
|
420
482
|
|
421
|
-
|
483
|
+
FOOTNOTE_BACKLINK_FMT = "%s<a href=\"#fnref:%s\" class=\"reversefootnote\" role=\"doc-backlink\">%s</a>"
|
484
|
+
|
485
|
+
# Return an HTML ordered list with the footnote content for the used footnotes.
|
422
486
|
def footnote_content
|
423
487
|
ol = Element.new(:ol)
|
424
488
|
ol.attr['start'] = @footnote_start if @footnote_start != 1
|
425
|
-
|
426
|
-
|
489
|
+
i = 0
|
490
|
+
backlink_text = escape_html(@options[:footnote_backlink], :text)
|
491
|
+
while i < @footnotes.length
|
492
|
+
name, data, _, repeat = *@footnotes[i]
|
493
|
+
li = Element.new(:li, nil, 'id' => "fn:#{name}", 'role' => 'doc-endnote')
|
427
494
|
li.children = Marshal.load(Marshal.dump(data.children))
|
428
|
-
ol.children << li
|
429
495
|
|
430
|
-
|
431
|
-
if li.children.last.type == :p
|
432
|
-
|
433
|
-
|
496
|
+
para = nil
|
497
|
+
if li.children.last.type == :p || @options[:footnote_backlink_inline]
|
498
|
+
parent = li
|
499
|
+
while !parent.children.empty? && ![:p, :header].include?(parent.children.last.type)
|
500
|
+
parent = parent.children.last
|
501
|
+
end
|
502
|
+
para = parent.children.last
|
503
|
+
insert_space = true
|
504
|
+
end
|
505
|
+
|
506
|
+
unless para
|
434
507
|
li.children << (para = Element.new(:p))
|
508
|
+
insert_space = false
|
435
509
|
end
|
436
|
-
|
510
|
+
|
511
|
+
unless @options[:footnote_backlink].empty?
|
512
|
+
nbsp = entity_to_str(ENTITY_NBSP)
|
513
|
+
value = sprintf(FOOTNOTE_BACKLINK_FMT, (insert_space ? nbsp : ''), name, backlink_text)
|
514
|
+
para.children << Element.new(:raw, value)
|
515
|
+
(1..repeat).each do |index|
|
516
|
+
value = sprintf(FOOTNOTE_BACKLINK_FMT, nbsp, "#{name}:#{index}",
|
517
|
+
"#{backlink_text}<sup>#{index + 1}</sup>")
|
518
|
+
para.children << Element.new(:raw, value)
|
519
|
+
end
|
520
|
+
end
|
521
|
+
|
522
|
+
ol.children << Element.new(:raw, convert(li, 4))
|
523
|
+
i += 1
|
524
|
+
end
|
525
|
+
if ol.children.empty?
|
526
|
+
''
|
527
|
+
else
|
528
|
+
format_as_indented_block_html('div', {class: "footnotes", role: "doc-endnotes"}, convert(ol, 2), 0)
|
437
529
|
end
|
438
|
-
(ol.children.empty? ? '' : format_as_indented_block_html('div', {:class => "footnotes"}, convert(ol, 2), 0))
|
439
530
|
end
|
440
531
|
|
441
532
|
end
|