mirror of
https://github.com/LGUG2Z/komorebi.git
synced 2026-07-07 21:45:19 +02:00
feat(config): allow multiple asc files
This commit allows either the single canonical applications.json file, or multiple files which adhere to the asc scheme to be given to the app_specific_configuration_path config option. I thought I had already implemented this earlier, but evidently I hadn't. This will be useful for people who want to maintain their own independent set of asc rules, as they can be kept in a dedicated file which won't be overwritten by the fetch-asc command. resolve #736
This commit is contained in:
@@ -52,6 +52,7 @@ pub use komorebi::workspace::Workspace;
|
|||||||
pub use komorebi::workspace::WorkspaceGlobals;
|
pub use komorebi::workspace::WorkspaceGlobals;
|
||||||
pub use komorebi::workspace::WorkspaceLayer;
|
pub use komorebi::workspace::WorkspaceLayer;
|
||||||
pub use komorebi::AnimationsConfig;
|
pub use komorebi::AnimationsConfig;
|
||||||
|
pub use komorebi::AppSpecificConfigurationPath;
|
||||||
pub use komorebi::AspectRatio;
|
pub use komorebi::AspectRatio;
|
||||||
pub use komorebi::BorderColours;
|
pub use komorebi::BorderColours;
|
||||||
pub use komorebi::CrossBoundaryBehaviour;
|
pub use komorebi::CrossBoundaryBehaviour;
|
||||||
|
|||||||
+177
-135
@@ -302,6 +302,16 @@ impl From<&Monitor> for MonitorConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||||
|
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||||
|
#[serde(untagged)]
|
||||||
|
pub enum AppSpecificConfigurationPath {
|
||||||
|
/// A single applications.json file
|
||||||
|
Single(PathBuf),
|
||||||
|
/// Multiple applications.json files
|
||||||
|
Multiple(Vec<PathBuf>),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq)]
|
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq)]
|
||||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||||
/// The `komorebi.json` static configuration file reference for `v0.1.35`
|
/// The `komorebi.json` static configuration file reference for `v0.1.35`
|
||||||
@@ -342,7 +352,7 @@ pub struct StaticConfig {
|
|||||||
pub mouse_follows_focus: Option<bool>,
|
pub mouse_follows_focus: Option<bool>,
|
||||||
/// Path to applications.json from komorebi-application-specific-configurations (default: None)
|
/// Path to applications.json from komorebi-application-specific-configurations (default: None)
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub app_specific_configuration_path: Option<PathBuf>,
|
pub app_specific_configuration_path: Option<AppSpecificConfigurationPath>,
|
||||||
/// Width of the window border (default: 8)
|
/// Width of the window border (default: 8)
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
#[serde(alias = "active_window_border_width")]
|
#[serde(alias = "active_window_border_width")]
|
||||||
@@ -1004,140 +1014,35 @@ impl StaticConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(path) = &self.app_specific_configuration_path {
|
if let Some(path) = &self.app_specific_configuration_path {
|
||||||
match path.extension() {
|
match path {
|
||||||
None => {}
|
AppSpecificConfigurationPath::Single(path) => handle_asc_file(
|
||||||
Some(ext) => match ext.to_string_lossy().to_string().as_str() {
|
path,
|
||||||
"yaml" => {
|
&mut ignore_identifiers,
|
||||||
tracing::info!("loading applications.yaml from: {}", path.display());
|
&mut object_name_change_identifiers,
|
||||||
let path = resolve_home_path(path)?;
|
&mut layered_identifiers,
|
||||||
let content = std::fs::read_to_string(path)?;
|
&mut tray_and_multi_window_identifiers,
|
||||||
let asc = ApplicationConfigurationGenerator::load(&content)?;
|
&mut manage_identifiers,
|
||||||
|
&mut floating_applications,
|
||||||
for mut entry in asc {
|
&mut transparency_blacklist,
|
||||||
if let Some(rules) = &mut entry.ignore_identifiers {
|
&mut slow_application_identifiers,
|
||||||
populate_rules(
|
&mut regex_identifiers,
|
||||||
rules,
|
)?,
|
||||||
&mut ignore_identifiers,
|
AppSpecificConfigurationPath::Multiple(paths) => {
|
||||||
&mut regex_identifiers,
|
for path in paths {
|
||||||
)?;
|
handle_asc_file(
|
||||||
}
|
path,
|
||||||
|
&mut ignore_identifiers,
|
||||||
if let Some(ref options) = entry.options {
|
&mut object_name_change_identifiers,
|
||||||
let options = options.clone();
|
&mut layered_identifiers,
|
||||||
for o in options {
|
&mut tray_and_multi_window_identifiers,
|
||||||
match o {
|
&mut manage_identifiers,
|
||||||
ApplicationOptions::ObjectNameChange => {
|
&mut floating_applications,
|
||||||
populate_option(
|
&mut transparency_blacklist,
|
||||||
&mut entry,
|
&mut slow_application_identifiers,
|
||||||
&mut object_name_change_identifiers,
|
&mut regex_identifiers,
|
||||||
&mut regex_identifiers,
|
)?
|
||||||
)?;
|
|
||||||
}
|
|
||||||
ApplicationOptions::Layered => {
|
|
||||||
populate_option(
|
|
||||||
&mut entry,
|
|
||||||
&mut layered_identifiers,
|
|
||||||
&mut regex_identifiers,
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
ApplicationOptions::TrayAndMultiWindow => {
|
|
||||||
populate_option(
|
|
||||||
&mut entry,
|
|
||||||
&mut tray_and_multi_window_identifiers,
|
|
||||||
&mut regex_identifiers,
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
ApplicationOptions::Force => {
|
|
||||||
populate_option(
|
|
||||||
&mut entry,
|
|
||||||
&mut manage_identifiers,
|
|
||||||
&mut regex_identifiers,
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
ApplicationOptions::BorderOverflow => {} // deprecated
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
"json" => {
|
}
|
||||||
tracing::info!("loading applications.json from: {}", path.display());
|
|
||||||
let path = resolve_home_path(path)?;
|
|
||||||
let mut asc = ApplicationSpecificConfiguration::load(&path)?;
|
|
||||||
|
|
||||||
for entry in asc.values_mut() {
|
|
||||||
match entry {
|
|
||||||
AscApplicationRulesOrSchema::Schema(_) => {}
|
|
||||||
AscApplicationRulesOrSchema::AscApplicationRules(entry) => {
|
|
||||||
if let Some(rules) = &mut entry.ignore {
|
|
||||||
populate_rules(
|
|
||||||
rules,
|
|
||||||
&mut ignore_identifiers,
|
|
||||||
&mut regex_identifiers,
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(rules) = &mut entry.manage {
|
|
||||||
populate_rules(
|
|
||||||
rules,
|
|
||||||
&mut manage_identifiers,
|
|
||||||
&mut regex_identifiers,
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(rules) = &mut entry.floating {
|
|
||||||
populate_rules(
|
|
||||||
rules,
|
|
||||||
&mut floating_applications,
|
|
||||||
&mut regex_identifiers,
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(rules) = &mut entry.transparency_ignore {
|
|
||||||
populate_rules(
|
|
||||||
rules,
|
|
||||||
&mut transparency_blacklist,
|
|
||||||
&mut regex_identifiers,
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(rules) = &mut entry.tray_and_multi_window {
|
|
||||||
populate_rules(
|
|
||||||
rules,
|
|
||||||
&mut tray_and_multi_window_identifiers,
|
|
||||||
&mut regex_identifiers,
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(rules) = &mut entry.layered {
|
|
||||||
populate_rules(
|
|
||||||
rules,
|
|
||||||
&mut layered_identifiers,
|
|
||||||
&mut regex_identifiers,
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(rules) = &mut entry.object_name_change {
|
|
||||||
populate_rules(
|
|
||||||
rules,
|
|
||||||
&mut object_name_change_identifiers,
|
|
||||||
&mut regex_identifiers,
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(rules) = &mut entry.slow_application {
|
|
||||||
populate_rules(
|
|
||||||
rules,
|
|
||||||
&mut slow_application_identifiers,
|
|
||||||
&mut regex_identifiers,
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1153,7 +1058,16 @@ impl StaticConfig {
|
|||||||
let mut value: Self = serde_json::from_str(&content)?;
|
let mut value: Self = serde_json::from_str(&content)?;
|
||||||
|
|
||||||
if let Some(path) = &mut value.app_specific_configuration_path {
|
if let Some(path) = &mut value.app_specific_configuration_path {
|
||||||
*path = resolve_home_path(&*path)?;
|
match path {
|
||||||
|
AppSpecificConfigurationPath::Single(path) => {
|
||||||
|
*path = resolve_home_path(&*path)?;
|
||||||
|
}
|
||||||
|
AppSpecificConfigurationPath::Multiple(paths) => {
|
||||||
|
for path in paths {
|
||||||
|
*path = resolve_home_path(&*path)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(monitors) = &mut value.monitors {
|
if let Some(monitors) = &mut value.monitors {
|
||||||
@@ -1722,6 +1636,134 @@ fn populate_rules(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
fn handle_asc_file(
|
||||||
|
path: &PathBuf,
|
||||||
|
ignore_identifiers: &mut Vec<MatchingRule>,
|
||||||
|
object_name_change_identifiers: &mut Vec<MatchingRule>,
|
||||||
|
layered_identifiers: &mut Vec<MatchingRule>,
|
||||||
|
tray_and_multi_window_identifiers: &mut Vec<MatchingRule>,
|
||||||
|
manage_identifiers: &mut Vec<MatchingRule>,
|
||||||
|
floating_applications: &mut Vec<MatchingRule>,
|
||||||
|
transparency_blacklist: &mut Vec<MatchingRule>,
|
||||||
|
slow_application_identifiers: &mut Vec<MatchingRule>,
|
||||||
|
regex_identifiers: &mut HashMap<String, Regex>,
|
||||||
|
) -> Result<()> {
|
||||||
|
match path.extension() {
|
||||||
|
None => {}
|
||||||
|
Some(ext) => match ext.to_string_lossy().to_string().as_str() {
|
||||||
|
"yaml" => {
|
||||||
|
tracing::info!("loading applications.yaml from: {}", path.display());
|
||||||
|
let path = resolve_home_path(path)?;
|
||||||
|
let content = std::fs::read_to_string(path)?;
|
||||||
|
let asc = ApplicationConfigurationGenerator::load(&content)?;
|
||||||
|
|
||||||
|
for mut entry in asc {
|
||||||
|
if let Some(rules) = &mut entry.ignore_identifiers {
|
||||||
|
populate_rules(rules, ignore_identifiers, regex_identifiers)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(ref options) = entry.options {
|
||||||
|
let options = options.clone();
|
||||||
|
for o in options {
|
||||||
|
match o {
|
||||||
|
ApplicationOptions::ObjectNameChange => {
|
||||||
|
populate_option(
|
||||||
|
&mut entry,
|
||||||
|
object_name_change_identifiers,
|
||||||
|
regex_identifiers,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
ApplicationOptions::Layered => {
|
||||||
|
populate_option(
|
||||||
|
&mut entry,
|
||||||
|
layered_identifiers,
|
||||||
|
regex_identifiers,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
ApplicationOptions::TrayAndMultiWindow => {
|
||||||
|
populate_option(
|
||||||
|
&mut entry,
|
||||||
|
tray_and_multi_window_identifiers,
|
||||||
|
regex_identifiers,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
ApplicationOptions::Force => {
|
||||||
|
populate_option(
|
||||||
|
&mut entry,
|
||||||
|
manage_identifiers,
|
||||||
|
regex_identifiers,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
ApplicationOptions::BorderOverflow => {} // deprecated
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"json" => {
|
||||||
|
tracing::info!("loading applications.json from: {}", path.display());
|
||||||
|
let path = resolve_home_path(path)?;
|
||||||
|
let mut asc = ApplicationSpecificConfiguration::load(&path)?;
|
||||||
|
|
||||||
|
for entry in asc.values_mut() {
|
||||||
|
match entry {
|
||||||
|
AscApplicationRulesOrSchema::Schema(_) => {}
|
||||||
|
AscApplicationRulesOrSchema::AscApplicationRules(entry) => {
|
||||||
|
if let Some(rules) = &mut entry.ignore {
|
||||||
|
populate_rules(rules, ignore_identifiers, regex_identifiers)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(rules) = &mut entry.manage {
|
||||||
|
populate_rules(rules, manage_identifiers, regex_identifiers)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(rules) = &mut entry.floating {
|
||||||
|
populate_rules(rules, floating_applications, regex_identifiers)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(rules) = &mut entry.transparency_ignore {
|
||||||
|
populate_rules(rules, transparency_blacklist, regex_identifiers)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(rules) = &mut entry.tray_and_multi_window {
|
||||||
|
populate_rules(
|
||||||
|
rules,
|
||||||
|
tray_and_multi_window_identifiers,
|
||||||
|
regex_identifiers,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(rules) = &mut entry.layered {
|
||||||
|
populate_rules(rules, layered_identifiers, regex_identifiers)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(rules) = &mut entry.object_name_change {
|
||||||
|
populate_rules(
|
||||||
|
rules,
|
||||||
|
object_name_change_identifiers,
|
||||||
|
regex_identifiers,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(rules) = &mut entry.slow_application {
|
||||||
|
populate_rules(
|
||||||
|
rules,
|
||||||
|
slow_application_identifiers,
|
||||||
|
regex_identifiers,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::StaticConfig;
|
use crate::StaticConfig;
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ use fs_tail::TailedFile;
|
|||||||
use komorebi_client::resolve_home_path;
|
use komorebi_client::resolve_home_path;
|
||||||
use komorebi_client::send_message;
|
use komorebi_client::send_message;
|
||||||
use komorebi_client::send_query;
|
use komorebi_client::send_query;
|
||||||
|
use komorebi_client::AppSpecificConfigurationPath;
|
||||||
use komorebi_client::ApplicationSpecificConfiguration;
|
use komorebi_client::ApplicationSpecificConfiguration;
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use miette::NamedSource;
|
use miette::NamedSource;
|
||||||
@@ -1660,11 +1661,12 @@ fn main() -> Result<()> {
|
|||||||
None => {
|
None => {
|
||||||
println!("Application specific configuration file path has not been set. Try running 'komorebic fetch-asc'\n");
|
println!("Application specific configuration file path has not been set. Try running 'komorebic fetch-asc'\n");
|
||||||
}
|
}
|
||||||
Some(path) => {
|
Some(AppSpecificConfigurationPath::Single(path)) => {
|
||||||
if !Path::exists(Path::new(&path)) {
|
if !Path::exists(Path::new(&path)) {
|
||||||
println!("Application specific configuration file path '{}' does not exist. Try running 'komorebic fetch-asc'\n", path.display());
|
println!("Application specific configuration file path '{}' does not exist. Try running 'komorebic fetch-asc'\n", path.display());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+13
-1
@@ -131,7 +131,19 @@
|
|||||||
},
|
},
|
||||||
"app_specific_configuration_path": {
|
"app_specific_configuration_path": {
|
||||||
"description": "Path to applications.json from komorebi-application-specific-configurations (default: None)",
|
"description": "Path to applications.json from komorebi-application-specific-configurations (default: None)",
|
||||||
"type": "string"
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"description": "A single applications.json file",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Multiple applications.json files",
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"bar_configurations": {
|
"bar_configurations": {
|
||||||
"description": "Komorebi status bar configuration files for multiple instances on different monitors",
|
"description": "Komorebi status bar configuration files for multiple instances on different monitors",
|
||||||
|
|||||||
Reference in New Issue
Block a user