aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib.rs
diff options
context:
space:
mode:
authorLibravatar Titus Wormer <tituswormer@gmail.com>2022-08-25 13:16:45 +0200
committerLibravatar Titus Wormer <tituswormer@gmail.com>2022-08-25 13:16:45 +0200
commit1e4c95079cb97b2b02440b21945c6d12741a7d19 (patch)
tree4f6a4a179e72630c1cdd058f84498e32b9a433e0 /src/lib.rs
parent49b6a4e72516e8b2a8768e761a60a4f461802d69 (diff)
downloadmarkdown-rs-1e4c95079cb97b2b02440b21945c6d12741a7d19.tar.gz
markdown-rs-1e4c95079cb97b2b02440b21945c6d12741a7d19.tar.bz2
markdown-rs-1e4c95079cb97b2b02440b21945c6d12741a7d19.zip
Add support for GFM footnotes
Diffstat (limited to 'src/lib.rs')
-rw-r--r--src/lib.rs254
1 files changed, 238 insertions, 16 deletions
diff --git a/src/lib.rs b/src/lib.rs
index 5b7836c..fd5e500 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -171,7 +171,20 @@ pub struct Constructs {
/// ^^^^^^^^^^^^^^^^^^^
/// ```
pub gfm_autolink_literal: bool,
- /// GFM: strikethrough.
+ /// GFM: footnote definition.
+ ///
+ /// ```markdown
+ /// > | [^a]: b
+ /// ^^^^^^^
+ /// ```
+ pub gfm_footnote_definition: bool,
+ /// GFM: footnote label start.
+ ///
+ /// ```markdown
+ /// > | a[^b]
+ /// ^^
+ /// ```
+ pub gfm_label_start_footnote: bool,
///
/// ```markdown
/// > | a ~b~ c.
@@ -283,6 +296,8 @@ impl Default for Constructs {
definition: true,
frontmatter: false,
gfm_autolink_literal: false,
+ gfm_label_start_footnote: false,
+ gfm_footnote_definition: false,
gfm_strikethrough: false,
gfm_task_list_item: false,
hard_break_escape: true,
@@ -308,6 +323,8 @@ impl Constructs {
pub fn gfm() -> Self {
Self {
gfm_autolink_literal: true,
+ gfm_footnote_definition: true,
+ gfm_label_start_footnote: true,
gfm_strikethrough: true,
gfm_task_list_item: true,
..Self::default()
@@ -376,6 +393,206 @@ pub struct Options {
/// ```
pub allow_dangerous_protocol: bool,
+ /// Label to use for the footnotes section.
+ ///
+ /// Change it when the markdown is not in English.
+ /// Typically affects screen readers (change `gfm_footnote_label_attributes`
+ /// to make it visible).
+ ///
+ /// ## Examples
+ ///
+ /// ```
+ /// use micromark::{micromark, micromark_with_options, Options, Constructs};
+ ///
+ /// // `"Footnotes"` is used by default:
+ /// assert_eq!(
+ /// micromark_with_options(
+ /// "[^a]\n\n[^a]: b",
+ /// &Options {
+ /// constructs: Constructs::gfm(),
+ /// ..Options::default()
+ /// }
+ /// ),
+ /// "<p><sup><a href=\"#user-content-fn-a\" id=\"user-content-fnref-a\" data-footnote-ref=\"\" aria-describedby=\"footnote-label\">1</a></sup></p>\n<section data-footnotes=\"\" class=\"footnotes\"><h2 id=\"footnote-label\" class=\"sr-only\">Footnotes</h2>\n<ol>\n<li id=\"user-content-fn-a\">\n<p>b <a href=\"#user-content-fnref-a\" data-footnote-backref=\"\" class=\"data-footnote-backref\" aria-label=\"Back to content\">↩</a></p>\n</li>\n</ol>\n</section>\n"
+ /// );
+ ///
+ /// // Pass `gfm_footnote_label` to use something else:
+ /// assert_eq!(
+ /// micromark_with_options(
+ /// "[^a]\n\n[^a]: b",
+ /// &Options {
+ /// constructs: Constructs::gfm(),
+ /// gfm_footnote_label: Some("Notes de bas de page".to_string()),
+ /// ..Options::default()
+ /// }
+ /// ),
+ /// "<p><sup><a href=\"#user-content-fn-a\" id=\"user-content-fnref-a\" data-footnote-ref=\"\" aria-describedby=\"footnote-label\">1</a></sup></p>\n<section data-footnotes=\"\" class=\"footnotes\"><h2 id=\"footnote-label\" class=\"sr-only\">Notes de bas de page</h2>\n<ol>\n<li id=\"user-content-fn-a\">\n<p>b <a href=\"#user-content-fnref-a\" data-footnote-backref=\"\" class=\"data-footnote-backref\" aria-label=\"Back to content\">↩</a></p>\n</li>\n</ol>\n</section>\n"
+ /// );
+ /// ```
+ pub gfm_footnote_label: Option<String>,
+
+ /// HTML tag to use for the footnote label.
+ ///
+ /// Change it to match your document structure and play well with your CSS.
+ ///
+ /// ## Examples
+ ///
+ /// ```
+ /// use micromark::{micromark, micromark_with_options, Options, Constructs};
+ ///
+ /// // `"h2"` is used by default:
+ /// assert_eq!(
+ /// micromark_with_options(
+ /// "[^a]\n\n[^a]: b",
+ /// &Options {
+ /// constructs: Constructs::gfm(),
+ /// ..Options::default()
+ /// }
+ /// ),
+ /// "<p><sup><a href=\"#user-content-fn-a\" id=\"user-content-fnref-a\" data-footnote-ref=\"\" aria-describedby=\"footnote-label\">1</a></sup></p>\n<section data-footnotes=\"\" class=\"footnotes\"><h2 id=\"footnote-label\" class=\"sr-only\">Footnotes</h2>\n<ol>\n<li id=\"user-content-fn-a\">\n<p>b <a href=\"#user-content-fnref-a\" data-footnote-backref=\"\" class=\"data-footnote-backref\" aria-label=\"Back to content\">↩</a></p>\n</li>\n</ol>\n</section>\n"
+ /// );
+ ///
+ /// // Pass `gfm_footnote_label_tag_name` to use something else:
+ /// assert_eq!(
+ /// micromark_with_options(
+ /// "[^a]\n\n[^a]: b",
+ /// &Options {
+ /// constructs: Constructs::gfm(),
+ /// gfm_footnote_label_tag_name: Some("h1".to_string()),
+ /// ..Options::default()
+ /// }
+ /// ),
+ /// "<p><sup><a href=\"#user-content-fn-a\" id=\"user-content-fnref-a\" data-footnote-ref=\"\" aria-describedby=\"footnote-label\">1</a></sup></p>\n<section data-footnotes=\"\" class=\"footnotes\"><h1 id=\"footnote-label\" class=\"sr-only\">Footnotes</h1>\n<ol>\n<li id=\"user-content-fn-a\">\n<p>b <a href=\"#user-content-fnref-a\" data-footnote-backref=\"\" class=\"data-footnote-backref\" aria-label=\"Back to content\">↩</a></p>\n</li>\n</ol>\n</section>\n"
+ /// );
+ /// ```
+ pub gfm_footnote_label_tag_name: Option<String>,
+
+ /// Attributes to use on the footnote label.
+ ///
+ /// > 👉 **Note**: `id="footnote-label"` is always added, because footnote
+ /// > calls use it with `aria-describedby` to provide an accessible label.
+ ///
+ /// A `class="sr-only"` is added by default to hide the label from sighted
+ /// users.
+ /// Change it to make the label visible, or add other classes or other
+ /// attributes.
+ ///
+ /// ## Examples
+ ///
+ /// ```
+ /// use micromark::{micromark, micromark_with_options, Options, Constructs};
+ ///
+ /// // `"class=\"sr-only\""` is used by default:
+ /// assert_eq!(
+ /// micromark_with_options(
+ /// "[^a]\n\n[^a]: b",
+ /// &Options {
+ /// constructs: Constructs::gfm(),
+ /// ..Options::default()
+ /// }
+ /// ),
+ /// "<p><sup><a href=\"#user-content-fn-a\" id=\"user-content-fnref-a\" data-footnote-ref=\"\" aria-describedby=\"footnote-label\">1</a></sup></p>\n<section data-footnotes=\"\" class=\"footnotes\"><h2 id=\"footnote-label\" class=\"sr-only\">Footnotes</h2>\n<ol>\n<li id=\"user-content-fn-a\">\n<p>b <a href=\"#user-content-fnref-a\" data-footnote-backref=\"\" class=\"data-footnote-backref\" aria-label=\"Back to content\">↩</a></p>\n</li>\n</ol>\n</section>\n"
+ /// );
+ ///
+ /// // Pass `gfm_footnote_label_attributes` to use something else:
+ /// assert_eq!(
+ /// micromark_with_options(
+ /// "[^a]\n\n[^a]: b",
+ /// &Options {
+ /// constructs: Constructs::gfm(),
+ /// gfm_footnote_label_attributes: Some("class=\"footnote-heading\"".to_string()),
+ /// ..Options::default()
+ /// }
+ /// ),
+ /// "<p><sup><a href=\"#user-content-fn-a\" id=\"user-content-fnref-a\" data-footnote-ref=\"\" aria-describedby=\"footnote-label\">1</a></sup></p>\n<section data-footnotes=\"\" class=\"footnotes\"><h2 id=\"footnote-label\" class=\"footnote-heading\">Footnotes</h2>\n<ol>\n<li id=\"user-content-fn-a\">\n<p>b <a href=\"#user-content-fnref-a\" data-footnote-backref=\"\" class=\"data-footnote-backref\" aria-label=\"Back to content\">↩</a></p>\n</li>\n</ol>\n</section>\n"
+ /// );
+ /// ```
+ pub gfm_footnote_label_attributes: Option<String>,
+
+ /// Label to use from backreferences back to their footnote call.
+ ///
+ /// Change it when the markdown is not in English.
+ /// Affects screen readers.
+ ///
+ /// ## Examples
+ ///
+ /// ```
+ /// use micromark::{micromark, micromark_with_options, Options, Constructs};
+ ///
+ /// // `"Back to content"` is used by default:
+ /// assert_eq!(
+ /// micromark_with_options(
+ /// "[^a]\n\n[^a]: b",
+ /// &Options {
+ /// constructs: Constructs::gfm(),
+ /// ..Options::default()
+ /// }
+ /// ),
+ /// "<p><sup><a href=\"#user-content-fn-a\" id=\"user-content-fnref-a\" data-footnote-ref=\"\" aria-describedby=\"footnote-label\">1</a></sup></p>\n<section data-footnotes=\"\" class=\"footnotes\"><h2 id=\"footnote-label\" class=\"sr-only\">Footnotes</h2>\n<ol>\n<li id=\"user-content-fn-a\">\n<p>b <a href=\"#user-content-fnref-a\" data-footnote-backref=\"\" class=\"data-footnote-backref\" aria-label=\"Back to content\">↩</a></p>\n</li>\n</ol>\n</section>\n"
+ /// );
+ ///
+ /// // Pass `gfm_footnote_back_label` to use something else:
+ /// assert_eq!(
+ /// micromark_with_options(
+ /// "[^a]\n\n[^a]: b",
+ /// &Options {
+ /// constructs: Constructs::gfm(),
+ /// gfm_footnote_back_label: Some("Arrière".to_string()),
+ /// ..Options::default()
+ /// }
+ /// ),
+ /// "<p><sup><a href=\"#user-content-fn-a\" id=\"user-content-fnref-a\" data-footnote-ref=\"\" aria-describedby=\"footnote-label\">1</a></sup></p>\n<section data-footnotes=\"\" class=\"footnotes\"><h2 id=\"footnote-label\" class=\"sr-only\">Footnotes</h2>\n<ol>\n<li id=\"user-content-fn-a\">\n<p>b <a href=\"#user-content-fnref-a\" data-footnote-backref=\"\" class=\"data-footnote-backref\" aria-label=\"Arrière\">↩</a></p>\n</li>\n</ol>\n</section>\n"
+ /// );
+ /// ```
+ pub gfm_footnote_back_label: Option<String>,
+
+ /// Prefix to use before the `id` attribute on footnotes to prevent them
+ /// from *clobbering*.
+ ///
+ /// DOM clobbering is this:
+ ///
+ /// ```html
+ /// <p id=x></p>
+ /// <script>alert(x) // `x` now refers to the DOM `p#x` element</script>
+ /// ```
+ ///
+ /// The above example shows that elements are made available by browsers,
+ /// by their ID, on the `window` object, which is a security risk because
+ /// you might be expecting some other variable at that place.
+ /// Using a prefix solves this problem.
+ ///
+ /// ## Examples
+ ///
+ /// ```
+ /// use micromark::{micromark, micromark_with_options, Options, Constructs};
+ ///
+ /// // `"user-content-"` is used by default:
+ /// assert_eq!(
+ /// micromark_with_options(
+ /// "[^a]\n\n[^a]: b",
+ /// &Options {
+ /// constructs: Constructs::gfm(),
+ /// ..Options::default()
+ /// }
+ /// ),
+ /// "<p><sup><a href=\"#user-content-fn-a\" id=\"user-content-fnref-a\" data-footnote-ref=\"\" aria-describedby=\"footnote-label\">1</a></sup></p>\n<section data-footnotes=\"\" class=\"footnotes\"><h2 id=\"footnote-label\" class=\"sr-only\">Footnotes</h2>\n<ol>\n<li id=\"user-content-fn-a\">\n<p>b <a href=\"#user-content-fnref-a\" data-footnote-backref=\"\" class=\"data-footnote-backref\" aria-label=\"Back to content\">↩</a></p>\n</li>\n</ol>\n</section>\n"
+ /// );
+ ///
+ /// // Pass `gfm_footnote_clobber_prefix` to use something else:
+ /// assert_eq!(
+ /// micromark_with_options(
+ /// "[^a]\n\n[^a]: b",
+ /// &Options {
+ /// constructs: Constructs::gfm(),
+ /// gfm_footnote_clobber_prefix: Some("".to_string()),
+ /// ..Options::default()
+ /// }
+ /// ),
+ /// "<p><sup><a href=\"#fn-a\" id=\"fnref-a\" data-footnote-ref=\"\" aria-describedby=\"footnote-label\">1</a></sup></p>\n<section data-footnotes=\"\" class=\"footnotes\"><h2 id=\"footnote-label\" class=\"sr-only\">Footnotes</h2>\n<ol>\n<li id=\"fn-a\">\n<p>b <a href=\"#fnref-a\" data-footnote-backref=\"\" class=\"data-footnote-backref\" aria-label=\"Back to content\">↩</a></p>\n</li>\n</ol>\n</section>\n"
+ /// );
+ /// ```
+ pub gfm_footnote_clobber_prefix: Option<String>,
+
/// Whether to support GFM strikethrough (if enabled in `constructs`) with
/// a single tilde (default: true).
///
@@ -389,26 +606,26 @@ pub struct Options {
/// // micromark supports single tildes by default:
/// assert_eq!(
/// micromark_with_options(
- /// "~a~",
- /// &Options {
- /// constructs: Constructs::gfm(),
- /// ..Options::default()
- /// }
- /// ),
- /// "<p><del>a</del></p>"
+ /// "~a~",
+ /// &Options {
+ /// constructs: Constructs::gfm(),
+ /// ..Options::default()
+ /// }
+ /// ),
+ /// "<p><del>a</del></p>"
/// );
///
/// // Pass `gfm_strikethrough_single_tilde: false` to turn that off:
/// assert_eq!(
/// micromark_with_options(
- /// "~a~",
- /// &Options {
- /// constructs: Constructs::gfm(),
- /// gfm_strikethrough_single_tilde: false,
- /// ..Options::default()
- /// }
- /// ),
- /// "<p>~a~</p>"
+ /// "~a~",
+ /// &Options {
+ /// constructs: Constructs::gfm(),
+ /// gfm_strikethrough_single_tilde: false,
+ /// ..Options::default()
+ /// }
+ /// ),
+ /// "<p>~a~</p>"
/// );
/// ```
pub gfm_strikethrough_single_tilde: bool,
@@ -488,6 +705,11 @@ impl Default for Options {
Self {
allow_dangerous_html: false,
allow_dangerous_protocol: false,
+ gfm_footnote_label: None,
+ gfm_footnote_label_tag_name: None,
+ gfm_footnote_label_attributes: None,
+ gfm_footnote_back_label: None,
+ gfm_footnote_clobber_prefix: None,
gfm_strikethrough_single_tilde: true,
default_line_ending: LineEnding::default(),
constructs: Constructs::default(),