use crate::{ prelude::{ RID, NodeTreeBase, Node }, structs::node_base::NodeStatus };
pub fn ensure_unique_name(name: &str, relative_to: &[String]) -> String {
fn extract_numerical_suffix(s: &str) -> Option<usize> {
let mut numerics: String = String::new();
let mut ptr: usize = s.len() - 1;
loop {
let char: char = s.get(ptr..(ptr + 1)).unwrap().chars().collect::<Vec<_>>()[0];
if !char.is_numeric() {
break;
}
numerics = char.to_string() + &numerics;
if ptr == 0 {
break;
}
ptr -= 1;
}
if numerics.is_empty() {
return None;
}
Some(numerics.parse::<usize>().unwrap())
}
if relative_to.is_empty() {
return name.to_string();
}
let given_value: Option<usize> = extract_numerical_suffix(name);
let name_without_suffix: String = match given_value {
Some(number) => name.split_at(name.find(&format!("{}", number)).unwrap()).0.to_string(),
None => name.to_string()
};
let mut similar_names: Vec<String> = Vec::new();
for set_name in relative_to {
let idx_found: Option<usize> = set_name.find(&name_without_suffix);
if let Some(idx) = idx_found {
if idx != 0 { continue;
}
similar_names.push(set_name.to_string());
}
}
if similar_names.is_empty() {
return name.to_string();
}
let mut new_value: usize = given_value.unwrap_or(0);
let values: Vec<usize> = similar_names.iter().map(|n| extract_numerical_suffix(n).unwrap_or(0)).collect(); loop { for value in values {
if new_value == value {
new_value += 1;
continue;
}
}
break;
}
let new_suffix: String = format!("{}", new_value);
name_without_suffix.to_string() + &new_suffix
}
pub fn draw_tree(node_tree: &NodeTreeBase, origin: RID, view_up: usize, view_down: usize) -> String {
fn get_start<'a>(tree: &'a NodeTreeBase, node: &'a dyn Node, view_left: usize) -> &'a dyn Node {
if node.is_root() || view_left == 0 {
return node;
}
get_start(tree, unsafe { tree.get_node(node.parent_dyn().unwrap_unchecked().rid()).unwrap_unchecked() }, view_left - 1)
}
let origin: &dyn Node = node_tree.get_node(origin).unwrap();
let draw_from: &dyn Node = get_start(node_tree, origin, view_up);
let levels: usize = view_up + view_down;
const OTHER_CHILD: &str = "│ "; const OTHER_ENTRY: &str = "├── "; const FINAL_CHILD: &str = " "; const FINAL_ENTRY: &str = "└── ";
let mut warnings: Vec<String> = Vec::new();
let mut panics: Vec<String> = Vec::new();
fn handle_name_and_status(child_name: &str, status: NodeStatus, warnings: &mut Vec<String>, panics: &mut Vec<String>) -> String {
match status {
NodeStatus::Normal => child_name.to_owned(),
NodeStatus::JustWarned(warn) => {
warnings.push(format!("{} - {}", child_name, warn));
format!("\u{001b}[33m{}\u{001b}[0m", child_name)
},
NodeStatus::JustPanicked(panic) => {
panics.push(format!("{} - {}", child_name, panic));
format!("\u{001b}[31m{}\u{001b}[0m", child_name)
}
}
}
fn walk(tree: &NodeTreeBase, node_rid: RID, prefix: &str, out: &mut String, warnings: &mut Vec<String>, panics: &mut Vec<String>, level: usize) {
let node: &dyn Node = unsafe { tree.get_node(node_rid).unwrap_unchecked() };
let mut count: usize = node.num_children();
for child in node.children() {
count -= 1;
let connector: &str = if count == 0 { FINAL_ENTRY } else { OTHER_ENTRY };
let mut child_name: String = child.name().to_string();
child_name = handle_name_and_status(&child_name, child.status(), warnings, panics);
*out += &format!("{}{}{}\n", prefix, connector, if level != 0 { child_name } else { "...".to_string() });
if !child.childless() && level != 0 {
let new_prefix: String = format!("{}{}", prefix, if count == 0 { FINAL_CHILD } else { OTHER_CHILD });
walk(tree, child.rid(), &new_prefix, out, warnings, panics, level - 1);
}
}
}
let mut out: String = format!("[REPORT START]\n{}\n", handle_name_and_status(draw_from.name(), draw_from.status(), &mut warnings, &mut panics));
walk(node_tree, draw_from.rid(), "", &mut out, &mut warnings, &mut panics, levels + 1);
out += "\n[Same-Frame Warnings]";
if !warnings.is_empty() {
for warning in warnings {
out += &format!("\n\u{001b}[33m{}\u{001b}[0m", warning);
}
} else {
out += "\nNone";
}
out += "\n\n[Same-Frame Panics]";
if !panics.is_empty() {
for panic in panics {
out += &format!("\n\u{001b}[31m{}\u{001b}[0m", panic);
}
} else {
out += "\nNone";
}
out += "\n\n[REPORT END]";
out
}