use f00_core::{Entry, IndicatorStyle};
use crate::color::Colorizer;
use crate::icons::icon_prefix;
use crate::perms::classify_suffix;
pub fn format_tree(
entries: &[Entry],
colorizer: &Colorizer,
icons: bool,
indicator: IndicatorStyle,
) -> String {
let items: Vec<&Entry> = entries.iter().filter(|e| !e.is_dir_header).collect();
if items.is_empty() {
return String::new();
}
let use_depth = items.iter().any(|e| e.depth > 0);
let mut out = String::new();
if use_depth {
format_tree_by_depth(&items, colorizer, icons, indicator, &mut out);
} else {
for (i, entry) in items.iter().enumerate() {
let last = i + 1 == items.len();
let branch = if last { "└── " } else { "├── " };
let icon = icon_prefix(entry, icons);
let suffix = classify_suffix(entry, indicator);
let plain = format!("{icon}{}{suffix}", entry.name);
let name = colorizer.paint_name(entry, &plain);
out.push_str(branch);
out.push_str(&name);
out.push('\n');
}
}
out
}
fn format_tree_by_depth(
items: &[&Entry],
colorizer: &Colorizer,
icons: bool,
indicator: IndicatorStyle,
out: &mut String,
) {
for (i, entry) in items.iter().enumerate() {
let depth = entry.depth.max(1); let level = depth - 1;
let is_last = is_last_sibling(items, i);
for d in 0..level {
let ancestor_has_more = ancestor_continues(items, i, d + 1);
if ancestor_has_more {
out.push_str("│ ");
} else {
out.push_str(" ");
}
}
out.push_str(if is_last { "└── " } else { "├── " });
let icon = icon_prefix(entry, icons);
let suffix = classify_suffix(entry, indicator);
let plain = format!("{icon}{}{suffix}", entry.name);
let name = colorizer.paint_name(entry, &plain);
out.push_str(&name);
out.push('\n');
}
}
fn is_last_sibling(items: &[&Entry], index: usize) -> bool {
let depth = items[index].depth;
let parent = items[index].path.parent().map(|p| p.to_path_buf());
for next in items.iter().skip(index + 1) {
if next.depth < depth {
return true;
}
if next.depth == depth {
let next_parent = next.path.parent().map(|p| p.to_path_buf());
if next_parent == parent {
return false;
}
if next.depth == depth {
return true;
}
}
}
true
}
fn ancestor_continues(items: &[&Entry], index: usize, ancestor_depth: usize) -> bool {
let path = &items[index].path;
let ancestors: Vec<_> = path.ancestors().collect();
for next in items.iter().skip(index + 1) {
if next.depth < ancestor_depth {
return false;
}
if next.depth == ancestor_depth {
return true;
}
}
let _ = ancestors;
false
}