mirror of
https://github.com/veeso/termscp.git
synced 2026-09-26 14:01:17 -07:00
fix: resolve . and .. in terminal cd and prevent panic in path elide
`absolutize` now lexically normalizes paths so `cd ..` navigates to the parent directory instead of appending `..` literally. Also guard against `file_name()` returning `None` in `fmt_path_elide_ex`, which caused a panic on paths containing unresolved `..` components. Closes #402
This commit is contained in:
+4
-2
@@ -67,8 +67,10 @@ pub fn fmt_path_elide_ex(p: &Path, width: usize, extra_len: usize) -> String {
|
|||||||
// If ancestors_len is bigger than 3, push '…' and parent too
|
// If ancestors_len is bigger than 3, push '…' and parent too
|
||||||
if ancestors_len > 3 {
|
if ancestors_len > 3 {
|
||||||
elided_path.push("…");
|
elided_path.push("…");
|
||||||
if let Some(parent) = p.ancestors().nth(1) {
|
if let Some(parent) = p.ancestors().nth(1)
|
||||||
elided_path.push(parent.file_name().unwrap());
|
&& let Some(name) = parent.file_name()
|
||||||
|
{
|
||||||
|
elided_path.push(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Push file_name
|
// Push file_name
|
||||||
|
|||||||
+59
-1
@@ -12,14 +12,34 @@ use std::path::{Component, Path, PathBuf};
|
|||||||
/// assert_eq!(absolutize(&Path::new("/home/omar"), &Path::new("/tmp/readme.txt")).as_path(), Path::new("/tmp/readme.txt"));
|
/// assert_eq!(absolutize(&Path::new("/home/omar"), &Path::new("/tmp/readme.txt")).as_path(), Path::new("/tmp/readme.txt"));
|
||||||
/// ```
|
/// ```
|
||||||
pub fn absolutize(wrkdir: &Path, target: &Path) -> PathBuf {
|
pub fn absolutize(wrkdir: &Path, target: &Path) -> PathBuf {
|
||||||
match target.is_absolute() {
|
let raw = match target.is_absolute() {
|
||||||
true => target.to_path_buf(),
|
true => target.to_path_buf(),
|
||||||
false => {
|
false => {
|
||||||
let mut p: PathBuf = wrkdir.to_path_buf();
|
let mut p: PathBuf = wrkdir.to_path_buf();
|
||||||
p.push(target);
|
p.push(target);
|
||||||
p
|
p
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
normalize(&raw)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Normalize a path by resolving `.` and `..` components lexically
|
||||||
|
/// (without touching the filesystem).
|
||||||
|
fn normalize(path: &Path) -> PathBuf {
|
||||||
|
let mut parts: Vec<Component> = Vec::new();
|
||||||
|
for component in path.components() {
|
||||||
|
match component {
|
||||||
|
Component::ParentDir => {
|
||||||
|
// Pop the last normal component; never pop past root
|
||||||
|
if let Some(Component::Normal(_)) = parts.last() {
|
||||||
|
parts.pop();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
Component::CurDir => {} // skip `.`
|
||||||
|
other => parts.push(other),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
parts.iter().collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This function will get the difference from path `path` to `base`. Basically will remove `base` from `path`
|
/// This function will get the difference from path `path` to `base`. Basically will remove `base` from `path`
|
||||||
@@ -99,6 +119,44 @@ mod test {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn absolutize_resolves_parent_dir() {
|
||||||
|
assert_eq!(
|
||||||
|
absolutize(Path::new("/home/omar"), Path::new("..")).as_path(),
|
||||||
|
Path::new("/home")
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
absolutize(Path::new("/home/omar"), Path::new("../docs")).as_path(),
|
||||||
|
Path::new("/home/docs")
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
absolutize(Path::new("/home"), Path::new("..")).as_path(),
|
||||||
|
Path::new("/")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn absolutize_resolves_current_dir() {
|
||||||
|
assert_eq!(
|
||||||
|
absolutize(Path::new("/home/omar"), Path::new(".")).as_path(),
|
||||||
|
Path::new("/home/omar")
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
absolutize(Path::new("/home/omar"), Path::new("./docs")).as_path(),
|
||||||
|
Path::new("/home/omar/docs")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn normalize_path() {
|
||||||
|
assert_eq!(normalize(Path::new("/a/b/../c")), Path::new("/a/c"));
|
||||||
|
assert_eq!(normalize(Path::new("/a/b/./c")), Path::new("/a/b/c"));
|
||||||
|
assert_eq!(normalize(Path::new("/a/b/c/../..")), Path::new("/a"));
|
||||||
|
assert_eq!(normalize(Path::new("/")), Path::new("/"));
|
||||||
|
// Parent beyond root stays at root
|
||||||
|
assert_eq!(normalize(Path::new("/..")), Path::new("/"));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn calc_diff_paths() {
|
fn calc_diff_paths() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|||||||
Reference in New Issue
Block a user