Skip to content

Commit

Permalink
feat(config): add cfgen for apps based on yaml def
Browse files Browse the repository at this point in the history
This commit introduces a configuration generator for
application-specific config options passed to the cli via a file path.

The hope is to have a public repository that any user can contribute
application-specific configs and fixes to, and for the generated AHK to
be available to any new user as part of the initial setup to make the
onboarding as frictionless as possible.

re #62
  • Loading branch information
LGUG2Z committed Apr 2, 2022
1 parent 4686d5e commit 09a24b8
Show file tree
Hide file tree
Showing 6 changed files with 174 additions and 8 deletions.
17 changes: 9 additions & 8 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

119 changes: 119 additions & 0 deletions komorebi-core/src/config_generation.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
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 ApplicationConfiguration {
name: String,
identifier: IdWithIdentifier,
options: Option<Vec<ApplicationOptions>>,
float_identifiers: Option<Vec<IdWithIdentifier>>,
}

#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
pub struct ApplicationConfigurationGenerator;

impl ApplicationConfigurationGenerator {
fn load(content: &str) -> Result<Vec<ApplicationConfiguration>> {
Ok(serde_yaml::from_str(content)?)
}

pub fn generate(content: &str) -> Result<Vec<String>> {
let mut cfgen = Self::load(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());
lines.push(float_rule);
}
}
}
lines.push(String::from(""));
}

Ok(lines)
}
}
2 changes: 2 additions & 0 deletions komorebi-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ pub use operation_direction::OperationDirection;
pub use rect::Rect;

pub mod arrangement;
pub mod config_generation;
pub mod custom_layout;
pub mod cycle_direction;
pub mod default_layout;
Expand Down Expand Up @@ -138,6 +139,7 @@ pub enum StateQuery {

#[derive(Clone, Debug, Serialize, Deserialize, Display, EnumString, ArgEnum, JsonSchema)]
#[strum(serialize_all = "snake_case")]
#[serde(rename_all = "snake_case")]
pub enum ApplicationIdentifier {
Exe,
Class,
Expand Down
4 changes: 4 additions & 0 deletions komorebic.lib.sample.ahk
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,10 @@ AhkLibrary() {
Run, komorebic.exe ahk-library, , Hide
}

ApplicationSpecificConfiguration(path) {
Run, komorebic.exe application-specific-configuration %path%, , Hide
}

NotificationSchema() {
Run, komorebic.exe notification-schema, , Hide
}
1 change: 1 addition & 0 deletions komorebic/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ paste = "1"
powershell_script = "0.3"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
serde_yaml = "0.8"
uds_windows = "1"

[dependencies.windows]
Expand Down
39 changes: 39 additions & 0 deletions komorebic/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#![warn(clippy::all, clippy::nursery, clippy::pedantic)]
#![allow(clippy::missing_errors_doc)]

use std::fs;
use std::fs::File;
use std::fs::OpenOptions;
use std::io::BufRead;
Expand Down Expand Up @@ -28,6 +29,7 @@ use windows::Win32::UI::WindowsAndMessaging::SW_RESTORE;

use derive_ahk::AhkFunction;
use derive_ahk::AhkLibrary;
use komorebi_core::config_generation::ApplicationConfigurationGenerator;
use komorebi_core::ApplicationIdentifier;
use komorebi_core::Axis;
use komorebi_core::CycleDirection;
Expand Down Expand Up @@ -420,6 +422,12 @@ struct Unsubscribe {
named_pipe: String,
}

#[derive(Parser, AhkFunction)]
pub struct ApplicationSpecificConfiguration {
/// YAML file from which the application-specific configurations should be loaded
path: String,
}

#[derive(Parser)]
#[clap(author, about, version, setting = AppSettings::DeriveDisplayOrder)]
struct Opts {
Expand Down Expand Up @@ -641,6 +649,10 @@ enum SubCommand {
ToggleMouseFollowsFocus,
/// Generate a library of AutoHotKey helper functions
AhkLibrary,
/// Generate a collection of common application configurations to use in komorebi.ahk
#[clap(arg_required_else_help = true)]
#[clap(alias = "app-specific-configuration")]
ApplicationSpecificConfiguration(ApplicationSpecificConfiguration),
/// Generate a JSON Schema of subscription notifications
NotificationSchema,
}
Expand Down Expand Up @@ -1135,6 +1147,33 @@ fn main() -> Result<()> {
SubCommand::WindowHidingBehaviour(arg) => {
send_message(&*SocketMessage::WindowHidingBehaviour(arg.hiding_behaviour).as_bytes()?)?;
}
SubCommand::ApplicationSpecificConfiguration(arg) => {
let content = fs::read_to_string(resolve_windows_path(&arg.path)?)?;
let lines = ApplicationConfigurationGenerator::generate(&content)?;

let mut generated_config = HOME_DIR.clone();
generated_config.push("komorebi.generated.ahk");
let mut file = OpenOptions::new()
.write(true)
.create(true)
.truncate(true)
.open(generated_config.clone())?;

file.write_all(lines.join("\n").as_bytes())?;

println!(
"\nApplication-specific generated configuration written to {}",
generated_config.to_str().ok_or_else(|| anyhow!(
"could not find the path to the generated configuration file"
))?
);

println!(
"\nYou can include the generated configuration at the top of your komorebi.ahk config with this line:"
);

println!("\n#Include %A_ScriptDir%\\komorebi.generated.ahk");
}
SubCommand::NotificationSchema => {
let home = HOME_DIR.clone();
let mut socket = home;
Expand Down

0 comments on commit 09a24b8

Please sign in to comment.