1use std::collections::HashMap;
2use std::iter::zip;
3use std::sync::LazyLock;
4
5use ratatui::buffer::Buffer;
6use ratatui::layout::Rect;
7use ratatui::widgets::Widget;
8
9pub struct BoxChar(char);
10
11impl BoxChar {
12 pub const fn new(c: char) -> Self {
13 Self(c)
14 }
15}
16
17impl Widget for &BoxChar {
18 fn render(self, area: Rect, buf: &mut Buffer) {
19 let c = self
20 .0
21 .to_uppercase() .next()
23 .and_then(|c| CHARS.get(&c))
24 .unwrap_or(&" ");
25 let lines = c.lines().collect::<Vec<_>>();
26 for (line, row) in zip(lines, area.rows()) {
27 for (char, cell) in zip(line.chars(), row.columns()) {
28 buf[cell.as_position()].set_symbol(&char.to_string());
29 }
30 }
31 }
32}
33
34macro_rules! char_table {
36 ( $($char:expr => $repr:expr),* $(,)? ) => {
37 {
38 let mut table = ::std::collections::HashMap::new();
39 $(
40 table.insert($char, ::indoc::indoc! {$repr});
41 )*
42 table
43 }
44 };
45}
46
47static CHARS: LazyLock<HashMap<char, &str>> = LazyLock::new(|| {
50 char_table!(
51 ' ' => " ",
52 '!' => "│
53 ╵
54 ╵",
55 '"' => "╭╭",
56 '#' => "┼─┼
57 ┼─┼",
58 '$' => "╭┼╴
59 └┼┐
60 ╶┼╯",
61 '%' => "o╱
62 ╱o",
63 '&' => "╭─╮
64 ╭╲╯
65 ╰─╲",
66 '\'' => "╭",
67 '(' => "╭
68 │
69 ╰",
70 ')' => "╮
71 │
72 ╯",
73 '*' => "
74
75 *
76 ",
77 '+' => "
78 ╷
79 ╶┼╴
80 ╵",
81 ',' => "
82
83
84 ╯",
85 '-' => "
86
87 ──
88 ",
89 '.' => "
90
91 .
92 ",
93 '/' => "
94 ╱
95 ╱
96 ",
97 '0' => "╭─╮
98 │╱│
99 ╰─╯",
100 '1' => "
101 ╶┐
102 │
103 ─┴─",
104 '2' => "╶─╮
105 ┌─┘
106 └─╴",
107 '3' => "╶─╮
108 ╶─┤
109 ╶─╯",
110 '4' => "╷ ╷
111 ╰─┤
112 ╵",
113 '5' => "┌─╴
114 └─╮
115 ╰─╯",
116 '6' => "╭─╴
117 ├─╮
118 ╰─╯",
119 '7' => "╶─┐
120 ╱
121 ╵ ",
122 '8' => "╭─╮
123 ├─┤
124 ╰─╯",
125 '9' => "╭─╮
126 ╰─┤
127 ╶─╯",
128 ':' => "╷
129 ╵
130 │
131 ",
132 ';' => "╷
133 ╵
134 ╯",
135 '<' => "
136 ╱
137 ╲
138 ",
139 '=' => "
140 ──
141 ──",
142 '>' => "
143 ╲
144 ╱
145 ",
146 '?' => "
147 ╶─╮
148 ╭╯
149 ╷",
150 '@' => "╭─╮
151 ╭╮│
152 ╰┴╯",
153 'A' => "╭─╮
154 ├─┤
155 ╵ ╵",
156 'B' => "┌╮
157 ├┴╮
158 ╰─╯",
159 'C' => "╭─╮
160 │
161 ╰─╯",
162 'D' => "┌─╮
163 │ │
164 └─╯",
165 'E' => "┌─╴
166 ├─
167 └─╴",
168 'F' => "┌─╴
169 ├─
170 ╵ ",
171 'G' => "╭─╮
172 │─╮
173 ╰─╯",
174 'H' => "╷ ╷
175 ├─┤
176 ╵ ╵",
177 'I' => "╶┬╴
178 │
179 ╶┴╴",
180 'J' => " ╶┐
181 │
182 ╰─╯",
183 'K' => "╷╭
184 ├┴╮
185 ╵ ╵",
186 'L' => "╷
187 │
188 └──",
189 'M' => "╭┬╮
190 │││
191 ╵╵╵",
192 'N' => "╭─╮
193 │ │
194 ╵ ╵",
195 'O' => "╭─╮
196 │ │
197 ╰─╯",
198 'P' => "┌─╮
199 ├─╯
200 ╵ ",
201 'Q' => "╭─╮
202 │ │
203 ╰─╳",
204 'R' => "┌─╮
205 ├┬╯
206 ╵╰ ",
207 'S' => "╭─╮
208 ╰─╮
209 ╰─╯",
210 'T' => "
211 ╶┬╴
212 │
213 ╵",
214 'U' => "╷ ╷
215 │ │
216 ╰─╯",
217 'V' => "╷ ╷
218 │ │
219 └─╯",
220 'W' => "╷╷╷
221 │││
222 ╰┴╯",
223 'X' => "╮ ╭
224 ╰─╮
225 ╯ ╰",
226 'Y' => "╮ ╭
227 ╰┬╯
228 ╵",
229 'Z' => "╶─╮
230 ╱
231 ╰─╴",
232 '[' => "┌─
233 │
234 └─",
235 '\\' => "
236 ╲
237 ╲
238 ",
239 ']' => "─┐
240 │
241 ─┘",
242 '^' => "╱╲",
243 '_' => "
244
245 ──",
246 '`' => "╮",
247 '{' => "
248 ╭
249 ┤
250 ╰",
251 '|' => "│
252 │
253 │",
254 '}' => "╮
255 ├
256 ╯",
257 '~' => "
258 ╭╮
259 ╰╯",
260 )
261});