diff --git a/src/app.rs b/src/app.rs index eccd892..ec7b8a4 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,12 +1,19 @@ -use crate::config::WindowStacking; -use crate::{config, script_var_handler::*, util, widgets}; -use crate::{config::WindowName, util::Coords, value::PrimitiveValue}; -use crate::{eww_state, value::VarName}; +use crate::{ + config, + config::{WindowName, WindowStacking}, + eww_state, + script_var_handler::*, + util, + util::Coords, + value::{PrimitiveValue, VarName}, + widgets, +}; use anyhow::*; -use crossbeam_channel::Sender; +use crossbeam_channel; use debug_stub_derive::*; use gdk::WindowExt; use gtk::{ContainerExt, CssProviderExt, GtkWindowExt, StyleContextExt, WidgetExt}; +use itertools::Itertools; use std::collections::HashMap; #[derive(Debug)] @@ -23,7 +30,7 @@ pub enum EwwCommand { window_name: WindowName, }, KillServer, - PrintState, + PrintState(crossbeam_channel::Sender), } #[derive(DebugStub)] @@ -38,7 +45,7 @@ pub struct App { } impl App { - pub fn handle_command(&mut self, event: EwwCommand, response_sender: Option>) { + pub fn handle_command(&mut self, event: EwwCommand) { log::debug!("Handling event: {:?}", &event); let result: Result<_> = match event { EwwCommand::UpdateVar(key, value) => self.update_state(key, value), @@ -50,16 +57,18 @@ impl App { } EwwCommand::OpenWindow { window_name, pos, size } => self.open_window(&window_name, pos, size), EwwCommand::CloseWindow { window_name } => self.close_window(&window_name), - EwwCommand::PrintState => Ok(()), + EwwCommand::PrintState(sender) => { + let output = self + .eww_state + .get_variables() + .iter() + .map(|(key, value)| format!("{}: {}", key, value)) + .join("\n"); + sender.send(output).context("sending response from main thread") + } }; - if let Err(err) = result { - if let Some(response_sender) = response_sender { - let _ = response_sender.send(format!("Error while handling event: {:?}", err)); - } else { - eprintln!("Error while handling event: {:?}", err); - } - } + util::print_result_err("while handling event", &result); } fn update_state(&mut self, fieldname: VarName, value: PrimitiveValue) -> Result<()> { @@ -144,9 +153,10 @@ impl App { pub fn reload_all_windows(&mut self, config: config::EwwConfig) -> Result<()> { // refresh script-var poll stuff - if let Err(e) = self.script_var_handler.initialize_clean(config.get_script_vars().clone()) { - eprintln!("Error while setting up script-var commands: {:?}", e); - } + util::print_result_err( + "while setting up script-var commands", + &self.script_var_handler.initialize_clean(config.get_script_vars().clone()), + ); self.eww_config = config; self.eww_state.clear_all_window_states(); diff --git a/src/eww_state.rs b/src/eww_state.rs index 19e2bd2..d876553 100644 --- a/src/eww_state.rs +++ b/src/eww_state.rs @@ -76,6 +76,10 @@ impl EwwState { } } + pub fn get_variables(&self) -> &HashMap { + &self.variables_state + } + /// remove all state stored specific to one window pub fn clear_window_state(&mut self, window_name: &WindowName) { self.windows.remove(window_name); diff --git a/src/main.rs b/src/main.rs index 3dfb473..9d09e9a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,9 +9,6 @@ extern crate gtk; use anyhow::*; use eww_state::*; -use gdk::*; -use gtk::prelude::*; -use hotwatch; use log; use pretty_env_logger; use serde::{Deserialize, Serialize}; @@ -79,10 +76,10 @@ pub struct Opt { } #[derive(StructOpt, Debug, Serialize, Deserialize, PartialEq)] pub enum OptAction { - #[structopt(name = "update")] + #[structopt(name = "update", help = "update the value of a variable")] Update { fieldname: VarName, value: PrimitiveValue }, - #[structopt(name = "open")] + #[structopt(name = "open", help = "open a window")] OpenWindow { window_name: config::WindowName, @@ -93,24 +90,27 @@ pub enum OptAction { size: Option, }, - #[structopt(name = "close")] + #[structopt(name = "close", help = "close the window with the given name")] CloseWindow { window_name: config::WindowName }, - #[structopt(name = "kill")] + #[structopt(name = "kill", help = "kill the eww daemon")] KillServer, - #[structopt(name = "state")] + #[structopt(name = "state", help = "Print the current eww-state")] ShowState, } -impl Into for OptAction { - fn into(self) -> app::EwwCommand { +impl OptAction { + fn into_eww_command(self) -> (app::EwwCommand, Option>) { match self { - OptAction::Update { fieldname, value } => app::EwwCommand::UpdateVar(fieldname, value), - OptAction::OpenWindow { window_name, pos, size } => app::EwwCommand::OpenWindow { window_name, pos, size }, - OptAction::CloseWindow { window_name } => app::EwwCommand::CloseWindow { window_name }, - OptAction::KillServer => app::EwwCommand::KillServer, - OptAction::ShowState => unimplemented!(), + OptAction::Update { fieldname, value } => (app::EwwCommand::UpdateVar(fieldname, value), None), + OptAction::OpenWindow { window_name, pos, size } => (app::EwwCommand::OpenWindow { window_name, pos, size }, None), + OptAction::CloseWindow { window_name } => (app::EwwCommand::CloseWindow { window_name }, None), + OptAction::KillServer => (app::EwwCommand::KillServer, None), + OptAction::ShowState => { + let (send, recv) = crossbeam_channel::unbounded(); + (app::EwwCommand::PrintState(send), Some(recv)) + } } } } @@ -121,6 +121,10 @@ fn try_main() -> Result<()> { if let Ok(mut stream) = net::UnixStream::connect(&*IPC_SOCKET_PATH) { log::info!("Forwarding options to server"); stream.write_all(&bincode::serialize(&opts)?)?; + + let mut buf = String::new(); + stream.read_to_string(&mut buf)?; + println!("{}", buf); } else { log::info!("No instance found... Initializing server."); @@ -175,13 +179,19 @@ fn initialize_server(opts: Opt) -> Result<()> { } // run the command that eww was started with - app.handle_command(opts.action.into(), None); + let (command, maybe_response_recv) = opts.action.into_eww_command(); + app.handle_command(command); + if let Some(response_recv) = maybe_response_recv { + if let Ok(response) = response_recv.recv_timeout(std::time::Duration::from_millis(100)) { + println!("{}", response); + } + } run_server_thread(evt_send.clone())?; let _hotwatch = run_filewatch_thread(&config_file_path, &scss_file_path, evt_send.clone())?; evt_recv.attach(None, move |msg| { - app.handle_command(msg, None); + app.handle_command(msg); glib::Continue(true) }); @@ -196,9 +206,19 @@ fn run_server_thread(evt_send: glib::Sender) -> Result<()> { log::info!("Starting up eww server"); let listener = net::UnixListener::bind(&*IPC_SOCKET_PATH)?; for stream in listener.incoming() { - let command: Opt = bincode::deserialize_from(stream?)?; - log::info!("received command from IPC: {:?}", &command); - evt_send.send(command.action.into())?; + try_logging_errors!("handling message from IPC client" => { + let mut stream = stream?; + let opts: Opt = bincode::deserialize_from(&stream)?; + log::info!("received command from IPC: {:?}", &opts); + let (command, maybe_response_recv) = opts.action.into_eww_command(); + evt_send.send(command)?; + if let Some(response_recv) = maybe_response_recv { + if let Ok(response) = response_recv.recv_timeout(std::time::Duration::from_millis(100)) { + let result = &stream.write_all(response.as_bytes()); + util::print_result_err("Sending text response to ipc client", &result); + } + } + }); } }; if let Err(err) = result { @@ -233,9 +253,7 @@ fn run_filewatch_thread>( evt_send.send(app::EwwCommand::ReloadCss(eww_css))?; }) }); - if let Err(e) = result { - eprintln!("WARN: error while loading CSS file for hot-reloading: \n{}", e) - }; + util::print_result_err("while loading CSS file for hot-reloading", &result); Ok(hotwatch) } diff --git a/src/util.rs b/src/util.rs index 2b566ed..cb9ab57 100644 --- a/src/util.rs +++ b/src/util.rs @@ -79,3 +79,10 @@ pub fn replace_env_var_references(input: String) -> String { }) .into_owned() } + +/// If the given result is `Err`, prints out the error value using `{:?}` +pub fn print_result_err(context: &str, result: &std::result::Result) { + if let Err(err) = result { + eprintln!("Error {}: {:?}", context, err); + } +}