use crate::entries::Entry;
use std::fmt::Display;
use std::{fmt, path};
use yansi::{Paint, Style};
#[derive(Debug)]
pub struct DisplayInvertedPath<'a>(pub &'a Entry);
#[derive(Debug)]
pub struct DisplayFilename<'a>(pub &'a Entry);
const DIR_STYLE: (Style, Style) = {
let parent_dir = Style::new().yellow();
(parent_dir, parent_dir.bold())
};
const FILE_STYLE: (Style, Style) = {
let parent_file = Style::new().cyan();
(parent_file, parent_file.bold())
};
impl Display for Entry {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let (parent, name, symbol) = display_parts(self);
let (p_style, n_style) = if self.is_dir { DIR_STYLE } else { FILE_STYLE };
write!(
f,
"{}{}{}",
parent.paint(p_style),
name.paint(n_style),
symbol.paint(n_style)
)
}
}
impl Display for DisplayInvertedPath<'_> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let entry = self.0;
let (parent, name, symbol) = display_parts(entry);
let (p_style, n_style) = if entry.is_dir { DIR_STYLE } else { FILE_STYLE };
write!(
f,
"{}{} {}",
name.paint(n_style),
symbol.paint(n_style),
parent.paint(p_style)
)
}
}
impl Display for DisplayFilename<'_> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let entry = self.0;
let (_, name, symbol) = display_parts(entry);
let (_, style) = if entry.is_dir { DIR_STYLE } else { FILE_STYLE };
write!(f, "{}{}", name.paint(style), symbol.paint(style))
}
}
fn display_parts(entry: &Entry) -> (&str, &str, &'static str) {
let full = entry.to_str();
let pos = full.rfind(path::MAIN_SEPARATOR).map_or(0, |p| p + 1);
let (parent, name) = full.split_at(pos);
let symbol = match entry.is_dir {
true => path::MAIN_SEPARATOR_STR,
false => "",
};
(parent, name, symbol)
}
#[cfg(test)]
mod tests {
use super::*;
use std::path::PathBuf;
#[test]
fn fn_display_parts() {
#[track_caller]
fn case(p: impl Into<PathBuf>, is_dir: bool, expected: (&str, &str, &str)) {
let path = p.into();
let entry = Entry { path, is_dir };
assert_eq!(expected, display_parts(&entry));
}
case("foo/dir", true, ("foo/", "dir", "/"));
case("/foo/dir", true, ("/foo/", "dir", "/"));
case("foo/dir/", true, ("foo/", "dir", "/"));
case("/foo/dir/", true, ("/foo/", "dir", "/"));
case("x/y/", true, ("x/", "y", "/"));
case("/x/y/", true, ("/x/", "y", "/"));
case(".", true, ("", ".", "/"));
case("..", true, ("", "..", "/"));
case("/", true, ("", "", "/"));
case("./", true, ("", ".", "/"));
case("../", true, ("", "..", "/"));
case("dir", true, ("", "dir", "/"));
case("dir/", true, ("", "dir", "/"));
case("./dir", true, ("./", "dir", "/"));
case("./dir/", true, ("./", "dir", "/"));
case("file.txt", false, ("", "file.txt", ""));
case("./file.txt", false, ("./", "file.txt", ""));
case("dir/file.txt", false, ("dir/", "file.txt", ""));
case("./dir/file.txt", false, ("./dir/", "file.txt", ""));
case(".hidden", false, ("", ".hidden", ""));
case("./dir/.hidden", false, ("./dir/", ".hidden", ""));
}
}