yog 0.0.1

yog: a balls-oriented session manager for lernie loops (egui frontend)
Documentation
//! egui widget: the whole-tree budget-spent figures (§11 Altitude-1 header
//! "budget-spent figures").
//!
//! A pure function of the [`BudgetSpend`] fold — the total that exhausts
//! `max_total_tokens` (ARCH §6) plus the four counters behind it. No click, so
//! it is a headless shape-walk-tested pure render; the spend fold itself is the
//! tested [`spend`](super::spend).

use super::BudgetSpend;

/// Render the focused agent's whole-tree spend on one line: the total tokens
/// billed against the ceiling, then the four counters that summed to it.
pub fn render(ui: &mut egui::Ui, spend: &BudgetSpend) {
    ui.horizontal(|ui| {
        ui.label(format!("budget {} tok", spend.total_tokens()));
        ui.weak(format!(
            "(in {} · out {} · cache r {} · w {})",
            spend.input_tokens,
            spend.output_tokens,
            spend.cache_read_tokens,
            spend.cache_write_tokens
        ));
    });
}

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

    fn painted(spend: &BudgetSpend) -> String {
        let ctx = egui::Context::default();
        let out = ctx.run(egui::RawInput::default(), |ctx| {
            egui::CentralPanel::default().show(ctx, |ui| render(ui, spend));
        });
        let mut text = String::new();
        for clipped in out.shapes {
            if let egui::Shape::Text(t) = &clipped.shape {
                text.push_str(t.galley.text());
                text.push('\n');
            }
        }
        text
    }

    #[test]
    fn renders_total_and_counters() {
        let spend = BudgetSpend {
            input_tokens: 10,
            output_tokens: 5,
            cache_read_tokens: 2,
            cache_write_tokens: 1,
        };
        let text = painted(&spend);
        assert!(text.contains("budget 18 tok"), "got:\n{text}");
        assert!(
            text.contains("in 10 · out 5 · cache r 2 · w 1"),
            "got:\n{text}"
        );
    }

    #[test]
    fn renders_zero_spend() {
        assert!(painted(&BudgetSpend::default()).contains("budget 0 tok"));
    }
}