92 lines
3.1 KiB
Rust
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 })
|
|
}
|