use arc_swap::ArcSwap; use parking_lot::Mutex; use std::collections::hash_map::DefaultHasher; use std::collections::HashMap; use std::hash::{Hash, Hasher}; use std::sync::Arc; use rand::rngs::StdRng; use rand::SeedableRng; use crate::model::{ScriptEngine, StepContext, Value}; use crate::state::{EditorContext, StackCache}; pub fn update_cache(editor_ctx: &EditorContext) { let lines = editor_ctx.editor.lines(); let cursor_line = editor_ctx.editor.cursor().0; let mut hasher = DefaultHasher::new(); for (i, line) in lines.iter().enumerate() { if i > cursor_line { break; } line.hash(&mut hasher); } let lines_hash = hasher.finish(); if let Some(ref c) = *editor_ctx.stack_cache.borrow() { if c.cursor_line == cursor_line && c.lines_hash == lines_hash { return; } } let partial: Vec<&str> = lines .iter() .take(cursor_line + 1) .map(|s| s.as_str()) .collect(); let script = partial.join("\n"); let result = if script.trim().is_empty() { "Stack: []".to_string() } else { let vars = Arc::new(ArcSwap::from_pointee(HashMap::new())); let dict = Arc::new(Mutex::new(HashMap::new())); let rng = Arc::new(Mutex::new(StdRng::seed_from_u64(42))); let mut engine = ScriptEngine::new(vars, dict, rng); let ctx = StepContext { step: 0, beat: 0.0, bank: 0, pattern: 0, tempo: 120.0, phase: 0.0, slot: 0, runs: 0, iter: 0, speed: 1.0, fill: false, nudge_secs: 0.0, cc_access: None, speed_key: "", mouse_x: 0.5, mouse_y: 0.5, mouse_down: 0.0, }; match engine.evaluate(&script, &ctx) { Ok(_) => { let stack = engine.stack(); let formatted: Vec = stack.iter().map(format_value).collect(); format!("Stack: [{}]", formatted.join(" ")) } Err(e) => format!("Error: {e}"), } }; *editor_ctx.stack_cache.borrow_mut() = Some(StackCache { cursor_line, lines_hash, result, }); } fn format_value(v: &Value) -> String { match v { Value::Int(n, _) => n.to_string(), Value::Float(f, _) => { if f.fract() == 0.0 && f.abs() < 1_000_000.0 { format!("{f:.1}") } else { format!("{f:.4}") } } Value::Str(s, _) => format!("\"{s}\""), Value::Quotation(..) => "[...]".to_string(), Value::CycleList(items) | Value::ArpList(items) => { let inner: Vec = items.iter().map(format_value).collect(); format!("({})", inner.join(" ")) } } }