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