1use std::io;
2
3use crate::render::{format_hex_dump, write_indent, INDENT_WIDTH};
4use crate::types::{BitPatternField, FixedWidthField, TermAnnotation, Value, VariableLengthField};
5use crate::write::SyntaxWrite;
6
7use super::text::TextRenderError;
8
9const DIM: &str = "\x1b[2m";
10const RESET: &str = "\x1b[0m";
11
12const KW: &str = "\x1b[1;35m";
14const ELEM: &str = "\x1b[1;36m";
16const FIELD: &str = "\x1b[1m";
18const DESC: &str = "\x1b[33m";
20const VAL: &str = "\x1b[32m";
22const COMMENT: &str = "\x1b[2m";
24const PUNCT: &str = "\x1b[2m";
26
27struct FieldColumns {
29 width_col: usize,
30 descriptor_col: usize,
31 value_col: usize,
32}
33
34const COLUMNS: FieldColumns = FieldColumns {
35 width_col: 49,
36 descriptor_col: 58,
37 value_col: 70,
38};
39
40pub struct AnsiRenderer<W> {
42 writer: W,
43 depth: usize,
44 block_stack: Vec<BlockKind>,
45}
46
47#[derive(Debug, Clone, Copy, PartialEq)]
48enum BlockKind {
49 Element,
50 If { taken: bool },
52 For,
53 While,
54 DoWhile,
55 Switch,
56 Case { taken: bool },
57}
58
59impl<W: io::Write> AnsiRenderer<W> {
60 pub fn new(writer: W) -> Self {
61 AnsiRenderer {
62 writer,
63 depth: 0,
64 block_stack: Vec::new(),
65 }
66 }
67
68 pub fn into_inner(self) -> W {
69 self.writer
70 }
71
72 fn indent(&mut self) -> io::Result<()> {
73 write_indent(&mut self.writer, self.depth)
74 }
75
76 fn current_indent_width(&self) -> usize {
77 self.depth * INDENT_WIDTH
78 }
79
80 fn write_fixed_field_line(
81 &mut self,
82 name: &str,
83 comment: Option<&str>,
84 bits: u32,
85 descriptor: &str,
86 value: Option<&Value>,
87 ) -> io::Result<()> {
88 self.indent()?;
89
90 let name_plain = match comment {
92 Some(c) => format!("{FIELD}{name}{RESET} {COMMENT}/* {c} */{RESET}"),
93 None => format!("{FIELD}{name}{RESET}"),
94 };
95 let name_visible_len = match comment {
96 Some(c) => name.len() + 2 + 3 + c.len() + 3, None => name.len(),
98 };
99
100 let indent_w = self.current_indent_width();
101 let name_end = indent_w + name_visible_len;
102
103 let width_str = bits.to_string();
104 let padding1 = if name_end < COLUMNS.width_col {
105 COLUMNS.width_col - name_end
106 } else {
107 1
108 };
109 write!(self.writer, "{name_plain}{:padding1$}{width_str}", "")?;
110
111 let width_end = COLUMNS.width_col + width_str.len();
112 let padding2 = if width_end < COLUMNS.descriptor_col {
113 COLUMNS.descriptor_col - width_end
114 } else {
115 1
116 };
117 write!(self.writer, "{:padding2$}{DESC}{descriptor}{RESET}", "")?;
118
119 if let Some(val) = value {
120 let desc_end = COLUMNS.descriptor_col + descriptor.len();
121 let padding3 = if desc_end < COLUMNS.value_col {
122 COLUMNS.value_col - desc_end
123 } else {
124 1
125 };
126 write!(self.writer, "{:padding3$}= {VAL}{val}{RESET}", "")?;
127 }
128
129 writeln!(self.writer)?;
130 Ok(())
131 }
132
133 fn write_variable_field_line(
134 &mut self,
135 name: &str,
136 comment: Option<&str>,
137 descriptor: &str,
138 value: Option<&Value>,
139 ) -> io::Result<()> {
140 self.indent()?;
141
142 let name_plain = match comment {
143 Some(c) => format!("{FIELD}{name}{RESET} {COMMENT}/* {c} */{RESET}"),
144 None => format!("{FIELD}{name}{RESET}"),
145 };
146 let name_visible_len = match comment {
147 Some(c) => name.len() + 2 + 3 + c.len() + 3,
148 None => name.len(),
149 };
150
151 let indent_w = self.current_indent_width();
152 let name_end = indent_w + name_visible_len;
153
154 let padding1 = if name_end < COLUMNS.descriptor_col {
155 COLUMNS.descriptor_col - name_end
156 } else {
157 1
158 };
159 write!(
160 self.writer,
161 "{name_plain}{:padding1$}{DESC}{descriptor}{RESET}",
162 ""
163 )?;
164
165 if let Some(val) = value {
166 let desc_end = COLUMNS.descriptor_col + descriptor.len();
167 let padding3 = if desc_end < COLUMNS.value_col {
168 COLUMNS.value_col - desc_end
169 } else {
170 1
171 };
172 write!(self.writer, "{:padding3$}= {VAL}{val}{RESET}", "")?;
173 }
174
175 writeln!(self.writer)?;
176 Ok(())
177 }
178
179 fn write_term_annotations(&mut self, terms: &[TermAnnotation<'_>]) -> io::Result<()> {
180 if !terms.is_empty() {
181 let inner: Vec<String> = terms
182 .iter()
183 .map(|t| format!("{}: {}", t.name, t.value))
184 .collect();
185 write!(self.writer, " {COMMENT}/* {} */{RESET}", inner.join(", "))?;
186 }
187 Ok(())
188 }
189}
190
191impl<W: io::Write> SyntaxWrite for AnsiRenderer<W> {
192 type Error = TextRenderError;
193
194 fn begin_element(&mut self, name: &str, params: Option<&str>) -> Result<(), Self::Error> {
195 self.indent()?;
196 match params {
197 Some(p) => writeln!(self.writer, "{ELEM}{name}{RESET}{PUNCT}({RESET}{p}{PUNCT}) {{{RESET}")?,
198 None => writeln!(self.writer, "{ELEM}{name}{RESET}{PUNCT}() {{{RESET}")?,
199 }
200 self.depth += 1;
201 self.block_stack.push(BlockKind::Element);
202 Ok(())
203 }
204
205 fn end_element(&mut self) -> Result<(), Self::Error> {
206 debug_assert_eq!(self.block_stack.pop(), Some(BlockKind::Element));
207 self.depth -= 1;
208 self.indent()?;
209 writeln!(self.writer, "{PUNCT}}}{RESET}")?;
210 Ok(())
211 }
212
213 fn fixed_width_field(&mut self, field: &FixedWidthField<'_>) -> Result<(), Self::Error> {
214 self.write_fixed_field_line(
215 field.name,
216 field.comment,
217 field.bits,
218 field.descriptor,
219 field.value.as_ref(),
220 )?;
221 Ok(())
222 }
223
224 fn variable_length_field(
225 &mut self,
226 field: &VariableLengthField<'_>,
227 ) -> Result<(), Self::Error> {
228 self.write_variable_field_line(
229 field.name,
230 field.comment,
231 field.descriptor,
232 field.value.as_ref(),
233 )?;
234 Ok(())
235 }
236
237 fn bit_pattern(&mut self, field: &BitPatternField<'_>) -> Result<(), Self::Error> {
238 self.write_fixed_field_line(
239 field.name,
240 None,
241 field.bits,
242 field.descriptor,
243 Some(&field.value),
244 )?;
245 Ok(())
246 }
247
248 fn raw_bytes(&mut self, data: &[u8]) -> Result<(), Self::Error> {
249 let lines = format_hex_dump(data);
250 for line in &lines {
251 self.indent()?;
252 writeln!(self.writer, "{DIM}{line}{RESET}")?;
253 }
254 Ok(())
255 }
256
257 fn begin_if(
258 &mut self,
259 condition: &str,
260 terms: &[TermAnnotation<'_>],
261 taken: bool,
262 ) -> Result<(), Self::Error> {
263 self.indent()?;
264 if taken {
265 write!(self.writer, "{KW}if{RESET} {PUNCT}({RESET}{condition}{PUNCT}) {{{RESET}")?;
266 } else {
267 write!(self.writer, "{DIM}if ({condition}) {{{RESET}")?;
268 }
269 self.write_term_annotations(terms)?;
270 writeln!(self.writer)?;
271 self.depth += 1;
272 self.block_stack.push(BlockKind::If { taken });
273 Ok(())
274 }
275
276 fn begin_else_if(
277 &mut self,
278 condition: &str,
279 terms: &[TermAnnotation<'_>],
280 taken: bool,
281 ) -> Result<(), Self::Error> {
282 debug_assert!(matches!(self.block_stack.last(), Some(BlockKind::If { .. })));
283 self.depth -= 1;
284 self.indent()?;
285 if taken {
286 write!(
287 self.writer,
288 "{PUNCT}}}{RESET} {KW}else if{RESET} {PUNCT}({RESET}{condition}{PUNCT}) {{{RESET}"
289 )?;
290 } else {
291 write!(
292 self.writer,
293 "{DIM}}} else if ({condition}) {{{RESET}"
294 )?;
295 }
296 self.write_term_annotations(terms)?;
297 writeln!(self.writer)?;
298 self.depth += 1;
299 if let Some(BlockKind::If { taken: t }) = self.block_stack.last_mut() {
301 *t = taken;
302 }
303 Ok(())
304 }
305
306 fn begin_else(&mut self, taken: bool) -> Result<(), Self::Error> {
307 debug_assert!(matches!(self.block_stack.last(), Some(BlockKind::If { .. })));
308 self.depth -= 1;
309 self.indent()?;
310 if taken {
311 writeln!(self.writer, "{PUNCT}}}{RESET} {KW}else{RESET} {PUNCT}{{{RESET}")?;
312 } else {
313 writeln!(self.writer, "{DIM}}} else {{{RESET}")?;
314 }
315 self.depth += 1;
316 if let Some(BlockKind::If { taken: t }) = self.block_stack.last_mut() {
317 *t = taken;
318 }
319 Ok(())
320 }
321
322 fn end_if(&mut self) -> Result<(), Self::Error> {
323 let block = self.block_stack.pop();
324 debug_assert!(matches!(block, Some(BlockKind::If { .. })));
325 let taken = matches!(block, Some(BlockKind::If { taken: true }));
326 self.depth -= 1;
327 self.indent()?;
328 if taken {
329 writeln!(self.writer, "{PUNCT}}}{RESET}")?;
330 } else {
331 writeln!(self.writer, "{DIM}}}{RESET}")?;
332 }
333 Ok(())
334 }
335
336 fn begin_for(
337 &mut self,
338 header: &str,
339 terms: &[TermAnnotation<'_>],
340 ) -> Result<(), Self::Error> {
341 self.indent()?;
342 write!(self.writer, "{KW}for{RESET} {PUNCT}({RESET}{header}{PUNCT}) {{{RESET}")?;
343 self.write_term_annotations(terms)?;
344 writeln!(self.writer)?;
345 self.depth += 1;
346 self.block_stack.push(BlockKind::For);
347 Ok(())
348 }
349
350 fn for_iteration(&mut self, variable: &str, index: u64) -> Result<(), Self::Error> {
351 self.indent()?;
352 writeln!(self.writer, "{COMMENT}/* {variable}: {index} */{RESET}")?;
353 Ok(())
354 }
355
356 fn end_for(&mut self) -> Result<(), Self::Error> {
357 debug_assert_eq!(self.block_stack.pop(), Some(BlockKind::For));
358 self.depth -= 1;
359 self.indent()?;
360 writeln!(self.writer, "{PUNCT}}}{RESET}")?;
361 Ok(())
362 }
363
364 fn begin_while(&mut self, condition: &str) -> Result<(), Self::Error> {
365 self.indent()?;
366 writeln!(self.writer, "{KW}while{RESET} {PUNCT}({RESET}{condition}{PUNCT}) {{{RESET}")?;
367 self.depth += 1;
368 self.block_stack.push(BlockKind::While);
369 Ok(())
370 }
371
372 fn while_iteration(&mut self, index: u64) -> Result<(), Self::Error> {
373 self.indent()?;
374 writeln!(self.writer, "{COMMENT}/* iteration: {index} */{RESET}")?;
375 Ok(())
376 }
377
378 fn end_while(&mut self) -> Result<(), Self::Error> {
379 debug_assert_eq!(self.block_stack.pop(), Some(BlockKind::While));
380 self.depth -= 1;
381 self.indent()?;
382 writeln!(self.writer, "{PUNCT}}}{RESET}")?;
383 Ok(())
384 }
385
386 fn begin_do_while(&mut self) -> Result<(), Self::Error> {
387 self.indent()?;
388 writeln!(self.writer, "{KW}do{RESET} {PUNCT}{{{RESET}")?;
389 self.depth += 1;
390 self.block_stack.push(BlockKind::DoWhile);
391 Ok(())
392 }
393
394 fn do_while_iteration(&mut self, index: u64) -> Result<(), Self::Error> {
395 self.indent()?;
396 writeln!(self.writer, "{COMMENT}/* iteration: {index} */{RESET}")?;
397 Ok(())
398 }
399
400 fn end_do_while(&mut self, condition: &str) -> Result<(), Self::Error> {
401 debug_assert_eq!(self.block_stack.pop(), Some(BlockKind::DoWhile));
402 self.depth -= 1;
403 self.indent()?;
404 writeln!(
405 self.writer,
406 "{PUNCT}}}{RESET} {KW}while{RESET} {PUNCT}({RESET}{condition}{PUNCT}){RESET}"
407 )?;
408 Ok(())
409 }
410
411 fn begin_switch(
412 &mut self,
413 expression: &str,
414 terms: &[TermAnnotation<'_>],
415 ) -> Result<(), Self::Error> {
416 self.indent()?;
417 write!(self.writer, "{KW}switch{RESET} {PUNCT}({RESET}{expression}{PUNCT}) {{{RESET}")?;
418 self.write_term_annotations(terms)?;
419 writeln!(self.writer)?;
420 self.depth += 1;
421 self.block_stack.push(BlockKind::Switch);
422 Ok(())
423 }
424
425 fn begin_case(&mut self, label: &str, taken: bool) -> Result<(), Self::Error> {
426 self.indent()?;
427 if taken {
428 writeln!(self.writer, "{KW}case{RESET} {label}:")?;
429 } else {
430 writeln!(self.writer, "{DIM}case {label}:{RESET}")?;
431 }
432 self.depth += 1;
433 self.block_stack.push(BlockKind::Case { taken });
434 Ok(())
435 }
436
437 fn end_case(&mut self) -> Result<(), Self::Error> {
438 let block = self.block_stack.pop();
439 debug_assert!(matches!(block, Some(BlockKind::Case { .. })));
440 let taken = matches!(block, Some(BlockKind::Case { taken: true }));
441 self.indent()?;
442 if taken {
443 writeln!(self.writer, "{KW}break{RESET}")?;
444 } else {
445 writeln!(self.writer, "{DIM}break{RESET}")?;
446 }
447 self.depth -= 1;
448 Ok(())
449 }
450
451 fn end_switch(&mut self) -> Result<(), Self::Error> {
452 debug_assert_eq!(self.block_stack.pop(), Some(BlockKind::Switch));
453 self.depth -= 1;
454 self.indent()?;
455 writeln!(self.writer, "{PUNCT}}}{RESET}")?;
456 Ok(())
457 }
458
459 fn assignment(
460 &mut self,
461 expression: &str,
462 computed_value: Option<&Value>,
463 ) -> Result<(), Self::Error> {
464 self.indent()?;
465 match computed_value {
466 Some(val) => {
467 let width = COLUMNS
468 .value_col
469 .saturating_sub(self.current_indent_width() + expression.len());
470 writeln!(
471 self.writer,
472 "{expression}{:width$}{COMMENT}/* = {VAL}{val}{COMMENT} */{RESET}",
473 ""
474 )?;
475 }
476 None => writeln!(self.writer, "{expression}")?,
477 }
478 Ok(())
479 }
480
481 fn comment(&mut self, text: &str) -> Result<(), Self::Error> {
482 self.indent()?;
483 writeln!(self.writer, "{COMMENT}/* {text} */{RESET}")?;
484 Ok(())
485 }
486
487 fn ellipsis(&mut self) -> Result<(), Self::Error> {
488 self.indent()?;
489 writeln!(self.writer, "...")?;
490 Ok(())
491 }
492}