use super::trivia::{Trivia, TriviaToken};
use crate::span::Span;
use crate::syntax::ast::{Child, Node};
#[derive(Default, Clone, Copy)]
pub struct NodeWidths {
pub id: usize,
pub ty: usize,
}
fn type_len(n: &Node) -> usize {
n.ty.as_ref().map_or(0, |t| 2 + t.len())
}
fn is_plain(c: &Child) -> bool {
match c {
Child::Box(n) => n.classes.is_empty() && n.style.is_empty(),
Child::Text(_) => true,
}
}
pub fn child_widths(children: &[Child], trivia: &[TriviaToken]) -> Vec<NodeWidths> {
let mut out = vec![NodeWidths::default(); children.len()];
for group in split_groups(children, trivia) {
let plain = group.iter().all(|&i| is_plain(&children[i]));
let mut w = NodeWidths::default();
for &i in &group {
if let Child::Box(n) = &children[i] {
if let Some(id) = &n.id {
w.id = w.id.max(id.len());
}
if plain {
w.ty = w.ty.max(type_len(n));
}
}
}
for i in group {
out[i] = w;
}
}
out
}
fn split_groups(children: &[Child], trivia: &[TriviaToken]) -> Vec<Vec<usize>> {
if children.is_empty() {
return Vec::new();
}
let mut groups: Vec<Vec<usize>> = vec![vec![0]];
for i in 1..children.len() {
let prev_end = child_span(&children[i - 1]).end;
let curr_start = child_span(&children[i]).start;
let blank = trivia.iter().any(|t| {
matches!(t.kind, Trivia::BlankLine) && t.pos >= prev_end && t.pos < curr_start
});
if blank {
groups.push(vec![i]);
} else {
groups.last_mut().unwrap().push(i);
}
}
groups
}
fn child_span(c: &Child) -> Span {
match c {
Child::Box(n) => n.span,
Child::Text(t) => t.span,
}
}