grav-bar 26.9.1

Fast, zero-dependency, and themed status line for the Google Antigravity CLI. Compatible also with Claude code.
//! Minimal JSON field extraction.
//!
//! grav-bar never parses the whole document. It looks up the handful of keys it
//! needs by string search, and scopes that search to a parent object with
//! [`object_slice`] whenever the same key appears in several places.

/// Returns the string value of the first `"field":` occurrence.
pub fn extract_string_field(json: &str, field: &str) -> Option<String> {
    let search = format!("\"{field}\":");
    let idx = json.find(&search)?;
    let remainder = json[idx + search.len()..].trim_start();
    let stripped = remainder.strip_prefix('"')?;
    let end = stripped.find('"')?;
    Some(stripped[..end].to_string())
}

/// Returns the numeric value of the first `"field":` occurrence.
/// `null` and non-numeric values yield `None`.
pub fn extract_f64_field(json: &str, field: &str) -> Option<f64> {
    let search = format!("\"{field}\":");
    let idx = json.find(&search)?;
    let remainder = json[idx + search.len()..].trim_start();
    let end = remainder
        .find(|c: char| !c.is_ascii_digit() && c != '.' && c != '-')
        .unwrap_or(remainder.len());
    remainder[..end].parse().ok()
}

/// Like [`extract_f64_field`] but truncated to a non-negative integer.
pub fn extract_u64_field(json: &str, field: &str) -> Option<u64> {
    let v = extract_f64_field(json, field)?;
    if v.is_finite() && v >= 0.0 {
        Some(v as u64)
    } else {
        None
    }
}

/// Returns the `{ ... }` object that is the value of the first `"key":`
/// occurrence, braces included. Braces inside string literals are ignored.
pub fn object_slice<'a>(json: &'a str, key: &str) -> Option<&'a str> {
    let search = format!("\"{key}\":");
    let idx = json.find(&search)?;
    let after = &json[idx + search.len()..];
    let start = idx + search.len() + (after.len() - after.trim_start().len());
    if !json[start..].starts_with('{') {
        return None;
    }

    let mut depth = 0usize;
    let mut in_str = false;
    let mut escaped = false;
    for (i, &b) in json.as_bytes()[start..].iter().enumerate() {
        if in_str {
            if escaped {
                escaped = false;
            } else if b == b'\\' {
                escaped = true;
            } else if b == b'"' {
                in_str = false;
            }
            continue;
        }
        match b {
            b'"' => in_str = true,
            b'{' => depth += 1,
            b'}' => {
                depth -= 1;
                if depth == 0 {
                    return Some(&json[start..start + i + 1]);
                }
            }
            _ => {}
        }
    }
    None
}

#[cfg(test)]
mod tests {
    use super::*;

    const SAMPLE: &str = r#"{
        "cwd": "/Users/ash/repos/grav-bar",
        "model": {"id": "claude-fable-5-1", "display_name": "Fable 5.1 (1M context)"},
        "context_window": {"used_percentage": 4.5, "note": "has } brace and \" quote"},
        "rate_limits": {
            "five_hour": {"used_percentage": 37.2, "resets_at": 1757000000},
            "seven_day": {"used_percentage": 62.9, "resets_at": 1757200000.7}
        },
        "nothing": null
    }"#;

    #[test]
    fn string_and_number_fields() {
        assert_eq!(
            extract_string_field(SAMPLE, "cwd").as_deref(),
            Some("/Users/ash/repos/grav-bar")
        );
        assert_eq!(
            extract_string_field(SAMPLE, "display_name").as_deref(),
            Some("Fable 5.1 (1M context)")
        );
        assert_eq!(extract_f64_field(SAMPLE, "nothing"), None);
        assert_eq!(extract_string_field(SAMPLE, "missing"), None);
        assert_eq!(extract_u64_field(SAMPLE, "resets_at"), Some(1757000000));
    }

    #[test]
    fn object_slice_scopes_duplicate_keys() {
        let ctx = object_slice(SAMPLE, "context_window").unwrap();
        assert!(ctx.starts_with('{') && ctx.ends_with('}'));
        assert_eq!(extract_f64_field(ctx, "used_percentage"), Some(4.5));

        let limits = object_slice(SAMPLE, "rate_limits").unwrap();
        let week = object_slice(limits, "seven_day").unwrap();
        assert_eq!(extract_f64_field(week, "used_percentage"), Some(62.9));
        assert_eq!(extract_u64_field(week, "resets_at"), Some(1757200000));
    }

    #[test]
    fn object_slice_rejects_non_objects() {
        assert_eq!(object_slice(SAMPLE, "cwd"), None);
        assert_eq!(object_slice(SAMPLE, "nothing"), None);
        assert_eq!(object_slice("{\"a\": {", "a"), None);
    }
}