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(detail: &str) -> Cirru {
Cirru::leaf(format!("'folded:{detail}"))
}
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!("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!("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 {
match node {
Cirru::Leaf(_) => node.clone(),
Cirru::List(xs) => {
if depth >= max_depth {
return folded_place("max-depth");
}
let Some((head, rest)) = xs.split_first() else {
return node.clone();
};
let mut result = vec![fold_children_impl(head, max_children, depth + 1, max_depth)];
let hidden = rest.len().saturating_sub(max_children);
if hidden <= 2 {
for c in rest {
result.push(fold_children_impl(c, max_children, depth + 1, max_depth));
}
return Cirru::List(result);
}
for c in rest.iter().take(max_children) {
result.push(fold_children_impl(c, max_children, depth + 1, max_depth));
}
result.push(folded_place(&format!("inside:{hidden}")));
Cirru::List(result)
}
}
}