icing/src/settings.rs

92 lines
3.1 KiB
Rust

use anyhow::{Context, Result};
use std::path::PathBuf;
use crate::{args, config, wallpaper};
pub struct WallpaperSettings {
pub path: PathBuf,
pub mode: wallpaper::ScalingMode,
}
pub fn resolve_wallpaper(
args: &args::Args,
config: Option<config::Config>,
) -> Result<WallpaperSettings> {
// Borrow the config once as `Option<&Config>`.
//
// 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();
// 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) {
// 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()
}
// 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.")
})?;
// Successfully loaded.
cfg.background_image.clone().into()
}
// Case: Both args `--set` & `--update`. This case is already rejected during argument parsing.
_ => unreachable!(),
};
// Resolve scaling mode by precedence:
// 1. CLI argument (`--mode`) if provided
// 2. Config file value if present
// 3. Default to Fill
let mode = if let Some(mode_arg) = &args.mode {
// CLI has highest priority
mode_arg
.parse::<wallpaper::ScalingMode>()
.with_context(|| "Invalid wallpaper mode in CLI")?
} else if let Some(cfg) = cfg_ref {
if let Some(mode_str) = &cfg.mode {
// Config-specified mode
mode_str
.parse::<wallpaper::ScalingMode>()
.with_context(|| "Invalid wallpaper mode in config")?
} else {
// Config exists, but mode not specified
wallpaper::ScalingMode::Fill
}
} else {
// No CLI and no config → default
wallpaper::ScalingMode::Fill
};
Ok(WallpaperSettings { path, mode })
}