use crate::alerts::*;
use egui::{Pos2, Vec2};
use pulldown_cmark::Options;
use std::ops::Range;
#[derive(Default, Debug)]
pub struct ScrollableCache {
pub available_size: Vec2,
pub page_size: Option<Vec2>,
pub split_points: Vec<(usize, Pos2, Pos2)>,
}
pub type EventIteratorItem<'e> = (usize, (pulldown_cmark::Event<'e>, Range<usize>));
pub fn delayed_events<'e>(
events: &mut impl Iterator<Item = EventIteratorItem<'e>>,
end_at: impl Fn(pulldown_cmark::TagEnd) -> bool,
) -> Vec<(pulldown_cmark::Event<'e>, Range<usize>)> {
let mut curr_event = events.next();
let mut total_events = Vec::new();
loop {
if let Some(event) = curr_event.take() {
total_events.push(event.1.clone());
if let (_, (pulldown_cmark::Event::End(tag), _range)) = event {
if end_at(tag) {
return total_events;
}
}
} else {
return total_events;
}
curr_event = events.next();
}
}
pub fn delayed_events_list_item<'e>(
events: &mut impl Iterator<Item = EventIteratorItem<'e>>,
) -> Vec<(pulldown_cmark::Event<'e>, Range<usize>)> {
let mut curr_event = events.next();
let mut total_events = Vec::new();
loop {
if let Some(event) = curr_event.take() {
total_events.push(event.1.clone());
if let (_, (pulldown_cmark::Event::End(pulldown_cmark::TagEnd::Item), _range)) = event {
return total_events;
}
if let (_, (pulldown_cmark::Event::Start(pulldown_cmark::Tag::List(_)), _range)) = event
{
return total_events;
}
} else {
return total_events;
}
curr_event = events.next();
}
}
type Column<'e> = Vec<(pulldown_cmark::Event<'e>, Range<usize>)>;
type Row<'e> = Vec<Column<'e>>;
pub struct Table<'e> {
pub header: Row<'e>,
pub rows: Vec<Row<'e>>,
}
fn parse_row<'e>(
events: &mut impl Iterator<Item = (pulldown_cmark::Event<'e>, Range<usize>)>,
) -> Vec<Column<'e>> {
let mut row = Vec::new();
let mut column = Vec::new();
for (e, src_span) in events.by_ref() {
if let pulldown_cmark::Event::End(pulldown_cmark::TagEnd::TableCell) = e {
row.push(column);
column = Vec::new();
}
if let pulldown_cmark::Event::End(pulldown_cmark::TagEnd::TableHead) = e {
break;
}
if let pulldown_cmark::Event::End(pulldown_cmark::TagEnd::TableRow) = e {
break;
}
column.push((e, src_span));
}
row
}
pub fn parse_table<'e>(events: &mut impl Iterator<Item = EventIteratorItem<'e>>) -> Table<'e> {
let mut all_events = delayed_events(events, |end| matches!(end, pulldown_cmark::TagEnd::Table))
.into_iter()
.peekable();
let header = parse_row(&mut all_events);
let mut rows = Vec::new();
while all_events.peek().is_some() {
let row = parse_row(&mut all_events);
rows.push(row);
}
Table { header, rows }
}
pub fn parse_alerts<'a>(
alerts: &'a AlertBundle,
events: &mut Vec<(pulldown_cmark::Event<'_>, Range<usize>)>,
) -> Option<&'a Alert> {
if !alerts.is_empty() {
let mut alert_ident = "".to_owned();
let mut alert_ident_ends_at = 0;
let mut has_extra_line = false;
for (i, (e, _src_span)) in events.iter().enumerate() {
if let pulldown_cmark::Event::End(_) = e {
alert_ident_ends_at = i;
has_extra_line = true;
break;
}
if let pulldown_cmark::Event::SoftBreak = e {
alert_ident_ends_at = i;
break;
}
if let pulldown_cmark::Event::HardBreak = e {
alert_ident_ends_at = i;
break;
}
if let pulldown_cmark::Event::Text(text) = e {
alert_ident += text;
}
}
let alert = try_get_alert(alerts, &alert_ident);
if alert.is_some() {
if has_extra_line {
for _ in 0..=alert_ident_ends_at {
events.remove(0);
}
} else {
for _ in 0..alert_ident_ends_at {
events.remove(1);
}
}
}
alert
} else {
None
}
}
#[inline]
pub fn parser_options() -> Options {
Options::ENABLE_TABLES
| Options::ENABLE_TASKLISTS
| Options::ENABLE_STRIKETHROUGH
| Options::ENABLE_FOOTNOTES
| Options::ENABLE_DEFINITION_LIST
}