Reuse zip warning message
[ouch.git] / src / utils / formatting.rs
blob0b3b3600fec9c5092f31303e80ecc5d6a05fa068
1 use std::{borrow::Cow, cmp, ffi::OsStr, path::Path};
3 /// Converts an OsStr to utf8 with custom formatting.
4 ///
5 /// This is different from [`Path::display`].
6 ///
7 /// See <https://gist.github.com/marcospb19/ebce5572be26397cf08bbd0fd3b65ac1> for a comparison.
8 pub fn to_utf(os_str: impl AsRef<OsStr>) -> String {
9     let text = format!("{:?}", os_str.as_ref());
10     text.trim_matches('"').to_string()
13 /// Removes the current dir from the beginning of a path
14 /// normally used for presentation sake.
15 /// If this function fails, it will return source path as a PathBuf.
16 pub fn strip_cur_dir(source_path: &Path) -> &Path {
17     let cwd = std::env::current_dir().unwrap_or_else(|_| Path::new(".").to_path_buf());
18     source_path.strip_prefix(cwd).unwrap_or(source_path)
21 /// Converts a slice of AsRef<OsStr> to comma separated String
22 ///
23 /// Panics if the slice is empty.
24 pub fn concatenate_os_str_list(os_strs: &[impl AsRef<OsStr>]) -> String {
25     let mut iter = os_strs.iter().map(AsRef::as_ref);
27     let mut string = to_utf(iter.next().unwrap()); // May panic
29     for os_str in iter {
30         string += ", ";
31         string += &to_utf(os_str);
32     }
33     string
36 /// Display the directory name, but change to "current directory" when necessary.
37 pub fn nice_directory_display(os_str: impl AsRef<OsStr>) -> Cow<'static, str> {
38     if os_str.as_ref() == "." {
39         Cow::Borrowed("current directory")
40     } else {
41         let text = to_utf(os_str);
42         Cow::Owned(format!("'{}'", text))
43     }
46 /// Struct useful to printing bytes as kB, MB, GB, etc.
47 pub struct Bytes {
48     bytes: f64,
51 impl Bytes {
52     const UNIT_PREFIXES: [&'static str; 6] = ["", "k", "M", "G", "T", "P"];
54     /// Create a new Bytes.
55     pub fn new(bytes: u64) -> Self {
56         Self { bytes: bytes as f64 }
57     }
60 impl std::fmt::Display for Bytes {
61     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
62         let num = self.bytes;
63         debug_assert!(num >= 0.0);
64         if num < 1_f64 {
65             return write!(f, "{} B", num);
66         }
67         let delimiter = 1000_f64;
68         let exponent = cmp::min((num.ln() / 6.90775).floor() as i32, 4);
70         write!(f, "{:.2} ", num / delimiter.powi(exponent))?;
71         write!(f, "{}B", Bytes::UNIT_PREFIXES[exponent as usize])
72     }
75 #[cfg(test)]
76 mod tests {
77     use super::*;
79     #[test]
80     fn test_pretty_bytes_formatting() {
81         fn format_bytes(bytes: u64) -> String {
82             format!("{}", Bytes::new(bytes))
83         }
84         let b = 1;
85         let kb = b * 1000;
86         let mb = kb * 1000;
87         let gb = mb * 1000;
89         assert_eq!("0 B", format_bytes(0)); // This is weird
90         assert_eq!("1.00 B", format_bytes(b));
91         assert_eq!("999.00 B", format_bytes(b * 999));
92         assert_eq!("12.00 MB", format_bytes(mb * 12));
93         assert_eq!("123.00 MB", format_bytes(mb * 123));
94         assert_eq!("5.50 MB", format_bytes(mb * 5 + kb * 500));
95         assert_eq!("7.54 GB", format_bytes(gb * 7 + 540 * mb));
96         assert_eq!("1.20 TB", format_bytes(gb * 1200));
98         // bytes
99         assert_eq!("234.00 B", format_bytes(234));
100         assert_eq!("999.00 B", format_bytes(999));
101         // kilobytes
102         assert_eq!("2.23 kB", format_bytes(2234));
103         assert_eq!("62.50 kB", format_bytes(62500));
104         assert_eq!("329.99 kB", format_bytes(329990));
105         // megabytes
106         assert_eq!("2.75 MB", format_bytes(2750000));
107         assert_eq!("55.00 MB", format_bytes(55000000));
108         assert_eq!("987.65 MB", format_bytes(987654321));
109         // gigabytes
110         assert_eq!("5.28 GB", format_bytes(5280000000));
111         assert_eq!("95.20 GB", format_bytes(95200000000));
112         assert_eq!("302.00 GB", format_bytes(302000000000));
113     }