ronq 0.1.1

ron query cli utility
use colored::Colorize;
use regex::Regex;
use ron::Value;
use std::fs;
use std::io::{self, Read};

pub fn load_value(file: &Option<String>) -> Value {
    let content = if let Some(f) = file {
        fs::read_to_string(f).expect("Failed to read file")
    } else {
        let mut buf = String::new();
        io::stdin()
            .read_to_string(&mut buf)
            .expect("Failed to read stdin");
        buf
    };

    ron::from_str(&content).expect("Failed to parse RON")
}

pub fn get_path<'a>(value: &'a Value, path: &str) -> Option<&'a Value> {
    let mut current = value;
    let re = Regex::new(r"([^\[\]]+)|\[(\d+)\]").unwrap();

    for part in path.split('.') {
        let mut temp = current;

        for cap in re.captures_iter(part) {
            if let Some(key_match) = cap.get(1) {
                let key = key_match.as_str();
                if let Value::Map(map) = temp {
                    temp = map.get(&Value::String(key.to_string()))?;
                } else {
                    return None;
                }
            } else if let Some(idx_match) = cap.get(2) {
                let idx: usize = idx_match.as_str().parse().ok()?;
                if let Value::Seq(seq) = temp {
                    temp = seq.get(idx)?;
                } else {
                    return None;
                }
            }
        }

        current = temp;
    }

    Some(current)
}

pub fn pretty_print(value: &Value, indent: usize) {
    let pad = " ".repeat(indent);

    match value {
        Value::Map(map) => {
            println!("{}{{", pad);
            for (k, v) in map.iter() {
                if let Value::String(key) = k {
                    print!("{}  {}: ", pad, key.cyan());
                    pretty_print(v, indent + 2);
                } else {
                    print!("{}  <non-string key>: ", pad);
                    pretty_print(v, indent + 2);
                }
            }
            println!("{}}}", pad);
        }
        Value::Seq(seq) => {
            println!("{}[", pad);
            for v in seq {
                pretty_print(v, indent + 2);
            }
            println!("{}]", pad);
        }
        Value::Number(n) => println!("{}{}", pad, n.into_f64().to_string().yellow()),
        Value::Bool(b) => println!("{}{}", pad, b.to_string().green()),
        Value::String(s) => println!("{}{}", pad, s),
        _ => println!("{}<unknown>", pad),
    }
}