Skip to main content

mpeg_syntax_dump/render/
ansi.rs

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
12/// Bold magenta for keywords (if, for, while, else, do)
13const KW: &str = "\x1b[1;35m";
14/// Bold cyan for element names
15const ELEM: &str = "\x1b[1;36m";
16/// Bold for field names (the actual bitstream data fields)
17const FIELD: &str = "\x1b[1m";
18/// Yellow for descriptors
19const DESC: &str = "\x1b[33m";
20/// Green for values
21const VAL: &str = "\x1b[32m";
22/// Dim for comments/annotations
23const COMMENT: &str = "\x1b[2m";
24/// Dim for structural punctuation ({, }, (, ))
25const PUNCT: &str = "\x1b[2m";
26
27/// Column positions (same as PlainTextRenderer).
28struct 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
40/// ANSI-colored renderer that writes MPEG syntax with color codes.
41pub 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    /// Tracks whether the most recent branch in this if/else chain was taken.
51    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        // Name portion (with optional inline comment)
91        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, // name + "  " + "/* " + comment + " */"
97            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        // Update the tracked taken state for this if-chain
300        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}