1use crate::ansi::{Ground, color_to_ansi, emphasis_to_ansi};
2use crate::lexer::{TagType, Token};
3
4pub fn render(tokens: Vec<Token>) -> String {
10 let mut result = String::new();
11 for tok in tokens {
12 match tok {
13 Token::Text(text) => result.push_str(text.as_str()),
14 Token::Tag(tag) => match tag {
15 TagType::Color(color) => {
16 result.push_str(color_to_ansi(&color, Ground::Foreground).as_str())
17 }
18 TagType::Emphasis(emphasis) => {
19 result.push_str(emphasis_to_ansi(&emphasis).as_str())
20 }
21 TagType::Reset => result.push_str("\x1b[0m"),
22 },
23 }
24 }
25
26 result
27}
28
29#[cfg(test)]
30mod tests {
31 use super::*;
32 use crate::ansi::{Color, NamedColor};
33 use crate::lexer::{EmphasisType, TagType, Token};
34
35 #[test]
38 fn test_render_empty_token_list() {
39 let result = render(vec![]);
40 assert_eq!(result, "");
41 }
42
43 #[test]
44 fn test_render_plain_text_token() {
45 let result = render(vec![Token::Text("hello".into())]);
46 assert_eq!(result, "hello");
47 }
48
49 #[test]
50 fn test_render_named_color_tag() {
51 let result = render(vec![Token::Tag(TagType::Color(Color::Named(
52 NamedColor::Red,
53 )))]);
54 assert_eq!(result, "\x1b[31m");
55 }
56
57 #[test]
58 fn test_render_emphasis_tag_bold() {
59 let result = render(vec![Token::Tag(TagType::Emphasis(EmphasisType::Bold))]);
60 assert_eq!(result, "\x1b[1m");
61 }
62
63 #[test]
64 fn test_render_reset_tag() {
65 let result = render(vec![Token::Tag(TagType::Reset)]);
66 assert_eq!(result, "\x1b[0m");
67 }
68
69 #[test]
70 fn test_render_color_then_text() {
71 let result = render(vec![
72 Token::Tag(TagType::Color(Color::Named(NamedColor::Red))),
73 Token::Text("hello".into()),
74 ]);
75 assert_eq!(result, "\x1b[31mhello");
76 }
77
78 #[test]
79 fn test_render_color_text_reset() {
80 let result = render(vec![
81 Token::Tag(TagType::Color(Color::Named(NamedColor::Green))),
82 Token::Text("go".into()),
83 Token::Tag(TagType::Reset),
84 ]);
85 assert_eq!(result, "\x1b[32mgo\x1b[0m");
86 }
87
88 #[test]
89 fn test_render_multiple_text_tokens() {
90 let result = render(vec![Token::Text("foo".into()), Token::Text("bar".into())]);
91 assert_eq!(result, "foobar");
92 }
93
94 #[test]
95 fn test_render_ansi256_color_tag() {
96 let result = render(vec![Token::Tag(TagType::Color(Color::Ansi256(21)))]);
97 assert_eq!(result, "\x1b[38;5;21m");
98 }
99
100 #[test]
101 fn test_render_rgb_color_tag() {
102 let result = render(vec![Token::Tag(TagType::Color(Color::Rgb(255, 0, 0)))]);
103 assert_eq!(result, "\x1b[38;2;255;0;0m");
104 }
105
106 #[test]
107 fn test_render_does_not_append_trailing_reset() {
108 let result = render(vec![Token::Text("plain".into())]);
110 assert!(!result.ends_with("\x1b[0m"));
111 }
112}
113
114