//! The flow content type.
//!
//! **Flow** represents the sections, such as headings and code, which are
//! parsed per line.
//! An example is HTML, which has a certain starting condition (such as
//! `<script>` on its own line), then continues for a while, until an end
//! condition is found (such as `</style>`).
//! If that line with an end condition is never found, that flow goes until
//! the end.
//!
//! The constructs found in flow are:
//!
//! * [Blank line][crate::construct::blank_line]
//! * [Code (fenced)][crate::construct::code_fenced]
//! * [Code (indented)][crate::construct::code_indented]
//! * [Definition][crate::construct::definition]
//! * [Heading (atx)][crate::construct::heading_atx]
//! * [Heading (setext)][crate::construct::heading_setext]
//! * [HTML (flow)][crate::construct::html_flow]
//! * [Thematic break][crate::construct::thematic_break]
use crate::token::Token;
use crate::tokenizer::{State, StateName, Tokenizer};
/// Before flow.
///
/// First we assume a blank line.
//
/// ```markdown
/// |
/// |## alpha
/// | bravo
/// |***
/// ```
pub fn start(tokenizer: &mut Tokenizer) -> State {
match tokenizer.current {
None => State::Ok,
_ => tokenizer.attempt(StateName::BlankLineStart, |ok| {
State::Fn(if ok {
StateName::FlowBlankLineAfter
} else {
StateName::FlowBefore
})
}),
}
}
/// Before flow (initial).
///
/// “Initial” flow means unprefixed flow, so right at the start of a line.
/// Interestingly, the only flow (initial) construct is indented code.
/// Move to `before` afterwards.
///
/// ```markdown
/// |qwe
/// | asd
/// |~~~js
/// |<div>
/// ```
pub fn before(tokenizer: &mut Tokenizer) -> State {
match tokenizer.current {
None => State::Ok,
_ => tokenizer.attempt_n(
vec![
StateName::CodeIndentedStart,
StateName::CodeFencedStart,
StateName::HtmlFlowStart,
StateName::HeadingAtxStart,
StateName::HeadingSetextStart,
StateName::ThematicBreakStart,
StateName::DefinitionStart,
],
|ok| {
State::Fn(if ok {
StateName::FlowAfter
} else {
StateName::FlowBeforeParagraph
})
},
),
}
}
/// After a blank line.
///
/// Move to `start` afterwards.
///
/// ```markdown
/// ␠␠|
/// ```
pub fn blank_line_after(tokenizer: &mut Tokenizer) -> State {
match tokenizer.current {
None => State::Ok,
Some(b'\n') => {
tokenizer.enter(Token::BlankLineEnding);
tokenizer.consume();
tokenizer.exit(Token::BlankLineEnding);
// Feel free to interrupt.
tokenizer.interrupt = false;
State::Fn(StateName::FlowStart)
}
_ => unreachable!("expected eol/eof"),
}
}
/// After something.
///
/// ```markdown
/// ## alpha|
/// |
/// ~~~js
/// asd
/// ~~~|
/// ```
pub fn after(tokenizer: &mut Tokenizer) -> State {
match tokenizer.current {
None => State::Ok,
Some(b'\n') => {
tokenizer.enter(Token::LineEnding);
tokenizer.consume();
tokenizer.exit(Token::LineEnding);
State::Fn(StateName::FlowStart)
}
_ => unreachable!("expected eol/eof"),
}
}
/// Before a paragraph.
///
/// ```markdown
/// |asd
/// ```
pub fn before_paragraph(tokenizer: &mut Tokenizer) -> State {
tokenizer.go(StateName::ParagraphStart, StateName::FlowAfter)
}