1use crate::{Arena, Cursor, CursorSink, Kind, SourceCursor, SourceCursorSink, SourceOffset, Span, ToSpan, Vec};
2use std::collections::BTreeMap;
3
4#[derive(Debug)]
5pub struct OverlaySegment<'a> {
6 span: Span,
7 cursors: Vec<'a, SourceCursor<'a>>,
8 kind: OverlayKind,
9}
10
11impl<'a> OverlaySegment<'a> {
12 pub fn new(span: Span, cursors: Vec<'a, SourceCursor<'a>>, kind: OverlayKind) -> Self {
13 Self { span, cursors, kind }
14 }
15
16 pub fn start(&self) -> SourceOffset {
17 self.span.start()
18 }
19
20 pub fn end(&self) -> SourceOffset {
21 self.span.end()
22 }
23
24 pub fn cursors(&self) -> &[SourceCursor<'a>] {
25 &self.cursors
26 }
27
28 pub fn is_insertion(&self) -> bool {
29 matches!(self.kind, OverlayKind::InsertBefore | OverlayKind::InsertAfter)
30 }
31
32 pub fn kind(&self) -> OverlayKind {
33 self.kind
34 }
35}
36
37#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
38pub enum OverlayKind {
39 Replace,
40 InsertBefore,
41 InsertAfter,
42}
43
44#[derive(Debug)]
45pub struct CursorOverlaySet<'a> {
46 segments: Vec<'a, OverlaySegment<'a>>,
47}
48
49impl<'a> CursorOverlaySet<'a> {
50 pub fn new(alloc: &'a Arena) -> Self {
51 Self { segments: Vec::new_in(alloc) }
52 }
53
54 pub fn insert(&mut self, span: Span, cursors: Vec<'a, SourceCursor<'a>>) {
55 #[cfg(debug_assertions)]
56 {
57 let has_non_eof = cursors.iter().any(|cursor| cursor.token() != Kind::Eof);
58 debug_assert!(has_non_eof || cursors.is_empty(), "Overlay for span {:?} produced no output", span);
59 }
60 self.push_segment(OverlaySegment::new(span, cursors, OverlayKind::Replace));
61 }
62
63 pub fn clear(&mut self) {
64 self.segments.clear();
65 }
66
67 pub fn has_overlay(&self, span: Span) -> bool {
68 let start = &span.start();
69 let end = &span.end();
70 self.segments
71 .iter()
72 .any(|segment| !segment.is_insertion() && segment.start() <= *start && *end <= segment.end())
73 }
74
75 pub fn push_segment(&mut self, segment: OverlaySegment<'a>) {
76 let idx = self.segments.partition_point(|existing| {
77 existing.start() < segment.start()
78 || (existing.start() == segment.start() && existing.end() <= segment.end())
79 });
80 self.segments.insert(idx, segment);
81 }
82
83 pub fn segments(&self) -> &[OverlaySegment<'a>] {
84 &self.segments
85 }
86}
87
88#[derive(Debug)]
97pub struct CursorOverlaySink<'a, 'o, T: SourceCursorSink<'a>> {
98 source_text: &'a str,
99 overlays: &'o CursorOverlaySet<'a>,
100 sink: T,
101 processed_overlay_ranges: BTreeMap<SourceOffset, SourceOffset>,
102 next_segment: usize,
103 #[cfg(debug_assertions)]
104 seen_eof: bool,
105}
106
107impl<'a, 'o, T: SourceCursorSink<'a>> CursorOverlaySink<'a, 'o, T> {
108 pub fn new(source_text: &'a str, overlays: &'o CursorOverlaySet<'a>, sink: T) -> Self {
109 Self {
110 source_text,
111 overlays,
112 sink,
113 processed_overlay_ranges: BTreeMap::new(),
114 next_segment: 0,
115 #[cfg(debug_assertions)]
116 seen_eof: false,
117 }
118 }
119
120 fn flush_segments_up_to(&mut self, limit: SourceOffset, include_after: bool) {
121 let segments = self.overlays.segments();
122 while self.next_segment < segments.len() {
123 let segment = &segments[self.next_segment];
124 if segment.start() > limit {
125 break;
126 }
127 if !include_after && segment.kind() == OverlayKind::InsertAfter && segment.start() == limit {
128 break;
129 }
130 for cursor in segment.cursors() {
131 if cursor.token() != Kind::Eof {
132 self.sink.append(*cursor);
133 }
134 }
135 if !segment.is_insertion() {
136 self.processed_overlay_ranges.insert(segment.start(), segment.end());
137 }
138 self.next_segment += 1;
139 }
140 }
141
142 fn cursor_is_consumed(&self, cursor_start: SourceOffset, cursor_end: SourceOffset) -> bool {
143 self.processed_overlay_ranges
144 .range(..=cursor_start)
145 .next_back()
146 .is_some_and(|(&range_start, &range_end)| cursor_start >= range_start && cursor_end <= range_end)
147 }
148}
149
150impl<'a, 'o, T: SourceCursorSink<'a>> SourceCursorSink<'a> for CursorOverlaySink<'a, 'o, T> {
151 fn append(&mut self, c: SourceCursor<'a>) {
152 let span = c.to_span();
153 let cursor_start = span.start();
154 let cursor_end = span.end();
155
156 self.flush_segments_up_to(cursor_start, false);
157
158 if self.cursor_is_consumed(cursor_start, cursor_end) {
159 return;
160 }
161
162 self.sink.append(c);
163
164 self.flush_segments_up_to(cursor_end, true);
165 }
166}
167
168impl<'a, 'o, T: SourceCursorSink<'a>> CursorSink for CursorOverlaySink<'a, 'o, T> {
169 fn append(&mut self, c: Cursor) {
170 #[cfg(debug_assertions)]
171 {
172 debug_assert!(!self.seen_eof, "Received cursor after EOF: {:?}", c);
173 if c == Kind::Eof {
174 self.seen_eof = true;
175 }
176 }
177
178 SourceCursorSink::append(self, SourceCursor::from(c, c.str_slice(self.source_text)))
179 }
180}
181
182#[cfg(test)]
183mod test {
184 use super::*;
185 use crate::Arena;
186 use crate::Vec;
187 use crate::{
188 ComponentValue, ComponentValues, CursorPrettyWriteSink, CursorToSourceCursorSink, CursorWriteSink,
189 EmptyAtomSet, Parser, QuoteStyle, T, ToCursors, ToSpan,
190 };
191 use css_lexer::Lexer;
192
193 fn snippet_cursors<'a>(alloc: &'a Arena, snippet: &'a str) -> Vec<'a, SourceCursor<'a>> {
194 let lexer = Lexer::new(&EmptyAtomSet::ATOMS, snippet);
195 let mut parser = Parser::new(alloc, snippet, lexer);
196 let parsed = parser.parse_entirely::<ComponentValues<'a>>();
197 let mut cursors = Vec::new_in(alloc);
198 let mut sink = CursorToSourceCursorSink::new(snippet, &mut cursors);
199 parsed.to_cursors(&mut sink);
200 cursors
201 }
202
203 #[test]
204 fn test_basic() {
205 let source_text = "black white";
206 let alloc = Arena::default();
207 let lexer = Lexer::new(&EmptyAtomSet::ATOMS, source_text);
208 let mut p = Parser::new(&alloc, source_text, lexer);
209 let output = p.parse_entirely::<(T![Ident], T![Ident])>().output.unwrap();
210
211 let overlay_text = "green";
212 let lexer = Lexer::new(&EmptyAtomSet::ATOMS, overlay_text);
213 let mut p = Parser::new(&alloc, overlay_text, lexer);
214 let overlay = p.parse_entirely::<T![Ident]>();
215 let mut source_cursors = Vec::new_in(&alloc);
216 let mut sink = CursorToSourceCursorSink::new(overlay_text, &mut source_cursors);
217 overlay.to_cursors(&mut sink);
218 let mut overlays = CursorOverlaySet::new(&alloc);
219 overlays.insert(output.1.to_span(), source_cursors);
220
221 let mut str = String::new();
222 let mut stream = CursorOverlaySink::new(source_text, &overlays, CursorWriteSink::new(source_text, &mut str));
223 output.to_cursors(&mut stream);
224
225 assert_eq!(str, "black green");
226 }
227
228 #[test]
229 fn test_with_pretty_writer() {
230 let source_text = "foo{use:other;}";
231 let alloc = Arena::default();
232 let lexer = Lexer::new(&EmptyAtomSet::ATOMS, source_text);
233 let mut p = Parser::new(&alloc, source_text, lexer);
234 let output = p.parse_entirely::<Vec<'_, ComponentValue>>().output.unwrap();
235 let ComponentValue::SimpleBlock(ref block) = output[1] else { panic!("output[1] was not a block") };
236
237 let overlay_text = "inner{foo: bar;}";
238 let lexer = Lexer::new(&EmptyAtomSet::ATOMS, overlay_text);
239 let mut p = Parser::new(&alloc, overlay_text, lexer);
240 let overlay = p.parse_entirely::<Vec<'_, ComponentValue>>();
241 let mut source_cursors = Vec::new_in(&alloc);
242 let mut sink = CursorToSourceCursorSink::new(overlay_text, &mut source_cursors);
243 overlay.to_cursors(&mut sink);
244 let mut overlays = CursorOverlaySet::new(&alloc);
245 overlays.insert(block.values.to_span(), source_cursors);
246
247 let mut str = String::new();
248 let mut stream = CursorOverlaySink::new(
249 source_text,
250 &overlays,
251 CursorPrettyWriteSink::new(source_text, &mut str, None, QuoteStyle::Double),
252 );
253 output.to_cursors(&mut stream);
254
255 assert_eq!(
256 str,
257 r#"
258foo {
259 inner {
260 foo: bar;
261 }
262}
263 "#
264 .trim()
265 );
266 }
267
268 #[test]
269 fn test_insert_before_and_after() {
270 let source_text = "ab";
271 let alloc = Arena::default();
272 let lexer = Lexer::new(&EmptyAtomSet::ATOMS, source_text);
273 let mut parser = Parser::new(&alloc, source_text, lexer);
274 let output = parser.parse_entirely::<Vec<'_, ComponentValue>>().output.unwrap();
275
276 let mut overlays = CursorOverlaySet::new(&alloc);
277 overlays.push_segment(OverlaySegment::new(
278 Span::new(SourceOffset(0), SourceOffset(0)),
279 snippet_cursors(&alloc, "pre"),
280 OverlayKind::InsertBefore,
281 ));
282 overlays.push_segment(OverlaySegment::new(
283 Span::new(SourceOffset(2), SourceOffset(2)),
284 snippet_cursors(&alloc, "post"),
285 OverlayKind::InsertAfter,
286 ));
287
288 let mut str = String::new();
289 let mut stream = CursorOverlaySink::new(source_text, &overlays, CursorWriteSink::new(source_text, &mut str));
290 output.to_cursors(&mut stream);
291 assert_eq!(str, "pre ab post");
292 }
293
294 #[test]
295 fn test_multiple_inserts_preserve_order() {
296 let source_text = "x";
297 let alloc = Arena::default();
298 let lexer = Lexer::new(&EmptyAtomSet::ATOMS, source_text);
299 let mut parser = Parser::new(&alloc, source_text, lexer);
300 let output = parser.parse_entirely::<Vec<'_, ComponentValue>>().output.unwrap();
301
302 let mut overlays = CursorOverlaySet::new(&alloc);
303 overlays.push_segment(OverlaySegment::new(
304 Span::new(SourceOffset(0), SourceOffset(0)),
305 snippet_cursors(&alloc, "A"),
306 OverlayKind::InsertBefore,
307 ));
308 overlays.push_segment(OverlaySegment::new(
309 Span::new(SourceOffset(0), SourceOffset(0)),
310 snippet_cursors(&alloc, "B"),
311 OverlayKind::InsertBefore,
312 ));
313 overlays.push_segment(OverlaySegment::new(
314 Span::new(SourceOffset(1), SourceOffset(1)),
315 snippet_cursors(&alloc, "C"),
316 OverlayKind::InsertAfter,
317 ));
318 overlays.push_segment(OverlaySegment::new(
319 Span::new(SourceOffset(1), SourceOffset(1)),
320 snippet_cursors(&alloc, "D"),
321 OverlayKind::InsertAfter,
322 ));
323
324 let mut str = String::new();
325 let mut stream = CursorOverlaySink::new(source_text, &overlays, CursorWriteSink::new(source_text, &mut str));
326 output.to_cursors(&mut stream);
327 assert_eq!(str, "A B x C D");
328 }
329}