#[derive(Debug, Clone)]
pub struct TreeNode {
pub label: String,
pub children: Vec<TreeNode>,
}
#[derive(Debug)]
pub struct TreeViewDiagram {
pub roots: Vec<TreeNode>,
}
pub fn parse(input: &str) -> crate::error::ParseResult<TreeViewDiagram> {
let mut items: Vec<(usize, String)> = Vec::new();
let mut past_header = false;
for raw in input.lines() {
let line = if let Some(pos) = raw.find("%%") {
&raw[..pos]
} else {
raw
};
let trimmed = line.trim();
if trimmed.is_empty() {
continue;
}
if !past_header {
let kw = trimmed.to_ascii_lowercase();
if kw.starts_with("treeview-beta") || kw.starts_with("treeview") {
past_header = true;
continue;
}
continue;
}
if trimmed.starts_with("accTitle") || trimmed.starts_with("accDescr") {
continue;
}
let indent = line.len() - line.trim_start().len();
let label = strip_quotes(trimmed);
if !label.is_empty() {
items.push((indent, label));
}
}
let roots = build_tree(&items);
crate::error::ParseResult::ok(TreeViewDiagram { roots })
}
fn strip_quotes(s: &str) -> String {
let s = s.trim();
if s.len() >= 2 && s.starts_with('"') && s.ends_with('"') {
s[1..s.len() - 1].to_string()
} else {
s.to_string()
}
}
fn build_tree(items: &[(usize, String)]) -> Vec<TreeNode> {
if items.is_empty() {
return Vec::new();
}
let mut nodes: Vec<TreeNode> = Vec::new();
let mut parents: Vec<Option<usize>> = Vec::new();
let mut stack: Vec<(usize, usize)> = Vec::new();
for (indent, label) in items {
let node = TreeNode {
label: label.clone(),
children: Vec::new(),
};
let idx = nodes.len();
nodes.push(node);
while let Some(&(top_indent, _)) = stack.last() {
if top_indent >= *indent {
stack.pop();
} else {
break;
}
}
let parent = stack.last().map(|&(_, i)| i);
parents.push(parent);
stack.push((*indent, idx));
}
let n = nodes.len();
let mut children_map: Vec<Vec<usize>> = vec![Vec::new(); n];
for (i, &parent) in parents.iter().enumerate() {
if let Some(p) = parent {
children_map[p].push(i);
}
}
let root_indices: Vec<usize> = (0..n).filter(|&i| parents[i].is_none()).collect();
fn build(idx: usize, all: &[TreeNode], cm: &[Vec<usize>]) -> TreeNode {
let src = &all[idx];
let children = cm[idx].iter().map(|&ci| build(ci, all, cm)).collect();
TreeNode {
label: src.label.clone(),
children,
}
}
root_indices
.iter()
.map(|&ri| build(ri, &nodes, &children_map))
.collect()
}