From 599f760a94583769ce55f6ff4218eeda14815443 Mon Sep 17 00:00:00 2001 From: Aiden Ghim Date: Mon, 6 Apr 2026 19:40:15 +0900 Subject: [PATCH 1/2] feat: shorten /home/user to ~ in fzf This commit impacts just the fzf component, used in `zi`. The fuzzy finder will no longer display absolute paths as /home/user or /Users/user (macOS). These prefixes will be shortened to '~'. This affects just fzf visuals -- that is, the final output of fzf still displays the full absolute path. `ls` preview within fzf and final `zi` command all work as expected. --- src/config.rs | 4 ++++ src/db/dir.rs | 22 ++++++++++++++++++++++ src/util.rs | 29 +++++++++++++++++++++++++---- 3 files changed, 51 insertions(+), 4 deletions(-) diff --git a/src/config.rs b/src/config.rs index 0aeda5c..2a38705 100644 --- a/src/config.rs +++ b/src/config.rs @@ -60,3 +60,7 @@ pub fn maxage() -> Result { pub fn resolve_symlinks() -> bool { env::var_os("_ZO_RESOLVE_SYMLINKS").is_some_and(|var| var == "1") } + +pub fn get_home_dir() -> OsString { + env::var_os("HOME").unwrap_or("".into()) +} diff --git a/src/db/dir.rs b/src/db/dir.rs index 5d6d62c..0c30af4 100644 --- a/src/db/dir.rs +++ b/src/db/dir.rs @@ -3,6 +3,7 @@ use std::fmt::{self, Display, Formatter}; use serde::{Deserialize, Serialize}; +use crate::config; use crate::util::{DAY, HOUR, WEEK}; #[derive(Clone, Debug, Deserialize, Serialize)] @@ -53,6 +54,27 @@ impl<'a> DirDisplay<'a> { self.separator = separator; self } + + pub fn shorten_home_dir(&self) -> String { + let prefix = config::get_home_dir(); + let prefix = prefix.to_str().expect("cannot convert $HOME to &str"); + let path = if prefix.is_empty() { + self.dir.path.to_string() + } else { + match self.dir.path.as_ref().strip_prefix(prefix) { + Some(path) => format!("~{path}"), + None => self.dir.path.to_string(), + } + }; + + match self.now { + Some(now) => { + let score = self.dir.score(now).clamp(0.0, 9999.0); + format!("{score:>6.1}{}{path}", self.separator) + } + None => path, + } + } } impl Display for DirDisplay<'_> { diff --git a/src/util.rs b/src/util.rs index 996f61d..d5dfa98 100644 --- a/src/util.rs +++ b/src/util.rs @@ -60,9 +60,9 @@ impl Fzf { self.args([ // Non-POSIX args are only available on certain operating systems. if cfg!(target_os = "linux") { - r"--preview=\command -p ls -Cp --color=always --group-directories-first {2..}" + r#"--preview=sh -c 'dir=$1; case $dir in "~") dir=$HOME ;; "~/"*) dir=$HOME/${dir#"~/"} ;; esac; \command -p ls -Cp --color=always --group-directories-first -- "$dir"' sh {2..}"# } else { - r"--preview=\command -p ls -Cp {2..}" + r#"--preview=sh -c 'dir=$1; case $dir in "~") dir=$HOME ;; "~/"*) dir=$HOME/${dir#"~/"} ;; esac; \command -p ls -Cp -- "$dir"' sh {2..}"# }, // Rounded edges don't display correctly on some terminals. "--preview-window=down,30%,sharp", @@ -123,7 +123,11 @@ pub struct FzfChild(Child); impl FzfChild { pub fn write(&mut self, dir: &Dir, now: Epoch) -> Result> { let handle = self.0.stdin.as_mut().unwrap(); - match write!(handle, "{}\0", dir.display().with_score(now).with_separator('\t')) { + match write!( + handle, + "{}\0", + dir.display().with_score(now).with_separator('\t').shorten_home_dir() + ) { Ok(()) => Ok(None), Err(e) if e.kind() == io::ErrorKind::BrokenPipe => self.wait().map(Some), Err(e) => Err(e).context("could not write to fzf"), @@ -140,7 +144,10 @@ impl FzfChild { let status = self.0.wait().context("wait failed on fzf")?; match status.code() { - Some(0) => Ok(output), + Some(0) => Ok(match output.split_once('\t') { + Some((score, path)) => format!("{score}\t{}", expand_home_dir(path)), + None => expand_home_dir(&output), + }), Some(1) => bail!("no match found"), Some(2) => bail!("fzf returned an error"), Some(130) => bail!(SilentExit { code: 130 }), @@ -150,6 +157,20 @@ impl FzfChild { } } +fn expand_home_dir(path: &str) -> String { + let home = crate::config::get_home_dir(); + if home.is_empty() { + return path.to_string(); + } + + match path.strip_prefix("~") { + Some(path) => { + format!("{}{}", home.to_str().expect("cannot convert OsString to &str"), path) + } + None => path.to_string(), + } +} + /// Similar to [`fs::write`], but atomic (best effort on Windows). pub fn write(path: impl AsRef, contents: impl AsRef<[u8]>) -> Result<()> { let path = path.as_ref(); From 39218609ad3ce8d2e3038c8fdc597179230bf675 Mon Sep 17 00:00:00 2001 From: Aiden Ghim Date: Mon, 6 Apr 2026 20:02:43 +0900 Subject: [PATCH 2/2] Deepsource lint compliance --- src/config.rs | 2 +- src/util.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/config.rs b/src/config.rs index 2a38705..70d031d 100644 --- a/src/config.rs +++ b/src/config.rs @@ -62,5 +62,5 @@ pub fn resolve_symlinks() -> bool { } pub fn get_home_dir() -> OsString { - env::var_os("HOME").unwrap_or("".into()) + env::var_os("HOME").unwrap_or_else(|| "".into()) } diff --git a/src/util.rs b/src/util.rs index d5dfa98..7a38b60 100644 --- a/src/util.rs +++ b/src/util.rs @@ -163,7 +163,7 @@ fn expand_home_dir(path: &str) -> String { return path.to_string(); } - match path.strip_prefix("~") { + match path.strip_prefix('~') { Some(path) => { format!("{}{}", home.to_str().expect("cannot convert OsString to &str"), path) }