From 08c27d1b22ae280da01832d510f7024f305c2990 Mon Sep 17 00:00:00 2001 From: Breadway Date: Fri, 17 Jul 2026 03:19:50 +0800 Subject: [PATCH] breadshot: expand ~ in save_dir, align Cargo.toml version with tag - config.rs: expand a leading ~ in the save_dir config value on load. The documented example config (save_dir = "~/Pictures/Screenshots") was previously taken literally, silently creating ./~/Pictures/... in the current working directory. Added unit tests. - Cargo.toml: 1.0.0 -> 0.1.0, matching the only existing tag (v0.1.0). breadshot --version previously reported nine releases ahead of the actual release history. --- Cargo.lock | 2 +- Cargo.toml | 2 +- src/config.rs | 59 +++++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 59 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8dbb11a..258d335 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -84,7 +84,7 @@ checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" [[package]] name = "breadshot" -version = "1.0.0" +version = "0.1.0" dependencies = [ "anyhow", "chrono", diff --git a/Cargo.toml b/Cargo.toml index 5df1443..87b2785 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "breadshot" -version = "1.0.0" +version = "0.1.0" edition = "2021" license = "MIT" authors = ["Breadway"] diff --git a/src/config.rs b/src/config.rs index 8f8ffd8..eb89f47 100644 --- a/src/config.rs +++ b/src/config.rs @@ -38,8 +38,10 @@ impl Config { } let content = std::fs::read_to_string(path) .with_context(|| format!("reading {}", path.display()))?; - toml::from_str(&content) - .with_context(|| format!("parsing {}", path.display())) + let mut config: Self = toml::from_str(&content) + .with_context(|| format!("parsing {}", path.display()))?; + config.save_dir = expand_tilde(config.save_dir); + Ok(config) } } @@ -49,3 +51,56 @@ pub fn default_path() -> PathBuf { .join("breadshot") .join("config.toml") } + +/// Expand a leading `~` (or `~/...`) to the user's home directory, the way a +/// shell would. `PathBuf`'s `Deserialize` does no such expansion, so a +/// documented config value like `save_dir = "~/Pictures/Screenshots"` would +/// otherwise be taken literally and create a `./~/Pictures/Screenshots` +/// directory relative to the current working directory. +fn expand_tilde(path: PathBuf) -> PathBuf { + let Some(s) = path.to_str() else { + return path; + }; + if s == "~" { + return dirs::home_dir().unwrap_or(path); + } + if let Some(rest) = s.strip_prefix("~/") { + if let Some(home) = dirs::home_dir() { + return home.join(rest); + } + } + path +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn expand_tilde_prefix() { + let home = dirs::home_dir().unwrap(); + assert_eq!( + expand_tilde(PathBuf::from("~/Pictures/Screenshots")), + home.join("Pictures/Screenshots") + ); + } + + #[test] + fn expand_tilde_bare() { + let home = dirs::home_dir().unwrap(); + assert_eq!(expand_tilde(PathBuf::from("~")), home); + } + + #[test] + fn expand_tilde_absolute_untouched() { + let p = PathBuf::from("/var/tmp/shots"); + assert_eq!(expand_tilde(p.clone()), p); + } + + #[test] + fn expand_tilde_no_expansion_mid_path() { + // Only a leading ~ is special, matching shell behavior. + let p = PathBuf::from("/home/user/~weird"); + assert_eq!(expand_tilde(p.clone()), p); + } +}