1use crate::{
2 Cursor, CursorSink, CursorToSourceCursorSink, Kind, ParserReturn, SourceCursor, SourceCursorSink, SourceOffset,
3 Span, ToCursors, ToSpan,
4};
5use bumpalo::{Bump, collections::Vec};
6use std::collections::BTreeMap;
7
8#[derive(Debug)]
9pub struct CursorOverlaySet<'a> {
10 bump: &'a Bump,
11 overlays: BTreeMap<SourceOffset, (SourceOffset, Vec<'a, SourceCursor<'a>>)>,
12}
13
14impl<'a> CursorOverlaySet<'a> {
15 pub fn new(bump: &'a Bump) -> Self {
16 Self { bump, overlays: BTreeMap::new() }
17 }
18
19 pub fn insert<T: ToCursors>(&mut self, span: Span, parser_return: ParserReturn<'a, T>) {
20 let start = span.start();
21 let end = span.end();
22 let mut cursors = Vec::new_in(self.bump);
23 let mut sink = CursorToSourceCursorSink::new(parser_return.source_text, &mut cursors);
24 parser_return.to_cursors(&mut sink);
25 self.overlays.insert(start, (end, cursors));
26 }
27
28 pub(crate) fn find(&self, end: SourceOffset) -> Option<&(SourceOffset, Vec<'a, SourceCursor<'a>>)> {
29 self.overlays.range(..=end).rev().find(|&(_, &(overlay_end, _))| end < overlay_end).map(|(_, ret)| ret)
30 }
31}
32
33#[derive(Debug)]
42pub struct CursorOverlaySink<'a, T: SourceCursorSink<'a>> {
43 source_text: &'a str,
44 overlays: &'a CursorOverlaySet<'a>,
45 sink: T,
46 processed_overlay_ranges: BTreeMap<SourceOffset, SourceOffset>,
47 #[cfg(debug_assertions)]
48 seen_eof: bool,
49}
50
51impl<'a, T: SourceCursorSink<'a>> CursorOverlaySink<'a, T> {
52 pub fn new(source_text: &'a str, overlays: &'a CursorOverlaySet<'a>, sink: T) -> Self {
53 Self {
54 source_text,
55 overlays,
56 sink,
57 processed_overlay_ranges: BTreeMap::new(),
58 #[cfg(debug_assertions)]
59 seen_eof: false,
60 }
61 }
62}
63
64impl<'a, T: SourceCursorSink<'a>> SourceCursorSink<'a> for CursorOverlaySink<'a, T> {
65 fn append(&mut self, c: SourceCursor<'a>) {
66 let cursor_start = c.to_span().start();
67 let cursor_end = c.to_span().end();
68
69 if let Some((&range_start, &range_end)) = self.processed_overlay_ranges.range(..=cursor_start).next_back()
72 && cursor_start >= range_start
73 && cursor_end <= range_end
74 {
75 return;
77 }
78
79 let mut pos = cursor_start;
80 while pos < cursor_end {
81 if let Some((overlay_end, overlay)) = self.overlays.find(pos) {
83 for c in overlay {
84 if *c != Kind::Eof {
85 self.sink.append(*c);
86 }
87 }
88 self.processed_overlay_ranges.insert(pos, *overlay_end);
89 pos = *overlay_end;
90 } else {
91 self.sink.append(c);
92 pos = c.to_span().end();
93 }
94 }
95 }
96}
97
98impl<'a, T: SourceCursorSink<'a>> CursorSink for CursorOverlaySink<'a, T> {
99 fn append(&mut self, c: Cursor) {
100 #[cfg(debug_assertions)]
101 {
102 debug_assert!(!self.seen_eof, "Received cursor after EOF: {:?}", c);
103 if c == Kind::Eof {
104 self.seen_eof = true;
105 }
106 }
107
108 SourceCursorSink::append(self, SourceCursor::from(c, c.str_slice(self.source_text)))
109 }
110}
111
112#[cfg(test)]
113mod test {
114 use super::*;
115 use crate::{
116 ComponentValue, CursorPrettyWriteSink, CursorWriteSink, EmptyAtomSet, Parser, QuoteStyle, T, ToCursors, ToSpan,
117 };
118 use bumpalo::{Bump, collections::Vec};
119 use css_lexer::Lexer;
120
121 #[test]
122 fn test_basic() {
123 let source_text = "black white";
125 let bump = Bump::default();
126 let lexer = Lexer::new(&EmptyAtomSet::ATOMS, source_text);
127 let mut p = Parser::new(&bump, source_text, lexer);
128 let output = p.parse_entirely::<(T![Ident], T![Ident])>().output.unwrap();
129
130 let overlay_text = "green";
132 let lexer = Lexer::new(&EmptyAtomSet::ATOMS, overlay_text);
133 let mut p = Parser::new(&bump, overlay_text, lexer);
134 let overlay = p.parse_entirely::<T![Ident]>();
135 let mut overlays = CursorOverlaySet::new(&bump);
136 overlays.insert(output.1.to_span(), overlay);
137
138 let mut str = String::new();
140 let mut stream = CursorOverlaySink::new(source_text, &overlays, CursorWriteSink::new(source_text, &mut str));
141 output.to_cursors(&mut stream);
142
143 assert_eq!(str, "black green");
145 }
146
147 #[test]
148 fn test_with_pretty_writer() {
149 let source_text = "foo{use:other;}";
151 let bump = Bump::default();
152 let lexer = Lexer::new(&EmptyAtomSet::ATOMS, source_text);
153 let mut p = Parser::new(&bump, source_text, lexer);
154 let output = p.parse_entirely::<Vec<'_, ComponentValue>>().output.unwrap();
155 let ComponentValue::SimpleBlock(ref block) = output[1] else { panic!("output[1] was not a block") };
156 dbg!(block.to_span(), block.values.to_span());
157
158 let overlay_text = "inner{foo: bar;}";
160 let lexer = Lexer::new(&EmptyAtomSet::ATOMS, overlay_text);
161 let mut p = Parser::new(&bump, overlay_text, lexer);
162 let overlay = p.parse_entirely::<Vec<'_, ComponentValue>>();
163 let mut overlays = CursorOverlaySet::new(&bump);
164 overlays.insert(dbg!(block.values.to_span()), overlay);
165
166 let mut str = String::new();
168 let mut stream = CursorOverlaySink::new(
169 source_text,
170 &overlays,
171 CursorPrettyWriteSink::new(source_text, &mut str, None, QuoteStyle::Double),
172 );
173 output.to_cursors(&mut stream);
174
175 assert_eq!(
177 str,
178 r#"
179foo {
180 inner {
181 foo: bar;
182 }
183}
184 "#
185 .trim()
186 );
187 }
188}