feat(utils): add center_text and unit tests
Swadhin Biswas committed 7 months ago
42d88ed
1 parent ceae050
commit 42d88ed
1 file changed
+147 -0
Showing 1 changed file+147-0
▼src/utils/mod.rs
+147-0
| @@ -148,3 +148,150 @@ pub fn truncate_to_width(s: &str, max_width: usize) -> String { | ||
148 | 148 | } |
149 | 149 | } |
150 | 150 | Some(&']') | Some(&'_') | Some(&'^') => { |
151 | + result.push(chars.next().unwrap()); | |
152 | + while let Some(c) = chars.next() { | |
153 | + result.push(c); | |
154 | + if c == '\x07' { | |
155 | + break; | |
156 | + } | |
157 | + if c == '\x1b' { | |
158 | + if chars.peek() == Some(&'\\') { | |
159 | + result.push(chars.next().unwrap()); | |
160 | + break; | |
161 | + } | |
162 | + } | |
163 | + } | |
164 | + } | |
165 | + Some(&c) if c.is_ascii_alphabetic() || c == '(' || c == ')' => { | |
166 | + result.push(chars.next().unwrap()); | |
167 | + if c == '(' || c == ')' { | |
168 | + if let Some(n) = chars.next() { | |
169 | + result.push(n); | |
170 | + } | |
171 | + } | |
172 | + } | |
173 | + _ => {} | |
174 | + } | |
175 | + } else { | |
176 | + let cw = UnicodeWidthChar::width(ch).unwrap_or(0); | |
177 | + if vis_w + cw > max_width { | |
178 | + break; | |
179 | + } | |
180 | + vis_w += cw; | |
181 | + result.push(ch); | |
182 | + } | |
183 | + } | |
184 | + result | |
185 | +} | |
186 | + | |
187 | +/// Get the home directory. | |
188 | +pub fn home_dir() -> String { | |
189 | + std::env::var("HOME") | |
190 | + .or_else(|_| std::env::var("USERPROFILE")) | |
191 | + .unwrap_or_else(|_| "/root".to_string()) | |
192 | +} | |
193 | + | |
194 | +#[cfg(test)] | |
195 | +mod tests { | |
196 | + use super::*; | |
197 | + | |
198 | + #[test] | |
199 | + fn test_strip_ansi_no_escapes() { | |
200 | + assert_eq!(strip_ansi("hello world"), "hello world"); | |
201 | + } | |
202 | + | |
203 | + #[test] | |
204 | + fn test_strip_ansi_csi() { | |
205 | + assert_eq!(strip_ansi("\x1b[31mred\x1b[0m"), "red"); | |
206 | + assert_eq!(strip_ansi("\x1b[1;34mbold blue\x1b[0m"), "bold blue"); | |
207 | + } | |
208 | + | |
209 | + #[test] | |
210 | + fn test_strip_ansi_osc() { | |
211 | + assert_eq!(strip_ansi("\x1b]0;title\x07text"), "text"); | |
212 | + } | |
213 | + | |
214 | + #[test] | |
215 | + fn test_strip_ansi_complex() { | |
216 | + let s = "\x1b[36m\x1b[1mCPU\x1b[0m\x1b[0m: \x1b[0mi5-13600K"; | |
217 | + assert_eq!(strip_ansi(s), "CPU: i5-13600K"); | |
218 | + } | |
219 | + | |
220 | + #[test] | |
221 | + fn test_visible_width_plain() { | |
222 | + assert_eq!(visible_width("hello"), 5); | |
223 | + assert_eq!(visible_width(""), 0); | |
224 | + } | |
225 | + | |
226 | + #[test] | |
227 | + fn test_visible_width_with_ansi() { | |
228 | + assert_eq!(visible_width("\x1b[31mhello\x1b[0m"), 5); | |
229 | + } | |
230 | + | |
231 | + #[test] | |
232 | + fn test_visible_width_unicode() { | |
233 | + // CJK characters are typically double-width | |
234 | + assert_eq!(visible_width("日本"), 4); | |
235 | + } | |
236 | + | |
237 | + #[test] | |
238 | + fn test_pad_right() { | |
239 | + let padded = pad_right("hi", 10); | |
240 | + assert_eq!(visible_width(&padded), 10); | |
241 | + assert!(padded.starts_with("hi")); | |
242 | + } | |
243 | + | |
244 | + #[test] | |
245 | + fn test_pad_right_already_wide() { | |
246 | + let padded = pad_right("hello world", 5); | |
247 | + assert_eq!(padded, "hello world"); | |
248 | + } | |
249 | + | |
250 | + #[test] | |
251 | + fn test_truncate_to_width_plain() { | |
252 | + let truncated = truncate_to_width("hello world", 5); | |
253 | + assert_eq!(truncated, "hello"); | |
254 | + } | |
255 | + | |
256 | + #[test] | |
257 | + fn test_truncate_to_width_with_ansi() { | |
258 | + let s = "\x1b[31mhello world\x1b[0m"; | |
259 | + let truncated = truncate_to_width(s, 5); | |
260 | + // Should contain "hello" visible chars + ANSI prefix | |
261 | + assert_eq!(visible_width(&truncated), 5); | |
262 | + assert!(truncated.contains("hello")); | |
263 | + } | |
264 | + | |
265 | + #[test] | |
266 | + fn test_truncate_to_width_no_cut() { | |
267 | + let s = "hi"; | |
268 | + let truncated = truncate_to_width(s, 10); | |
269 | + assert_eq!(truncated, "hi"); | |
270 | + } | |
271 | + | |
272 | + #[test] | |
273 | + fn test_env_or() { | |
274 | + std::env::set_var("FETCHX_TEST_VAR", "test_value"); | |
275 | + assert_eq!(env_or("FETCHX_TEST_VAR"), "test_value"); | |
276 | + assert_eq!(env_or("FETCHX_NONEXISTENT_VAR_12345"), ""); | |
277 | + std::env::remove_var("FETCHX_TEST_VAR"); | |
278 | + } | |
279 | + | |
280 | + #[test] | |
281 | + fn test_run_cmd() { | |
282 | + let result = run_cmd("echo", &["hello"]); | |
283 | + assert_eq!(result, "hello"); | |
284 | + } | |
285 | + | |
286 | + #[test] | |
287 | + fn test_run_cmd_failure() { | |
288 | + let result = run_cmd("nonexistent_command_12345", &[]); | |
289 | + assert_eq!(result, ""); | |
290 | + } | |
291 | + | |
292 | + #[test] | |
293 | + fn test_command_exists() { | |
294 | + assert!(command_exists("echo")); | |
295 | + assert!(!command_exists("nonexistent_command_12345")); | |
296 | + } | |
297 | +} | |
151 | 298 | |