glass_easel_stylesheet_compiler/
output.rs1use std::fmt::Write;
2
3use cssparser::{ToCss, Token, TokenSerializationType};
4use sourcemap::{SourceMap, SourceMapBuilder};
5
6use crate::step::StepToken;
7
8pub struct StyleSheetOutput {
9 s: String,
10 prev_ser_type: TokenSerializationType,
11 source_map: SourceMapBuilder,
12 source_id: u32,
13 utf16_len: u32,
14}
15
16impl StyleSheetOutput {
17 pub(crate) fn new(path: &str, source_css: &str) -> Self {
18 let mut source_map = SourceMapBuilder::new(None);
19 let source_id = source_map.add_source(path);
20 source_map.set_source_contents(source_id, Some(source_css));
21 Self {
22 s: String::new(),
23 prev_ser_type: TokenSerializationType::Nothing,
24 source_id,
25 source_map,
26 utf16_len: 0,
27 }
28 }
29
30 pub fn write(&self, mut w: impl std::io::Write) -> std::io::Result<()> {
31 w.write_all(self.s.as_bytes())
32 }
33
34 pub fn write_str(&self, mut w: impl std::fmt::Write) -> std::fmt::Result {
35 write!(w, "{}", self.s)
36 }
37
38 pub fn write_source_map(self, w: impl std::io::Write) -> Result<(), sourcemap::Error> {
39 self.source_map.into_sourcemap().to_writer(w)
40 }
41
42 pub fn extract_source_map(self) -> SourceMap {
43 self.source_map.into_sourcemap()
44 }
45
46 pub(crate) fn cur_utf8_len(&self) -> usize {
47 self.s.len()
48 }
49
50 pub(crate) fn get_output_segment(&self, range: std::ops::Range<usize>) -> &str {
51 &self.s[range]
52 }
53
54 pub(crate) fn append_raw(&mut self, s: &str) {
55 self.prev_ser_type = TokenSerializationType::Nothing;
56 let output_start_pos = self.s.len();
57 self.s += s;
58 self.utf16_len += str::encode_utf16(&self.s[output_start_pos..]).count() as u32;
59 }
60
61 pub(crate) fn append_token(&mut self, token: StepToken, src: Option<Token>) {
62 let next_ser_type = token.serialization_type();
63 if self
64 .prev_ser_type
65 .needs_separator_when_before(next_ser_type)
66 {
67 write!(&mut self.s, " ").unwrap();
68 self.utf16_len += 1;
69 }
70 self.prev_ser_type = next_ser_type;
71 let output_start_pos = self.s.len();
72 token.to_css(&mut self.s).unwrap();
73 let name = src.map(|x| {
74 let s = x.to_css_string();
75 self.source_map.add_name(&s)
76 });
77 self.source_map.add_raw(
78 0,
79 self.utf16_len,
80 token.position.line,
81 token.position.utf16_col,
82 Some(self.source_id),
83 name,
84 );
85 self.utf16_len += str::encode_utf16(&self.s[output_start_pos..]).count() as u32;
86 }
87
88 pub(crate) fn append_token_space_preserved(&mut self, token: StepToken, src: Option<Token>) {
89 if let Token::WhiteSpace(_) = &*token {
90 self.prev_ser_type = token.serialization_type();
91 self.s.push(' ');
92 self.utf16_len += 1;
93 } else {
94 self.append_token(token, src);
95 }
96 }
97}