//! Tiny shared S-expression helpers used by both the PCB and schematic
//! renderers (balanced-paren block slicing + escaping).

/// Balanced-paren slice of every `(<tag>` block whose tag is followed by a
/// whitespace/paren boundary (so `(net` never matches `(net_name`).
pub fn blocks<'a>(s: &'a str, tag: &str) -> Vec<&'a str> {
    let bytes = s.as_bytes();
    let needle = format!("({}", tag);
    let mut out = Vec::new();
    let mut search = 0;
    while let Some(rel) = s[search..].find(&needle) {
        let start = search + rel;
        let after = start + needle.len();
        let ok = bytes.get(after).map(|c| c.is_ascii_whitespace() || *c == b'(').unwrap_or(false);
        if !ok { search = after; continue; }
        let mut depth = 0i32;
        let mut end = start;
        for i in start..s.len() {
            match bytes[i] {
                b'(' => depth += 1,
                b')' => { depth -= 1; if depth == 0 { end = i; break; } }
                _ => {}
            }
        }
        out.push(&s[start..=end.min(s.len() - 1)]);
        search = end + 1;
    }
    out
}

pub fn esc(s: &str) -> String {
    s.replace('&', "&amp;").replace('<', "&lt;").replace('>', "&gt;").replace('"', "&quot;")
}

pub fn f(cap: Option<regex::Match>) -> f64 { cap.and_then(|m| m.as_str().parse().ok()).unwrap_or(0.0) }