store config to ~/.config

This commit is contained in:
Alex Janka 2024-07-24 16:00:14 +10:00
parent e1e3265e70
commit bc538f27ea
3 changed files with 321 additions and 43 deletions

238
Cargo.lock generated
View file

@ -42,7 +42,7 @@ dependencies = [
"rustix",
"slab",
"tracing",
"windows-sys",
"windows-sys 0.52.0",
]
[[package]]
@ -126,6 +126,27 @@ version = "0.8.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
[[package]]
name = "directories"
version = "5.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a49173b84e034382284f27f1af4dcbbd231ffa358c0fe316541a7337f376a35"
dependencies = [
"dirs-sys",
]
[[package]]
name = "dirs-sys"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c"
dependencies = [
"libc",
"option-ext",
"redox_users",
"windows-sys 0.48.0",
]
[[package]]
name = "env_logger"
version = "0.10.2"
@ -139,6 +160,12 @@ dependencies = [
"termcolor",
]
[[package]]
name = "equivalent"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
[[package]]
name = "errno"
version = "0.3.9"
@ -146,7 +173,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
dependencies = [
"libc",
"windows-sys",
"windows-sys 0.52.0",
]
[[package]]
@ -232,12 +259,29 @@ dependencies = [
"slab",
]
[[package]]
name = "getrandom"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "gimli"
version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd"
[[package]]
name = "hashbrown"
version = "0.14.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
[[package]]
name = "hermit-abi"
version = "0.3.9"
@ -256,6 +300,16 @@ version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]]
name = "indexmap"
version = "2.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
dependencies = [
"equivalent",
"hashbrown",
]
[[package]]
name = "is-terminal"
version = "0.4.12"
@ -264,7 +318,7 @@ checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b"
dependencies = [
"hermit-abi 0.3.9",
"libc",
"windows-sys",
"windows-sys 0.52.0",
]
[[package]]
@ -285,6 +339,16 @@ version = "0.2.155"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
[[package]]
name = "libredox"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
dependencies = [
"bitflags",
"libc",
]
[[package]]
name = "linux-raw-sys"
version = "0.4.14"
@ -331,7 +395,7 @@ dependencies = [
"hermit-abi 0.3.9",
"libc",
"wasi",
"windows-sys",
"windows-sys 0.52.0",
]
[[package]]
@ -343,6 +407,12 @@ dependencies = [
"memchr",
]
[[package]]
name = "option-ext"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
[[package]]
name = "parking"
version = "2.2.0"
@ -369,7 +439,7 @@ dependencies = [
"libc",
"redox_syscall",
"smallvec",
"windows-targets",
"windows-targets 0.52.6",
]
[[package]]
@ -396,7 +466,7 @@ dependencies = [
"pin-project-lite",
"rustix",
"tracing",
"windows-sys",
"windows-sys 0.52.0",
]
[[package]]
@ -436,6 +506,17 @@ dependencies = [
"bitflags",
]
[[package]]
name = "redox_users"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891"
dependencies = [
"getrandom",
"libredox",
"thiserror",
]
[[package]]
name = "regex"
version = "1.10.5"
@ -481,7 +562,7 @@ dependencies = [
"errno",
"libc",
"linux-raw-sys",
"windows-sys",
"windows-sys 0.52.0",
]
[[package]]
@ -527,6 +608,15 @@ dependencies = [
"serde",
]
[[package]]
name = "serde_spanned"
version = "0.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0"
dependencies = [
"serde",
]
[[package]]
name = "signal-hook-registry"
version = "1.4.2"
@ -558,19 +648,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c"
dependencies = [
"libc",
"windows-sys",
"windows-sys 0.52.0",
]
[[package]]
name = "sway-flash-indicator"
version = "0.1.0"
dependencies = [
"directories",
"futures-util",
"lab",
"log",
"pretty_env_logger",
"serde",
"swayipc-async",
"tokio",
"toml",
]
[[package]]
@ -653,7 +746,7 @@ dependencies = [
"signal-hook-registry",
"socket2",
"tokio-macros",
"windows-sys",
"windows-sys 0.52.0",
]
[[package]]
@ -667,6 +760,40 @@ dependencies = [
"syn",
]
[[package]]
name = "toml"
version = "0.8.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac2caab0bf757388c6c0ae23b3293fdb463fee59434529014f85e3263b995c28"
dependencies = [
"serde",
"serde_spanned",
"toml_datetime",
"toml_edit",
]
[[package]]
name = "toml_datetime"
version = "0.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf"
dependencies = [
"serde",
]
[[package]]
name = "toml_edit"
version = "0.22.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "278f3d518e152219c994ce877758516bca5e118eaed6996192a774fb9fbf0788"
dependencies = [
"indexmap",
"serde",
"serde_spanned",
"toml_datetime",
"winnow",
]
[[package]]
name = "tracing"
version = "0.1.40"
@ -701,7 +828,16 @@ version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b"
dependencies = [
"windows-sys",
"windows-sys 0.52.0",
]
[[package]]
name = "windows-sys"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
"windows-targets 0.48.5",
]
[[package]]
@ -710,7 +846,22 @@ version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [
"windows-targets",
"windows-targets 0.52.6",
]
[[package]]
name = "windows-targets"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
dependencies = [
"windows_aarch64_gnullvm 0.48.5",
"windows_aarch64_msvc 0.48.5",
"windows_i686_gnu 0.48.5",
"windows_i686_msvc 0.48.5",
"windows_x86_64_gnu 0.48.5",
"windows_x86_64_gnullvm 0.48.5",
"windows_x86_64_msvc 0.48.5",
]
[[package]]
@ -719,28 +870,46 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_aarch64_gnullvm 0.52.6",
"windows_aarch64_msvc 0.52.6",
"windows_i686_gnu 0.52.6",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
"windows_i686_msvc 0.52.6",
"windows_x86_64_gnu 0.52.6",
"windows_x86_64_gnullvm 0.52.6",
"windows_x86_64_msvc 0.52.6",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
@ -753,26 +922,59 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "winnow"
version = "0.6.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "557404e450152cd6795bb558bca69e43c585055f4606e3bcae5894fc6dac9ba0"
dependencies = [
"memchr",
]

View file

@ -10,3 +10,6 @@ swayipc-async = "2.0.3"
tokio = { version = "1.39.1", features = ["full"] }
futures-util = "0.3.30"
lab = "0.11.0"
directories = "5.0.1"
toml = "0.8.15"
serde = { version = "1.0.204", features = ["derive"] }

View file

@ -1,5 +1,6 @@
use futures_util::StreamExt;
use lab::Lab;
use serde::{Deserialize, Serialize};
#[derive(Debug)]
struct NoMatchingConfig;
@ -12,17 +13,54 @@ impl std::fmt::Display for NoMatchingConfig {
impl std::error::Error for NoMatchingConfig {}
const INTERPOLATE_FROM: Lab = Lab {
l: 53.2,
a: 80.1,
b: 67.2,
};
#[derive(Debug)]
struct HexParse;
const FRAMES_DELAY: u32 = 5;
const FRAMES_ANIM: u32 = 20;
impl std::fmt::Display for HexParse {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "invalid hex colour")
}
}
const REFRESH_RATE: u64 = 60;
const DUR_PER_FRAME: std::time::Duration = std::time::Duration::from_millis(1000 / REFRESH_RATE);
impl std::error::Error for HexParse {}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
struct Config {
frames_delay: u32,
frames_anim: u32,
refresh_rate: u64,
#[serde(serialize_with = "lab_ser", deserialize_with = "lab_de")]
flash_colour: Lab,
}
impl Default for Config {
fn default() -> Self {
Self {
frames_delay: 10,
frames_anim: 20,
refresh_rate: 60,
flash_colour: Lab {
l: 53.2,
a: 80.1,
b: 67.2,
},
}
}
}
fn lab_ser<S: serde::Serializer>(colour: &Lab, serializer: S) -> Result<S::Ok, S::Error> {
let [r, g, b] = colour.to_rgb();
format!("#{r:02x}{g:02x}{b:02x}").serialize(serializer)
}
fn lab_de<'a, D: serde::Deserializer<'a>>(deserializer: D) -> Result<Lab, D::Error> {
use serde::de::Error;
let hex = String::deserialize(deserializer)?;
parse_hex(&hex).map_err(|_| D::Error::custom("couldn't parse hex"))
}
static CONFIG: tokio::sync::OnceCell<Config> = tokio::sync::OnceCell::const_new();
static DEFAULT_COLOURS: tokio::sync::OnceCell<String> = tokio::sync::OnceCell::const_new();
static DEFAULT_BORDER: tokio::sync::OnceCell<Lab> = tokio::sync::OnceCell::const_new();
@ -34,9 +72,11 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
}
pretty_env_logger::init();
parse_config()?;
let mut event_connection = swayipc_async::Connection::new().await?;
get_config(&mut event_connection).await?;
get_sway_config(&mut event_connection).await?;
let mut events = event_connection
.subscribe([swayipc_async::EventType::Binding])
@ -67,7 +107,35 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
Ok(())
}
async fn get_config(
fn parse_config() -> Result<(), Box<dyn std::error::Error>> {
let dirs = directories::ProjectDirs::from("com", "alexjanka", "sway-flash-indicator")
.ok_or(NoMatchingConfig)?;
let config_dir = dirs.config_dir();
if let Ok(false) = config_dir.try_exists() {
log::info!("config dir doesn't exist, creating");
std::fs::create_dir_all(config_dir)?;
}
let config_path = config_dir.join("config.toml");
let config = if config_path.try_exists().is_ok_and(|v| v) {
let v = toml::from_str(&std::fs::read_to_string(&config_path)?)?;
log::info!("read config from {config_path:?}");
v
} else {
let c = Config::default();
let stringified = toml::to_string(&c)?;
std::fs::write(&config_path, stringified)?;
log::info!("wrote default to {config_path:?}");
c
};
CONFIG.set(config)?;
Ok(())
}
async fn get_sway_config(
connection: &mut swayipc_async::Connection,
) -> Result<(), Box<dyn std::error::Error>> {
let config = connection.get_config().await?;
@ -81,39 +149,44 @@ async fn get_config(
let default_border = default_colours
.split_whitespace()
.nth(2)
.and_then(|v| v.strip_prefix('#'))
.ok_or(NoMatchingConfig)?;
let r = u8::from_str_radix(&default_border[..2], 16)?;
let g = u8::from_str_radix(&default_border[2..4], 16)?;
let b = u8::from_str_radix(&default_border[4..], 16)?;
DEFAULT_BORDER.set(Lab::from_rgb(&[r, g, b]))?;
DEFAULT_BORDER.set(parse_hex(default_border)?)?;
DEFAULT_COLOURS.set(default_colours.to_string())?;
Ok(())
}
fn parse_hex(hex: &str) -> Result<Lab, HexParse> {
let hex = hex.strip_prefix('#').unwrap_or(hex);
let r = u8::from_str_radix(&hex[..2], 16).map_err(|_| HexParse)?;
let g = u8::from_str_radix(&hex[2..4], 16).map_err(|_| HexParse)?;
let b = u8::from_str_radix(&hex[4..], 16).map_err(|_| HexParse)?;
Ok(Lab::from_rgb(&[r, g, b]))
}
async fn interpolate_task() -> Result<(), Box<dyn std::error::Error>> {
let mut connection = swayipc_async::Connection::new().await?;
let to = DEFAULT_BORDER.get().ok_or(NoMatchingConfig)?;
let per_frame = 1.0 / FRAMES_ANIM as f32;
let config = CONFIG.get().ok_or(NoMatchingConfig)?;
let per_frame = 1.0 / config.frames_anim as f32;
let (d_l, d_a, d_b) = (
(to.l - INTERPOLATE_FROM.l) * per_frame,
(to.a - INTERPOLATE_FROM.a) * per_frame,
(to.b - INTERPOLATE_FROM.b) * per_frame,
(to.l - config.flash_colour.l) * per_frame,
(to.a - config.flash_colour.a) * per_frame,
(to.b - config.flash_colour.b) * per_frame,
);
let mut c = INTERPOLATE_FROM;
let mut c = config.flash_colour;
connection.run_command(set_command(&c)).await?;
let dur_per_frame = std::time::Duration::from_secs_f64(1.0 / config.refresh_rate as f64);
tokio::time::sleep(DUR_PER_FRAME * FRAMES_DELAY).await;
for _ in 0..FRAMES_ANIM {
tokio::time::sleep(dur_per_frame * config.frames_delay).await;
for _ in 0..config.frames_anim {
c.l += d_l;
c.a += d_a;
c.b += d_b;
connection.run_command(set_command(&c)).await?;
tokio::time::sleep(DUR_PER_FRAME).await;
tokio::time::sleep(dur_per_frame).await;
}
connection
.run_command(DEFAULT_COLOURS.get().ok_or(NoMatchingConfig)?)