feat(cli): add --toggle to open-many, allow closing multiple windows at once
This commit is contained in:
parent
7ffebf6903
commit
9ce219a420
3 changed files with 69 additions and 43 deletions
|
@ -25,6 +25,7 @@ pub enum DaemonCommand {
|
|||
UpdateCss(String),
|
||||
OpenMany {
|
||||
windows: Vec<String>,
|
||||
should_toggle: bool,
|
||||
sender: DaemonResponseSender,
|
||||
},
|
||||
OpenWindow {
|
||||
|
@ -36,8 +37,8 @@ pub enum DaemonCommand {
|
|||
should_toggle: bool,
|
||||
sender: DaemonResponseSender,
|
||||
},
|
||||
CloseWindow {
|
||||
window_name: String,
|
||||
CloseWindows {
|
||||
windows: Vec<String>,
|
||||
sender: DaemonResponseSender,
|
||||
},
|
||||
KillServer,
|
||||
|
@ -97,23 +98,15 @@ impl App {
|
|||
let mut errors = Vec::new();
|
||||
|
||||
let config_result = config::read_from_file(&self.paths.get_yuck_path());
|
||||
match config_result.and_then(|new_config| self.load_config(new_config)) {
|
||||
Ok(()) => {}
|
||||
Err(e) => errors.push(e),
|
||||
if let Err(e) = config_result.and_then(|new_config| self.load_config(new_config)) {
|
||||
errors.push(e)
|
||||
}
|
||||
|
||||
let css_result = crate::util::parse_scss_from_file(&self.paths.get_eww_scss_path());
|
||||
match css_result.and_then(|css| self.load_css(&css)) {
|
||||
Ok(()) => {}
|
||||
Err(e) => errors.push(e),
|
||||
if let Err(e) = css_result.and_then(|css| self.load_css(&css)) {
|
||||
errors.push(e)
|
||||
}
|
||||
|
||||
let errors = errors.into_iter().map(|e| error_handling_ctx::format_error(&e)).join("\n");
|
||||
if errors.is_empty() {
|
||||
sender.send_success(String::new())?;
|
||||
} else {
|
||||
sender.send_failure(errors)?;
|
||||
}
|
||||
sender.respond_with_error_list(errors)?;
|
||||
}
|
||||
DaemonCommand::UpdateConfig(config) => {
|
||||
self.load_config(config)?;
|
||||
|
@ -132,9 +125,18 @@ impl App {
|
|||
self.close_window(&window_name)?;
|
||||
}
|
||||
}
|
||||
DaemonCommand::OpenMany { windows, sender } => {
|
||||
let result = windows.iter().try_for_each(|w| self.open_window(w, None, None, None, None));
|
||||
respond_with_result(sender, result)?;
|
||||
DaemonCommand::OpenMany { windows, should_toggle, sender } => {
|
||||
let errors = windows
|
||||
.iter()
|
||||
.map(|w| {
|
||||
if should_toggle && self.open_windows.contains_key(w) {
|
||||
self.close_window(w)
|
||||
} else {
|
||||
self.open_window(w, None, None, None, None)
|
||||
}
|
||||
})
|
||||
.filter_map(Result::err);
|
||||
sender.respond_with_error_list(errors)?;
|
||||
}
|
||||
DaemonCommand::OpenWindow { window_name, pos, size, anchor, screen: monitor, should_toggle, sender } => {
|
||||
let result = if should_toggle && self.open_windows.contains_key(&window_name) {
|
||||
|
@ -142,11 +144,11 @@ impl App {
|
|||
} else {
|
||||
self.open_window(&window_name, pos, size, monitor, anchor)
|
||||
};
|
||||
respond_with_result(sender, result)?;
|
||||
sender.respond_with_result(result)?;
|
||||
}
|
||||
DaemonCommand::CloseWindow { window_name, sender } => {
|
||||
let result = self.close_window(&window_name);
|
||||
respond_with_result(sender, result)?;
|
||||
DaemonCommand::CloseWindows { windows, sender } => {
|
||||
let errors = windows.iter().map(|window| self.close_window(&window)).filter_map(Result::err);
|
||||
sender.respond_with_error_list(errors)?;
|
||||
}
|
||||
DaemonCommand::PrintState { all, sender } => {
|
||||
let vars = self.eww_state.get_variables().iter();
|
||||
|
@ -269,7 +271,8 @@ impl App {
|
|||
self.eww_config = config;
|
||||
self.eww_state.clear_all_window_states();
|
||||
|
||||
let window_names: Vec<String> = self.open_windows.keys().cloned().chain(self.failed_windows.iter().cloned()).dedup().collect();
|
||||
let window_names: Vec<String> =
|
||||
self.open_windows.keys().cloned().chain(self.failed_windows.iter().cloned()).dedup().collect();
|
||||
for window_name in &window_names {
|
||||
self.open_window(&window_name, None, None, None, None)?;
|
||||
}
|
||||
|
@ -381,19 +384,6 @@ fn get_monitor_geometry(n: Option<i32>) -> Result<gdk::Rectangle> {
|
|||
Ok(monitor.get_geometry())
|
||||
}
|
||||
|
||||
/// In case of an Err, send the error message to a sender.
|
||||
fn respond_with_result<T>(sender: DaemonResponseSender, result: Result<T>) -> Result<()> {
|
||||
match result {
|
||||
Ok(_) => sender.send_success(String::new()),
|
||||
Err(e) => {
|
||||
let formatted = error_handling_ctx::format_error(&e);
|
||||
println!("Action failed with error: {}", formatted);
|
||||
sender.send_failure(formatted)
|
||||
},
|
||||
}
|
||||
.context("sending response from main thread")
|
||||
}
|
||||
|
||||
pub fn get_window_rectangle(geometry: WindowGeometry, screen_rect: gdk::Rectangle) -> gdk::Rectangle {
|
||||
let (offset_x, offset_y) = geometry.offset.relative_to(screen_rect.width, screen_rect.height);
|
||||
let (width, height) = geometry.size.relative_to(screen_rect.width, screen_rect.height);
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
use anyhow::*;
|
||||
use itertools::Itertools;
|
||||
|
||||
use crate::error_handling_ctx;
|
||||
|
||||
/// Response that the app may send as a response to a event.
|
||||
/// This is used in `DaemonCommand`s that contain a response sender.
|
||||
|
@ -34,6 +37,33 @@ impl DaemonResponseSender {
|
|||
pub fn send_failure(&self, s: String) -> Result<()> {
|
||||
self.0.send(DaemonResponse::Failure(s)).context("Failed to send failure response from application thread")
|
||||
}
|
||||
|
||||
/// Given a list of errors, respond with an error value if there are any errors, and respond with success otherwise.
|
||||
pub fn respond_with_error_list(&self, errors: impl IntoIterator<Item = anyhow::Error>) -> Result<()> {
|
||||
let errors = errors.into_iter().map(|e| error_handling_ctx::format_error(&e)).join("\n");
|
||||
if errors.is_empty() {
|
||||
self.send_success(String::new())
|
||||
} else {
|
||||
self.respond_with_error_msg(errors)
|
||||
}
|
||||
}
|
||||
|
||||
/// In case of an Err, send the error message to a sender.
|
||||
pub fn respond_with_result<T>(&self, result: Result<T>) -> Result<()> {
|
||||
match result {
|
||||
Ok(_) => self.send_success(String::new()),
|
||||
Err(e) => {
|
||||
let formatted = error_handling_ctx::format_error(&e);
|
||||
self.respond_with_error_msg(formatted)
|
||||
}
|
||||
}
|
||||
.context("sending response from main thread")
|
||||
}
|
||||
|
||||
fn respond_with_error_msg(&self, msg: String) -> Result<()> {
|
||||
println!("Action failed with error: {}", msg);
|
||||
self.send_failure(msg)
|
||||
}
|
||||
}
|
||||
|
||||
pub type DaemonResponseReceiver = tokio::sync::mpsc::UnboundedReceiver<DaemonResponse>;
|
||||
|
|
|
@ -106,11 +106,17 @@ pub enum ActionWithServer {
|
|||
/// Open multiple windows at once.
|
||||
/// NOTE: This will in the future be part of eww open, and will then be removed.
|
||||
#[structopt(name = "open-many")]
|
||||
OpenMany { windows: Vec<String> },
|
||||
OpenMany {
|
||||
windows: Vec<String>,
|
||||
|
||||
/// Close the window with the given name
|
||||
/// If a window is already open, close it instead
|
||||
#[structopt(long = "toggle")]
|
||||
should_toggle: bool,
|
||||
},
|
||||
|
||||
/// Close the given windows
|
||||
#[structopt(name = "close", alias = "c")]
|
||||
CloseWindow { window_name: String },
|
||||
CloseWindows { windows: Vec<String> },
|
||||
|
||||
/// Reload the configuration
|
||||
#[structopt(name = "reload", alias = "r")]
|
||||
|
@ -184,8 +190,8 @@ impl ActionWithServer {
|
|||
let _ = send.send(DaemonResponse::Success("pong".to_owned()));
|
||||
return (app::DaemonCommand::NoOp, Some(recv));
|
||||
}
|
||||
ActionWithServer::OpenMany { windows } => {
|
||||
return with_response_channel(|sender| app::DaemonCommand::OpenMany { windows, sender });
|
||||
ActionWithServer::OpenMany { windows, should_toggle } => {
|
||||
return with_response_channel(|sender| app::DaemonCommand::OpenMany { windows, should_toggle, sender });
|
||||
}
|
||||
ActionWithServer::OpenWindow { window_name, pos, size, screen, anchor, should_toggle } => {
|
||||
return with_response_channel(|sender| app::DaemonCommand::OpenWindow {
|
||||
|
@ -198,8 +204,8 @@ impl ActionWithServer {
|
|||
sender,
|
||||
})
|
||||
}
|
||||
ActionWithServer::CloseWindow { window_name } => {
|
||||
return with_response_channel(|sender| app::DaemonCommand::CloseWindow { window_name, sender });
|
||||
ActionWithServer::CloseWindows { windows } => {
|
||||
return with_response_channel(|sender| app::DaemonCommand::CloseWindows { windows, sender });
|
||||
}
|
||||
ActionWithServer::Reload => return with_response_channel(app::DaemonCommand::ReloadConfigAndCss),
|
||||
ActionWithServer::ShowWindows => return with_response_channel(app::DaemonCommand::PrintWindows),
|
||||
|
|
Loading…
Add table
Reference in a new issue