use crate::mdx_parser::event::{Event, Kind, Name, Point};
use crate::mdx_parser::message;
use crate::mdx_parser::state::State;
use crate::mdx_parser::tokenizer::Tokenizer;
use crate::mdx_parser::util::slice::{Position, Slice};
use alloc::{boxed::Box, string::String, vec::Vec};
pub type Stop = (usize, usize);
#[derive(Debug, Default)]
pub struct Result {
pub value: String,
pub stops: Vec<Stop>,
}
pub fn collect(events: &[Event], bytes: &[u8], from: usize, names: &[Name], stop: &[Name]) -> Result {
let mut result = Result::default();
collect_more(events, bytes, from, names, stop, &mut result);
result
}
pub fn collect_more(
events: &[Event],
bytes: &[u8],
from: usize,
names: &[Name],
stop: &[Name],
result: &mut Result,
) -> usize {
let mut index = from;
while index < events.len() {
if events[index].kind == Kind::Enter {
if names.contains(&events[index].name) {
let slice = Slice::from_position(
bytes,
&Position {
start: &events[index].point,
end: &events[index + 1].point,
},
);
result.stops.push((result.value.len(), events[index].point.index));
result.value.extend(core::iter::repeat(' ').take(slice.before));
result.value.push_str(slice.as_str());
result.value.extend(core::iter::repeat(' ').take(slice.after));
}
} else if stop.contains(&events[index].name) {
break;
}
index += 1;
}
index
}
pub fn reset_collect(tokenizer: &mut Tokenizer) {
if let Some(collect) = &mut tokenizer.tokenize_state.mdx_collect {
let (cursor, result) = &mut **collect;
*cursor = tokenizer.tokenize_state.start;
result.value.clear();
result.stops.clear();
}
}
pub fn collect_new(tokenizer: &mut Tokenizer, names: &[Name]) {
let start = tokenizer.tokenize_state.start;
let (cursor, result) = &mut **tokenizer
.tokenize_state
.mdx_collect
.get_or_insert_with(|| Box::new((start, Result::default())));
*cursor = collect_more(
&tokenizer.events,
tokenizer.parse_state.bytes,
*cursor,
names,
&[],
result,
);
}
pub fn collected<'a>(tokenizer: &'a Tokenizer) -> &'a Result {
&tokenizer.tokenize_state.mdx_collect.as_ref().unwrap().1
}
pub fn charge_parse_budget(tokenizer: &Tokenizer, len: usize, place: &Point) -> Option<State> {
let budget = tokenizer.parse_state.mdx_parse_budget.as_ref()?;
if let Some(left) = budget.get().checked_sub(len) {
budget.set(left);
None
} else {
Some(State::Error(Box::new(message::Message {
place: Some(Box::new(message::Place::Point(place.to_unist()))),
reason: "Unexpected MDX expression or ESM that needs more parsing than `mdx_parse_budget_factor` allows"
.into(),
rule_id: Box::new("mdx-parse-budget".into()),
source: Box::new("markdown-rs".into()),
})))
}
}