diff options
author | Titus Wormer <tituswormer@gmail.com> | 2022-07-18 16:31:14 +0200 |
---|---|---|
committer | Titus Wormer <tituswormer@gmail.com> | 2022-07-18 16:31:14 +0200 |
commit | 5403261e8213f68633a09fc3e9bc2e6e2cd777b2 (patch) | |
tree | bb3a6419ef42f7611c2cb24fe7024228f579331b /src | |
parent | 03544cafaa82ba4bd7e0bc3372fc59549a8dc0cc (diff) | |
download | markdown-rs-5403261e8213f68633a09fc3e9bc2e6e2cd777b2.tar.gz markdown-rs-5403261e8213f68633a09fc3e9bc2e6e2cd777b2.tar.bz2 markdown-rs-5403261e8213f68633a09fc3e9bc2e6e2cd777b2.zip |
Add support for turning off constructs
Diffstat (limited to 'src')
-rw-r--r-- | src/construct/attention.rs | 2 | ||||
-rw-r--r-- | src/construct/autolink.rs | 2 | ||||
-rw-r--r-- | src/construct/block_quote.rs | 20 | ||||
-rw-r--r-- | src/construct/character_escape.rs | 2 | ||||
-rw-r--r-- | src/construct/character_reference.rs | 2 | ||||
-rw-r--r-- | src/construct/code_fenced.rs | 34 | ||||
-rw-r--r-- | src/construct/code_indented.rs | 2 | ||||
-rw-r--r-- | src/construct/code_text.rs | 6 | ||||
-rw-r--r-- | src/construct/definition.rs | 6 | ||||
-rw-r--r-- | src/construct/hard_break_escape.rs | 2 | ||||
-rw-r--r-- | src/construct/hard_break_trailing.rs | 2 | ||||
-rw-r--r-- | src/construct/heading_atx.rs | 15 | ||||
-rw-r--r-- | src/construct/heading_setext.rs | 10 | ||||
-rw-r--r-- | src/construct/html_flow.rs | 33 | ||||
-rw-r--r-- | src/construct/html_text.rs | 2 | ||||
-rw-r--r-- | src/construct/label_end.rs | 2 | ||||
-rw-r--r-- | src/construct/label_start_image.rs | 2 | ||||
-rw-r--r-- | src/construct/label_start_link.rs | 2 | ||||
-rw-r--r-- | src/construct/list.rs | 15 | ||||
-rw-r--r-- | src/construct/thematic_break.rs | 15 | ||||
-rw-r--r-- | src/content/string.rs | 1 | ||||
-rw-r--r-- | src/content/text.rs | 1 | ||||
-rw-r--r-- | src/lib.rs | 232 | ||||
-rw-r--r-- | src/parser.rs | 5 |
24 files changed, 353 insertions, 62 deletions
diff --git a/src/construct/attention.rs b/src/construct/attention.rs index 86c9249..3e15f9a 100644 --- a/src/construct/attention.rs +++ b/src/construct/attention.rs @@ -175,7 +175,7 @@ struct Sequence { /// ``` pub fn start(tokenizer: &mut Tokenizer, code: Code) -> StateFnResult { match code { - Code::Char('*' | '_') => { + Code::Char('*' | '_') if tokenizer.parse_state.constructs.attention => { tokenizer.enter(Token::AttentionSequence); inside(tokenizer, code, MarkerKind::from_code(code)) } diff --git a/src/construct/autolink.rs b/src/construct/autolink.rs index fe8f380..0ef4607 100644 --- a/src/construct/autolink.rs +++ b/src/construct/autolink.rs @@ -115,7 +115,7 @@ use crate::tokenizer::{Code, State, StateFnResult, Tokenizer}; /// ``` pub fn start(tokenizer: &mut Tokenizer, code: Code) -> StateFnResult { match code { - Code::Char('<') => { + Code::Char('<') if tokenizer.parse_state.constructs.autolink => { tokenizer.enter(Token::Autolink); tokenizer.enter(Token::AutolinkMarker); tokenizer.consume(code); diff --git a/src/construct/block_quote.rs b/src/construct/block_quote.rs index 6c3f270..a8a8fa8 100644 --- a/src/construct/block_quote.rs +++ b/src/construct/block_quote.rs @@ -45,8 +45,16 @@ use crate::tokenizer::{Code, State, StateFnResult, Tokenizer}; /// ^ /// ``` pub fn start(tokenizer: &mut Tokenizer, code: Code) -> StateFnResult { - // To do: allow arbitrary when code (indented) is turned off. - tokenizer.go(space_or_tab_min_max(0, TAB_SIZE - 1), before)(tokenizer, code) + let max = if tokenizer.parse_state.constructs.code_indented { + TAB_SIZE - 1 + } else { + usize::MAX + }; + if tokenizer.parse_state.constructs.block_quote { + tokenizer.go(space_or_tab_min_max(0, max), before)(tokenizer, code) + } else { + (State::Nok, None) + } } /// Start of block quote, after whitespace, before `>`. @@ -73,8 +81,12 @@ fn before(tokenizer: &mut Tokenizer, code: Code) -> StateFnResult { /// ^ /// ``` pub fn cont(tokenizer: &mut Tokenizer, code: Code) -> StateFnResult { - // To do: allow arbitrary when code (indented) is turned off. - tokenizer.go(space_or_tab_min_max(0, TAB_SIZE - 1), cont_before)(tokenizer, code) + let max = if tokenizer.parse_state.constructs.code_indented { + TAB_SIZE - 1 + } else { + usize::MAX + }; + tokenizer.go(space_or_tab_min_max(0, max), cont_before)(tokenizer, code) } /// After whitespace, before `>`. diff --git a/src/construct/character_escape.rs b/src/construct/character_escape.rs index 811adcf..f171d38 100644 --- a/src/construct/character_escape.rs +++ b/src/construct/character_escape.rs @@ -44,7 +44,7 @@ use crate::tokenizer::{Code, State, StateFnResult, Tokenizer}; /// ``` pub fn start(tokenizer: &mut Tokenizer, code: Code) -> StateFnResult { match code { - Code::Char('\\') => { + Code::Char('\\') if tokenizer.parse_state.constructs.character_escape => { tokenizer.enter(Token::CharacterEscape); tokenizer.enter(Token::CharacterEscapeMarker); tokenizer.consume(code); diff --git a/src/construct/character_reference.rs b/src/construct/character_reference.rs index 544458a..ce7cd31 100644 --- a/src/construct/character_reference.rs +++ b/src/construct/character_reference.rs @@ -138,7 +138,7 @@ struct Info { /// ``` pub fn start(tokenizer: &mut Tokenizer, code: Code) -> StateFnResult { match code { - Code::Char('&') => { + Code::Char('&') if tokenizer.parse_state.constructs.character_reference => { tokenizer.enter(Token::CharacterReference); tokenizer.enter(Token::CharacterReferenceMarker); tokenizer.consume(code); diff --git a/src/construct/code_fenced.rs b/src/construct/code_fenced.rs index d5001e7..49bcae3 100644 --- a/src/construct/code_fenced.rs +++ b/src/construct/code_fenced.rs @@ -189,10 +189,18 @@ struct Info { /// | ~~~ /// ``` pub fn start(tokenizer: &mut Tokenizer, code: Code) -> StateFnResult { - tokenizer.enter(Token::CodeFenced); - tokenizer.enter(Token::CodeFencedFence); - // To do: allow arbitrary when code (indented) is turned off. - tokenizer.go(space_or_tab_min_max(0, TAB_SIZE - 1), before_sequence_open)(tokenizer, code) + let max = if tokenizer.parse_state.constructs.code_indented { + TAB_SIZE - 1 + } else { + usize::MAX + }; + if tokenizer.parse_state.constructs.code_fenced { + tokenizer.enter(Token::CodeFenced); + tokenizer.enter(Token::CodeFencedFence); + tokenizer.go(space_or_tab_min_max(0, max), before_sequence_open)(tokenizer, code) + } else { + (State::Nok, None) + } } /// Inside the opening fence, after an optional prefix, before a sequence. @@ -445,10 +453,20 @@ fn close_begin(tokenizer: &mut Tokenizer, code: Code, info: Info) -> StateFnResu /// ^ /// ``` fn close_start(tokenizer: &mut Tokenizer, code: Code, info: Info) -> StateFnResult { - tokenizer.enter(Token::CodeFencedFence); - tokenizer.go(space_or_tab_min_max(0, TAB_SIZE - 1), |t, c| { - close_before(t, c, info) - })(tokenizer, code) + let max = if tokenizer.parse_state.constructs.code_indented { + TAB_SIZE - 1 + } else { + usize::MAX + }; + + if tokenizer.parse_state.constructs.code_fenced { + tokenizer.enter(Token::CodeFencedFence); + tokenizer.go(space_or_tab_min_max(0, max), |t, c| { + close_before(t, c, info) + })(tokenizer, code) + } else { + (State::Nok, None) + } } /// In a closing fence, after optional whitespace, before sequence. diff --git a/src/construct/code_indented.rs b/src/construct/code_indented.rs index 6778b62..eb0811b 100644 --- a/src/construct/code_indented.rs +++ b/src/construct/code_indented.rs @@ -62,7 +62,7 @@ use crate::tokenizer::{Code, State, StateFnResult, Tokenizer}; /// ``` pub fn start(tokenizer: &mut Tokenizer, code: Code) -> StateFnResult { // Do not interrupt paragraphs. - if tokenizer.interrupt { + if tokenizer.interrupt || !tokenizer.parse_state.constructs.code_indented { (State::Nok, None) } else { tokenizer.enter(Token::CodeIndented); diff --git a/src/construct/code_text.rs b/src/construct/code_text.rs index 5e40d03..eb143ba 100644 --- a/src/construct/code_text.rs +++ b/src/construct/code_text.rs @@ -99,8 +99,10 @@ pub fn start(tokenizer: &mut Tokenizer, code: Code) -> StateFnResult { match code { Code::Char('`') - if tokenizer.previous != Code::Char('`') - || (len > 0 && tokenizer.events[len - 1].token_type == Token::CharacterEscape) => + if tokenizer.parse_state.constructs.code_text + && (tokenizer.previous != Code::Char('`') + || (len > 0 + && tokenizer.events[len - 1].token_type == Token::CharacterEscape)) => { tokenizer.enter(Token::CodeText); tokenizer.enter(Token::CodeTextSequence); diff --git a/src/construct/definition.rs b/src/construct/definition.rs index 6ce3a04..231011f 100644 --- a/src/construct/definition.rs +++ b/src/construct/definition.rs @@ -120,12 +120,12 @@ pub fn start(tokenizer: &mut Tokenizer, code: Code) -> StateFnResult { == Token::Definition; // Do not interrupt paragraphs (but do follow definitions). - if tokenizer.interrupt && !definition_before { - (State::Nok, None) - } else { + if (!tokenizer.interrupt || definition_before) && tokenizer.parse_state.constructs.definition { tokenizer.enter(Token::Definition); // Note: arbitrary whitespace allowed even if code (indented) is on. tokenizer.attempt_opt(space_or_tab(), before)(tokenizer, code) + } else { + (State::Nok, None) } } diff --git a/src/construct/hard_break_escape.rs b/src/construct/hard_break_escape.rs index de8afe6..191ef67 100644 --- a/src/construct/hard_break_escape.rs +++ b/src/construct/hard_break_escape.rs @@ -52,7 +52,7 @@ use crate::tokenizer::{Code, State, StateFnResult, Tokenizer}; /// ``` pub fn start(tokenizer: &mut Tokenizer, code: Code) -> StateFnResult { match code { - Code::Char('\\') => { + Code::Char('\\') if tokenizer.parse_state.constructs.hard_break_escape => { tokenizer.enter(Token::HardBreakEscape); tokenizer.enter(Token::HardBreakEscapeMarker); tokenizer.consume(code); diff --git a/src/construct/hard_break_trailing.rs b/src/construct/hard_break_trailing.rs index d83bf60..88c668a 100644 --- a/src/construct/hard_break_trailing.rs +++ b/src/construct/hard_break_trailing.rs @@ -53,7 +53,7 @@ use crate::tokenizer::{Code, State, StateFnResult, Tokenizer}; /// ``` pub fn start(tokenizer: &mut Tokenizer, code: Code) -> StateFnResult { match code { - Code::Char(' ') => { + Code::Char(' ') if tokenizer.parse_state.constructs.hard_break_trailing => { tokenizer.enter(Token::HardBreakTrailing); tokenizer.enter(Token::HardBreakTrailingSpace); tokenizer.consume(code); diff --git a/src/construct/heading_atx.rs b/src/construct/heading_atx.rs index 8947f64..68a6be7 100644 --- a/src/construct/heading_atx.rs +++ b/src/construct/heading_atx.rs @@ -67,9 +67,18 @@ use crate::util::edit_map::EditMap; /// ^ /// ``` pub fn start(tokenizer: &mut Tokenizer, code: Code) -> StateFnResult { - tokenizer.enter(Token::HeadingAtx); - // To do: allow arbitrary when code (indented) is turned off. - tokenizer.go(space_or_tab_min_max(0, TAB_SIZE - 1), before)(tokenizer, code) + let max = if tokenizer.parse_state.constructs.code_indented { + TAB_SIZE - 1 + } else { + usize::MAX + }; + + if tokenizer.parse_state.constructs.heading_atx { + tokenizer.enter(Token::HeadingAtx); + tokenizer.go(space_or_tab_min_max(0, max), before)(tokenizer, code) + } else { + (State::Nok, None) + } } /// Start of a heading (atx), after whitespace. diff --git a/src/construct/heading_setext.rs b/src/construct/heading_setext.rs index deab558..7cd259b 100644 --- a/src/construct/heading_setext.rs +++ b/src/construct/heading_setext.rs @@ -117,6 +117,11 @@ impl Kind { /// ^ /// ``` pub fn start(tokenizer: &mut Tokenizer, code: Code) -> StateFnResult { + let max = if tokenizer.parse_state.constructs.code_indented { + TAB_SIZE - 1 + } else { + usize::MAX + }; let paragraph_before = !tokenizer.events.is_empty() && tokenizer.events[skip_opt_back( &tokenizer.events, @@ -127,9 +132,8 @@ pub fn start(tokenizer: &mut Tokenizer, code: Code) -> StateFnResult { == Token::Paragraph; // Require a paragraph before and do not allow on a lazy line. - if paragraph_before && !tokenizer.lazy { - // To do: allow arbitrary when code (indented) is turned off. - tokenizer.go(space_or_tab_min_max(0, TAB_SIZE - 1), before)(tokenizer, code) + if paragraph_before && !tokenizer.lazy && tokenizer.parse_state.constructs.heading_setext { + tokenizer.go(space_or_tab_min_max(0, max), before)(tokenizer, code) } else { (State::Nok, None) } diff --git a/src/construct/html_flow.rs b/src/construct/html_flow.rs index 822b9dd..1255081 100644 --- a/src/construct/html_flow.rs +++ b/src/construct/html_flow.rs @@ -204,18 +204,27 @@ struct Info { /// ^ /// ``` pub fn start(tokenizer: &mut Tokenizer, code: Code) -> StateFnResult { - tokenizer.enter(Token::HtmlFlow); - // To do: allow arbitrary when code (indented) is turned off. - tokenizer.go( - space_or_tab_with_options(SpaceOrTabOptions { - kind: Token::HtmlFlowData, - min: 0, - max: TAB_SIZE - 1, - connect: false, - content_type: None, - }), - before, - )(tokenizer, code) + let max = if tokenizer.parse_state.constructs.code_indented { + TAB_SIZE - 1 + } else { + usize::MAX + }; + + if tokenizer.parse_state.constructs.html_flow { + tokenizer.enter(Token::HtmlFlow); + tokenizer.go( + space_or_tab_with_options(SpaceOrTabOptions { + kind: Token::HtmlFlowData, + min: 0, + max, + connect: false, + content_type: None, + }), + before, + )(tokenizer, code) + } else { + (State::Nok, None) + } } /// After optional whitespace, before `<`. diff --git a/src/construct/html_text.rs b/src/construct/html_text.rs index be1f1fe..db00551 100644 --- a/src/construct/html_text.rs +++ b/src/construct/html_text.rs @@ -66,7 +66,7 @@ use crate::util::codes::parse; /// ^ /// ``` pub fn start(tokenizer: &mut Tokenizer, code: Code) -> StateFnResult { - if Code::Char('<') == code { + if Code::Char('<') == code && tokenizer.parse_state.constructs.html_text { tokenizer.enter(Token::HtmlText); tokenizer.enter(Token::HtmlTextData); tokenizer.consume(code); diff --git a/src/construct/label_end.rs b/src/construct/label_end.rs index e232cbe..2ac2500 100644 --- a/src/construct/label_end.rs +++ b/src/construct/label_end.rs @@ -184,7 +184,7 @@ struct Info { /// > | [a] b /// ``` pub fn start(tokenizer: &mut Tokenizer, code: Code) -> StateFnResult { - if Code::Char(']') == code { + if Code::Char(']') == code && tokenizer.parse_state.constructs.label_end { let mut label_start_index: Option<usize> = None; let mut index = tokenizer.label_start_stack.len(); diff --git a/src/construct/label_start_image.rs b/src/construct/label_start_image.rs index b4e0433..fd7a42d 100644 --- a/src/construct/label_start_image.rs +++ b/src/construct/label_start_image.rs @@ -40,7 +40,7 @@ use crate::tokenizer::{Code, LabelStart, State, StateFnResult, Tokenizer}; /// ``` pub fn start(tokenizer: &mut Tokenizer, code: Code) -> StateFnResult { match code { - Code::Char('!') => { + Code::Char('!') if tokenizer.parse_state.constructs.label_start_image => { tokenizer.enter(Token::LabelImage); tokenizer.enter(Token::LabelImageMarker); tokenizer.consume(code); diff --git a/src/construct/label_start_link.rs b/src/construct/label_start_link.rs index 7e8e511..aeaa4eb 100644 --- a/src/construct/label_start_link.rs +++ b/src/construct/label_start_link.rs @@ -39,7 +39,7 @@ use crate::tokenizer::{Code, LabelStart, State, StateFnResult, Tokenizer}; /// ``` pub fn start(tokenizer: &mut Tokenizer, code: Code) -> StateFnResult { match code { - Code::Char('[') => { + Code::Char('[') if tokenizer.parse_state.constructs.label_start_link => { let start = tokenizer.events.len(); tokenizer.enter(Token::LabelLink); tokenizer.enter(Token::LabelMarker); diff --git a/src/construct/list.rs b/src/construct/list.rs index fce8f00..5fd0849 100644 --- a/src/construct/list.rs +++ b/src/construct/list.rs @@ -138,9 +138,18 @@ impl Kind { /// ^ /// ``` pub fn start(tokenizer: &mut Tokenizer, code: Code) -> StateFnResult { - tokenizer.enter(Token::ListItem); - // To do: allow arbitrary when code (indented) is turned off. - tokenizer.go(space_or_tab_min_max(0, TAB_SIZE - 1), before)(tokenizer, code) + let max = if tokenizer.parse_state.constructs.code_indented { + TAB_SIZE - 1 + } else { + usize::MAX + }; + + if tokenizer.parse_state.constructs.list { + tokenizer.enter(Token::ListItem); + tokenizer.go(space_or_tab_min_max(0, max), before)(tokenizer, code) + } else { + (State::Nok, None) + } } /// Start of list item, after whitespace. diff --git a/src/construct/thematic_break.rs b/src/construct/thematic_break.rs index f0b6052..48fb838 100644 --- a/src/construct/thematic_break.rs +++ b/src/construct/thematic_break.rs @@ -135,9 +135,18 @@ struct Info { /// ^ /// ``` pub fn start(tokenizer: &mut Tokenizer, code: Code) -> StateFnResult { - tokenizer.enter(Token::ThematicBreak); - // To do: allow arbitrary when code (indented) is turned off. - tokenizer.go(space_or_tab_min_max(0, TAB_SIZE - 1), before)(tokenizer, code) + let max = if tokenizer.parse_state.constructs.code_indented { + TAB_SIZE - 1 + } else { + usize::MAX + }; + + if tokenizer.parse_state.constructs.thematic_break { + tokenizer.enter(Token::ThematicBreak); + tokenizer.go(space_or_tab_min_max(0, max), before)(tokenizer, code) + } else { + (State::Nok, None) + } } /// Start of a thematic break, after whitespace. diff --git a/src/content/string.rs b/src/content/string.rs index cc8ee53..f2650df 100644 --- a/src/content/string.rs +++ b/src/content/string.rs @@ -19,6 +19,7 @@ use crate::construct::{ use crate::tokenizer::{Code, State, StateFnResult, Tokenizer}; const MARKERS: [Code; 5] = [ + // To do: build this vec based on whether they are enabled? Code::VirtualSpace, // `whitespace` Code::Char('\t'), // `whitespace` Code::Char(' '), // `whitespace` diff --git a/src/content/text.rs b/src/content/text.rs index cf630f1..f797b11 100644 --- a/src/content/text.rs +++ b/src/content/text.rs @@ -58,6 +58,7 @@ pub fn start(tokenizer: &mut Tokenizer, code: Code) -> StateFnResult { Code::None => (State::Ok, None), _ => tokenizer.attempt_n( vec![ + // To do: build this vec based on whether they are enabled? Box::new(attention), Box::new(autolink), Box::new(character_escape), @@ -75,8 +75,193 @@ impl LineEnding { } } +/// Control which constructs are enabled. +/// +/// Not all constructs can be configured. +/// Notably, blank lines and paragraphs cannot be turned off. +#[allow(clippy::struct_excessive_bools)] +#[derive(Clone, Debug)] +pub struct Constructs { + /// Attention. + /// + /// ```markdown + /// > | a *b* c **d**. + /// ^^^ ^^^^^ + /// ``` + pub attention: bool, + /// Autolink. + /// + /// ```markdown + /// > | a <https://example.com> b <user@example.org>. + /// ^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^ + /// ``` + pub autolink: bool, + /// Block quote. + /// + /// ```markdown + /// > | > a + /// ^^^ + /// ``` + pub block_quote: bool, + /// Character escape. + /// + /// ```markdown + /// > | a \* b + /// ^^ + /// ``` + pub character_escape: bool, + /// Character reference. + /// + /// ```markdown + /// > | a & b + /// ^^^^^ + /// ``` + pub character_reference: bool, + /// Code (indented). + /// + /// ```markdown + /// > | a + /// ^^^^^ + /// ``` + pub code_indented: bool, + /// Code (fenced). + /// + /// ```markdown + /// > | ~~~js + /// ^^^^^ + /// > | console.log(1) + /// ^^^^^^^^^^^^^^ + /// > | ~~~ + /// ^^^ + /// ``` + pub code_fenced: bool, + /// Code (text). + /// + /// ```markdown + /// > | a `b` c + /// ^^^ + /// ``` + pub code_text: bool, + /// Definition. + /// + /// ```markdown + /// > | [a]: b "c" + /// ^^^^^^^^^^ + /// ``` + pub definition: bool, + /// Hard break (escape). + /// + /// ```markdown + /// > | a\ + /// ^ + /// | b + /// ``` + pub hard_break_escape: bool, + /// Hard break (trailing). + /// + /// ```markdown + /// > | a␠␠ + /// ^^ + /// | b + /// ``` + pub hard_break_trailing: bool, + /// Heading (atx). + /// + /// ```markdown + /// > | # a + /// ^^^ + /// ``` + pub heading_atx: bool, + /// Heading (setext). + /// + /// ```markdown + /// > | a + /// ^^ + /// > | == + /// ^^ + /// ``` + pub heading_setext: bool, + /// HTML (flow). + /// + /// ```markdown + /// > | <div> + /// ^^^^^ + /// ``` + pub html_flow: bool, + /// HTML (text). + /// + /// ```markdown + /// > | a <b> c + /// ^^^ + /// ``` + pub html_text: bool, + /// Label start (image). + /// + /// ```markdown + /// > | a ![b](c) d + /// ^^ + /// ``` + pub label_start_image: bool, + /// Label start (link). + /// + /// ```markdown + /// > | a [b](c) d + /// ^ + /// ``` + pub label_start_link: bool, + /// Label end. + /// + /// ```markdown + /// > | a [b](c) d + /// ^^^^ + /// ``` + pub label_end: bool, + /// List. + /// + /// ```markdown + /// > | * a + /// ^^^ + /// ``` + pub list: bool, + /// Thematic break. + /// + /// ```markdown + /// > | *** + /// ^^^ + /// ``` + pub thematic_break: bool, +} + +impl Default for Constructs { + /// `CommonMark`. + fn default() -> Self { + Self { + attention: true, + autolink: true, + block_quote: true, + character_escape: true, + character_reference: true, + code_indented: true, + code_fenced: true, + code_text: true, + definition: true, + hard_break_escape: true, + hard_break_trailing: true, + heading_atx: true, + heading_setext: true, + html_flow: true, + html_text: true, + label_start_image: true, + label_start_link: true, + label_end: true, + list: true, + thematic_break: true, + } + } +} + /// Configuration (optional). -#[derive(Default, Debug)] +#[derive(Clone, Debug, Default)] pub struct Options { /// Whether to allow (dangerous) HTML. /// The default is `false`, you can turn it on to `true` for trusted @@ -99,8 +284,7 @@ pub struct Options { /// "Hi, <i>venus</i>!", /// &Options { /// allow_dangerous_html: true, - /// allow_dangerous_protocol: false, - /// default_line_ending: None, + /// ..Options::default() /// } /// ), /// "<p>Hi, <i>venus</i>!</p>" @@ -128,9 +312,8 @@ pub struct Options { /// micromark_with_options( /// "<javascript:alert(1)>", /// &Options { - /// allow_dangerous_html: false, /// allow_dangerous_protocol: true, - /// default_line_ending: None, + /// ..Options::default() /// } /// ), /// "<p><a href=\"javascript:alert(1)\">javascript:alert(1)</a></p>" @@ -166,15 +349,46 @@ pub struct Options { /// micromark_with_options( /// "> a", /// &Options { - /// allow_dangerous_html: false, - /// allow_dangerous_protocol: false, /// default_line_ending: Some(LineEnding::CarriageReturnLineFeed), + /// ..Options::default() /// } /// ), /// "<blockquote>\r\n<p>a</p>\r\n</blockquote>" /// ); /// ``` + // To do: use `default`? <https://doc.rust-lang.org/std/default/trait.Default.html#enums> pub default_line_ending: Option<LineEnding>, + + /// Which constructs to enable and disable. + /// The default is to follow `CommonMark`. + /// + /// ## Examples + /// + /// ```rust + /// use micromark::{micromark, micromark_with_options, Options, Constructs}; + /// + /// // micromark follows CommonMark by default: + /// assert_eq!( + /// micromark(" indented code?"), + /// "<pre><code>indented code?\n</code></pre>" + /// ); + /// + /// // Pass `constructs` to choose what to enable and disable: + /// assert_eq!( + /// micromark_with_options( + /// " indented code?", + /// &Options { + /// constructs: Constructs { + /// code_indented: false, + /// ..Constructs::default() + /// }, + /// ..Options::default() + /// } + /// ), + /// "<p>indented code?</p>" + /// ); + /// ``` + pub constructs: Constructs, } /// Turn markdown into HTML. @@ -203,13 +417,13 @@ pub fn micromark(value: &str) -> String { /// let result = micromark_with_options("<div>\n\n# Hello, world!\n\n</div>", &Options { /// allow_dangerous_html: true, /// allow_dangerous_protocol: true, -/// default_line_ending: None, +/// ..Options::default() /// }); /// /// assert_eq!(result, "<div>\n<h1>Hello, world!</h1>\n</div>"); /// ``` #[must_use] pub fn micromark_with_options(value: &str, options: &Options) -> String { - let (events, result) = parse(value); + let (events, result) = parse(value, options); compile(&events, &result.codes, options) } diff --git a/src/parser.rs b/src/parser.rs index 725f326..409e812 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -3,6 +3,7 @@ use crate::content::document::document; use crate::tokenizer::{Code, Event, Point}; use crate::util::codes::parse as parse_codes; +use crate::{Constructs, Options}; use std::collections::HashSet; /// Information needed, in all content types, when parsing markdown. @@ -11,6 +12,7 @@ use std::collections::HashSet; /// It also references the input value as [`Code`][]s. #[derive(Debug)] pub struct ParseState { + pub constructs: Constructs, /// List of codes. pub codes: Vec<Code>, /// Set of defined identifiers. @@ -20,8 +22,9 @@ pub struct ParseState { /// Turn a string of markdown into events. /// /// Passes the codes back so the compiler can access the source. -pub fn parse(value: &str) -> (Vec<Event>, ParseState) { +pub fn parse(value: &str, options: &Options) -> (Vec<Event>, ParseState) { let mut parse_state = ParseState { + constructs: options.constructs.clone(), codes: parse_codes(value), definitions: HashSet::new(), }; |