use clap::ArgEnum; use color_eyre::Result; use schemars::JsonSchema; use serde::Deserialize; use serde::Serialize; use strum::Display; use strum::EnumString; use crate::ApplicationIdentifier; #[derive(Clone, Debug, Serialize, Deserialize, Display, EnumString, ArgEnum, JsonSchema)] #[strum(serialize_all = "snake_case")] #[serde(rename_all = "snake_case")] pub enum ApplicationOptions { ObjectNameChange, Layered, BorderOverflow, TrayAndMultiWindow, Force, } impl ApplicationOptions { #[must_use] pub fn cfgen(&self, kind: &ApplicationIdentifier, id: &str) -> String { format!( "Run, {}, , Hide", match self { ApplicationOptions::ObjectNameChange => { format!( "komorebic.exe identify-object-name-change-application {} \"{}\"", kind, id ) } ApplicationOptions::Layered => { format!( "komorebic.exe identify-layered-application {} \"{}\"", kind, id ) } ApplicationOptions::BorderOverflow => { format!( "komorebic.exe identify-border-overflow-application {} \"{}\"", kind, id ) } ApplicationOptions::TrayAndMultiWindow => { format!( "komorebic.exe identify-tray-application {} \"{}\"", kind, id ) } ApplicationOptions::Force => { format!("komorebic.exe manage-rule {} \"{}\"", kind, id) } } ) } } #[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] pub struct IdWithIdentifier { kind: ApplicationIdentifier, id: String, } #[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] pub struct IdWithIdentifierAndComment { kind: ApplicationIdentifier, id: String, #[serde(skip_serializing_if = "Option::is_none")] comment: Option, } #[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] pub struct ApplicationConfiguration { name: String, identifier: IdWithIdentifier, #[serde(skip_serializing_if = "Option::is_none")] options: Option>, #[serde(skip_serializing_if = "Option::is_none")] float_identifiers: Option>, } #[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] pub struct ApplicationConfigurationGenerator; impl ApplicationConfigurationGenerator { fn load(content: &str) -> Result> { Ok(serde_yaml::from_str(content)?) } pub fn format(content: &str) -> Result { let mut cfgen = Self::load(content)?; cfgen.sort_by(|a, b| a.name.cmp(&b.name)); Ok(serde_yaml::to_string(&cfgen)?) } fn merge(base_content: &str, override_content: &str) -> Result> { let base_cfgen = Self::load(base_content)?; let override_cfgen = Self::load(override_content)?; let mut final_cfgen = base_cfgen.clone(); for entry in override_cfgen { let mut replace_idx = None; for (idx, base_entry) in base_cfgen.iter().enumerate() { if base_entry.name == entry.name { replace_idx = Option::from(idx); } } match replace_idx { None => final_cfgen.push(entry), Some(idx) => final_cfgen[idx] = entry, } } Ok(final_cfgen) } pub fn generate_ahk(base_content: &str, override_content: Option<&str>) -> Result> { let mut cfgen = if let Some(override_content) = override_content { Self::merge(base_content, override_content)? } else { Self::load(base_content)? }; cfgen.sort_by(|a, b| a.name.cmp(&b.name)); let mut lines = vec![ String::from("; Generated by komorebic.exe"), String::from("; To use this file, add the line below to the top of your komorebi.ahk configuration file"), String::from("; #Include %A_ScriptDir%\\komorebi.generated.ahk"), String::from("") ]; let mut float_rules = vec![]; for app in cfgen { lines.push(format!("; {}", app.name)); if let Some(options) = app.options { for opt in options { if let ApplicationOptions::TrayAndMultiWindow = opt { lines.push(String::from("; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line")); } lines.push(opt.cfgen(&app.identifier.kind, &app.identifier.id)); } } if let Some(float_identifiers) = app.float_identifiers { for float in float_identifiers { let float_rule = format!( "Run, komorebic.exe float-rule {} \"{}\", , Hide", float.kind, float.id ); // Don't want to send duped signals especially as configs get larger if !float_rules.contains(&float_rule) { float_rules.push(float_rule.clone()); if let Some(comment) = float.comment { lines.push(format!("; {}", comment)); }; lines.push(float_rule); } } } lines.push(String::from("")); } Ok(lines) } }