use std::path::{Path, PathBuf}; use anyhow::{Context, Result}; use clap::Parser; use cli::{Args, Command}; use log::trace; use mapping::map_tree::MappingTree; use walkdir::{DirEntry, WalkDir}; use crate::mapping::MapKey; mod cli; mod mapping; fn main() -> anyhow::Result<()> { let args = Args::parse(); stderrlog::new() .module(module_path!()) .quiet(args.quiet) .show_module_names(false) .color(stderrlog::ColorChoice::Auto) .verbosity(args.verbosity as usize) .timestamp(stderrlog::Timestamp::Off) .init()?; let mut mappings = MappingTree::new(); let relevant_directories = match &args.command { Command::Visualize { options } => &options.relevant_directories, Command::Generate { options } => &options.relevant_directories, }; for dir in relevant_directories { trace!("Processing '{}'..", dir.display()); let path = strip_path(&dir, &args.home_name)?; mappings .include(path_to_str(path)?) .with_context(|| format!("Failed to include path: '{}'", path.display()))?; } let home = path_to_str(&args.home_name)?.to_owned(); let mut current_depth = 1; while current_depth != args.depth { for (key, value) in mappings.iter(false) { trace!( "Adding to child ('{}' -> '{}')", MapKey::display(&key), value ); let mut local_mappings = MappingTree::new(); for dir in WalkDir::new(extend(&home, &value)?) .min_depth(1) .max_depth(1) .into_iter() .filter_entry(|e| is_dir(e) && !is_hidden(e)) { let directory = dir .with_context(|| format!("Failed to read dir ('{}')", home.clone() + &value))?; let path_to_strip = &PathBuf::from(extend(&home, &value)?); let path = strip_path(&directory.path(), &path_to_strip)?; trace!( "Including: '{}' (after stripping '{}' from '{}' -> '{}' + '/' + '{}')", path.display(), directory.path().display(), path_to_strip.display(), home, value ); let gen_key = MapKey::new_ones_from_path(path_to_str(path)?, 1); local_mappings .insert( &gen_key, path_to_str(strip_path(&directory.path(), &PathBuf::from(&home))?)?, ) .with_context(|| format!("Failed to include path: '{}'", path.display()))?; } trace!("{}", local_mappings); trace!( "'{}' -> '{:#?}'", MapKey::display(&key), local_mappings.root_node() ); mappings.interleave(&key, local_mappings.root_node().to_owned())?; } current_depth += 1; } match args.command { Command::Visualize { .. } => println!("{}", mappings), Command::Generate { .. } => println!("{}", mappings.to_lf_mappings(args.home_name)), } Ok(()) } fn extend(base: &str, value: &str) -> Result<String> { let base_path = PathBuf::from(base); let value_path = PathBuf::from(value); Ok(path_to_str(&base_path.join(&value_path))?.to_owned()) } fn is_hidden(entry: &DirEntry) -> bool { entry .file_name() .to_str() .map(|s| s.starts_with(".")) .unwrap_or(false) } fn is_dir(entry: &DirEntry) -> bool { entry.file_type().is_dir() } fn strip_path<'a>(path: &'a Path, to_strip: &Path) -> Result<&'a Path> { path.strip_prefix(&to_strip).with_context(|| { format!( "'{}' is not under the specified home path ('{}')!", path.display(), to_strip.display() ) }) } fn path_to_str(path: &Path) -> Result<&str> { path.to_str().with_context(|| { format!( "\ Can't derive a keymapping from path: '{}' \ because it can't be turned to a string ", path.display() ) }) } // fn gen_lf_mappings(home_name: PathBuf, char_num: usize, rel_dirs: Vec<PathBuf>) { // let mut mappings_vec = vec![]; // let mut index_counter = 0; // rel_dirs.iter().for_each(|rel_dir| { // mappings_vec.push(vec![Mapping::new( // &gen_hot_key(rel_dir, rel_dir, char_num), // rel_dir, // rel_dir, // None, // )]); // get_dir(rel_dir.to_owned()).iter().for_each(|path| { // mappings_vec[index_counter].push(Mapping::new( // &gen_hot_key( // path, // path.parent().expect("All paths here should have parents"), // char_num, // ), // path, // &path // .parent() // .expect("All paths here should have parents") // .to_owned(), // None, // )); // }); // index_counter += 1; // }); // print_mappings(&mappings_vec, home_name); // mappings_vec // .into_iter() // .for_each(|rel_dir_mapping: Vec<Mapping>| { // let mut hash_map = sort_mapping_by_hot_key(rel_dir_mapping.clone()); // //dbg!(hash_map); // hash_map.insert("gsi".to_owned(), vec![rel_dir_mapping[0].clone()]); // }); // } // // fn sort_mapping_by_hot_key(mut mappings: Vec<Mapping>) -> HashMap<String, Vec<Mapping>> { // mappings.sort_by_key(|mapping| mapping.hot_key.clone()); // // let mut filtered_mappings: HashMap<String, Vec<Mapping>> = HashMap::new(); // mappings.iter().for_each(|mapping| { // filtered_mappings.insert(mapping.hot_key.clone(), vec![]); // }); // //dbg!(&mappings); // // let mut index_counter = 1; // mappings.iter().for_each(|mapping| { // if mappings.len() > index_counter { // let next_mapping = &mappings[index_counter]; // let vec = filtered_mappings // .get_mut(&mapping.hot_key) // .expect("This existst as it has been initialized"); // // if &next_mapping.hot_key == &mapping.hot_key { // vec.push(mapping.clone()); // vec.push(next_mapping.clone()); // } else { // vec.push(mapping.clone()); // } // // let new_vec = vec.to_owned(); // filtered_mappings.insert(mapping.hot_key.to_owned(), new_vec); // } // // index_counter += 1; // }); // filtered_mappings // } // // fn print_mappings(mappings: &Vec<Vec<Mapping>>, home_name: PathBuf) { // for mapping in mappings { // mapping.iter().for_each(|map| { // println!( // "{} = \"cd {}\";", // map.hot_key, // map.path // .display() // .to_string() // .replace(home_name.to_str().expect("This should be UTF-8"), "~") // ); // }); // // println!("# -------------"); // } // }