use std::{fs, io, path}; use crate::config::option::DisplayOption; use crate::fs::{FileType, JoshutoMetadata}; #[cfg(feature = "devicons")] use crate::util::devicons::*; #[derive(Clone, Debug)] pub struct JoshutoDirEntry { name: String, label: String, path: path::PathBuf, pub metadata: JoshutoMetadata, selected: bool, marked: bool, } impl JoshutoDirEntry { pub fn from(direntry: &fs::DirEntry, options: &DisplayOption) -> io::Result { let path = direntry.path(); let mut metadata = JoshutoMetadata::from(&path)?; let name = direntry .file_name() .as_os_str() .to_string_lossy() .to_string(); if options.automatically_count_files() && metadata.file_type().is_dir() { if let Ok(size) = get_directory_size(path.as_path()) { metadata.update_directory_size(size); } } #[cfg(feature = "devicons")] let label = if options.show_icons() { create_icon_label(name.as_str(), &metadata) } else { name.clone() }; #[cfg(not(feature = "devicons"))] let label = name.clone(); Ok(Self { name, label, path, metadata, selected: false, marked: false, }) } pub fn update_label(&mut self, label: String) { self.label = label; } pub fn file_name(&self) -> &str { self.name.as_str() } pub fn label(&self) -> &str { self.label.as_str() } pub fn file_path(&self) -> &path::Path { self.path.as_path() } pub fn is_selected(&self) -> bool { self.selected } pub fn set_selected(&mut self, selected: bool) { self.selected = selected; } pub fn get_ext(&self) -> &str { let fname = self.file_name(); match fname.rfind('.') { Some(pos) => &fname[pos..], None => "", } } } impl std::fmt::Display for JoshutoDirEntry { fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { write!(f, "{}", self.file_name()) } } impl std::convert::AsRef for JoshutoDirEntry { fn as_ref(&self) -> &str { self.file_name() } } impl std::cmp::PartialEq for JoshutoDirEntry { fn eq(&self, other: &Self) -> bool { self.file_path() == other.file_path() } } impl std::cmp::Eq for JoshutoDirEntry {} impl std::cmp::PartialOrd for JoshutoDirEntry { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } impl std::cmp::Ord for JoshutoDirEntry { fn cmp(&self, other: &Self) -> std::cmp::Ordering { self.file_path().cmp(other.file_path()) } } fn create_icon_label(name: &str, metadata: &JoshutoMetadata) -> String { let label = { let icon = match metadata.file_type() { FileType::Directory => DIR_NODE_EXACT_MATCHES .get(name) .cloned() .unwrap_or(DEFAULT_DIR), _ => FILE_NODE_EXACT_MATCHES.get(name).cloned().unwrap_or( match name.rsplit_once('.') { Some((_, ext)) => FILE_NODE_EXTENSIONS.get(ext).unwrap_or(&DEFAULT_FILE), None => DEFAULT_FILE, }, ), }; format!("{} {}", icon, name) }; label } fn get_directory_size(path: &path::Path) -> io::Result { fs::read_dir(path).map(|s| s.count()) }