Add: Argument parsing
- Set wallpaper from arg - Update config from arg
This commit is contained in:
parent
c02d53464d
commit
8e52d12226
33
src/args.rs
Normal file
33
src/args.rs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
use anyhow::{Result, bail};
|
||||||
|
use pico_args::Arguments;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
/// Parsed command-line arguments.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Args {
|
||||||
|
pub set: Option<PathBuf>,
|
||||||
|
pub update: Option<PathBuf>,
|
||||||
|
pub mode: Option<String>, // parsed now, used later
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Args {
|
||||||
|
pub fn parse() -> Result<Self> {
|
||||||
|
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")?;
|
||||||
|
|
||||||
|
if set.is_some() && update.is_some() {
|
||||||
|
bail!("--set and --update cannot be used together");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fail if unknown arguments are present
|
||||||
|
let remaining = args.finish();
|
||||||
|
if !remaining.is_empty() {
|
||||||
|
bail!("Unknown arguments: {remaining:?}");
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Self { set, update, mode })
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,10 +1,10 @@
|
|||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use serde::Deserialize;
|
use serde::{Deserialize, Serialize};
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
/// Runtime configuration for `icing`.
|
/// Runtime configuration for `icing`.
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub background_image: String,
|
pub background_image: String,
|
||||||
pub mode: Option<String>, // Unused now, deal with it later
|
pub mode: Option<String>, // Unused now, deal with it later
|
||||||
@ -23,6 +23,23 @@ impl Config {
|
|||||||
|
|
||||||
Ok(config)
|
Ok(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Update config with image specifeid by CLI arg
|
||||||
|
pub fn update_background_image(&self, new_path: &str) -> Result<()> {
|
||||||
|
let path = config_path()?;
|
||||||
|
|
||||||
|
let updated = toml::to_string(&Config {
|
||||||
|
background_image: new_path.to_string(),
|
||||||
|
mode: self.mode.clone(),
|
||||||
|
})?;
|
||||||
|
|
||||||
|
fs::create_dir_all(path.parent().expect("config path has parent"))?;
|
||||||
|
|
||||||
|
fs::write(&path, updated)
|
||||||
|
.with_context(|| format!("Failed to write config file: {}", path.display()))?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn config_path() -> Result<PathBuf> {
|
fn config_path() -> Result<PathBuf> {
|
||||||
|
|||||||
52
src/main.rs
52
src/main.rs
@ -10,13 +10,53 @@ use x11rb::{
|
|||||||
},
|
},
|
||||||
rust_connection::RustConnection,
|
rust_connection::RustConnection,
|
||||||
};
|
};
|
||||||
|
mod args;
|
||||||
mod config;
|
mod config;
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
// Load config
|
// Parse CLI arguments
|
||||||
let config = config::Config::load()?;
|
let args = args::Args::parse()?;
|
||||||
// Path to wallpaper image in config
|
|
||||||
let image_path = &config.background_image;
|
// Load config file if it exists. Can be missing.
|
||||||
|
let config = config::Config::load().ok();
|
||||||
|
|
||||||
|
// Resolve wallpaper image path by precedence:
|
||||||
|
// 1. args (`--set`, `--update`): Use path from args.
|
||||||
|
// 2. config: Use path from config.
|
||||||
|
let image_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)) => {
|
||||||
|
let cfg = config.unwrap_or_else(|| 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 = config.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.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Case: Both args `--set` & `--update`. This case is already rejected during argument parsing.
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
// Connect to the running graphical session, the X11 server.
|
// Connect to the running graphical session, the X11 server.
|
||||||
let (conn, screen_num) = RustConnection::connect(None)?;
|
let (conn, screen_num) = RustConnection::connect(None)?;
|
||||||
@ -61,8 +101,8 @@ fn main() -> Result<()> {
|
|||||||
conn.create_pixmap(depth, pixmap, root, width, height)?;
|
conn.create_pixmap(depth, pixmap, root, width, height)?;
|
||||||
|
|
||||||
// Load the wallpaper image from disk.
|
// Load the wallpaper image from disk.
|
||||||
let img =
|
let img = image::open(&image_path)
|
||||||
image::open(image_path).with_context(|| format!("Failed to open image: {image_path}"))?;
|
.with_context(|| format!("Failed to open image: {}", image_path.display()))?;
|
||||||
|
|
||||||
// Convert the image into RGBA8 (4 bytes per pixel).
|
// Convert the image into RGBA8 (4 bytes per pixel).
|
||||||
// Predictable, CPU-friendly format to work on.
|
// Predictable, CPU-friendly format to work on.
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user