From f6a3935bcb214034737547a3c29ff26d350d5a8b Mon Sep 17 00:00:00 2001 From: pagedmov Date: Sun, 15 Mar 2026 11:30:40 -0400 Subject: [PATCH] implement tilde expansion for `~user` and `~uid` using nix User lookups --- src/expand.rs | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/expand.rs b/src/expand.rs index 731012b..4f5f6ae 100644 --- a/src/expand.rs +++ b/src/expand.rs @@ -4,6 +4,7 @@ use std::str::{Chars, FromStr}; use ariadne::Fmt; use glob::Pattern; +use nix::unistd::{Uid, User}; use regex::Regex; use crate::libsh::error::{ShErr, ShErrKind, ShResult, ShResultExt, next_color}; @@ -473,7 +474,26 @@ pub fn expand_raw(chars: &mut Peekable>) -> ShResult { while let Some(ch) = chars.next() { match ch { markers::TILDE_SUB => { - let home = env::var("HOME").unwrap_or_default(); + let mut username = String::new(); + while chars.peek().is_some_and(|ch| *ch != '/') { + let ch = chars.next().unwrap(); + username.push(ch); + } + let home = if username.is_empty() { + env::var("HOME").unwrap_or_default() + } + else if let Ok(result) = User::from_name(&username) + && let Some(user) = result { + user.dir.to_string_lossy().to_string() + } + else if let Ok(id) = username.parse::() + && let Ok(result) = User::from_uid(Uid::from_raw(id)) + && let Some(user) = result { + user.dir.to_string_lossy().to_string() + } + else { + format!("~{username}") + }; result.push_str(&home); } markers::PROC_SUB_OUT => {