diff --git a/src/cli.rs b/src/cli.rs index 946a9a6..48e9a40 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -63,6 +63,9 @@ pub struct Interface { pub portable: bool, #[clap(default_value = ".")] pub path: String, + /// Collapse directories single entries. + #[clap(long, parse(from_flag))] + pub collapse: bool, } #[cfg(test)] diff --git a/src/diagram_formatting.rs b/src/diagram_formatting.rs index 53b7e7d..4cfc71d 100644 --- a/src/diagram_formatting.rs +++ b/src/diagram_formatting.rs @@ -1,6 +1,7 @@ use super::file_tree::{File, FileTree, FileType}; use std::collections::HashMap; use std::fs; +use std::path::Path; #[derive(Debug, Clone, PartialEq)] enum PrefixSegment { @@ -32,11 +33,12 @@ fn make_prefix(tree: &FileTree, file: &File, format_history: &HashMap { + segments.push(PrefixSegment::Empty) + } + Some(_) => segments.push(PrefixSegment::ShapeI), + None => {} } current = ancestor; } @@ -58,19 +60,34 @@ fn format_file( format_history: &mut HashMap, result: &mut Vec, make_absolute: bool, + collapse: bool, ) { - let prefix = make_prefix(tree, file, format_history); - let path = if make_absolute { - fs::canonicalize(&file.path).unwrap().display().to_string() - } else { - file.path.clone() - }; + let mut current = file; + let mut path = current.path.clone(); + let mut name = current.display_name.clone(); + + let prefix = make_prefix(tree, current, format_history); + + if collapse { + while current.children_count() == 1 { + let child = current.children().unwrap().values().next().unwrap(); + let child_node = tree.get(*child); + let child_name = child_node.display_name.clone(); + name = Path::new(&name).join(child_name).display().to_string(); + path = child_node.path.clone(); + current = child_node; + } + } + + if make_absolute { + path = fs::canonicalize(&path).unwrap().display().to_string(); + } result.push(FormattedEntry { - name: file.display_name.clone(), + name, path, prefix, - link: file.link(), + link: current.link(), }); if let Some(parent) = tree.get_parent(file) { @@ -79,11 +96,11 @@ fn format_file( } } - if let FileType::Directory = file.file_type { - format_history.insert(file.id, 0); + if let FileType::Directory = current.file_type { + format_history.insert(current.id, 0); } - if let Some(children) = file.children() { + if let Some(children) = current.children() { for child_id in children.values() { format_file( tree, @@ -91,6 +108,7 @@ fn format_file( format_history, result, make_absolute, + collapse, ); } } @@ -100,13 +118,21 @@ pub fn format_paths( root_path: &str, children: Vec<(String, FileType)>, make_absolute: bool, + collapse: bool, ) -> Vec { let mut history = HashMap::new(); let mut result = Vec::new(); match FileTree::new(root_path, children) { Some(tree) => { let root = tree.get_root(); - format_file(&tree, root, &mut history, &mut result, make_absolute); + format_file( + &tree, + root, + &mut history, + &mut result, + make_absolute, + collapse, + ); result } None => Vec::new(), @@ -128,6 +154,7 @@ mod test { (format!("b{}c", path::MAIN_SEPARATOR), FileType::File), ], false, + false, ); let bc_path = format!("b{}c", path::MAIN_SEPARATOR); diff --git a/src/tre.rs b/src/tre.rs index 6295fd5..55210c1 100644 --- a/src/tre.rs +++ b/src/tre.rs @@ -26,6 +26,7 @@ pub struct RunOptions { pub exclude_patterns: Vec, pub coloring: cli::Coloring, pub portable_aliases: bool, + pub collapse: bool, } #[cfg(not(windows))] @@ -65,6 +66,7 @@ impl From for RunOptions { .collect(), coloring: inputs.color, portable_aliases: inputs.portable, + collapse: inputs.collapse, } } } @@ -99,8 +101,12 @@ pub fn run(option: RunOptions) { if option.output_json { println!("{}", json_formatting::format_paths(&option.root, paths)); } else { - let format_result = - diagram_formatting::format_paths(&option.root, paths, option.portable_aliases); + let format_result = diagram_formatting::format_paths( + &option.root, + paths, + option.portable_aliases, + option.collapse, + ); let lscolors = LsColors::from_env().unwrap_or_default(); let coloring = match option.coloring { cli::Coloring::Never => None,