use std::cell::Cell;
use rust_dynamic::value::Value;
const MAX_DEPTH: u32 = 4;
thread_local! {
static DEPTH: Cell<u32> = const { Cell::new(0) };
}
pub fn fire(name: &str, args: Vec<Value>) {
if super::is_in_eval() {
return;
}
let depth = DEPTH.with(|c| c.get());
if depth >= MAX_DEPTH {
tracing::warn!(
target: "inkhaven::scripting::hooks",
"hook {} skipped: depth {} >= max {}",
name,
depth,
MAX_DEPTH
);
return;
}
if let Err(e) = super::init_adam() {
tracing::warn!(
target: "inkhaven::scripting::hooks",
"hook {} init_adam failed: {}",
name,
e
);
return;
}
DEPTH.with(|c| c.set(depth + 1));
let _ = super::stdlib::io::drain_print_buffer();
let outcome = super::with_adam(|bund| {
if !bund.vm.lambdas.contains_key(name) {
return Ok(());
}
for arg in args {
let _ = bund.vm.stack.push(arg);
}
bund.eval(name.to_string())
.map(|_| ())
.map_err(|e| anyhow::anyhow!("eval: {e}"))
});
DEPTH.with(|c| c.set(depth));
let stdout = super::stdlib::io::drain_print_buffer();
if !stdout.is_empty() {
for line in stdout.lines() {
if !line.is_empty() {
tracing::info!(target: "inkhaven::hook::out", hook = name, "{line}");
}
}
}
match outcome {
Some(Ok(())) => {}
Some(Err(e)) => {
tracing::warn!(
target: "inkhaven::scripting::hooks",
"hook {} failed: {}",
name,
e
);
}
None => {
}
}
}