From 736e258d25f3bc3120ff6c7461031b98a7e237c4 Mon Sep 17 00:00:00 2001 From: Candifloss Date: Sat, 20 Dec 2025 15:07:28 +0530 Subject: [PATCH] Change behaviour of `--update` - Bool option to overwrite config file - Set scaling mode, too --- README.md | 79 ++++++++++++++++++++++++++++--------------------- src/args.rs | 11 +++---- src/config.rs | 17 ++++++----- src/settings.rs | 60 +++++++++++++------------------------ 4 files changed, 82 insertions(+), 85 deletions(-) diff --git a/README.md b/README.md index a416568..8a7f7f5 100644 --- a/README.md +++ b/README.md @@ -7,51 +7,64 @@ Configuration is optional, and the app exits immediately after setting the wallp ## Features -* Simple CLI usage -* Optional config file -* Two image scaling modes: **Fill** and **Stretch** -* Minimal dependencies -* X11 only (Wayland not supported) +- Simple CLI usage +- Optional config file +- Two image scaling modes: **Fill** and **Stretch** +- Minimal dependencies +- X11 only (Wayland not supported) --- ## Usage -### Set wallpaper once (no config change) +`icing` can be used in two ways. + +1. Specify a wallpaper explicitly as an argument ```sh icing --set /path/to/image.png ``` -Sets the wallpaper immediately but does **not** update the config file. -### Update config and set wallpaper +Sets the wallpaper immediately without modifying the config file. -```sh -icing --update /path/to/image.png -``` - -* Writes the image path to the config file -* Sets the wallpaper immediately -* Future runs of `icing` will reuse this image - -### Use config only +2. Use the config file ```sh icing -``` +``` -Uses the image path and settings from the config file. -Fails if no config exists. +Run without arguments to apply the wallpaper defined in the config file. +Fails if no config exists. -### Optional arguments +See below for config instructions. + + +### Additional options + +#### `--mode` + +Use the `--mode` option to specify the image scaling mode. ```sh ---mode fill|stretch -``` +icing --set /path/to/image.png --mode fill +``` Overrides the default or configured scaling mode (see below). +#### `--update` +Use the `--update` flag to persist the new settings to the config file. + +```sh +icing --set /path/to/image.png --update +icing --set /path/to/image.png --mode stretch --update +``` + +- Sets the wallpaper +- Writes the settings to the config file +- Future runs of `icing` will reuse these settings + + ## Configuration Config file location: @@ -110,31 +123,31 @@ Optionally move it to your `$PATH` (for example `/usr/bin/`) if desired. ## Requirements -* X11 (Xorg) -* A window manager -* Rust (for building) +- X11 (Xorg) +- A window manager +- Rust (for building) ## Future plans -* Multi-monitor support via `--monitor ` +- Multi-monitor support via `--monitor ` ```sh icing --monitor HDMI-1 --set image.png icing --monitor HDMI-2 --set image2.jpg --mode stretch ``` -* Probably not: +- Probably not: - * Additional scaling modes (unless they make sense) - * Wayland support + - Additional scaling modes (unless they make sense) + - Wayland support ## Notes -* `icing` does not run in the background -* No daemon, no config watcher -* Intended to be called explicitly (startup scripts, keybindings, etc.) +- `icing` does not run in the background +- No daemon, no config watcher +- Intended to be called explicitly (startup scripts, keybindings, etc.) --- diff --git a/src/args.rs b/src/args.rs index 615a364..ff5478d 100644 --- a/src/args.rs +++ b/src/args.rs @@ -6,8 +6,8 @@ use std::path::PathBuf; #[derive(Debug)] pub struct Args { pub set: Option, - pub update: Option, - pub mode: Option, // parsed now, used later + pub update: bool, + pub mode: Option, } impl Args { @@ -15,11 +15,12 @@ impl Args { let mut args = Arguments::from_env(); let set = args.opt_value_from_str("--set")?; - let update = args.opt_value_from_str("--update")?; let mode = args.opt_value_from_str("--mode")?; + let update = args.contains("--update"); - if set.is_some() && update.is_some() { - bail!("--set and --update cannot be used together"); + // --update is only meaningful if --set is provided + if update && set.is_none() { + bail!("--update requires --set"); } // Fail if unknown arguments are present diff --git a/src/config.rs b/src/config.rs index 0c143f7..9905baa 100644 --- a/src/config.rs +++ b/src/config.rs @@ -24,18 +24,19 @@ impl Config { Ok(config) } - /// Update config with image specifeid by CLI arg - pub fn update_background_image(&self, new_path: &str) -> Result<()> { + /// Persist wallpaper settings to config. + pub fn write(background_image: &str, mode: Option<&str>) -> Result<()> { let path = config_path()?; - let updated = toml::to_string(&Config { - background_image: new_path.to_string(), - mode: self.mode.clone(), - })?; + let config = Config { + background_image: background_image.to_string(), + mode: mode.map(str::to_string), + }; + + let serialized = toml::to_string(&config)?; fs::create_dir_all(path.parent().expect("config path has parent"))?; - - fs::write(&path, updated) + fs::write(&path, serialized) .with_context(|| format!("Failed to write config file: {}", path.display()))?; Ok(()) diff --git a/src/settings.rs b/src/settings.rs index 121f0b8..0ad035f 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -17,50 +17,22 @@ pub fn resolve_wallpaper( // Avoids moving `config`, allows to: // - read values multiple times // - decide later whether we need to write a new config - let cfg_ref = config.as_ref(); + let cfg = config.as_ref(); // Resolve wallpaper image path by precedence: // 1. args (`--set`, `--update`): Use path from args. // 2. config: Use path from config. - let path = match (&args.set, &args.update) { + let path = if let Some(path) = &args.set { // Case: arg `--set`: One-shot wallpaper change. Not persistent. - (Some(path), None) => path.clone(), - - // Case: arg `--update`. Persist wallpaper path to config (create if missing), then apply it. - (None, Some(path)) => { - // Use existing config if present. - // Otherwise, create a minimal temporary config only for writing. - // Avoids moving or cloning the original config, keeps ownership simple. - let cfg = match cfg_ref { - Some(cfg) => cfg, - None => &config::Config { - background_image: String::new(), - mode: None, - }, - }; - - // Write to config. - cfg.update_background_image( - path.to_str() - // Unsupported path format. - .ok_or_else(|| anyhow::anyhow!("Non-UTF8 path"))?, - )?; - path.clone() - } - + path.clone() + } else { // Case: No args. Fallback to config file. - (None, None) => { - let cfg = cfg_ref.ok_or_else(|| { - // No CLI args and no valid config. - anyhow::anyhow!("No or invalid image path specified in config or args.") - })?; + let cfg = cfg.ok_or_else(|| { + // No CLI args and no valid config. + anyhow::anyhow!("No or invalid image settings specified in config or args.") + })?; - // Successfully loaded. - cfg.background_image.clone().into() - } - - // Case: Both args `--set` & `--update`. This case is already rejected during argument parsing. - _ => unreachable!(), + cfg.background_image.clone().into() }; // Resolve scaling mode by precedence: @@ -72,7 +44,7 @@ pub fn resolve_wallpaper( mode_arg .parse::() .with_context(|| "Invalid wallpaper mode in CLI")? - } else if let Some(cfg) = cfg_ref { + } else if let Some(cfg) = cfg { if let Some(mode_str) = &cfg.mode { // Config-specified mode mode_str @@ -83,9 +55,19 @@ pub fn resolve_wallpaper( wallpaper::ScalingMode::Fill } } else { - // No CLI and no config → default + // No CLI and no config -> default wallpaper::ScalingMode::Fill }; + // Persist if requested + if args.update { + config::Config::write( + path.to_str() + // Unsupported path format. + .ok_or_else(|| anyhow::anyhow!("Non-UTF8 path"))?, + args.mode.as_deref().or(cfg.and_then(|c| c.mode.as_deref())), + )?; + } + Ok(WallpaperSettings { path, mode }) }