1use std::str::Chars;
2
3struct Lexer<'a> {
4 chars: Chars<'a>,
5}
6
7impl<'a> Lexer<'a> {
8 fn new(s: &'a str) -> Self {
9 let chars = s.chars();
10 Lexer { chars }
11 }
12}
13
14#[derive(Debug, Clone)]
15pub enum Token {
16 Char(char),
17 Color(u32),
18 Bold,
19 Reset,
20 Up(u32),
21 Down(u32),
22 Left(u32),
23 Right(u32),
24}
25
26impl<'a> Iterator for Lexer<'a> {
27 type Item = Token;
28
29 fn next(&mut self) -> Option<Self::Item> {
30 let c = self.chars.next()?;
31 if c.is_ascii_control() && c != '\n' {
32 match self.chars.next()? {
33 '[' => {
34 let mut num = 0;
35 let t = loop {
36 let n = self.chars.next()?;
37 if n.is_numeric() {
38 num = num * 10 + (n.to_digit(10)?);
39 } else {
40 break n;
41 }
42 };
43
44 match c {
45 '\x1b' => match t {
46 'm' | 'M' => {
47 if num == 0 {
48 return Some(Token::Reset);
49 }
50 if num == 1 {
51 return Some(Token::Bold);
52 }
53 Some(Token::Color(num))
54 }
55 'a' | 'A' => Some(Token::Up(num)),
56 'b' | 'B' => Some(Token::Down(num)),
57 'c' | 'C' => Some(Token::Right(num)),
58 'd' | 'D' => Some(Token::Left(num)),
59 _ => {
60 self.next()
61 }
62 },
63 _ => {
64 todo!()
65 }
66 }
67 }
68 '\n' => self.next(),
69 _ => {
70 todo!()
71 }
72 }
73 } else {
74 Some(Token::Char(c))
75 }
76 }
77}
78
79#[derive(Debug, Clone)]
80pub struct AnsiColor(pub u32);
81
82impl AnsiColor {
83 pub fn new(c: u32) -> Self {
84 AnsiColor(c)
85 }
86
87 pub fn to_rgb(&self) -> &'static str {
88 match self.0 {
89 30 | 40 => "rgb(0,0,0)",
90 31 | 41 => "rgb(205, 49, 49)",
91 32 | 42 => "rgb(13, 188, 121)",
92 33 | 43 => "rgb(229, 229, 16)",
93 34 | 44 => "rgb(36, 114, 200)",
94 35 | 45 => "rgb(188, 63, 188)",
95 36 | 46 => "rgb(17, 168, 205)",
96 37 | 47 => "rgb(229, 229, 229)",
97
98 90 | 100 => "rgb(102, 102, 102)",
99 91 | 101 => "rgb(241, 76, 76)",
100 92 | 102 => "rgb(35, 209, 139)",
101 93 | 103 => "rgb(245, 245, 67)",
102 94 | 104 => "rgb(59, 142, 234)",
103 95 | 105 => "rgb(214, 112, 214)",
104 96 | 106 => "rgb(41, 184, 219)",
105 97 | 107 => "rgb(229, 229, 229)",
106 _ => "white",
107 }
108 }
109}
110
111#[derive(Debug, Clone)]
112pub struct Node {
113 pub bg_color: AnsiColor,
114 pub color: AnsiColor,
115 pub bold: bool,
116 pub char: char,
117}
118
119#[derive(Debug, Clone)]
120pub struct Canvas {
121 pub pixels: Vec<Vec<Node>>,
122 pub w: usize,
123 pub h: usize,
124}
125
126fn set_node(v: &mut Vec<Vec<Node>>, node: Node, x: usize, y: usize) {
127 while y >= v.len() {
128 v.push(Vec::new());
129 }
130
131 let row = &mut v[y];
132 while x >= row.len() {
133 let mut empty = node.clone();
134 empty.char = ' ';
135 row.push(empty);
136 }
137
138 row[x] = node;
139}
140
141impl Canvas {
142 pub fn new(s: &str) -> Self {
143 let lex = Lexer::new(s);
144
145 let mut cur_x = 0;
146 let mut cur_y = 0;
147 let mut cur_c = 0;
148 let mut cur_bg_c = 0;
149 let mut bold = false;
150 let mut w = 0;
151 let mut h = 0;
152 let mut pixels = Vec::new();
153
154 for i in lex {
155 match i {
156 Token::Char(c) => {
157 if c == '\n' {
158 cur_y += 1;
159 cur_x = 0;
160 } else {
161 let node = Node {
162 char: c,
163 bg_color: AnsiColor::new(cur_bg_c),
164 color: AnsiColor::new(cur_c),
165 bold,
166 };
167 set_node(&mut pixels, node, cur_x, cur_y);
168 cur_x += 1;
169 }
170
171 w = w.max(cur_x + 1);
172 h = h.max(cur_y + 1);
173 }
174 Token::Color(c) => {
175 if (40..=47).contains(&c) | (100..=107).contains(&c) {
176 cur_bg_c = c
177 } else {
178 cur_c = c
179 }
180 }
181 Token::Bold => bold = true,
182 Token::Reset => {
183 bold = false;
184 cur_c = 0;
185 cur_bg_c = 0;
186 }
187 Token::Up(c) => {
188 if cur_y > c as usize {
189 cur_y -= c as usize
190 } else {
191 cur_y = 0;
192 }
193 }
194 Token::Down(c) => {
195 cur_y += c as usize;
196 }
197 Token::Left(c) => {
198 if cur_x > c as usize {
199 cur_x -= c as usize
200 } else {
201 cur_x = 0;
202 }
203 }
204 Token::Right(c) => {
205 cur_x += c as usize;
206 }
207 }
208 }
209
210 Canvas { pixels, w, h }
211 }
212}