Compare commits
No commits in common. "1b6c9e46be4733f2a8a5f47e98a84a4433731178" and "23dc47a008e19b4e533cd10b7a69d4d662d4f7d3" have entirely different histories.
1b6c9e46be
...
23dc47a008
3 changed files with 11 additions and 72 deletions
|
@ -8,13 +8,9 @@ edition = "2021"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.75"
|
anyhow = "1.0.75"
|
||||||
byteorder = "1.5.0"
|
byteorder = "1.5.0"
|
||||||
clap = { version = "4.4.6", features = ["derive"] }
|
|
||||||
env_logger = "0.10.0"
|
|
||||||
futures = "0.3.28"
|
futures = "0.3.28"
|
||||||
log = "0.4.20"
|
|
||||||
rust_lisp = { git = "https://github.com/brundonsmith/rust_lisp.git", branch = "arc-feature-addition", features = ["arc"] }
|
rust_lisp = { git = "https://github.com/brundonsmith/rust_lisp.git", branch = "arc-feature-addition", features = ["arc"] }
|
||||||
serde = { version = "1.0.188", features = ["std", "derive", "serde_derive"] }
|
serde = { version = "1.0.188", features = ["std", "derive", "serde_derive"] }
|
||||||
serde_json = "1.0.107"
|
serde_json = "1.0.107"
|
||||||
serde_yaml = "0.9.25"
|
serde_yaml = "0.9.25"
|
||||||
tokio = { version = "1.33.0", features = ["full"] }
|
tokio = { version = "1.33.0", features = ["full"] }
|
||||||
xdg = "2.5.2"
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
use std::fmt::{Display, Formatter};
|
|
||||||
use serde::{Serialize, Deserialize, Serializer, Deserializer};
|
use serde::{Serialize, Deserialize, Serializer, Deserializer};
|
||||||
use rust_lisp::model::Value as RValue;
|
use rust_lisp::model::Value as RValue;
|
||||||
|
|
||||||
|
@ -19,18 +18,6 @@ impl Into<Vec<RValue>> for Value {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Value {
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
|
|
||||||
let mut s = String::new();
|
|
||||||
s.push_str("(begin\n");
|
|
||||||
for i in &self.0 {
|
|
||||||
s.push_str(&format!("{}\n", i));
|
|
||||||
}
|
|
||||||
s.push_str(")");
|
|
||||||
write!(f, "{}", &s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'de> Deserialize<'de> for Value {
|
impl<'de> Deserialize<'de> for Value {
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
where
|
where
|
||||||
|
@ -42,6 +29,7 @@ impl<'de> Deserialize<'de> for Value {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct Program {
|
pub struct Program {
|
||||||
|
|
65
src/main.rs
65
src/main.rs
|
@ -1,10 +1,6 @@
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use tokio::time::{timeout, Duration};
|
use tokio::time::{timeout, Duration};
|
||||||
use tokio::io::AsyncReadExt;
|
use tokio::io::AsyncReadExt;
|
||||||
use clap::Parser;
|
|
||||||
use log::{info, debug, warn};
|
|
||||||
use std::path::PathBuf;
|
|
||||||
use std::str::FromStr;
|
|
||||||
|
|
||||||
mod config;
|
mod config;
|
||||||
mod i3ipc;
|
mod i3ipc;
|
||||||
|
@ -13,69 +9,37 @@ mod lisp;
|
||||||
use config::Config;
|
use config::Config;
|
||||||
use i3ipc::{Connection, MessageType};
|
use i3ipc::{Connection, MessageType};
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
#[derive(Parser)]
|
|
||||||
#[command(author, version, about, long_about = None)]
|
|
||||||
struct Args {
|
|
||||||
#[arg(short, long, value_name = "FILE")]
|
|
||||||
config: Option<PathBuf>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Args {
|
|
||||||
fn finish(&mut self) {
|
|
||||||
// TODO maybe return separate type
|
|
||||||
if self.config.is_none() {
|
|
||||||
self.config = Some(xdg::BaseDirectories::with_prefix("i3toolwait").unwrap().get_config_file("config.yaml"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new_window_cb(
|
fn new_window_cb(
|
||||||
b: MessageType,
|
b: MessageType,
|
||||||
c: serde_json::Value,
|
c: serde_json::Value,
|
||||||
config: &Config,
|
config: &Config,
|
||||||
args: &Args,
|
|
||||||
) -> futures::future::BoxFuture<'static, Vec<(MessageType, Vec<u8>)>> {
|
) -> futures::future::BoxFuture<'static, Vec<(MessageType, Vec<u8>)>> {
|
||||||
let config_ = config.clone();
|
let config_ = config.clone();
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
debug!("Received window event: {}", &c);
|
|
||||||
for p in config_.programs.iter() {
|
for p in config_.programs.iter() {
|
||||||
debug!("Evaluating program: {}", &p.match_);
|
|
||||||
let e = lisp::env(&c);
|
let e = lisp::env(&c);
|
||||||
let init: Vec<rust_lisp::model::Value> = config_.init.clone().into();
|
let init: Vec<rust_lisp::model::Value> = config_.init.clone().into();
|
||||||
let prog: Vec<rust_lisp::model::Value> = p.match_.clone().into();
|
let prog: Vec<rust_lisp::model::Value> = p.match_.clone().into();
|
||||||
let m = init.into_iter().chain(prog.into_iter());
|
let m = init.into_iter().chain(prog.into_iter());
|
||||||
let result = rust_lisp::interpreter::eval_block(rust_lisp::model::reference::new(e), m);
|
let result = rust_lisp::interpreter::eval_block(rust_lisp::model::reference::new(e), m);
|
||||||
|
println!("{:?}", result);
|
||||||
if let Ok(rust_lisp::model::Value::True) = result {
|
if let Ok(rust_lisp::model::Value::True) = result {
|
||||||
debug!("Match found");
|
|
||||||
return vec![(MessageType::Command, p.cmd.clone().into_bytes())];
|
return vec![(MessageType::Command, p.cmd.clone().into_bytes())];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
debug!("No match found");
|
|
||||||
Vec::new()
|
Vec::new()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn run<'a>(connection: &mut Connection<'a>, config: &Config) -> Result<(), anyhow::Error> {
|
async fn run<'a>(connection: &mut Connection<'a>, config: &Config) -> Result<(), anyhow::Error> {
|
||||||
let (_, resp) = connection.communicate(&MessageType::Version, b"").await?;
|
let resp = connection.communicate(&MessageType::Version, b"").await?;
|
||||||
info!("i3 version is {}", resp.get("human_readable").unwrap());
|
println!("{:?}", resp);
|
||||||
|
|
||||||
for p in config.programs.iter() {
|
for p in config.programs.iter() {
|
||||||
if let Some(r) = &p.run {
|
if let Some(r) = &p.run {
|
||||||
let (_, responses) = connection.communicate(&MessageType::Command, r.as_bytes()).await?;
|
let (message_type, response) = connection.communicate(&MessageType::Command, r.as_bytes()).await?;
|
||||||
match responses {
|
println!("{:?}", (message_type, response));
|
||||||
serde_json::Value::Array(responses) => {
|
|
||||||
for response in responses {
|
|
||||||
if let serde_json::Value::Bool(v) = response.get("success").unwrap() {
|
|
||||||
if !v {
|
|
||||||
warn!("Failed to run command {}: {}", r, response);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => panic!("invalid response"),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -83,25 +47,16 @@ async fn run<'a>(connection: &mut Connection<'a>, config: &Config) -> Result<(),
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<()> {
|
async fn main() -> Result<()> {
|
||||||
env_logger::init_from_env(env_logger::Env::new().filter("I3TOOLWAIT_LOG").write_style("I3TOOLWAIT_LOG_STYLE"));
|
let mut connection = Connection::connect((i3ipc::get_socket_path().await?).as_ref())?;
|
||||||
|
let mut sub_connection = connection.clone();
|
||||||
|
|
||||||
let mut args = Args::parse();
|
|
||||||
args.finish();
|
|
||||||
let args = std::sync::Arc::new(args);
|
|
||||||
let mut config = String::new();
|
let mut config = String::new();
|
||||||
if args.config.as_ref().unwrap() == &PathBuf::from_str("-").unwrap() {
|
tokio::fs::File::open("/home/redxef/CODE/i3toolwait/i3_autostart.yaml").await?.read_to_string(&mut config).await?;
|
||||||
tokio::io::stdin().read_to_string(&mut config).await?;
|
|
||||||
} else {
|
|
||||||
tokio::fs::File::open(args.config.as_ref().unwrap()).await?.read_to_string(&mut config).await?;
|
|
||||||
}
|
|
||||||
let config: Config = serde_yaml::from_str(&config)?;
|
let config: Config = serde_yaml::from_str(&config)?;
|
||||||
let config = std::sync::Arc::new(config);
|
let config = std::sync::Arc::new(config);
|
||||||
|
|
||||||
let mut connection = Connection::connect((i3ipc::get_socket_path().await?).as_ref())?;
|
|
||||||
let mut sub_connection = connection.clone();
|
|
||||||
let cb_config = config.clone();
|
let cb_config = config.clone();
|
||||||
let cb_args = args.clone();
|
let cb = move |a, b| {new_window_cb(a, b, &cb_config)};
|
||||||
let cb = move |a, b| {new_window_cb(a, b, &cb_config, &cb_args)};
|
|
||||||
sub_connection
|
sub_connection
|
||||||
.subscribe(&[MessageType::SubWindow], &cb)
|
.subscribe(&[MessageType::SubWindow], &cb)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
Loading…
Reference in a new issue