use std::collections::HashMap; use std::fs; use kdl::KdlDocument; /// Configuration for swayout. pub struct Config { /// Monitor name is independent of output name. It can be anything. pub monitors: HashMap, /// Definition of layouts: a map of the layout name to the outputs. /// The outputs is a map of the monitor name (in `monitors`) to the configuration /// of that monitor for this layout. /// Available outputs that do not match a monitor in the map are disabled. pub layouts: HashMap>, } /// Defines a monitor by make, model, and serial. pub struct Monitor { pub make: String, pub model: String, pub serial: String, } /// Configuration for an enabled output. pub struct OutputConfig { /// mode. See man 5 sway-output pub mode: String, /// scale. See man 5 sway-output pub scale: String, /// x value for position. See man 5 sway-output pub x: u16, /// y value for position. See man 5 sway-output pub y: u16, /// transform. See man 5 sway-output pub transform: String, } /// Get a `Config` from ~/.config/swayout/config.kdl. /// (It really uses XDG config dirs.) pub fn get_config() -> Config { let xdg_dirs = xdg::BaseDirectories::with_prefix("swayout").unwrap(); if let Some(path) = xdg_dirs.find_config_file("config.kdl") { let kdl = fs::read_to_string(path).expect("error reading file"); parse_config(kdl) } else { // no config files, use an empty rules Config { monitors: HashMap::new(), layouts: HashMap::new(), } } } fn parse_config(kdl:String) -> Config { let doc:KdlDocument = kdl.parse().expect("failed to parse config KDL"); let monitors:HashMap = doc.nodes().iter() .filter(|node| node.name().value() == "monitor") .map(|monitor_node| { let name = String::from(monitor_node[0].as_string().unwrap()); let monitor = Monitor { 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()), }; (name, monitor) }) .collect(); let layouts:HashMap> = doc.nodes().iter() .filter(|node| node.name().value() == "layout") .map(|layout_node| { let layout_name = String::from(layout_node[0].as_string().unwrap()); let monitor_name_to_output_config: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_i64().unwrap() as u16, y : output_node["y"].as_i64().unwrap() as u16, }; (output, output_config) }) .collect(); (layout_name,monitor_name_to_output_config) }) .collect(); Config { monitors, layouts } }