forked from extern/nushell
@ -7,7 +7,6 @@ mod errors;
|
||||
mod flag;
|
||||
mod lex;
|
||||
mod parse;
|
||||
mod path;
|
||||
mod scope;
|
||||
mod shapes;
|
||||
mod signature;
|
||||
@ -15,8 +14,6 @@ mod signature;
|
||||
pub use lex::lexer::{lex, parse_block};
|
||||
pub use lex::tokens::{LiteBlock, LiteCommand, LiteGroup, LitePipeline};
|
||||
pub use parse::{classify_block, garbage, parse, parse_full_column_path, parse_math_expression};
|
||||
pub use path::expand_ndots;
|
||||
pub use path::expand_path;
|
||||
pub use scope::ParserScope;
|
||||
pub use shapes::shapes;
|
||||
pub use signature::{Signature, SignatureRegistry};
|
||||
|
@ -1,9 +1,14 @@
|
||||
use std::{path::Path, sync::Arc};
|
||||
use std::borrow::Cow;
|
||||
use std::{
|
||||
path::{Path, PathBuf},
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use bigdecimal::BigDecimal;
|
||||
use indexmap::IndexMap;
|
||||
use log::trace;
|
||||
use nu_errors::{ArgumentError, ParseError};
|
||||
use nu_path::{expand_path, expand_path_string};
|
||||
use nu_protocol::hir::{
|
||||
self, Binary, Block, ClassifiedCommand, Expression, ExternalRedirection, Flag, FlagKind, Group,
|
||||
InternalCommand, Member, NamedArguments, Operator, Pipeline, RangeOperator, SpannedExpression,
|
||||
@ -13,6 +18,7 @@ use nu_protocol::{NamedType, PositionalType, Signature, SyntaxShape, UnspannedPa
|
||||
use nu_source::{HasSpan, Span, Spanned, SpannedItem};
|
||||
use num_bigint::BigInt;
|
||||
|
||||
use crate::parse::def::parse_parameter;
|
||||
use crate::{
|
||||
lex::lexer::{lex, parse_block},
|
||||
ParserScope,
|
||||
@ -24,7 +30,6 @@ use crate::{
|
||||
},
|
||||
parse::def::lex_split_baseline_tokens_on,
|
||||
};
|
||||
use crate::{parse::def::parse_parameter, path::expand_path};
|
||||
|
||||
use self::{
|
||||
def::{parse_definition, parse_definition_prototype},
|
||||
@ -67,7 +72,7 @@ pub fn parse_simple_column_path(
|
||||
output.push(Member::Int(row_number, part_span));
|
||||
} else {
|
||||
let trimmed = trim_quotes(¤t_part);
|
||||
output.push(Member::Bare(trimmed.clone().spanned(part_span)));
|
||||
output.push(Member::Bare(trimmed.spanned(part_span)));
|
||||
}
|
||||
current_part.clear();
|
||||
// Note: I believe this is safe because of the delimiter we're using,
|
||||
@ -944,8 +949,8 @@ fn parse_arg(
|
||||
)
|
||||
}
|
||||
SyntaxShape::GlobPattern => {
|
||||
let trimmed = trim_quotes(&lite_arg.item);
|
||||
let expanded = expand_path(&trimmed).to_string();
|
||||
let trimmed = Cow::Owned(trim_quotes(&lite_arg.item));
|
||||
let expanded = expand_path_string(trimmed).to_string();
|
||||
(
|
||||
SpannedExpression::new(Expression::glob_pattern(expanded), lite_arg.span),
|
||||
None,
|
||||
@ -961,10 +966,10 @@ fn parse_arg(
|
||||
SyntaxShape::Duration => parse_duration(lite_arg),
|
||||
SyntaxShape::FilePath => {
|
||||
let trimmed = trim_quotes(&lite_arg.item);
|
||||
let expanded = expand_path(&trimmed).to_string();
|
||||
let path = Path::new(&expanded);
|
||||
let path = PathBuf::from(trimmed);
|
||||
let expanded = expand_path(Cow::Owned(path)).to_path_buf();
|
||||
(
|
||||
SpannedExpression::new(Expression::FilePath(path.to_path_buf()), lite_arg.span),
|
||||
SpannedExpression::new(Expression::FilePath(expanded), lite_arg.span),
|
||||
None,
|
||||
)
|
||||
}
|
||||
@ -1647,8 +1652,8 @@ fn parse_external_call(
|
||||
) -> (Option<ClassifiedCommand>, Option<ParseError>) {
|
||||
let mut error = None;
|
||||
let name = lite_cmd.parts[0].clone().map(|v| {
|
||||
let trimmed = trim_quotes(&v);
|
||||
expand_path(&trimmed).to_string()
|
||||
let trimmed = Cow::Owned(trim_quotes(&v));
|
||||
expand_path_string(trimmed).to_string()
|
||||
});
|
||||
|
||||
let mut args = vec![];
|
||||
@ -1877,9 +1882,9 @@ fn parse_call(
|
||||
)),
|
||||
);
|
||||
}
|
||||
if let Ok(contents) =
|
||||
std::fs::read_to_string(expand_path(&lite_cmd.parts[1].item).into_owned())
|
||||
{
|
||||
if let Ok(contents) = std::fs::read_to_string(&expand_path(Cow::Borrowed(Path::new(
|
||||
&lite_cmd.parts[1].item,
|
||||
)))) {
|
||||
let _ = parse(&contents, 0, scope);
|
||||
} else {
|
||||
return (
|
||||
|
@ -1,180 +0,0 @@
|
||||
use std::borrow::Cow;
|
||||
|
||||
const EXPAND_STR: &str = if cfg!(windows) { r"..\" } else { "../" };
|
||||
|
||||
fn handle_dots_push(string: &mut String, count: u8) {
|
||||
if count < 1 {
|
||||
return;
|
||||
}
|
||||
|
||||
if count == 1 {
|
||||
string.push('.');
|
||||
return;
|
||||
}
|
||||
|
||||
for _ in 0..(count - 1) {
|
||||
string.push_str(EXPAND_STR);
|
||||
}
|
||||
|
||||
string.pop(); // remove last '/'
|
||||
}
|
||||
|
||||
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 ndots_present = {
|
||||
for chr in path.chars() {
|
||||
if chr == '.' {
|
||||
dots_count += 1;
|
||||
} else {
|
||||
if is_separator(chr) && (dots_count > 2) {
|
||||
// this path component had >2 dots
|
||||
break;
|
||||
}
|
||||
|
||||
dots_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
dots_count > 2
|
||||
};
|
||||
|
||||
if !ndots_present {
|
||||
return path.into();
|
||||
}
|
||||
|
||||
let mut dots_count = 0u8;
|
||||
let mut expanded = String::new();
|
||||
for chr in path.chars() {
|
||||
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);
|
||||
dots_count = 0;
|
||||
} else {
|
||||
// got non-dot within path component => do not expand any dots
|
||||
while dots_count > 0 {
|
||||
expanded.push('.');
|
||||
dots_count -= 1;
|
||||
}
|
||||
}
|
||||
expanded.push(chr);
|
||||
}
|
||||
}
|
||||
|
||||
handle_dots_push(&mut expanded, dots_count);
|
||||
|
||||
expanded.into()
|
||||
}
|
||||
|
||||
pub fn expand_path<'a>(path: &'a str) -> Cow<'a, str> {
|
||||
let tilde_expansion: Cow<'a, str> = shellexpand::tilde(path);
|
||||
let ndots_expansion: Cow<'a, str> = match tilde_expansion {
|
||||
Cow::Borrowed(b) => expand_ndots(b),
|
||||
Cow::Owned(o) => expand_ndots(&o).to_string().into(),
|
||||
};
|
||||
|
||||
ndots_expansion
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
// common tests
|
||||
#[test]
|
||||
fn string_without_ndots() {
|
||||
assert_eq!("../hola", &expand_ndots("../hola").to_string());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn string_with_three_ndots_and_chars() {
|
||||
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]
|
||||
fn string_with_three_ndots_and_final_slash() {
|
||||
assert_eq!("../../", &expand_ndots(".../").to_string());
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
#[test]
|
||||
fn string_with_three_ndots_and_garbage() {
|
||||
assert_eq!(
|
||||
"ls ../../ garbage.*[",
|
||||
&expand_ndots("ls .../ garbage.*[").to_string(),
|
||||
);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user