From 0f68a76507bb818f21b4edf9a3dc1665aa8bc519 Mon Sep 17 00:00:00 2001 From: ElKowar <5300871+elkowar@users.noreply.github.com> Date: Fri, 30 Oct 2020 22:12:21 +0100 Subject: [PATCH] Implement multiple value update, breakign syntax of eww update (#51) --- src/app.rs | 66 ++++++++++++++++++++++++--------------- src/opts.rs | 51 +++++++++++++++++++++++------- src/script_var_handler.rs | 6 ++-- 3 files changed, 83 insertions(+), 40 deletions(-) diff --git a/src/app.rs b/src/app.rs index 324ff67..e040299 100644 --- a/src/app.rs +++ b/src/app.rs @@ -18,7 +18,7 @@ use std::collections::HashMap; #[derive(Debug)] pub enum EwwCommand { - UpdateVar(VarName, PrimitiveValue), + UpdateVars(Vec<(VarName, PrimitiveValue)>), ReloadConfig(config::EwwConfig), ReloadCss(String), OpenWindow { @@ -55,31 +55,45 @@ pub struct App { impl App { 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), - EwwCommand::ReloadConfig(config) => self.reload_all_windows(config), - EwwCommand::ReloadCss(css) => self.load_css(&css), - EwwCommand::KillServer => { - log::info!("Received kill command, stopping server!"); - self.script_var_handler.stop(); - self.windows.values().for_each(|w| w.gtk_window.close()); - script_var_process::on_application_death(); - std::process::exit(0); - } - EwwCommand::OpenWindow { window_name, pos, size } => self.open_window(&window_name, pos, size), - EwwCommand::CloseWindow { window_name } => self.close_window(&window_name), - 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") - } - EwwCommand::PrintDebug(sender) => { - let output = format!("state: {:#?}\n\nconfig: {:#?}", &self.eww_state, &self.eww_config); - sender.send(output).context("sending response from main thread") + let result: Result<_> = try { + match event { + EwwCommand::UpdateVars(mappings) => { + for (var_name, new_value) in mappings { + self.update_state(var_name, new_value)?; + } + } + EwwCommand::ReloadConfig(config) => { + self.reload_all_windows(config)?; + } + EwwCommand::ReloadCss(css) => { + self.load_css(&css)?; + } + EwwCommand::KillServer => { + log::info!("Received kill command, stopping server!"); + self.script_var_handler.stop(); + self.windows.values().for_each(|w| w.gtk_window.close()); + script_var_process::on_application_death(); + std::process::exit(0); + } + EwwCommand::OpenWindow { window_name, pos, size } => { + self.open_window(&window_name, pos, size)?; + } + EwwCommand::CloseWindow { window_name } => { + self.close_window(&window_name)?; + } + 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")? + } + EwwCommand::PrintDebug(sender) => { + let output = format!("state: {:#?}\n\nconfig: {:#?}", &self.eww_state, &self.eww_config); + sender.send(output).context("sending response from main thread")? + } } }; diff --git a/src/opts.rs b/src/opts.rs index 442b2f6..1a4bf5e 100644 --- a/src/opts.rs +++ b/src/opts.rs @@ -1,3 +1,4 @@ +use anyhow::*; use serde::{Deserialize, Serialize}; use structopt::StructOpt; @@ -12,6 +13,8 @@ pub struct Opt { #[structopt(subcommand)] pub action: Action, + /// Run Eww in the background, daemonizing it. + /// When daemonized, to kill eww you can run `eww kill`. To see logs, use `eww logs`. #[structopt(short = "-d", long = "--detach")] pub should_detach: bool, } @@ -26,43 +29,69 @@ pub enum Action { #[derive(StructOpt, Debug, Serialize, Deserialize, PartialEq)] pub enum ActionClientOnly { - #[structopt(name = "logs", help = "Print and watch the eww logs")] + /// Print and watch the eww logs + #[structopt(name = "logs")] Logs, } #[derive(StructOpt, Debug, Serialize, Deserialize, PartialEq)] pub enum ActionWithServer { - #[structopt(name = "update", help = "update the value of a variable, in a running eww instance")] - Update { fieldname: VarName, value: PrimitiveValue }, + /// Update the value of a variable, in a running eww instance + #[structopt(name = "update")] + Update { + /// variable_name="new_value"-pairs that will be updated + #[structopt(parse(try_from_str = parse_var_update_arg))] + mappings: Vec<(VarName, PrimitiveValue)>, + }, - #[structopt(name = "open", help = "open a window")] + /// open a window + #[structopt(name = "open")] OpenWindow { + /// Name of the window you want to open. window_name: WindowName, - #[structopt(short, long, help = "The position of the window, where it should open.")] + /// The position of the window, where it should open. + #[structopt(short, long)] pos: Option, - #[structopt(short, long, help = "The size of the window to open")] + /// The size of the window to open + #[structopt(short, long)] size: Option, }, - #[structopt(name = "close", help = "close the window with the given name")] + /// Close the window with the given name + #[structopt(name = "close")] CloseWindow { window_name: WindowName }, - #[structopt(name = "kill", help("kill the eww daemon"))] + /// kill the eww daemon + #[structopt(name = "kill")] KillServer, - #[structopt(name = "state", help = "Print the current eww-state")] + /// Print the current eww-state + #[structopt(name = "state")] ShowState, - #[structopt(name = "debug", help = "Print out the widget structure as seen by eww")] + /// Print out the widget structure as seen by eww. + /// + /// This may be useful if you are facing issues with how eww is interpreting your configuration, + /// and to provide additional context to the eww developers if you are filing a bug. + #[structopt(name = "debug")] ShowDebug, } +fn parse_var_update_arg(s: &str) -> Result<(VarName, PrimitiveValue)> { + let (name, value) = s + .split_once('=') + .with_context(|| format!("arguments must be in the shape `variable_name=\"new_value\"`, but got: {}", s))?; + Ok((name.into(), PrimitiveValue::from_string(value.to_owned()))) +} + impl ActionWithServer { pub fn into_eww_command(self) -> (app::EwwCommand, Option>) { let command = match self { - ActionWithServer::Update { fieldname, value } => app::EwwCommand::UpdateVar(fieldname, value), + ActionWithServer::Update { mappings } => { + app::EwwCommand::UpdateVars(mappings.into_iter().map(|x| x.into()).collect()) + } ActionWithServer::OpenWindow { window_name, pos, size } => app::EwwCommand::OpenWindow { window_name, pos, size }, ActionWithServer::CloseWindow { window_name } => app::EwwCommand::CloseWindow { window_name }, ActionWithServer::KillServer => app::EwwCommand::KillServer, diff --git a/src/script_var_handler.rs b/src/script_var_handler.rs index 2d03784..b445a69 100644 --- a/src/script_var_handler.rs +++ b/src/script_var_handler.rs @@ -70,7 +70,7 @@ impl ScriptVarHandler { var.interval, glib::clone!(@strong var, @strong evt_send => move |_| { let result: Result<_> = try { - evt_send.send(app::EwwCommand::UpdateVar(var.name.clone(), var.run_once()?))?; + evt_send.send(app::EwwCommand::UpdateVars(vec![(var.name.clone(), var.run_once()?)]))?; }; util::print_result_err("while running script-var command", &result); }), @@ -112,10 +112,10 @@ impl ScriptVarHandler { .with_context(|| format!("No command output handle found for variable '{}'", var_name))?; let mut buffer = String::new(); handle.stdout_reader.read_line(&mut buffer)?; - evt_send.send(EwwCommand::UpdateVar( + evt_send.send(EwwCommand::UpdateVars(vec![( var_name.to_owned(), PrimitiveValue::from_string(buffer.trim_matches('\n').to_owned()), - ))?; + )]))?; } else if event.hangup { script_var_processes.remove(var_name); sources.unregister(var_name);