tui_box_text/lib.rs
1use std::{collections::HashMap, iter::zip, sync::LazyLock};
2
3use ratatui::{buffer::Buffer, layout::Rect, widgets::Widget};
4
5pub struct BoxChar(char);
6
7impl BoxChar {
8 pub fn new(c: char) -> Self {
9 Self(c)
10 }
11}
12
13impl Widget for &BoxChar {
14 fn render(self, area: Rect, buf: &mut Buffer) {
15 let c = self
16 .0
17 .to_uppercase() // TODO: add support for lower case characters
18 .next()
19 .and_then(|c| CHARS.get(&c))
20 .unwrap_or(&" ");
21 let lines = c.lines().collect::<Vec<_>>();
22 for (line, row) in zip(lines, area.rows()) {
23 for (char, cell) in zip(line.chars(), row.columns()) {
24 buf[cell.as_position()].set_symbol(&char.to_string());
25 }
26 }
27 }
28}
29
30/// A macro for creating a hash table that maps single characters to strings.
31macro_rules! char_table {
32 ( $($char:expr => $repr:expr),* $(,)? ) => {
33 {
34 let mut table = ::std::collections::HashMap::new();
35 $(
36 table.insert($char, ::indoc::indoc! {$repr});
37 )*
38 table
39 }
40 };
41}
42
43/// A hash table that maps single characters to strings that are 3 lines high and made up of box
44/// drawing characters.
45static CHARS: LazyLock<HashMap<char, &str>> = LazyLock::new(|| {
46 char_table!(
47 ' ' => " ",
48 '!' => "│
49 ╵
50 ╵",
51 '"' => "╭╭",
52 '#' => "┼─┼
53 ┼─┼",
54 '$' => "╭┼╴
55 └┼┐
56 ╶┼╯",
57 '%' => "o╱
58 ╱o",
59 '&' => "╭─╮
60 ╭╲╯
61 ╰─╲",
62 '\'' => "╭",
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 '0' => "╭─╮
94 │╱│
95 ╰─╯",
96 '1' => "
97 ╶┐
98 │
99 ─┴─",
100 '2' => "╶─╮
101 ┌─┘
102 └─╴",
103 '3' => "╶─╮
104 ╶─┤
105 ╶─╯",
106 '4' => "╷ ╷
107 ╰─┤
108 ╵",
109 '5' => "┌─╴
110 └─╮
111 ╰─╯",
112 '6' => "╭─╴
113 ├─╮
114 ╰─╯",
115 '7' => "╶─┐
116 ╱
117 ╵ ",
118 '8' => "╭─╮
119 ├─┤
120 ╰─╯",
121 '9' => "╭─╮
122 ╰─┤
123 ╶─╯",
124 ':' => "╷
125 ╵
126 │
127 ",
128 ';' => "╷
129 ╵
130 ╯",
131 '<' => "
132 ╱
133 ╲
134 ",
135 '=' => "
136 ──
137 ──",
138 '>' => "
139 ╲
140 ╱
141 ",
142 '?' => "
143 ╶─╮
144 ╭╯
145 ╷",
146 '@' => "╭─╮
147 ╭╮│
148 ╰┴╯",
149 'A' => "╭─╮
150 ├─┤
151 ╵ ╵",
152 'B' => "┌╮
153 ├┴╮
154 ╰─╯",
155 'C' => "╭─╮
156 │
157 ╰─╯",
158 'D' => "┌─╮
159 │ │
160 └─╯",
161 'E' => "┌─╴
162 ├─
163 └─╴",
164 'F' => "┌─╴
165 ├─
166 ╵ ",
167 'G' => "╭─╮
168 │─╮
169 ╰─╯",
170 'H' => "╷ ╷
171 ├─┤
172 ╵ ╵",
173 'I' => "╶┬╴
174 │
175 ╶┴╴",
176 'J' => " ╶┐
177 │
178 ╰─╯",
179 'K' => "╷╭
180 ├┴╮
181 ╵ ╵",
182 'L' => "╷
183 │
184 └──",
185 'M' => "╭┬╮
186 │││
187 ╵╵╵",
188 'N' => "╭─╮
189 │ │
190 ╵ ╵",
191 'O' => "╭─╮
192 │ │
193 ╰─╯",
194 'P' => "┌─╮
195 ├─╯
196 ╵ ",
197 'Q' => "╭─╮
198 │ │
199 ╰─╳",
200 'R' => "┌─╮
201 ├┬╯
202 ╵╰ ",
203 'S' => "╭─╮
204 ╰─╮
205 ╰─╯",
206 'T' => "
207 ╶┬╴
208 │
209 ╵",
210 'U' => "╷ ╷
211 │ │
212 ╰─╯",
213 'V' => "╷ ╷
214 │ │
215 └─╯",
216 'W' => "╷╷╷
217 │││
218 ╰┴╯",
219 'X' => "╮ ╭
220 ╰─╮
221 ╯ ╰",
222 'Y' => "╮ ╭
223 ╰┬╯
224 ╵",
225 'Z' => "╶─╮
226 ╱
227 ╰─╴",
228 '[' => "┌─
229 │
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});