fix clippy warning
[ouch.git] / src / utils / formatting.rs
blob7a409e5e927aea1625a768b147c1698efabba31b
1 use std::{borrow::Cow, fmt::Display, path::Path};
3 use crate::CURRENT_DIRECTORY;
5 /// Converts invalid UTF-8 bytes to the Unicode replacement codepoint (�) in its Display implementation.
6 pub struct EscapedPathDisplay<'a> {
7     path: &'a Path,
10 impl<'a> EscapedPathDisplay<'a> {
11     pub fn new(path: &'a Path) -> Self {
12         Self { path }
13     }
16 #[cfg(unix)]
17 impl Display for EscapedPathDisplay<'_> {
18     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
19         use std::os::unix::prelude::OsStrExt;
21         let bstr = bstr::BStr::new(self.path.as_os_str().as_bytes());
23         write!(f, "{bstr}")
24     }
27 #[cfg(windows)]
28 impl Display for EscapedPathDisplay<'_> {
29     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
30         use std::{char, fmt::Write, os::windows::prelude::OsStrExt};
32         let utf16 = self.path.as_os_str().encode_wide();
33         let chars = char::decode_utf16(utf16).map(|decoded| decoded.unwrap_or(char::REPLACEMENT_CHARACTER));
35         for char in chars {
36             f.write_char(char)?;
37         }
39         Ok(())
40     }
43 /// Converts an OsStr to utf8 with custom formatting.
44 ///
45 /// This is different from [`Path::display`].
46 ///
47 /// See <https://gist.github.com/marcospb19/ebce5572be26397cf08bbd0fd3b65ac1> for a comparison.
48 pub fn to_utf(os_str: &Path) -> Cow<str> {
49     let format = || {
50         let text = format!("{os_str:?}");
51         Cow::Owned(text.trim_matches('"').to_string())
52     };
54     os_str.to_str().map_or_else(format, Cow::Borrowed)
57 /// Removes the current dir from the beginning of a path as it's redundant information,
58 /// useful for presentation sake.
59 pub fn strip_cur_dir(source_path: &Path) -> &Path {
60     let current_dir = &*CURRENT_DIRECTORY;
62     source_path.strip_prefix(current_dir).unwrap_or(source_path)
65 /// Converts a slice of `AsRef<OsStr>` to comma separated String
66 ///
67 /// Panics if the slice is empty.
68 pub fn pretty_format_list_of_paths(os_strs: &[impl AsRef<Path>]) -> String {
69     let mut iter = os_strs.iter().map(AsRef::as_ref);
71     let first_element = iter.next().unwrap();
72     let mut string = to_utf(first_element).into_owned();
74     for os_str in iter {
75         string += ", ";
76         string += &to_utf(os_str);
77     }
78     string
81 /// Display the directory name, but use "current directory" when necessary.
82 pub fn nice_directory_display(path: &Path) -> Cow<str> {
83     if path == Path::new(".") {
84         Cow::Borrowed("current directory")
85     } else {
86         to_utf(path)
87     }