use crate::primes::Cirru;
const FOLD_SIBLINGS_HALF: usize = 1;
const FOLD_CHILDREN_NON_TARGET: usize = 2;
const FOLD_CHILDREN_TARGET: usize = 4;
const FOLD_NON_TARGET_DEPTH: usize = 2;
const FOLD_TARGET_DEPTH: usize = 3;
fn folded_place(label: &str) -> Cirru {
Cirru::List(vec![Cirru::leaf("folded"), Cirru::leaf(label)])
}
pub fn focus_cirru_preview(node: &Cirru, path: &[usize]) -> Cirru {
focus_cirru_preview_impl(node, path, 0)
}
fn focus_cirru_preview_impl(node: &Cirru, path: &[usize], depth: usize) -> Cirru {
match node {
Cirru::Leaf(_) => node.clone(),
Cirru::List(xs) => {
if path.is_empty() {
return fold_children_impl(node, FOLD_CHILDREN_TARGET, 0, FOLD_TARGET_DEPTH);
}
let target_idx = path[0];
if target_idx >= xs.len() {
return fold_children_impl(node, FOLD_CHILDREN_NON_TARGET, 0, FOLD_NON_TARGET_DEPTH);
}
let start = target_idx.saturating_sub(FOLD_SIBLINGS_HALF);
let end = (target_idx + FOLD_SIBLINGS_HALF + 1).min(xs.len());
let rest_path = &path[1..];
let mut result: Vec<Cirru> = Vec::new();
if start > 2 {
result.push(fold_children_impl(&xs[0], FOLD_CHILDREN_NON_TARGET, 0, FOLD_NON_TARGET_DEPTH));
result.push(folded_place(&format!("|…+{} nodes before", start - 1)));
} else {
for i in 0..start {
result.push(fold_children_impl(&xs[i], FOLD_CHILDREN_NON_TARGET, 0, FOLD_NON_TARGET_DEPTH));
}
}
for i in start..end {
if i == target_idx {
result.push(focus_cirru_preview_impl(&xs[i], rest_path, depth + 1));
} else {
result.push(fold_children_impl(&xs[i], FOLD_CHILDREN_NON_TARGET, 0, FOLD_NON_TARGET_DEPTH));
}
}
let remaining = xs.len() - end;
if remaining > 2 {
result.push(folded_place(&format!("|…+{} nodes after", remaining)));
} else {
for i in end..xs.len() {
result.push(fold_children_impl(&xs[i], FOLD_CHILDREN_NON_TARGET, 0, FOLD_NON_TARGET_DEPTH));
}
}
Cirru::List(result)
}
}
}
fn fold_children_impl(node: &Cirru, max_children: usize, depth: usize, max_depth: usize) -> Cirru {
if depth >= max_depth {
return folded_place("|… max depth");
}
match node {
Cirru::Leaf(_) => node.clone(),
Cirru::List(xs) => {
let hidden = xs.len().saturating_sub(max_children);
if hidden <= 2 {
let children: Vec<Cirru> = xs.iter().map(|c| fold_children_impl(c, max_children, depth + 1, max_depth)).collect();
return Cirru::List(children);
}
let mut result: Vec<Cirru> = Vec::new();
for c in xs.iter().take(max_children) {
result.push(fold_children_impl(c, max_children, depth + 1, max_depth));
}
result.push(folded_place(&format!("|…+{} nodes inside", hidden)));
Cirru::List(result)
}
}
}