diff --git a/Cargo.lock b/Cargo.lock index ca056887..70dc75b0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -286,6 +286,12 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "dtoa" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0" + [[package]] name = "either" version = "1.6.1" @@ -544,6 +550,7 @@ dependencies = [ "color-eyre", "serde", "serde_json", + "serde_yaml", "strum", ] @@ -584,6 +591,12 @@ version = "0.2.103" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd8f7255a17a627354f321ef0055d63b898c6fb27eff628af4d1b66b7331edf6" +[[package]] +name = "linked-hash-map" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" + [[package]] name = "lock_api" version = "0.4.5" @@ -1111,6 +1124,18 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_yaml" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8c608a35705a5d3cdc9fbe403147647ff34b921f8e833e49306df898f9b20af" +dependencies = [ + "dtoa", + "indexmap", + "serde", + "yaml-rust", +] + [[package]] name = "sharded-slab" version = "0.1.4" @@ -1525,3 +1550,12 @@ dependencies = [ "winapi 0.2.8", "winapi-build", ] + +[[package]] +name = "yaml-rust" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +dependencies = [ + "linked-hash-map", +] diff --git a/komorebi-core/Cargo.toml b/komorebi-core/Cargo.toml index efa83547..3e22f028 100644 --- a/komorebi-core/Cargo.toml +++ b/komorebi-core/Cargo.toml @@ -12,4 +12,5 @@ clap = "3.0.0-beta.4" color-eyre = "0.5" serde = { version = "1", features = ["derive"] } serde_json = "1" +serde_yaml = "0.8" strum = { version = "0.21", features = ["derive"] } diff --git a/komorebi-core/src/custom_layout.rs b/komorebi-core/src/custom_layout.rs index 79ad64d6..08cc5393 100644 --- a/komorebi-core/src/custom_layout.rs +++ b/komorebi-core/src/custom_layout.rs @@ -1,6 +1,11 @@ use std::collections::HashMap; +use std::fs::File; +use std::io::BufReader; use std::ops::Deref; +use std::path::PathBuf; +use color_eyre::eyre::anyhow; +use color_eyre::Result; use serde::Deserialize; use serde::Serialize; @@ -18,6 +23,28 @@ impl Deref for CustomLayout { } impl CustomLayout { + pub fn from_path_buf(path: PathBuf) -> Result { + let invalid_filetype = anyhow!("custom layouts must be json or yaml files"); + let layout: Self = match path.extension() { + Some(extension) => { + if extension == "yaml" || extension == "yml" { + serde_yaml::from_reader(BufReader::new(File::open(path)?))? + } else if extension == "json" { + serde_json::from_reader(BufReader::new(File::open(path)?))? + } else { + return Err(invalid_filetype); + } + } + None => return Err(invalid_filetype), + }; + + if !layout.is_valid() { + return Err(anyhow!("the layout file provided was invalid")); + } + + Ok(layout) + } + #[must_use] pub fn column_with_idx(&self, idx: usize) -> (usize, Option<&Column>) { let column_idx = self.column_for_container_idx(idx); diff --git a/komorebi/src/window_manager.rs b/komorebi/src/window_manager.rs index ab1864d4..7b43500d 100644 --- a/komorebi/src/window_manager.rs +++ b/komorebi/src/window_manager.rs @@ -1,6 +1,4 @@ use std::collections::VecDeque; -use std::fs::File; -use std::io::BufReader; use std::io::ErrorKind; use std::num::NonZeroUsize; use std::path::PathBuf; @@ -1059,11 +1057,8 @@ impl WindowManager { #[tracing::instrument(skip(self))] pub fn change_workspace_custom_layout(&mut self, path: PathBuf) -> Result<()> { tracing::info!("changing layout"); - let layout: CustomLayout = serde_json::from_reader(BufReader::new(File::open(path)?))?; - if !layout.is_valid() { - return Err(anyhow!("the layout file provided was invalid")); - } + let layout = CustomLayout::from_path_buf(path)?; let workspace = self.focused_workspace_mut()?; match workspace.layout() { @@ -1182,13 +1177,7 @@ impl WindowManager { path: PathBuf, ) -> Result<()> { tracing::info!("setting workspace layout"); - let file = File::open(path)?; - let reader = BufReader::new(file); - let layout: CustomLayout = serde_json::from_reader(reader)?; - if !layout.is_valid() { - return Err(anyhow!("the layout file provided was invalid")); - } - + let layout = CustomLayout::from_path_buf(path)?; let invisible_borders = self.invisible_borders; let offset = self.work_area_offset; let focused_monitor_idx = self.focused_monitor_idx(); diff --git a/komorebic/src/main.rs b/komorebic/src/main.rs index 0a2a176c..e42692a2 100644 --- a/komorebic/src/main.rs +++ b/komorebic/src/main.rs @@ -299,7 +299,7 @@ struct Load { #[derive(Clap, AhkFunction)] struct LoadLayout { - /// File from which the custom layout definition should be loaded + /// JSON or YAML file from which the custom layout definition should be loaded path: String, }