Repository: sxyazi/yazi
File: yazi-fs/src/path.rs (Rust)

Code before:
	let mut out = vec![];
	for c in path.components() {
		match c {
			CurDir => {}
			ParentDir => match out.last() {
				Some(RootDir) => {}
				Some(Normal(_)) => _ = out.pop(),
				None | Some(CurDir) | Some(ParentDir) | Some(Prefix(_)) => out.push(c),
			},
			c => out.push(c),
		}
	}

	if out.is_empty() { PathBuf::from(".") } else { out.iter().collect() }
}

// FIXME: VFS
#[inline]
pub fn expand_path(p: impl AsRef<Path>) -> PathBuf { _expand_path(p.as_ref()) }

// FIXME: keep the original scheme of the Url
#[inline]
pub fn expand_url<'a>(url: impl Into<Cow<'a, Url>>) -> Cow<'a, Url> {
	let u: Cow<'a, Url> = url.into();
	if let Some(p) = u.as_path() { Url::from(_expand_path(p)).into() } else { u }
}

fn _expand_path(p: &Path) -> PathBuf {
	// ${HOME} or $HOME
	#[cfg(unix)]
	let re = regex::bytes::Regex::new(r"\$(?:\{([^}]+)\}|([a-zA-Z\d_]+))").unwrap();

	// %USERPROFILE%
	#[cfg(windows)]
	let re = regex::bytes::Regex::new(r"%([^%]+)%").unwrap();

	let b = re.replace_all(p.as_os_str().as_encoded_bytes(), |caps: &regex::bytes::Captures| {
		let name = caps.get(2).or_else(|| caps.get(1)).unwrap();
		str::from_utf8(name.as_bytes())
			.ok()
			.and_then(env::var_os)
			.map_or_else(|| caps.get(0).unwrap().as_bytes().to_owned(), |s| s.into_encoded_bytes())
	});

	// Windows paths that only have a drive letter but no root, e.g. "D:"
	#[cfg(windows)]
	if b.len() == 2 {
		if b[1] == b':' && b[0].is_ascii_alphabetic() {
			return PathBuf::from(format!("{}:\\", b[0].to_ascii_uppercase() as char));
		}
	}

Review comment (suggestion):
The scheme is being cloned unnecessarily. Consider using `u.scheme` directly or storing the scheme in a variable to avoid the clone operation, especially if this function is called frequently.
```suggestion
	let scheme = &u.scheme;
	Url { loc: Loc::with(u.loc.base(), _expand_path(p)), scheme: scheme.clone() }.into()
```

Code after:
	let mut out = vec![];
	for c in path.components() {
		match c {
			CurDir => {}
			ParentDir => match out.last() {
				Some(RootDir) => {}
				Some(Normal(_)) => _ = out.pop(),
				None | Some(CurDir) | Some(ParentDir) | Some(Prefix(_)) => out.push(c),
			},
			c => out.push(c),
		}
	}

	if out.is_empty() { PathBuf::from(".") } else { out.iter().collect() }
}

// FIXME: VFS
#[inline]
pub fn expand_path(p: impl AsRef<Path>) -> PathBuf { _expand_path(p.as_ref()) }

#[inline]
pub fn expand_url<'a>(url: impl Into<Cow<'a, Url>>) -> Cow<'a, Url> {
	let u: Cow<'a, Url> = url.into();
	let Some(p) = u.as_path() else { return u };

	Url { loc: Loc::with(u.loc.base(), _expand_path(p)), scheme: u.scheme.clone() }.into()
}

fn _expand_path(p: &Path) -> PathBuf {
	// ${HOME} or $HOME
	#[cfg(unix)]
	let re = regex::bytes::Regex::new(r"\$(?:\{([^}]+)\}|([a-zA-Z\d_]+))").unwrap();

	// %USERPROFILE%
	#[cfg(windows)]
	let re = regex::bytes::Regex::new(r"%([^%]+)%").unwrap();

	let b = re.replace_all(p.as_os_str().as_encoded_bytes(), |caps: &regex::bytes::Captures| {
		let name = caps.get(2).or_else(|| caps.get(1)).unwrap();
		str::from_utf8(name.as_bytes())
			.ok()
			.and_then(env::var_os)
			.map_or_else(|| caps.get(0).unwrap().as_bytes().to_owned(), |s| s.into_encoded_bytes())
	});

	// Windows paths that only have a drive letter but no root, e.g. "D:"
	#[cfg(windows)]
	if b.len() == 2 {
		if b[1] == b':' && b[0].is_ascii_alphabetic() {
			return PathBuf::from(format!("{}:\\", b[0].to_ascii_uppercase() as char));
		}