use std::{io::Result, path::PathBuf, sync::Arc};
use super::{File, FileExplorer, Filter};
use crate::Theme;
#[derive(Clone, Default, educe::Educe)]
#[educe(Debug, PartialEq, Eq, Hash)]
pub struct FileExplorerBuilder {
cwd: Option<PathBuf>,
theme: Option<Theme>,
show_hidden: bool,
#[educe(Debug(ignore), PartialEq(ignore), Hash(ignore))]
filter: Option<Arc<Filter>>,
custom_selected: bool,
}
impl FileExplorerBuilder {
pub fn working_dir<P: Into<PathBuf>>(mut self, working_dir: P) -> Self {
self.cwd = Some(working_dir.into());
self
}
pub fn working_file<P: Into<PathBuf>>(mut self, working_file: P) -> Self {
self.custom_selected = true;
self.working_dir(working_file)
}
pub fn show_hidden(mut self, show: bool) -> Self {
self.show_hidden = show;
self
}
pub fn filter_map(mut self, f: impl Fn(File) -> Option<File> + Send + Sync + 'static) -> Self {
self.filter = Some(Arc::new(f));
self
}
pub fn theme(mut self, theme: Theme) -> Self {
self.theme = Some(theme);
self
}
#[allow(clippy::unwrap_or_default)]
pub fn build(self) -> Result<FileExplorer> {
let show_hidden = self.show_hidden;
let theme = self.theme.unwrap_or_else(Theme::new);
let filter = self.filter;
let mut file_explorer = FileExplorer {
cwd: PathBuf::new(),
files: Vec::new(),
show_hidden,
selected: 0,
theme,
filter,
};
if self.custom_selected {
file_explorer.set_working_file(self.cwd.unwrap())?;
} else {
file_explorer.set_cwd(self.cwd.clone().unwrap_or(std::env::current_dir()?))?;
}
Ok(file_explorer)
}
pub fn build_with_theme(theme: Theme) -> Result<FileExplorer> {
Self::default().theme(theme).build()
}
pub fn build_with_working_dir<P: Into<PathBuf>>(working_dir: P) -> Result<FileExplorer> {
Self::default().working_dir(working_dir).build()
}
pub fn build_with_working_file<P: Into<PathBuf>>(working_dir: P) -> Result<FileExplorer> {
Self::default().working_file(working_dir).build()
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::fs::{self, File};
use tempfile::TempDir;
fn build_tmp_file_system() -> Result<TempDir> {
let root = TempDir::new()?;
let git_path = root.path().join(".git");
let documents_path = root.path().join("Documents");
let passport_path = root.path().join("Documents/passport.png");
let resume_path = root.path().join("Documents/resume.pdf");
fs::create_dir(git_path)?;
fs::create_dir(documents_path)?;
File::create(passport_path)?;
File::create(resume_path)?;
Ok(root)
}
#[test]
fn test_thread_safe() {
fn is_sync<T: Sync>() {}
fn is_send<T: Send>() {}
is_send::<FileExplorerBuilder>();
is_sync::<FileExplorerBuilder>();
}
#[test]
fn test_working_file_correcty_set_selected_file() -> Result<()> {
let root = build_tmp_file_system()?;
let documents_path = root.path().join("Documents");
let passport_path = documents_path.join("passport.png");
let file_explorer = FileExplorerBuilder::default()
.working_file(&passport_path)
.build()
.unwrap();
assert_eq!(*file_explorer.cwd(), documents_path);
assert_eq!(file_explorer.current().path, passport_path);
Ok(())
}
#[test]
fn test_working_file_correcty_set_selected_dir() -> Result<()> {
let root = build_tmp_file_system()?;
let documents_path = root.path().join("Documents");
let file_explorer = FileExplorerBuilder::default()
.show_hidden(true)
.working_file(&documents_path)
.build()
.unwrap();
assert_eq!(*file_explorer.cwd(), root.path());
assert_eq!(*file_explorer.current().path, documents_path);
Ok(())
}
}