feat(config): add fmt cmd & float rule comments

This commit adds a fmt command which allows users to prepare PRs to the
configuration repository in a unified way.

The 'custom' formatter basically just ensures that the yaml array is
sorted by application name to make for easier diffs.

Serializing of Option::None has been disabled to keep the yaml file more
concise.

Finally, an option for adding comments to float rules has been included
as some of these rules can be quite esoteric and there is value in
having them annotated with comments in the configuration to preserve and
pass down the knowledge.

The config generation command has been renamed to
'ahk-app-specific-configuration' (with a short alias of 'ahk-asc') to
emphasise that an ahk file is being generated (similar to
'ahk-library').

re #62
This commit is contained in:
LGUG2Z
2022-04-03 13:42:31 -07:00
parent c2cc21d09d
commit c426c06c01
4 changed files with 73 additions and 15 deletions

4
Cargo.lock generated
View File

@@ -1117,9 +1117,9 @@ dependencies = [
[[package]]
name = "slab"
version = "0.4.5"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5"
checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32"
[[package]]
name = "smallvec"

View File

@@ -57,12 +57,22 @@ pub struct IdWithIdentifier {
id: String,
}
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
pub struct IdWithIdentifierAndComment {
kind: ApplicationIdentifier,
id: String,
#[serde(skip_serializing_if = "Option::is_none")]
comment: Option<String>,
}
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
pub struct ApplicationConfiguration {
name: String,
identifier: IdWithIdentifier,
#[serde(skip_serializing_if = "Option::is_none")]
options: Option<Vec<ApplicationOptions>>,
float_identifiers: Option<Vec<IdWithIdentifier>>,
#[serde(skip_serializing_if = "Option::is_none")]
float_identifiers: Option<Vec<IdWithIdentifierAndComment>>,
}
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
@@ -73,7 +83,13 @@ impl ApplicationConfigurationGenerator {
Ok(serde_yaml::from_str(content)?)
}
pub fn generate(content: &str) -> Result<Vec<String>> {
pub fn format(content: &str) -> Result<String> {
let mut cfgen = Self::load(content)?;
cfgen.sort_by(|a, b| a.name.cmp(&b.name));
Ok(serde_yaml::to_string(&cfgen)?)
}
pub fn generate_ahk(content: &str) -> Result<Vec<String>> {
let mut cfgen = Self::load(content)?;
cfgen.sort_by(|a, b| a.name.cmp(&b.name));
@@ -93,6 +109,7 @@ impl ApplicationConfigurationGenerator {
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));
}
}
@@ -107,10 +124,16 @@ impl ApplicationConfigurationGenerator {
// 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(""));
}

View File

@@ -304,8 +304,12 @@ AhkLibrary() {
Run, komorebic.exe ahk-library, , Hide
}
ApplicationSpecificConfiguration(path) {
Run, komorebic.exe application-specific-configuration %path%, , Hide
AhkAppSpecificConfiguration(path) {
Run, komorebic.exe ahk-app-specific-configuration %path%, , Hide
}
FormatAppSpecificConfiguration(path) {
Run, komorebic.exe format-app-specific-configuration %path%, , Hide
}
NotificationSchema() {

View File

@@ -422,10 +422,22 @@ struct Unsubscribe {
named_pipe: String,
}
#[derive(Parser, AhkFunction)]
pub struct ApplicationSpecificConfiguration {
/// YAML file from which the application-specific configurations should be loaded
path: String,
macro_rules! gen_application_specific_configuration_subcommand_args {
// SubCommand Pattern
( $( $name:ident ),+ $(,)? ) => {
$(
#[derive(clap::Parser, derive_ahk::AhkFunction)]
pub struct $name {
/// YAML file from which the application-specific configurations should be loaded
path: String,
}
)+
};
}
gen_application_specific_configuration_subcommand_args! {
AhkAppSpecificConfiguration,
FormatAppSpecificConfiguration,
}
#[derive(Parser)]
@@ -649,10 +661,14 @@ enum SubCommand {
ToggleMouseFollowsFocus,
/// Generate a library of AutoHotKey helper functions
AhkLibrary,
/// Generate a collection of common application configurations to use in komorebi.ahk
/// Generate common app-specific configurations and fixes to use in komorebi.ahk
#[clap(arg_required_else_help = true)]
#[clap(alias = "app-specific-configuration")]
ApplicationSpecificConfiguration(ApplicationSpecificConfiguration),
#[clap(alias = "ahk-asc")]
AhkAppSpecificConfiguration(AhkAppSpecificConfiguration),
/// Format a YAML file for use with the 'ahk-app-specific-configuration' command
#[clap(arg_required_else_help = true)]
#[clap(alias = "fmt-asc")]
FormatAppSpecificConfiguration(FormatAppSpecificConfiguration),
/// Generate a JSON Schema of subscription notifications
NotificationSchema,
}
@@ -1147,9 +1163,9 @@ fn main() -> Result<()> {
SubCommand::WindowHidingBehaviour(arg) => {
send_message(&*SocketMessage::WindowHidingBehaviour(arg.hiding_behaviour).as_bytes()?)?;
}
SubCommand::ApplicationSpecificConfiguration(arg) => {
SubCommand::AhkAppSpecificConfiguration(arg) => {
let content = fs::read_to_string(resolve_windows_path(&arg.path)?)?;
let lines = ApplicationConfigurationGenerator::generate(&content)?;
let lines = ApplicationConfigurationGenerator::generate_ahk(&content)?;
let mut generated_config = HOME_DIR.clone();
generated_config.push("komorebi.generated.ahk");
@@ -1174,6 +1190,21 @@ fn main() -> Result<()> {
println!("\n#Include %A_ScriptDir%\\komorebi.generated.ahk");
}
SubCommand::FormatAppSpecificConfiguration(arg) => {
let file_path = resolve_windows_path(&arg.path)?;
let content = fs::read_to_string(&file_path)?;
let formatted_content = ApplicationConfigurationGenerator::format(&content)?;
let mut file = OpenOptions::new()
.write(true)
.create(true)
.truncate(true)
.open(file_path)?;
file.write_all(formatted_content.as_bytes())?;
println!("File successfully formatted for PRs to https://github.com/LGUG2Z/komorebi-application-specific-configuration");
}
SubCommand::NotificationSchema => {
let home = HOME_DIR.clone();
let mut socket = home;