From 1e4c95079cb97b2b02440b21945c6d12741a7d19 Mon Sep 17 00:00:00 2001 From: Titus Wormer Date: Thu, 25 Aug 2022 13:16:45 +0200 Subject: Add support for GFM footnotes --- src/lib.rs | 254 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 238 insertions(+), 16 deletions(-) (limited to 'src/lib.rs') 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() + /// } + /// ), + /// "

1

\n

Footnotes

\n
    \n
  1. \n

    b

    \n
  2. \n
\n
\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() + /// } + /// ), + /// "

1

\n

Notes de bas de page

\n
    \n
  1. \n

    b

    \n
  2. \n
\n
\n" + /// ); + /// ``` + pub gfm_footnote_label: Option, + + /// 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() + /// } + /// ), + /// "

1

\n

Footnotes

\n
    \n
  1. \n

    b

    \n
  2. \n
\n
\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() + /// } + /// ), + /// "

1

\n

Footnotes

\n
    \n
  1. \n

    b

    \n
  2. \n
\n
\n" + /// ); + /// ``` + pub gfm_footnote_label_tag_name: Option, + + /// 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() + /// } + /// ), + /// "

1

\n

Footnotes

\n
    \n
  1. \n

    b

    \n
  2. \n
\n
\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() + /// } + /// ), + /// "

1

\n

Footnotes

\n
    \n
  1. \n

    b

    \n
  2. \n
\n
\n" + /// ); + /// ``` + pub gfm_footnote_label_attributes: Option, + + /// 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() + /// } + /// ), + /// "

1

\n

Footnotes

\n
    \n
  1. \n

    b

    \n
  2. \n
\n
\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() + /// } + /// ), + /// "

1

\n

Footnotes

\n
    \n
  1. \n

    b

    \n
  2. \n
\n
\n" + /// ); + /// ``` + pub gfm_footnote_back_label: Option, + + /// Prefix to use before the `id` attribute on footnotes to prevent them + /// from *clobbering*. + /// + /// DOM clobbering is this: + /// + /// ```html + ///

+ /// + /// ``` + /// + /// 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() + /// } + /// ), + /// "

1

\n

Footnotes

\n
    \n
  1. \n

    b

    \n
  2. \n
\n
\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() + /// } + /// ), + /// "

1

\n

Footnotes

\n
    \n
  1. \n

    b

    \n
  2. \n
\n
\n" + /// ); + /// ``` + pub gfm_footnote_clobber_prefix: Option, + /// 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() - /// } - /// ), - /// "

a

" + /// "~a~", + /// &Options { + /// constructs: Constructs::gfm(), + /// ..Options::default() + /// } + /// ), + /// "

a

" /// ); /// /// // 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() - /// } - /// ), - /// "

~a~

" + /// "~a~", + /// &Options { + /// constructs: Constructs::gfm(), + /// gfm_strikethrough_single_tilde: false, + /// ..Options::default() + /// } + /// ), + /// "

~a~

" /// ); /// ``` 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(), -- cgit