mirror of
https://github.com/nushell/nushell.git
synced 2024-12-23 15:39:06 +01:00
Fix path dots expansion (#3491)
* Fix parser expanding dots where it shouldn't Previously, the parser would expand "a...b" as "a../..b". Now, >2 dots are only expanded when the whole path component consists of dots (i.e., "..." expands to "../.." while "a...b" stays as it is). * Respect OS separator when expanding >2 dots "..." now expands to either "../.." or "..\..", based on the host OS.
This commit is contained in:
parent
41834d16d6
commit
6ae7884786
@ -1,5 +1,7 @@
|
|||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
|
const EXPAND_STR: &str = if cfg!(windows) { r"..\" } else { "../" };
|
||||||
|
|
||||||
fn handle_dots_push(string: &mut String, count: u8) {
|
fn handle_dots_push(string: &mut String, count: u8) {
|
||||||
if count < 1 {
|
if count < 1 {
|
||||||
return;
|
return;
|
||||||
@ -11,20 +13,34 @@ fn handle_dots_push(string: &mut String, count: u8) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _ in 0..(count - 1) {
|
for _ in 0..(count - 1) {
|
||||||
string.push_str("../");
|
string.push_str(EXPAND_STR);
|
||||||
}
|
}
|
||||||
|
|
||||||
string.pop(); // remove last '/'
|
string.pop(); // remove last '/'
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expand_ndots(path: &str) -> Cow<'_, str> {
|
pub fn expand_ndots(path: &str) -> Cow<'_, str> {
|
||||||
|
// helpers
|
||||||
|
#[cfg(windows)]
|
||||||
|
fn is_separator(c: char) -> bool {
|
||||||
|
// AFAIK, Windows can have both \ and / as path components separators
|
||||||
|
(c == '/') || (c == '\\')
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(windows))]
|
||||||
|
fn is_separator(c: char) -> bool {
|
||||||
|
c == '/'
|
||||||
|
}
|
||||||
|
|
||||||
|
// find if we need to expand any >2 dot paths and early exit if not
|
||||||
let mut dots_count = 0u8;
|
let mut dots_count = 0u8;
|
||||||
let ndots_present = {
|
let ndots_present = {
|
||||||
for chr in path.chars() {
|
for chr in path.chars() {
|
||||||
if chr == '.' {
|
if chr == '.' {
|
||||||
dots_count += 1;
|
dots_count += 1;
|
||||||
} else {
|
} else {
|
||||||
if dots_count > 2 {
|
if is_separator(chr) && (dots_count > 2) {
|
||||||
|
// this path component had >2 dots
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,12 +58,21 @@ pub fn expand_ndots(path: &str) -> Cow<'_, str> {
|
|||||||
let mut dots_count = 0u8;
|
let mut dots_count = 0u8;
|
||||||
let mut expanded = String::new();
|
let mut expanded = String::new();
|
||||||
for chr in path.chars() {
|
for chr in path.chars() {
|
||||||
if chr != '.' {
|
if chr == '.' {
|
||||||
|
dots_count += 1;
|
||||||
|
} else {
|
||||||
|
if is_separator(chr) {
|
||||||
|
// check for dots expansion only at path component boundaries
|
||||||
handle_dots_push(&mut expanded, dots_count);
|
handle_dots_push(&mut expanded, dots_count);
|
||||||
dots_count = 0;
|
dots_count = 0;
|
||||||
expanded.push(chr);
|
|
||||||
} else {
|
} else {
|
||||||
dots_count += 1;
|
// got non-dot within path component => do not expand any dots
|
||||||
|
while dots_count > 0 {
|
||||||
|
expanded.push('.');
|
||||||
|
dots_count -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expanded.push(chr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,21 +95,81 @@ pub fn expand_path<'a>(path: &'a str) -> Cow<'a, str> {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
// common tests
|
||||||
#[test]
|
#[test]
|
||||||
fn string_without_ndots() {
|
fn string_without_ndots() {
|
||||||
assert_eq!("../hola", &expand_ndots("../hola").to_string());
|
assert_eq!("../hola", &expand_ndots("../hola").to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn string_with_three_ndots() {
|
fn string_with_three_ndots_and_chars() {
|
||||||
assert_eq!("../..", &expand_ndots("...").to_string());
|
assert_eq!("a...b", &expand_ndots("a...b").to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn string_with_two_ndots_and_chars() {
|
||||||
|
assert_eq!("a..b", &expand_ndots("a..b").to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn string_with_one_dot_and_chars() {
|
||||||
|
assert_eq!("a.b", &expand_ndots("a.b").to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Windows tests
|
||||||
|
#[cfg(windows)]
|
||||||
|
#[test]
|
||||||
|
fn string_with_three_ndots() {
|
||||||
|
assert_eq!(r"..\..", &expand_ndots("...").to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
#[test]
|
||||||
|
fn string_with_mixed_ndots_and_chars() {
|
||||||
|
assert_eq!(
|
||||||
|
r"a...b/./c..d/../e.f/..\..\..//.",
|
||||||
|
&expand_ndots("a...b/./c..d/../e.f/....//.").to_string()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
#[test]
|
||||||
|
fn string_with_three_ndots_and_final_slash() {
|
||||||
|
assert_eq!(r"..\../", &expand_ndots(".../").to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
#[test]
|
||||||
|
fn string_with_three_ndots_and_garbage() {
|
||||||
|
assert_eq!(
|
||||||
|
r"ls ..\../ garbage.*[",
|
||||||
|
&expand_ndots("ls .../ garbage.*[").to_string(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// non-Windows tests
|
||||||
|
#[cfg(not(windows))]
|
||||||
|
#[test]
|
||||||
|
fn string_with_three_ndots() {
|
||||||
|
assert_eq!(r"../..", &expand_ndots("...").to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(windows))]
|
||||||
|
#[test]
|
||||||
|
fn string_with_mixed_ndots_and_chars() {
|
||||||
|
assert_eq!(
|
||||||
|
"a...b/./c..d/../e.f/../../..//.",
|
||||||
|
&expand_ndots("a...b/./c..d/../e.f/....//.").to_string()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(windows))]
|
||||||
#[test]
|
#[test]
|
||||||
fn string_with_three_ndots_and_final_slash() {
|
fn string_with_three_ndots_and_final_slash() {
|
||||||
assert_eq!("../../", &expand_ndots(".../").to_string());
|
assert_eq!("../../", &expand_ndots(".../").to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(windows))]
|
||||||
#[test]
|
#[test]
|
||||||
fn string_with_three_ndots_and_garbage() {
|
fn string_with_three_ndots_and_garbage() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
Loading…
Reference in New Issue
Block a user