use super::read_file;
use crate::error::CliError;
use colored::Colorize;
use hedl_core::{parse, Item, Value};
use std::collections::BTreeMap;
pub fn inspect(file: &str, verbose: bool) -> Result<(), CliError> {
let content = read_file(file)?;
let doc =
parse(content.as_bytes()).map_err(|e| CliError::parse(format!("Parse error: {e}")))?;
println!("{}", "HEDL Document".bold().underline());
println!();
println!("{} {}.{}", "Version:".cyan(), doc.version.0, doc.version.1);
if !doc.structs.is_empty() {
println!();
println!("{}", "Structs:".cyan());
for (name, cols) in &doc.structs {
println!(" {}: [{}]", name.green(), cols.join(", "));
}
}
if !doc.aliases.is_empty() {
println!();
println!("{}", "Aliases:".cyan());
for (name, value) in &doc.aliases {
println!(" %{}: \"{}\"", name.green(), value);
}
}
if !doc.nests.is_empty() {
println!();
println!("{}", "Nests:".cyan());
for (parent, children) in &doc.nests {
for child in children {
println!(" {} > {}", parent.green(), child);
}
}
}
println!();
println!("{}", "Root:".cyan());
print_items(&doc.root, 1, verbose);
Ok(())
}
fn print_items(items: &BTreeMap<String, Item>, indent: usize, verbose: bool) {
let prefix = " ".repeat(indent);
for (key, item) in items {
match item {
Item::Scalar(value) => {
println!("{}{}: {}", prefix, key.yellow(), format_value(value));
}
Item::Object(child) => {
println!("{}{}:", prefix, key.yellow());
print_items(child, indent + 1, verbose);
}
Item::List(list) => {
println!(
"{}{}:@{} ({} rows)",
prefix,
key.yellow(),
list.type_name.green(),
list.rows.len()
);
if verbose {
println!("{} schema: [{}]", prefix, list.schema.join(", "));
for (i, row) in list.rows.iter().enumerate() {
println!("{} [{}] id={}", prefix, i, row.id);
for (field_idx, col) in list.schema.iter().enumerate() {
if let Some(v) = row.fields.get(field_idx) {
println!("{} {}: {}", prefix, col, format_value(v));
}
}
}
}
}
}
}
}
fn format_value(value: &Value) -> String {
match value {
Value::Null => "~".dimmed().to_string(),
Value::Bool(b) => b.to_string().magenta().to_string(),
Value::Int(n) => n.to_string().cyan().to_string(),
Value::Float(f) => f.to_string().cyan().to_string(),
Value::String(s) => format!("\"{s}\""),
Value::Tensor(t) => format!("{t:?}").cyan().to_string(),
Value::Reference(r) => r.to_ref_string().green().to_string(),
Value::Expression(e) => format!("$({e})").yellow().to_string(),
Value::List(items) => {
let formatted: Vec<String> = items.iter().map(format_value).collect();
format!("({})", formatted.join(", ")).cyan().to_string()
}
}
}