aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLibravatar Titus Wormer <tituswormer@gmail.com>2022-07-18 16:31:14 +0200
committerLibravatar Titus Wormer <tituswormer@gmail.com>2022-07-18 16:31:14 +0200
commit5403261e8213f68633a09fc3e9bc2e6e2cd777b2 (patch)
treebb3a6419ef42f7611c2cb24fe7024228f579331b /src
parent03544cafaa82ba4bd7e0bc3372fc59549a8dc0cc (diff)
downloadmarkdown-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.rs2
-rw-r--r--src/construct/autolink.rs2
-rw-r--r--src/construct/block_quote.rs20
-rw-r--r--src/construct/character_escape.rs2
-rw-r--r--src/construct/character_reference.rs2
-rw-r--r--src/construct/code_fenced.rs34
-rw-r--r--src/construct/code_indented.rs2
-rw-r--r--src/construct/code_text.rs6
-rw-r--r--src/construct/definition.rs6
-rw-r--r--src/construct/hard_break_escape.rs2
-rw-r--r--src/construct/hard_break_trailing.rs2
-rw-r--r--src/construct/heading_atx.rs15
-rw-r--r--src/construct/heading_setext.rs10
-rw-r--r--src/construct/html_flow.rs33
-rw-r--r--src/construct/html_text.rs2
-rw-r--r--src/construct/label_end.rs2
-rw-r--r--src/construct/label_start_image.rs2
-rw-r--r--src/construct/label_start_link.rs2
-rw-r--r--src/construct/list.rs15
-rw-r--r--src/construct/thematic_break.rs15
-rw-r--r--src/content/string.rs1
-rw-r--r--src/content/text.rs1
-rw-r--r--src/lib.rs232
-rw-r--r--src/parser.rs5
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),
diff --git a/src/lib.rs b/src/lib.rs
index ff8e938..224f8d0 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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 &amp; 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(),
};