From fd2430062f85896fcd592233d0eb4a657b76bc41 Mon Sep 17 00:00:00 2001 From: Vivek Kethineni Date: Thu, 10 Oct 2024 17:43:26 -0500 Subject: [PATCH 1/7] Allow path relative-to to use parent directory symbols --- crates/nu-command/src/path/relative_to.rs | 41 +++++++++++++++++++---- 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/crates/nu-command/src/path/relative_to.rs b/crates/nu-command/src/path/relative_to.rs index 71cfa8b2a9..2e797b0dc4 100644 --- a/crates/nu-command/src/path/relative_to.rs +++ b/crates/nu-command/src/path/relative_to.rs @@ -144,14 +144,41 @@ path."# fn relative_to(path: &Path, span: Span, args: &Arguments) -> Value { let lhs = expand_to_real_path(path); let rhs = expand_to_real_path(&args.path.item); - match lhs.strip_prefix(&rhs) { - Ok(p) => Value::string(p.to_string_lossy(), span), - Err(e) => Value::error( - ShellError::CantConvert { - to_type: e.to_string(), - from_type: "string".into(), + + match (lhs.to_str(), rhs.to_str()) { + (Some(child_str), Some(parent_str)) => { + let common: String = child_str + .split("/") + .zip(parent_str.split("/")) + .take_while(|(x, y)| x == y) + .map(|(x, _)| x.to_string() + "/") + .collect(); + + if let Some(x) = child_str.strip_prefix(&common) { + if parent_str == common.trim_end_matches("/") { + return Value::string(x.to_string(), span); + } + if let Some(remaining_parent) = parent_str.strip_prefix(&common) { + let mut path: String = remaining_parent.split("/").map(|_| "../").collect(); + path.push_str(x); + return Value::string(path.to_string(), span); + } + } + + Value::error( + ShellError::IncorrectValue { + msg: "Either the input or the argument path is incorrect".into(), + val_span: span, + call_span: span, + }, span, - help: None, + ) + } + _ => Value::error( + ShellError::IncorrectValue { + msg: "Either the input or the argument path is incorrect".into(), + val_span: span, + call_span: span, }, span, ), From f89eeda3f84d16e5a0aee9124326ad0d5e06a32a Mon Sep 17 00:00:00 2001 From: Vivek Kethineni Date: Sun, 26 Jan 2025 13:55:32 -0600 Subject: [PATCH 2/7] Fixed clippy errors, inconsistent behaviour --- crates/nu-command/src/path/relative_to.rs | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/crates/nu-command/src/path/relative_to.rs b/crates/nu-command/src/path/relative_to.rs index 2e797b0dc4..9a2371477f 100644 --- a/crates/nu-command/src/path/relative_to.rs +++ b/crates/nu-command/src/path/relative_to.rs @@ -142,24 +142,37 @@ path."# } fn relative_to(path: &Path, span: Span, args: &Arguments) -> Value { + // Assume right arguemnt always is a directory (i.e. /a/b is really /a/b/) + // The output, when typed into a termiinal at the right arugment leads to the left. let lhs = expand_to_real_path(path); let rhs = expand_to_real_path(&args.path.item); match (lhs.to_str(), rhs.to_str()) { (Some(child_str), Some(parent_str)) => { + let mut parent_str = parent_str + .trim_end_matches('/') + .trim_start_matches('/') + .to_string(); + parent_str.push('/'); + let common: String = child_str - .split("/") - .zip(parent_str.split("/")) + .trim_start_matches('/') + .split('/') + .zip(parent_str.split('/')) .take_while(|(x, y)| x == y) .map(|(x, _)| x.to_string() + "/") .collect(); if let Some(x) = child_str.strip_prefix(&common) { - if parent_str == common.trim_end_matches("/") { + if parent_str == common { return Value::string(x.to_string(), span); } if let Some(remaining_parent) = parent_str.strip_prefix(&common) { - let mut path: String = remaining_parent.split("/").map(|_| "../").collect(); + let mut path: String = remaining_parent + .split('/') + .filter(|&x| x.is_empty()) + .map(|_| "../") + .collect(); path.push_str(x); return Value::string(path.to_string(), span); } @@ -176,7 +189,7 @@ fn relative_to(path: &Path, span: Span, args: &Arguments) -> Value { } _ => Value::error( ShellError::IncorrectValue { - msg: "Either the input or the argument path is incorrect".into(), + msg: "Unable to convert one or more of the arugments into strings!".into(), val_span: span, call_span: span, }, From 577be7321fa461e122efb3b20565ca10135bff8f Mon Sep 17 00:00:00 2001 From: Vivek Kethineni Date: Tue, 28 Jan 2025 17:48:38 -0600 Subject: [PATCH 3/7] Use pathbuf instead of strings --- crates/nu-command/src/path/relative_to.rs | 112 ++++++++-------------- 1 file changed, 41 insertions(+), 71 deletions(-) diff --git a/crates/nu-command/src/path/relative_to.rs b/crates/nu-command/src/path/relative_to.rs index 9a2371477f..bd91e38391 100644 --- a/crates/nu-command/src/path/relative_to.rs +++ b/crates/nu-command/src/path/relative_to.rs @@ -2,7 +2,7 @@ use super::PathSubcommandArguments; use nu_engine::command_prelude::*; use nu_path::expand_to_real_path; use nu_protocol::engine::StateWorkingSet; -use std::path::Path; +use std::path::{Path, PathBuf}; struct Arguments { path: Spanned, @@ -92,30 +92,6 @@ path."# ) } - #[cfg(windows)] - fn examples(&self) -> Vec { - vec![ - Example { - description: "Find a relative path from two absolute paths", - example: r"'C:\Users\viking' | path relative-to 'C:\Users'", - result: Some(Value::test_string(r"viking")), - }, - Example { - description: "Find a relative path from absolute paths in list", - example: r"[ C:\Users\viking, C:\Users\spam ] | path relative-to C:\Users", - result: Some(Value::test_list(vec![ - Value::test_string("viking"), - Value::test_string("spam"), - ])), - }, - Example { - description: "Find a relative path from two relative paths", - example: r"'eggs\bacon\sausage\spam' | path relative-to 'eggs\bacon\sausage'", - result: Some(Value::test_string(r"spam")), - }, - ] - } - #[cfg(not(windows))] fn examples(&self) -> Vec { vec![ @@ -137,67 +113,61 @@ path."# example: r"'eggs/bacon/sausage/spam' | path relative-to 'eggs/bacon/sausage'", result: Some(Value::test_string(r"spam")), }, + Example { + description: "Find a relative path that requires parent directory symbols", + example: r"'a/b/c' | path relative-to 'a/d/e'", + + result: Some(Value::test_string(r"../../b/c")), + }, ] } } fn relative_to(path: &Path, span: Span, args: &Arguments) -> Value { - // Assume right arguemnt always is a directory (i.e. /a/b is really /a/b/) - // The output, when typed into a termiinal at the right arugment leads to the left. - let lhs = expand_to_real_path(path); - let rhs = expand_to_real_path(&args.path.item); + let child = expand_to_real_path(path); + let parent = expand_to_real_path(&args.path.item); - match (lhs.to_str(), rhs.to_str()) { - (Some(child_str), Some(parent_str)) => { - let mut parent_str = parent_str - .trim_end_matches('/') - .trim_start_matches('/') - .to_string(); - parent_str.push('/'); + let common: PathBuf = child + .iter() + .zip(parent.iter()) + .take_while(|(x, y)| x == y) + .map(|(x, _)| x) + .collect(); - let common: String = child_str - .trim_start_matches('/') - .split('/') - .zip(parent_str.split('/')) - .take_while(|(x, y)| x == y) - .map(|(x, _)| x.to_string() + "/") - .collect(); - - if let Some(x) = child_str.strip_prefix(&common) { - if parent_str == common { - return Value::string(x.to_string(), span); - } - if let Some(remaining_parent) = parent_str.strip_prefix(&common) { - let mut path: String = remaining_parent - .split('/') - .filter(|&x| x.is_empty()) - .map(|_| "../") - .collect(); - path.push_str(x); - return Value::string(path.to_string(), span); - } - } - - Value::error( + let differing_parent = match parent.strip_prefix(&common) { + Ok(p) => p, + Err(_) => { + return Value::error( ShellError::IncorrectValue { - msg: "Either the input or the argument path is incorrect".into(), + msg: "Unable to strip common prefix from parent".into(), val_span: span, call_span: span, }, span, ) } - _ => Value::error( - ShellError::IncorrectValue { - msg: "Unable to convert one or more of the arugments into strings!".into(), - val_span: span, - call_span: span, - }, - span, - ), - } -} + }; + let differing_child = match child.strip_prefix(&common) { + Ok(p) => p, + Err(_) => { + return Value::error( + ShellError::IncorrectValue { + msg: "Unable to strip common prefix from child".into(), + val_span: span, + call_span: span, + }, + span, + ) + } + }; + + let mut path: String = differing_parent.iter().map(|_| "../").collect(); + + path.push_str(&differing_child.to_string_lossy()); + + Value::string(path, span) +} #[cfg(test)] mod tests { use super::*; From 5fffbdef2ae599bd6d014a80b3a983143a5c6d8c Mon Sep 17 00:00:00 2001 From: Vivek Kethineni Date: Tue, 28 Jan 2025 18:47:12 -0600 Subject: [PATCH 4/7] push to pathbuf instead of creating string --- crates/nu-command/src/path/relative_to.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/crates/nu-command/src/path/relative_to.rs b/crates/nu-command/src/path/relative_to.rs index bd91e38391..5ca6c584f7 100644 --- a/crates/nu-command/src/path/relative_to.rs +++ b/crates/nu-command/src/path/relative_to.rs @@ -162,11 +162,12 @@ fn relative_to(path: &Path, span: Span, args: &Arguments) -> Value { } }; - let mut path: String = differing_parent.iter().map(|_| "../").collect(); + let mut path = PathBuf::new(); + differing_parent.iter().for_each(|_| path.push("..")); - path.push_str(&differing_child.to_string_lossy()); + path.push(&differing_child); - Value::string(path, span) + Value::string(path.to_string_lossy(), span) } #[cfg(test)] mod tests { From 3256352742431c1eec5907fc68ca62ee00b12bb9 Mon Sep 17 00:00:00 2001 From: Vivek Date: Wed, 29 Jan 2025 19:48:13 -0600 Subject: [PATCH 5/7] clippy --- crates/nu-command/src/path/relative_to.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/nu-command/src/path/relative_to.rs b/crates/nu-command/src/path/relative_to.rs index 5ca6c584f7..9f1c8de77e 100644 --- a/crates/nu-command/src/path/relative_to.rs +++ b/crates/nu-command/src/path/relative_to.rs @@ -165,7 +165,7 @@ fn relative_to(path: &Path, span: Span, args: &Arguments) -> Value { let mut path = PathBuf::new(); differing_parent.iter().for_each(|_| path.push("..")); - path.push(&differing_child); + path.push(differing_child); Value::string(path.to_string_lossy(), span) } From 2c814a43c3751f39a0d1c0e613f51d787bdee74f Mon Sep 17 00:00:00 2001 From: Vivek Date: Wed, 29 Jan 2025 20:09:33 -0600 Subject: [PATCH 6/7] returned accidentally removed tests --- crates/nu-command/src/path/relative_to.rs | 24 +++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/crates/nu-command/src/path/relative_to.rs b/crates/nu-command/src/path/relative_to.rs index 9f1c8de77e..b7bc5dad87 100644 --- a/crates/nu-command/src/path/relative_to.rs +++ b/crates/nu-command/src/path/relative_to.rs @@ -92,6 +92,30 @@ path."# ) } + #[cfg(windows)] + fn examples(&self) -> Vec { + vec![ + Example { + description: "Find a relative path from two absolute paths", + example: r"'C:\Users\viking' | path relative-to 'C:\Users'", + result: Some(Value::test_string(r"viking")), + }, + Example { + description: "Find a relative path from absolute paths in list", + example: r"[ C:\Users\viking, C:\Users\spam ] | path relative-to C:\Users", + result: Some(Value::test_list(vec![ + Value::test_string("viking"), + Value::test_string("spam"), + ])), + }, + Example { + description: "Find a relative path from two relative paths", + example: r"'eggs\bacon\sausage\spam' | path relative-to 'eggs\bacon\sausage'", + result: Some(Value::test_string(r"spam")), + }, + ] + } + #[cfg(not(windows))] fn examples(&self) -> Vec { vec![ From 4a06821a5edd35ab576b2bb4a66b03f3b2b548e8 Mon Sep 17 00:00:00 2001 From: Vivek Date: Wed, 29 Jan 2025 20:25:40 -0600 Subject: [PATCH 7/7] added parent path test to windows examples --- crates/nu-command/src/path/relative_to.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/crates/nu-command/src/path/relative_to.rs b/crates/nu-command/src/path/relative_to.rs index b7bc5dad87..3be9a12c52 100644 --- a/crates/nu-command/src/path/relative_to.rs +++ b/crates/nu-command/src/path/relative_to.rs @@ -113,6 +113,12 @@ path."# example: r"'eggs\bacon\sausage\spam' | path relative-to 'eggs\bacon\sausage'", result: Some(Value::test_string(r"spam")), }, + Example { + description: "Find a relative path that requires parent directory symbols", + example: r"'a\b\c' | path relative-to 'a\d\e'", + + result: Some(Value::test_string(r"..\..\b\c")), + }, ] }