diff --git a/src/main.rs b/src/main.rs index 9fa14b8..722368f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,6 @@ use anyhow::Result; use std::cell::RefCell; +use std::collections::HashMap; use std::rc::Rc; use tokio::time::{timeout, Duration}; @@ -7,16 +8,133 @@ mod i3ipc; use i3ipc::{Connection, MessageType}; +fn serde_lisp_value(value: &serde_json::Value) -> rust_lisp::model::Value { + match value { + serde_json::Value::Null => rust_lisp::model::Value::NIL, + serde_json::Value::Bool(b) => { + if *b { + rust_lisp::model::Value::True + } else { + rust_lisp::model::Value::False + } + } + serde_json::Value::Number(n) => { + if n.is_i64() { + rust_lisp::model::Value::Int(n.as_i64().unwrap() as rust_lisp::model::IntType) + } else if n.is_u64() { + rust_lisp::model::Value::Int(n.as_u64().unwrap() as rust_lisp::model::IntType) + } else if n.is_f64() { + rust_lisp::model::Value::Float(n.as_f64().unwrap() as rust_lisp::model::FloatType) + } else { + panic!("should never happen"); + } + } + serde_json::Value::String(s) => rust_lisp::model::Value::String(s.clone()), + serde_json::Value::Array(a) => { + let mut l = rust_lisp::model::List::NIL; + for li in a.into_iter().rev() { + l = l.cons(serde_lisp_value(li)); + } + rust_lisp::model::Value::List(l) + } + serde_json::Value::Object(o) => { + let mut r = HashMap::new(); + for (k, v) in o.into_iter() { + let k_ = rust_lisp::model::Value::String(k.clone()); + let v_ = serde_lisp_value(v); + r.insert(k_, v_); + } + rust_lisp::model::Value::HashMap(Rc::new(RefCell::new(r))) + } + } +} + fn new_window_cb( b: MessageType, c: serde_json::Value, + d: bool, ) -> futures::future::BoxFuture<'static, Vec<(MessageType, Vec)>> { Box::pin(async move { - //println!("{:?}", c); - let environment = rust_lisp::default_env(); - let code = "(= 1 1)"; + let mut environment = rust_lisp::default_env(); + environment.define( + rust_lisp::model::Symbol::from("__input__"), + serde_lisp_value(&c), + ); + environment.define( + rust_lisp::model::Symbol::from("load"), + rust_lisp::model::Value::NativeClosure(Rc::new(RefCell::new( + move |e: Rc>, args: Vec| { + let path: &String = + rust_lisp::utils::require_typed_arg::<&String>("load", &args, 0)?; + let path = (*path).as_str().split('.'); + let mut i: rust_lisp::model::Value = e + .as_ref() + .borrow() + .get(&rust_lisp::model::Symbol::from("__input__")) + .unwrap(); + for p in path + .into_iter() + .filter(|x| !(*x).eq("")) + .map(|x| rust_lisp::model::Value::String(x.into())) + { + match i { + rust_lisp::model::Value::HashMap(x) => { + if let Some(_i) = x.as_ref().borrow().get(&p) { + i = _i.clone(); + } else { + return Err(rust_lisp::model::RuntimeError { + msg: format!(r#"No such key {:?}"#, p).into(), + }); + } + } + _ => { + return Err(rust_lisp::model::RuntimeError { + msg: format!(r#"No such key {:?}"#, p).into(), + }) + } + }; + } + Ok(i) + }, + ))), + ); + environment.define( + rust_lisp::model::Symbol::from("has-key"), + rust_lisp::model::Value::NativeClosure(Rc::new(RefCell::new( + move |e: Rc>, args: Vec| { + let path: &String = + rust_lisp::utils::require_typed_arg::<&String>("has-key", &args, 0)?; + let path = (*path).as_str().split('.'); + let mut i: rust_lisp::model::Value = e + .as_ref() + .borrow() + .get(&rust_lisp::model::Symbol::from("__input__")) + .unwrap(); + for p in path + .into_iter() + .filter(|x| !(*x).eq("")) + .map(|x| rust_lisp::model::Value::String(x.into())) + { + match i { + rust_lisp::model::Value::HashMap(x) => { + if let Some(_i) = x.as_ref().borrow().get(&p) { + i = _i.clone(); + } else { + return Ok(rust_lisp::model::Value::False); + } + } + _ => return Ok(rust_lisp::model::Value::False), + }; + } + Ok(rust_lisp::model::Value::True) + }, + ))), + ); + let environment = environment; + let code = r#"(load ".container.geometry")"#; let ast = rust_lisp::parser::parse(code).filter_map(|a| a.ok()); let result = rust_lisp::interpreter::eval_block(Rc::new(RefCell::new(environment)), ast); + println!("{:?}", result); Vec::new() }) @@ -36,8 +154,10 @@ async fn main() -> Result<()> { let mut connection = Connection::connect((i3ipc::get_socket_path().await?).as_ref())?; let mut sub_connection = connection.clone(); + let b_ = true; + let cb = move |a, b| {new_window_cb(a,b,b_)}; sub_connection - .subscribe(&[MessageType::SubWindow], &new_window_cb) + .subscribe(&[MessageType::SubWindow], &cb) .await?; tokio::join!( timeout(Duration::from_secs(1), sub_connection.run()),