mirror of
https://github.com/nushell/nushell.git
synced 2025-04-18 18:28:19 +02:00
# Description Fixes: #11455 ### For arguments which is annotated with `:path/:directory/:glob` To fix the issue, we need to have a way to know if a path is originally quoted during runtime. So the information needed to be added at several levels: * parse time (from user input to expression) We need to add quoted information into `Expr::Filepath`, `Expr::Directory`, `Expr::GlobPattern` * eval time When convert from `Expr::Filepath`, `Expr::Directory`, `Expr::GlobPattern` to `Value::String` during runtime, we won't auto expanded the path if it's quoted ### For `ls` It's really special, because it accepts a `String` as a pattern, and it generates `glob` expression inside the command itself. So the idea behind the change is introducing a special SyntaxShape to ls: `SyntaxShape::LsGlobPattern`. So we can track if the pattern is originally quoted easier, and we don't auto expand the path either. Then when constructing a glob pattern inside ls, we check if input pattern is quoted, if so: we escape the input pattern, so we can run `ls a[123]b`, because it's already escaped. Finally, to accomplish the checking process, we also need to introduce a new value type called `Value::QuotedString` to differ from `Value::String`, it's used to generate an enum called `NuPath`, which is finally used in `ls` function. `ls` learned from `NuPath` to know if user input is quoted. # User-Facing Changes Actually it contains several changes ### For arguments which is annotated with `:path/:directory/:glob` #### Before ```nushell > def foo [p: path] { echo $p }; print (foo "~/a"); print (foo '~/a') /home/windsoilder/a /home/windsoilder/a > def foo [p: directory] { echo $p }; print (foo "~/a"); print (foo '~/a') /home/windsoilder/a /home/windsoilder/a > def foo [p: glob] { echo $p }; print (foo "~/a"); print (foo '~/a') /home/windsoilder/a /home/windsoilder/a ``` #### After ```nushell > def foo [p: path] { echo $p }; print (foo "~/a"); print (foo '~/a') ~/a ~/a > def foo [p: directory] { echo $p }; print (foo "~/a"); print (foo '~/a') ~/a ~/a > def foo [p: glob] { echo $p }; print (foo "~/a"); print (foo '~/a') ~/a ~/a ``` ### For ls command `touch '[uwu]'` #### Before ``` ❯ ls -D "[uwu]" Error: × No matches found for [uwu] ╭─[entry #6:1:1] 1 │ ls -D "[uwu]" · ───┬─── · ╰── Pattern, file or folder not found ╰──── help: no matches found ``` #### After ``` ❯ ls -D "[uwu]" ╭───┬───────┬──────┬──────┬──────────╮ │ # │ name │ type │ size │ modified │ ├───┼───────┼──────┼──────┼──────────┤ │ 0 │ [uwu] │ file │ 0 B │ now │ ╰───┴───────┴──────┴──────┴──────────╯ ``` # Tests + Formatting Done # After Submitting NaN
63 lines
1.9 KiB
Rust
63 lines
1.9 KiB
Rust
use chrono::FixedOffset;
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
use super::{
|
|
Call, CellPath, Expression, ExternalArgument, FullCellPath, MatchPattern, Operator,
|
|
RangeOperator,
|
|
};
|
|
use crate::{ast::ImportPattern, BlockId, Signature, Span, Spanned, Unit, VarId};
|
|
|
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
|
pub enum Expr {
|
|
Bool(bool),
|
|
Int(i64),
|
|
Float(f64),
|
|
Binary(Vec<u8>),
|
|
Range(
|
|
Option<Box<Expression>>, // from
|
|
Option<Box<Expression>>, // next value after "from"
|
|
Option<Box<Expression>>, // to
|
|
RangeOperator,
|
|
),
|
|
Var(VarId),
|
|
VarDecl(VarId),
|
|
Call(Box<Call>),
|
|
ExternalCall(Box<Expression>, Vec<ExternalArgument>, bool), // head, args, is_subexpression
|
|
Operator(Operator),
|
|
RowCondition(BlockId),
|
|
UnaryNot(Box<Expression>),
|
|
BinaryOp(Box<Expression>, Box<Expression>, Box<Expression>), //lhs, op, rhs
|
|
Subexpression(BlockId),
|
|
Block(BlockId),
|
|
Closure(BlockId),
|
|
MatchBlock(Vec<(MatchPattern, Expression)>),
|
|
List(Vec<Expression>),
|
|
Table(Vec<Expression>, Vec<Vec<Expression>>),
|
|
Record(Vec<RecordItem>),
|
|
Keyword(Vec<u8>, Span, Box<Expression>),
|
|
ValueWithUnit(Box<Expression>, Spanned<Unit>),
|
|
DateTime(chrono::DateTime<FixedOffset>),
|
|
Filepath(String, bool),
|
|
Directory(String, bool),
|
|
GlobPattern(String, bool),
|
|
LsGlobPattern(String, bool),
|
|
String(String),
|
|
CellPath(CellPath),
|
|
FullCellPath(Box<FullCellPath>),
|
|
ImportPattern(ImportPattern),
|
|
Overlay(Option<BlockId>), // block ID of the overlay's origin module
|
|
Signature(Box<Signature>),
|
|
StringInterpolation(Vec<Expression>),
|
|
Spread(Box<Expression>),
|
|
Nothing,
|
|
Garbage,
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
|
pub enum RecordItem {
|
|
/// A key: val mapping
|
|
Pair(Expression, Expression),
|
|
/// Span for the "..." and the expression that's being spread
|
|
Spread(Span, Expression),
|
|
}
|