#![cfg(feature = "pulldown-cmark")]
use core::ops::Range;
use std::borrow::Cow;
use std::boxed::Box;
use std::string::String;
use std::sync::Arc;
use std::vec::Vec;
use pulldown_cmark::Event;
use crate::TextSource;
#[derive(Clone, Debug, PartialEq)]
pub enum CMarkItem {
Parsed {
event: Event<'static>,
range: Range<usize>,
text_source: TextSource,
},
Created {
event: Event<'static>,
note: Cow<'static, str>,
},
Modified {
event: Event<'static>,
nodes: Box<[Arc<CMarkItem>]>,
note: Cow<'static, str>,
},
Removed {
nodes: Box<[Arc<CMarkItem>]>,
note: Cow<'static, str>,
},
Noted {
node: Arc<CMarkItem>,
note: Cow<'static, str>,
},
}
#[allow(single_use_lifetimes)]
#[derive(Clone, Debug, PartialEq)]
pub struct CMarkSpan<'a> {
pub range: &'a Range<usize>,
pub text_source: &'a TextSource,
pub note: String,
}
impl<'a> CMarkItem {
pub fn new(event: Event<'static>, note: Cow<'static, str>) -> Arc<Self> {
Arc::new(Self::Created { event, note })
}
pub fn from(event: Event<'static>, range: Range<usize>, text_source: TextSource) -> Arc<Self> {
Arc::new(Self::Parsed {
event,
range,
text_source,
})
}
pub fn event(&self) -> Option<&Event<'static>> {
match self {
Self::Parsed { event, .. } => Some(event),
Self::Created { event, .. } => Some(event),
Self::Modified { event, .. } => Some(event),
Self::Removed { .. } => None,
Self::Noted { node, .. } => node.event(),
}
}
pub fn spans(&self) -> Vec<CMarkSpan<'_>> {
match self {
Self::Parsed {
event,
range,
text_source,
} => std::vec![CMarkSpan {
range: &range,
text_source: &text_source,
note: std::format!("{:?}", event),
}],
Self::Created { .. } => Vec::new(),
Self::Modified { event, nodes, note } => nodes
.iter()
.flat_map(|node| node.spans())
.map(|span| CMarkSpan {
note: span.note + " : " + note + " -> " + &std::format!("{:?}", event),
..span
})
.collect(),
Self::Removed { nodes, note } => nodes
.iter()
.flat_map(|node| node.spans())
.map(|span| CMarkSpan {
note: span.note + " : " + note,
..span
})
.collect(),
Self::Noted { node, note } => node
.spans()
.into_iter()
.map(|span| CMarkSpan {
note: span.note + " : " + note,
..span
})
.collect(),
}
}
}
pub trait CMarkItemAsModified {
fn as_modified(self, event: Event<'static>, note: Cow<'static, str>) -> Arc<CMarkItem>;
}
pub trait CMarkItemAsRemoved {
fn as_removed(self, note: Cow<'static, str>) -> Arc<CMarkItem>;
}
pub trait CMarkItemWithNote {
fn with_note(self, note: Cow<'static, str>) -> Arc<CMarkItem>;
}
impl CMarkItemAsModified for Arc<CMarkItem> {
fn as_modified(self, event: Event<'static>, note: Cow<'static, str>) -> Arc<CMarkItem> {
Arc::new(CMarkItem::Modified {
nodes: Box::new([self]),
event,
note,
})
}
}
impl CMarkItemAsModified for Box<[Arc<CMarkItem>]> {
fn as_modified(self, event: Event<'static>, note: Cow<'static, str>) -> Arc<CMarkItem> {
assert!(!self.is_empty());
Arc::new(CMarkItem::Modified {
nodes: self,
event,
note,
})
}
}
impl CMarkItemAsModified for Vec<Arc<CMarkItem>> {
fn as_modified(self, event: Event<'static>, note: Cow<'static, str>) -> Arc<CMarkItem> {
assert!(!self.is_empty());
Arc::new(CMarkItem::Modified {
nodes: self.into_boxed_slice(),
event,
note,
})
}
}
impl CMarkItemAsRemoved for Arc<CMarkItem> {
fn as_removed(self, note: Cow<'static, str>) -> Arc<CMarkItem> {
Arc::new(CMarkItem::Removed {
nodes: Box::new([self]),
note,
})
}
}
impl CMarkItemAsRemoved for Box<[Arc<CMarkItem>]> {
fn as_removed(self, note: Cow<'static, str>) -> Arc<CMarkItem> {
assert!(!self.is_empty());
Arc::new(CMarkItem::Removed { nodes: self, note })
}
}
impl CMarkItemAsRemoved for Vec<Arc<CMarkItem>> {
fn as_removed(self, note: Cow<'static, str>) -> Arc<CMarkItem> {
assert!(!self.is_empty());
Arc::new(CMarkItem::Removed {
nodes: self.into_boxed_slice(),
note,
})
}
}
impl CMarkItemWithNote for Arc<CMarkItem> {
fn with_note(self, note: Cow<'static, str>) -> Arc<CMarkItem> {
Arc::new(CMarkItem::Noted { node: self, note })
}
}