diff --git a/src/config.rs b/src/config.rs index 6b8b001..da1be46 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,6 +1,6 @@ +use kdl::KdlDocument; use std::collections::HashMap; use std::fs; -use kdl::KdlDocument; /// Configuration for swayout. pub struct Config { @@ -16,7 +16,7 @@ pub struct Config { pub struct Layout { pub name: String, pub automatic: bool, - pub outputs: HashMap, + pub outputs: HashMap, } /// Defines a monitor by make, model, and serial. @@ -56,44 +56,51 @@ pub fn get_config() -> Config { } } } -fn parse_config(kdl:String) -> Config { - let doc:KdlDocument = kdl.parse().expect("failed to parse config KDL"); +fn parse_config(kdl: String) -> Config { + let doc: KdlDocument = kdl.parse().expect("failed to parse config KDL"); - let monitors:Vec = doc.nodes().iter() + let monitors: Vec = doc + .nodes() + .iter() .filter(|node| node.name().value() == "monitor") - .map(|monitor_node| { - Monitor { - name : String::from(monitor_node[0].as_string().unwrap()), - make : String::from(monitor_node["make"].as_string().unwrap()), - model : String::from(monitor_node["model"].as_string().unwrap()), - serial : String::from(monitor_node["serial"].as_string().unwrap()), - } + .map(|monitor_node| Monitor { + name: String::from(monitor_node[0].as_string().unwrap()), + make: String::from(monitor_node["make"].as_string().unwrap()), + model: String::from(monitor_node["model"].as_string().unwrap()), + serial: String::from(monitor_node["serial"].as_string().unwrap()), }) .collect(); - let layouts:Vec = doc.nodes().iter() + let layouts: Vec = doc + .nodes() + .iter() .filter(|node| node.name().value() == "layout") .map(|layout_node| { - let layout_name = String::from(layout_node[0].as_string().unwrap()); - let automatic = layout_node.get("automatic").is_some_and(|v| v.as_bool().is_some_and(|a| a)); - let monitor_name_to_output_config:HashMap = layout_node - .children().unwrap().nodes().iter() + let name = String::from(layout_node[0].as_string().unwrap()); + let automatic = layout_node + .get("automatic") + .is_some_and(|v| v.as_bool().is_some_and(|a| a)); + let outputs: HashMap = layout_node + .children() + .unwrap() + .nodes() + .iter() .map(|output_node| { let output = String::from(output_node[0].as_string().unwrap()); let output_config = OutputConfig { - mode : String::from(output_node["mode"].as_string().unwrap()), - scale : String::from(output_node["scale"].as_string().unwrap()), - transform : String::from(output_node["transform"].as_string().unwrap()), - x : output_node["x"].as_integer().unwrap() as u16, - y : output_node["y"].as_integer().unwrap() as u16, + mode: String::from(output_node["mode"].as_string().unwrap()), + scale: String::from(output_node["scale"].as_string().unwrap()), + transform: String::from(output_node["transform"].as_string().unwrap()), + x: output_node["x"].as_integer().unwrap() as u16, + y: output_node["y"].as_integer().unwrap() as u16, }; (output, output_config) }) .collect(); Layout { - name : layout_name, - automatic: automatic, - outputs: monitor_name_to_output_config + name, + automatic, + outputs, } }) .collect(); diff --git a/src/lib.rs b/src/lib.rs index fd5775c..59d0663 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -27,12 +27,11 @@ fn get_layouts() -> HashSet { // add each individual output (by monitor name if the monitor is defined, else by output name) available_outputs.iter().for_each(|output| { // if there is a monitor for the output, use the monitor name, else use the output name - let monitor_opt = config.monitors.iter() - .find(|monitor| { - monitor.make == output.make - && monitor.model == output.model - && monitor.serial == output.serial - }); + let monitor_opt = config.monitors.iter().find(|monitor| { + monitor.make == output.make + && monitor.model == output.model + && monitor.serial == output.serial + }); if let Some(monitor) = monitor_opt { layout_names.insert(String::from(&monitor.name)); } else { @@ -44,28 +43,39 @@ fn get_layouts() -> HashSet { } /// Get the names of monitors that are available (that match an available output) -fn get_available_monitor_names<'a,'b>(config:&'a Config, available_outputs:&'b Vec) -> Vec<&'a String> { - config.monitors.iter() - .filter(|monitor| - available_outputs.iter().any(|output| +fn get_available_monitor_names<'a, 'b>( + config: &'a Config, + available_outputs: &'b Vec, +) -> Vec<&'a String> { + config + .monitors + .iter() + .filter(|monitor| { + available_outputs.iter().any(|output| { monitor.make == output.make && monitor.model == output.model && output.serial == monitor.serial - ) - ) + }) + }) .map(|monitor| &monitor.name) .collect() } /// Get the layouts for which all monitors are available. -fn get_available_layouts<'a,'b>(config:&'a Config, available_outputs:&'b Vec) -> Vec<&'a Layout> { - let available_monitor_names:Vec<&String> = get_available_monitor_names(&config, available_outputs); +fn get_available_layouts<'a, 'b>( + config: &'a Config, + available_outputs: &'b Vec, +) -> Vec<&'a Layout> { + let available_monitor_names: Vec<&String> = + get_available_monitor_names(&config, available_outputs); let mut layouts: Vec<&'a Layout> = Vec::new(); // Add each layout defined in the config file for which all outputs are available config.layouts.iter().for_each(|layout| { - if layout.outputs.iter() + if layout + .outputs + .iter() .all(|(output_name, _output)| available_monitor_names.contains(&output_name)) { layouts.push(&layout); @@ -92,30 +102,46 @@ pub fn apply_layout(layout_name: &String) { let mut output_config_map: HashMap<&String, &OutputConfig> = HashMap::new(); // First check if the layout is defined in the rules - if let Some(layout) = rules.layouts.iter().find(|layout| &layout.name == layout_name) { + if let Some(layout) = rules + .layouts + .iter() + .find(|layout| &layout.name == layout_name) + { // The layout is defined in the rules. - layout.outputs.iter().for_each(|(monitor_name, output_config)| { - let monitor = &rules.monitors.iter().find(|monitor| &monitor.name == monitor_name).unwrap(); + layout + .outputs + .iter() + .for_each(|(monitor_name, output_config)| { + let monitor = &rules + .monitors + .iter() + .find(|monitor| &monitor.name == monitor_name) + .unwrap(); - // find the output for the monitor to get the output name. - let output_opt = outputs.iter().find(|output| { - output.make == monitor.make - && output.model == monitor.model - && output.serial == monitor.serial + // find the output for the monitor to get the output name. + let output_opt = outputs.iter().find(|output| { + output.make == monitor.make + && output.model == monitor.model + && output.serial == monitor.serial + }); + if let Some(output) = output_opt { + output_config_map.insert(&output.name, &output_config); + } else { + panic!("Missing output for monitor {monitor_name}"); + } }); - if let Some(output) = output_opt { - output_config_map.insert(&output.name, &output_config); - } else { - panic!("Missing output for monitor {monitor_name}"); - } - }); } else { // The layout is not defined in the rules. // See if it is a monitor name... - if let Some(monitor) = rules.monitors.iter().find(|monitor| &monitor.name == layout_name) { + if let Some(monitor) = rules + .monitors + .iter() + .find(|monitor| &monitor.name == layout_name) + { // It is a monitor name. Find the matching output... if let Some(output) = outputs.iter().find(|output| { - output.make == monitor.make && output.model == monitor.model + output.make == monitor.make + && output.model == monitor.model && output.serial == monitor.serial }) { output_config_map.insert(&output.name, &output.output_config); @@ -124,8 +150,7 @@ pub fn apply_layout(layout_name: &String) { } } else { // See if it is an output name... - if let Some(output) = outputs.iter() - .find(|output| &output.name == layout_name) { + if let Some(output) = outputs.iter().find(|output| &output.name == layout_name) { output_config_map.insert(&output.name, &output.output_config); } else { panic!("could not find layout, monitor, or output {layout_name}") @@ -144,10 +169,11 @@ pub fn apply_automatic() -> Option { if let Some(layout) = get_available_layouts(&config, &outputs) .iter() - .find(|layout| layout.automatic) { + .find(|layout| layout.automatic) + { apply_layout(&layout.name); Some(String::from(&layout.name)) } else { None } -} \ No newline at end of file +} diff --git a/src/main.rs b/src/main.rs index 44fa79d..3f39f17 100644 --- a/src/main.rs +++ b/src/main.rs @@ -21,4 +21,4 @@ fn main() { eprintln!("Usage: {} [layout]", args[0].as_str()); process::exit(1) } -} \ No newline at end of file +} diff --git a/src/sway.rs b/src/sway.rs index 261941a..d7af4d3 100644 --- a/src/sway.rs +++ b/src/sway.rs @@ -1,8 +1,8 @@ +use crate::config::OutputConfig; +use serde_json::{from_str, Value}; use std::collections::HashMap; use std::process::Command; use std::str::from_utf8; -use serde_json::{from_str, Value}; -use crate::config::OutputConfig; /// An output, as returned by `swaymsg -t get_outputs`. pub struct Output { @@ -68,12 +68,11 @@ fn get_mode(output: &Value) -> String { /// Apply the specified outputs. Enable all outputs in [outputs], disable others. pub fn apply_outputs(all_outputs: &Vec, outputs: &HashMap<&String, &OutputConfig>) { - // set enabled outputs first, then set disabled outputs. // That way if some work before an error, you have at least one output enabled. // for outputs to be enabled: map of output name to config - let mut enabled: HashMap<&String,&OutputConfig> = HashMap::new(); + let mut enabled: HashMap<&String, &OutputConfig> = HashMap::new(); // for outputs to be disabled: output names let mut disabled: Vec<&String> = Vec::new(); @@ -86,7 +85,7 @@ pub fn apply_outputs(all_outputs: &Vec, outputs: &HashMap<&String, &Outp }); let mut cmd = Command::new("swaymsg"); - enabled.iter().for_each(|(output_name,output_config)| { + enabled.iter().for_each(|(output_name, output_config)| { cmd.arg("output"); cmd.arg(&output_name); cmd.arg("enable");