1#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
5pub enum BoxLines {
6 #[default]
8 Single,
9 Double,
11 Heavy,
13 Simple,
15 Rounded,
17 Padded,
19 None,
21}
22
23impl BoxLines {
24 #[must_use]
26 pub fn parse(value: Option<&str>) -> Self {
27 match value.unwrap_or("single") {
28 "double" => Self::Double,
29 "heavy" => Self::Heavy,
30 "simple" => Self::Simple,
31 "rounded" => Self::Rounded,
32 "padded" => Self::Padded,
33 "none" => Self::None,
34 _ => Self::Single,
35 }
36 }
37
38 #[must_use]
40 pub const fn visible(self) -> bool {
41 !matches!(self, Self::None)
42 }
43
44 #[must_use]
46 pub const fn vertical(self) -> char {
47 match self {
48 Self::Single | Self::Rounded => '│',
49 Self::Double => '║',
50 Self::Heavy => '┃',
51 Self::Simple => '|',
52 Self::Padded | Self::None => ' ',
53 }
54 }
55
56 #[must_use]
58 pub const fn horizontal(self) -> char {
59 match self {
60 Self::Single | Self::Rounded => '─',
61 Self::Double => '═',
62 Self::Heavy => '━',
63 Self::Simple => '-',
64 Self::Padded | Self::None => ' ',
65 }
66 }
67
68 #[must_use]
70 pub const fn top_left(self) -> char {
71 match self {
72 Self::Single => '┌',
73 Self::Double => '╔',
74 Self::Heavy => '┏',
75 Self::Simple => '+',
76 Self::Rounded => '╭',
77 Self::Padded | Self::None => ' ',
78 }
79 }
80
81 #[must_use]
83 pub const fn top_right(self) -> char {
84 match self {
85 Self::Single => '┐',
86 Self::Double => '╗',
87 Self::Heavy => '┓',
88 Self::Simple => '+',
89 Self::Rounded => '╮',
90 Self::Padded | Self::None => ' ',
91 }
92 }
93
94 #[must_use]
96 pub const fn bottom_left(self) -> char {
97 match self {
98 Self::Single => '└',
99 Self::Double => '╚',
100 Self::Heavy => '┗',
101 Self::Simple => '+',
102 Self::Rounded => '╰',
103 Self::Padded | Self::None => ' ',
104 }
105 }
106
107 #[must_use]
109 pub const fn bottom_right(self) -> char {
110 match self {
111 Self::Single => '┘',
112 Self::Double => '╝',
113 Self::Heavy => '┛',
114 Self::Simple => '+',
115 Self::Rounded => '╯',
116 Self::Padded | Self::None => ' ',
117 }
118 }
119
120 #[must_use]
122 pub const fn top_join(self) -> char {
123 match self {
124 Self::Single => '┬',
125 Self::Double => '╦',
126 Self::Heavy | Self::Rounded => '┳',
127 Self::Simple => '+',
128 Self::Padded | Self::None => ' ',
129 }
130 }
131
132 #[must_use]
134 pub const fn bottom_join(self) -> char {
135 match self {
136 Self::Single => '┴',
137 Self::Double => '╩',
138 Self::Heavy | Self::Rounded => '┻',
139 Self::Simple => '+',
140 Self::Padded | Self::None => ' ',
141 }
142 }
143
144 #[must_use]
146 pub const fn left_join(self) -> char {
147 match self {
148 Self::Single | Self::Rounded => '├',
149 Self::Double => '╠',
150 Self::Heavy => '┣',
151 Self::Simple => '+',
152 Self::Padded | Self::None => ' ',
153 }
154 }
155
156 #[must_use]
158 pub const fn right_join(self) -> char {
159 match self {
160 Self::Single | Self::Rounded => '┤',
161 Self::Double => '╣',
162 Self::Heavy => '┫',
163 Self::Simple => '+',
164 Self::Padded | Self::None => ' ',
165 }
166 }
167
168 #[must_use]
170 pub const fn join(self) -> char {
171 match self {
172 Self::Single => '┼',
173 Self::Double => '╬',
174 Self::Heavy | Self::Rounded => '╋',
175 Self::Simple => '+',
176 Self::Padded | Self::None => ' ',
177 }
178 }
179
180 #[must_use]
182 pub const fn outside(self) -> char {
183 match self {
184 Self::Single | Self::Double | Self::Heavy | Self::Rounded => '·',
185 Self::Simple => '.',
186 Self::Padded | Self::None => ' ',
187 }
188 }
189}
190
191#[cfg(test)]
192mod tests {
193 use super::BoxLines;
194
195 #[test]
196 fn parses_tmux_popup_border_choices() {
197 assert_eq!(BoxLines::parse(None), BoxLines::Single);
198 assert_eq!(BoxLines::parse(Some("double")), BoxLines::Double);
199 assert_eq!(BoxLines::parse(Some("heavy")), BoxLines::Heavy);
200 assert_eq!(BoxLines::parse(Some("simple")), BoxLines::Simple);
201 assert_eq!(BoxLines::parse(Some("rounded")), BoxLines::Rounded);
202 assert_eq!(BoxLines::parse(Some("padded")), BoxLines::Padded);
203 assert_eq!(BoxLines::parse(Some("none")), BoxLines::None);
204 assert_eq!(BoxLines::parse(Some("unknown")), BoxLines::Single);
205 }
206
207 #[test]
208 fn exposes_tmux_join_glyphs_for_all_border_sets() {
209 assert_eq!(BoxLines::Single.top_join(), '┬');
210 assert_eq!(BoxLines::Single.bottom_join(), '┴');
211 assert_eq!(BoxLines::Single.join(), '┼');
212
213 assert_eq!(BoxLines::Double.top_join(), '╦');
214 assert_eq!(BoxLines::Double.bottom_join(), '╩');
215 assert_eq!(BoxLines::Double.join(), '╬');
216
217 assert_eq!(BoxLines::Heavy.top_join(), '┳');
218 assert_eq!(BoxLines::Heavy.bottom_join(), '┻');
219 assert_eq!(BoxLines::Heavy.join(), '╋');
220
221 assert_eq!(BoxLines::Simple.top_join(), '+');
222 assert_eq!(BoxLines::Simple.bottom_join(), '+');
223 assert_eq!(BoxLines::Simple.join(), '+');
224
225 assert_eq!(BoxLines::Rounded.top_join(), '┳');
226 assert_eq!(BoxLines::Rounded.bottom_join(), '┻');
227 assert_eq!(BoxLines::Rounded.join(), '╋');
228
229 assert_eq!(BoxLines::Padded.top_join(), ' ');
230 assert_eq!(BoxLines::Padded.bottom_join(), ' ');
231 assert_eq!(BoxLines::Padded.join(), ' ');
232
233 assert_eq!(BoxLines::None.top_join(), ' ');
234 assert_eq!(BoxLines::None.bottom_join(), ' ');
235 assert_eq!(BoxLines::None.join(), ' ');
236 }
237
238 #[test]
239 fn outside_glyph_matches_tmux_border_tables() {
240 assert_eq!(BoxLines::Single.outside(), '·');
241 assert_eq!(BoxLines::Double.outside(), '·');
242 assert_eq!(BoxLines::Heavy.outside(), '·');
243 assert_eq!(BoxLines::Simple.outside(), '.');
244 assert_eq!(BoxLines::Rounded.outside(), '·');
245 assert_eq!(BoxLines::Padded.outside(), ' ');
246 assert_eq!(BoxLines::None.outside(), ' ');
247 }
248}