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!("# -------------");
// }
// }