use crate::construct::partial_space_or_tab::space_or_tab;
use crate::event::Name;
use crate::state::{Name as StateName, State};
use crate::tokenizer::Tokenizer;
use crate::util::constant::FRONTMATTER_SEQUENCE_SIZE;
pub fn start(tokenizer: &mut Tokenizer) -> State {
if tokenizer.parse_state.options.constructs.frontmatter
&& matches!(tokenizer.current, Some(b'+' | b'-'))
{
tokenizer.tokenize_state.marker = tokenizer.current.unwrap();
tokenizer.enter(Name::Frontmatter);
tokenizer.enter(Name::FrontmatterFence);
tokenizer.enter(Name::FrontmatterSequence);
State::Retry(StateName::FrontmatterOpenSequence)
} else {
State::Nok
}
}
pub fn open_sequence(tokenizer: &mut Tokenizer) -> State {
if tokenizer.current == Some(tokenizer.tokenize_state.marker) {
tokenizer.tokenize_state.size += 1;
tokenizer.consume();
State::Next(StateName::FrontmatterOpenSequence)
} else if tokenizer.tokenize_state.size == FRONTMATTER_SEQUENCE_SIZE {
tokenizer.tokenize_state.size = 0;
tokenizer.exit(Name::FrontmatterSequence);
if matches!(tokenizer.current, Some(b'\t' | b' ')) {
tokenizer.attempt(State::Next(StateName::FrontmatterOpenAfter), State::Nok);
State::Retry(space_or_tab(tokenizer))
} else {
State::Retry(StateName::FrontmatterOpenAfter)
}
} else {
tokenizer.tokenize_state.marker = 0;
tokenizer.tokenize_state.size = 0;
State::Nok
}
}
pub fn open_after(tokenizer: &mut Tokenizer) -> State {
if let Some(b'\n') = tokenizer.current {
tokenizer.exit(Name::FrontmatterFence);
tokenizer.enter(Name::LineEnding);
tokenizer.consume();
tokenizer.exit(Name::LineEnding);
tokenizer.attempt(
State::Next(StateName::FrontmatterAfter),
State::Next(StateName::FrontmatterContentStart),
);
State::Next(StateName::FrontmatterCloseStart)
} else {
tokenizer.tokenize_state.marker = 0;
State::Nok
}
}
pub fn close_start(tokenizer: &mut Tokenizer) -> State {
if tokenizer.current == Some(tokenizer.tokenize_state.marker) {
tokenizer.enter(Name::FrontmatterFence);
tokenizer.enter(Name::FrontmatterSequence);
State::Retry(StateName::FrontmatterCloseSequence)
} else {
State::Nok
}
}
pub fn close_sequence(tokenizer: &mut Tokenizer) -> State {
if tokenizer.current == Some(tokenizer.tokenize_state.marker) {
tokenizer.tokenize_state.size += 1;
tokenizer.consume();
State::Next(StateName::FrontmatterCloseSequence)
} else if tokenizer.tokenize_state.size == FRONTMATTER_SEQUENCE_SIZE {
tokenizer.tokenize_state.size = 0;
tokenizer.exit(Name::FrontmatterSequence);
if matches!(tokenizer.current, Some(b'\t' | b' ')) {
tokenizer.attempt(State::Next(StateName::FrontmatterCloseAfter), State::Nok);
State::Retry(space_or_tab(tokenizer))
} else {
State::Retry(StateName::FrontmatterCloseAfter)
}
} else {
tokenizer.tokenize_state.size = 0;
State::Nok
}
}
pub fn close_after(tokenizer: &mut Tokenizer) -> State {
match tokenizer.current {
None | Some(b'\n') => {
tokenizer.exit(Name::FrontmatterFence);
State::Ok
}
_ => State::Nok,
}
}
pub fn content_start(tokenizer: &mut Tokenizer) -> State {
match tokenizer.current {
None | Some(b'\n') => State::Retry(StateName::FrontmatterContentEnd),
Some(_) => {
tokenizer.enter(Name::FrontmatterChunk);
State::Retry(StateName::FrontmatterContentInside)
}
}
}
pub fn content_inside(tokenizer: &mut Tokenizer) -> State {
match tokenizer.current {
None | Some(b'\n') => {
tokenizer.exit(Name::FrontmatterChunk);
State::Retry(StateName::FrontmatterContentEnd)
}
Some(_) => {
tokenizer.consume();
State::Next(StateName::FrontmatterContentInside)
}
}
}
pub fn content_end(tokenizer: &mut Tokenizer) -> State {
match tokenizer.current {
None => {
tokenizer.tokenize_state.marker = 0;
State::Nok
}
Some(b'\n') => {
tokenizer.enter(Name::LineEnding);
tokenizer.consume();
tokenizer.exit(Name::LineEnding);
tokenizer.attempt(
State::Next(StateName::FrontmatterAfter),
State::Next(StateName::FrontmatterContentStart),
);
State::Next(StateName::FrontmatterCloseStart)
}
Some(_) => unreachable!("expected eof/eol"),
}
}
pub fn after(tokenizer: &mut Tokenizer) -> State {
debug_assert!(
matches!(tokenizer.current, None | Some(b'\n')),
"expected eol/eof after closing fence"
);
tokenizer.exit(Name::Frontmatter);
State::Ok
}