1use core::ops::Range;
2use std::borrow::Cow;
3use std::boxed::Box;
4use std::string::String;
5use std::sync::Arc;
6use std::vec::Vec;
7
8use pulldown_cmark::Event;
9
10use crate::TextSource;
11
12#[derive(Clone, Debug, PartialEq)]
15pub enum CMarkItem {
16 Parsed {
18 event: Event<'static>,
20 range: Range<usize>,
22 text_source: TextSource,
24 },
25 Created {
27 event: Event<'static>,
29 note: Cow<'static, str>,
31 },
32 Modified {
34 event: Event<'static>,
36 nodes: Box<[Arc<CMarkItem>]>,
38 note: Cow<'static, str>,
40 },
41 Removed {
43 nodes: Box<[Arc<CMarkItem>]>,
45 note: Cow<'static, str>,
47 },
48 Noted {
50 node: Arc<CMarkItem>,
52 note: Cow<'static, str>,
54 },
55}
56
57#[allow(single_use_lifetimes)] #[derive(Clone, Debug, PartialEq)]
60pub struct CMarkSpan<'a> {
61 pub range: &'a Range<usize>,
63 pub text_source: &'a TextSource,
65 pub note: String,
67}
68
69impl CMarkItem {
70 pub fn new(event: Event<'static>, note: Cow<'static, str>) -> Arc<Self> {
72 Arc::new(Self::Created { event, note })
73 }
74
75 pub fn from(event: Event<'static>, range: Range<usize>, text_source: TextSource) -> Arc<Self> {
77 Arc::new(Self::Parsed {
78 event,
79 range,
80 text_source,
81 })
82 }
83
84 pub fn event(&self) -> Option<&Event<'static>> {
86 match self {
87 Self::Parsed { event, .. } => Some(event),
88 Self::Created { event, .. } => Some(event),
89 Self::Modified { event, .. } => Some(event),
90 Self::Removed { .. } => None,
91 Self::Noted { node, .. } => node.event(),
92 }
93 }
94
95 pub fn spans(&self) -> Vec<CMarkSpan<'_>> {
97 match self {
98 Self::Parsed {
99 event,
100 range,
101 text_source,
102 } => std::vec![CMarkSpan {
103 range,
104 text_source,
105 note: std::format!("{:?}", event),
106 }],
107 Self::Created { .. } => Vec::new(),
108 Self::Modified { event, nodes, note } => nodes
109 .iter()
110 .flat_map(|node| node.spans())
111 .map(|span| CMarkSpan {
112 note: span.note + " : " + note + " -> " + &std::format!("{:?}", event),
113 ..span
114 })
115 .collect(),
116 Self::Removed { nodes, note } => nodes
117 .iter()
118 .flat_map(|node| node.spans())
119 .map(|span| CMarkSpan {
120 note: span.note + " : " + note,
121 ..span
122 })
123 .collect(),
124 Self::Noted { node, note } => node
125 .spans()
126 .into_iter()
127 .map(|span| CMarkSpan {
128 note: span.note + " : " + note,
129 ..span
130 })
131 .collect(),
132 }
133 }
134}
135
136pub trait CMarkItemAsModified {
138 fn into_modified(self, event: Event<'static>, note: Cow<'static, str>) -> Arc<CMarkItem>;
140}
141
142pub trait CMarkItemAsRemoved {
144 fn into_removed(self, note: Cow<'static, str>) -> Arc<CMarkItem>;
146}
147
148pub trait CMarkItemWithNote {
150 fn with_note(self, note: Cow<'static, str>) -> Arc<CMarkItem>;
152}
153
154impl CMarkItemAsModified for Arc<CMarkItem> {
155 fn into_modified(self, event: Event<'static>, note: Cow<'static, str>) -> Arc<CMarkItem> {
156 Arc::new(CMarkItem::Modified {
157 nodes: Box::new([self]),
158 event,
159 note,
160 })
161 }
162}
163
164impl CMarkItemAsModified for Box<[Arc<CMarkItem>]> {
165 fn into_modified(self, event: Event<'static>, note: Cow<'static, str>) -> Arc<CMarkItem> {
166 assert!(!self.is_empty());
167 Arc::new(CMarkItem::Modified {
168 nodes: self,
169 event,
170 note,
171 })
172 }
173}
174
175impl CMarkItemAsModified for Vec<Arc<CMarkItem>> {
176 fn into_modified(self, event: Event<'static>, note: Cow<'static, str>) -> Arc<CMarkItem> {
177 assert!(!self.is_empty());
178 Arc::new(CMarkItem::Modified {
179 nodes: self.into_boxed_slice(),
180 event,
181 note,
182 })
183 }
184}
185
186impl CMarkItemAsRemoved for Arc<CMarkItem> {
187 fn into_removed(self, note: Cow<'static, str>) -> Arc<CMarkItem> {
188 Arc::new(CMarkItem::Removed {
189 nodes: Box::new([self]),
190 note,
191 })
192 }
193}
194
195impl CMarkItemAsRemoved for Box<[Arc<CMarkItem>]> {
196 fn into_removed(self, note: Cow<'static, str>) -> Arc<CMarkItem> {
197 assert!(!self.is_empty());
198 Arc::new(CMarkItem::Removed { nodes: self, note })
199 }
200}
201
202impl CMarkItemAsRemoved for Vec<Arc<CMarkItem>> {
203 fn into_removed(self, note: Cow<'static, str>) -> Arc<CMarkItem> {
204 assert!(!self.is_empty());
205 Arc::new(CMarkItem::Removed {
206 nodes: self.into_boxed_slice(),
207 note,
208 })
209 }
210}
211
212impl CMarkItemWithNote for Arc<CMarkItem> {
213 fn with_note(self, note: Cow<'static, str>) -> Arc<CMarkItem> {
214 Arc::new(CMarkItem::Noted { node: self, note })
215 }
216}