mirror of
https://github.com/nushell/nushell.git
synced 2024-11-22 16:33:37 +01:00
Added glob patterns to the syntax shapes
Bare words now represent literal file names, and globs are a different syntax shape called "Pattern". This allows commands like `cp` to ask for a pattern as a source and a literal file as a target. This also means that attempting to pass a glob to a command that expects a literal path will produce an error.
This commit is contained in:
parent
4d3e7efe25
commit
b15bb2c667
@ -21,7 +21,7 @@ impl PerItemCommand for Cpy {
|
|||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("cp")
|
Signature::build("cp")
|
||||||
.required("src", SyntaxType::Path)
|
.required("src", SyntaxType::Pattern)
|
||||||
.required("dst", SyntaxType::Path)
|
.required("dst", SyntaxType::Path)
|
||||||
.named("file", SyntaxType::Any)
|
.named("file", SyntaxType::Any)
|
||||||
.switch("recursive")
|
.switch("recursive")
|
||||||
|
@ -50,6 +50,7 @@ pub fn value_to_bson_value(v: &Tagged<Value>) -> Result<Bson, ShellError> {
|
|||||||
}
|
}
|
||||||
Value::Primitive(Primitive::Nothing) => Bson::Null,
|
Value::Primitive(Primitive::Nothing) => Bson::Null,
|
||||||
Value::Primitive(Primitive::String(s)) => Bson::String(s.clone()),
|
Value::Primitive(Primitive::String(s)) => Bson::String(s.clone()),
|
||||||
|
Value::Primitive(Primitive::Pattern(p)) => Bson::String(p.clone()),
|
||||||
Value::Primitive(Primitive::Path(s)) => Bson::String(s.display().to_string()),
|
Value::Primitive(Primitive::Path(s)) => Bson::String(s.display().to_string()),
|
||||||
Value::Table(l) => Bson::Array(
|
Value::Table(l) => Bson::Array(
|
||||||
l.iter()
|
l.iter()
|
||||||
|
@ -45,6 +45,7 @@ pub fn value_to_json_value(v: &Tagged<Value>) -> Result<serde_json::Value, Shell
|
|||||||
CoerceInto::<i64>::coerce_into(i.tagged(v.tag), "converting to JSON number")?,
|
CoerceInto::<i64>::coerce_into(i.tagged(v.tag), "converting to JSON number")?,
|
||||||
)),
|
)),
|
||||||
Value::Primitive(Primitive::Nothing) => serde_json::Value::Null,
|
Value::Primitive(Primitive::Nothing) => serde_json::Value::Null,
|
||||||
|
Value::Primitive(Primitive::Pattern(s)) => serde_json::Value::String(s.clone()),
|
||||||
Value::Primitive(Primitive::String(s)) => serde_json::Value::String(s.clone()),
|
Value::Primitive(Primitive::String(s)) => serde_json::Value::String(s.clone()),
|
||||||
Value::Primitive(Primitive::Path(s)) => serde_json::Value::String(s.display().to_string()),
|
Value::Primitive(Primitive::Path(s)) => serde_json::Value::String(s.display().to_string()),
|
||||||
|
|
||||||
|
@ -91,6 +91,7 @@ fn nu_value_to_sqlite_string(v: Value) -> String {
|
|||||||
Primitive::Int(i) => format!("{}", i),
|
Primitive::Int(i) => format!("{}", i),
|
||||||
Primitive::Decimal(f) => format!("{}", f),
|
Primitive::Decimal(f) => format!("{}", f),
|
||||||
Primitive::Bytes(u) => format!("{}", u),
|
Primitive::Bytes(u) => format!("{}", u),
|
||||||
|
Primitive::Pattern(s) => format!("'{}'", s.replace("'", "''")),
|
||||||
Primitive::String(s) => format!("'{}'", s.replace("'", "''")),
|
Primitive::String(s) => format!("'{}'", s.replace("'", "''")),
|
||||||
Primitive::Boolean(true) => "1".into(),
|
Primitive::Boolean(true) => "1".into(),
|
||||||
Primitive::Boolean(_) => "0".into(),
|
Primitive::Boolean(_) => "0".into(),
|
||||||
|
@ -44,6 +44,7 @@ pub fn value_to_toml_value(v: &Tagged<Value>) -> Result<toml::Value, ShellError>
|
|||||||
toml::Value::Integer(i.tagged(v.tag).coerce_into("converting to TOML integer")?)
|
toml::Value::Integer(i.tagged(v.tag).coerce_into("converting to TOML integer")?)
|
||||||
}
|
}
|
||||||
Value::Primitive(Primitive::Nothing) => toml::Value::String("<Nothing>".to_string()),
|
Value::Primitive(Primitive::Nothing) => toml::Value::String("<Nothing>".to_string()),
|
||||||
|
Value::Primitive(Primitive::Pattern(s)) => toml::Value::String(s.clone()),
|
||||||
Value::Primitive(Primitive::String(s)) => toml::Value::String(s.clone()),
|
Value::Primitive(Primitive::String(s)) => toml::Value::String(s.clone()),
|
||||||
Value::Primitive(Primitive::Path(s)) => toml::Value::String(s.display().to_string()),
|
Value::Primitive(Primitive::Path(s)) => toml::Value::String(s.display().to_string()),
|
||||||
|
|
||||||
|
@ -42,6 +42,7 @@ pub fn value_to_yaml_value(v: &Tagged<Value>) -> Result<serde_yaml::Value, Shell
|
|||||||
CoerceInto::<i64>::coerce_into(i.tagged(v.tag), "converting to YAML number")?,
|
CoerceInto::<i64>::coerce_into(i.tagged(v.tag), "converting to YAML number")?,
|
||||||
)),
|
)),
|
||||||
Value::Primitive(Primitive::Nothing) => serde_yaml::Value::Null,
|
Value::Primitive(Primitive::Nothing) => serde_yaml::Value::Null,
|
||||||
|
Value::Primitive(Primitive::Pattern(s)) => serde_yaml::Value::String(s.clone()),
|
||||||
Value::Primitive(Primitive::String(s)) => serde_yaml::Value::String(s.clone()),
|
Value::Primitive(Primitive::String(s)) => serde_yaml::Value::String(s.clone()),
|
||||||
Value::Primitive(Primitive::Path(s)) => serde_yaml::Value::String(s.display().to_string()),
|
Value::Primitive(Primitive::Path(s)) => serde_yaml::Value::String(s.display().to_string()),
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@ pub enum Primitive {
|
|||||||
Decimal(BigDecimal),
|
Decimal(BigDecimal),
|
||||||
Bytes(u64),
|
Bytes(u64),
|
||||||
String(String),
|
String(String),
|
||||||
|
Pattern(String),
|
||||||
Boolean(bool),
|
Boolean(bool),
|
||||||
Date(DateTime<Utc>),
|
Date(DateTime<Utc>),
|
||||||
Path(PathBuf),
|
Path(PathBuf),
|
||||||
@ -53,6 +54,7 @@ impl Primitive {
|
|||||||
Int(_) => "int",
|
Int(_) => "int",
|
||||||
Decimal(_) => "decimal",
|
Decimal(_) => "decimal",
|
||||||
Bytes(_) => "bytes",
|
Bytes(_) => "bytes",
|
||||||
|
Pattern(_) => "pattern",
|
||||||
String(_) => "string",
|
String(_) => "string",
|
||||||
Boolean(_) => "boolean",
|
Boolean(_) => "boolean",
|
||||||
Date(_) => "date",
|
Date(_) => "date",
|
||||||
@ -71,6 +73,7 @@ impl Primitive {
|
|||||||
Path(path) => write!(f, "{}", path.display()),
|
Path(path) => write!(f, "{}", path.display()),
|
||||||
Decimal(decimal) => write!(f, "{}", decimal),
|
Decimal(decimal) => write!(f, "{}", decimal),
|
||||||
Bytes(bytes) => write!(f, "{}", bytes),
|
Bytes(bytes) => write!(f, "{}", bytes),
|
||||||
|
Pattern(string) => write!(f, "{:?}", string),
|
||||||
String(string) => write!(f, "{:?}", string),
|
String(string) => write!(f, "{:?}", string),
|
||||||
Boolean(boolean) => write!(f, "{}", boolean),
|
Boolean(boolean) => write!(f, "{}", boolean),
|
||||||
Date(date) => write!(f, "{}", date),
|
Date(date) => write!(f, "{}", date),
|
||||||
@ -108,6 +111,7 @@ impl Primitive {
|
|||||||
}
|
}
|
||||||
Primitive::Int(i) => format!("{}", i),
|
Primitive::Int(i) => format!("{}", i),
|
||||||
Primitive::Decimal(decimal) => format!("{}", decimal),
|
Primitive::Decimal(decimal) => format!("{}", decimal),
|
||||||
|
Primitive::Pattern(s) => format!("{}", s),
|
||||||
Primitive::String(s) => format!("{}", s),
|
Primitive::String(s) => format!("{}", s),
|
||||||
Primitive::Boolean(b) => match (b, field_name) {
|
Primitive::Boolean(b) => match (b, field_name) {
|
||||||
(true, None) => format!("Yes"),
|
(true, None) => format!("Yes"),
|
||||||
@ -577,6 +581,10 @@ impl Value {
|
|||||||
Value::Primitive(Primitive::String(s.into()))
|
Value::Primitive(Primitive::String(s.into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn pattern(s: impl Into<String>) -> Value {
|
||||||
|
Value::Primitive(Primitive::String(s.into()))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn path(s: impl Into<PathBuf>) -> Value {
|
pub fn path(s: impl Into<PathBuf>) -> Value {
|
||||||
Value::Primitive(Primitive::Path(s.into()))
|
Value::Primitive(Primitive::Path(s.into()))
|
||||||
}
|
}
|
||||||
|
@ -114,6 +114,7 @@ fn evaluate_literal(literal: Tagged<&hir::Literal>, source: &Text) -> Tagged<Val
|
|||||||
hir::Literal::Number(int) => int.into(),
|
hir::Literal::Number(int) => int.into(),
|
||||||
hir::Literal::Size(int, unit) => unit.compute(int),
|
hir::Literal::Size(int, unit) => unit.compute(int),
|
||||||
hir::Literal::String(span) => Value::string(span.slice(source)),
|
hir::Literal::String(span) => Value::string(span.slice(source)),
|
||||||
|
hir::Literal::GlobPattern => Value::pattern(literal.span().slice(source)),
|
||||||
hir::Literal::Bare => Value::string(literal.span().slice(source)),
|
hir::Literal::Bare => Value::string(literal.span().slice(source)),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ use crate::evaluate::Scope;
|
|||||||
|
|
||||||
pub(crate) use self::baseline_parse::{
|
pub(crate) use self::baseline_parse::{
|
||||||
baseline_parse_single_token, baseline_parse_token_as_number, baseline_parse_token_as_path,
|
baseline_parse_single_token, baseline_parse_token_as_number, baseline_parse_token_as_path,
|
||||||
baseline_parse_token_as_string,
|
baseline_parse_token_as_pattern, baseline_parse_token_as_string,
|
||||||
};
|
};
|
||||||
pub(crate) use self::baseline_parse_tokens::{baseline_parse_next_expr, TokensIterator};
|
pub(crate) use self::baseline_parse_tokens::{baseline_parse_next_expr, TokensIterator};
|
||||||
pub(crate) use self::binary::Binary;
|
pub(crate) use self::binary::Binary;
|
||||||
@ -90,6 +90,7 @@ pub enum RawExpression {
|
|||||||
Block(Vec<Expression>),
|
Block(Vec<Expression>),
|
||||||
List(Vec<Expression>),
|
List(Vec<Expression>),
|
||||||
Path(Box<Path>),
|
Path(Box<Path>),
|
||||||
|
|
||||||
FilePath(PathBuf),
|
FilePath(PathBuf),
|
||||||
ExternalCommand(ExternalCommand),
|
ExternalCommand(ExternalCommand),
|
||||||
|
|
||||||
@ -164,6 +165,10 @@ impl Expression {
|
|||||||
Tagged::from_simple_spanned_item(RawExpression::Literal(Literal::Bare), span.into())
|
Tagged::from_simple_spanned_item(RawExpression::Literal(Literal::Bare), span.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn pattern(tag: impl Into<Tag>) -> Expression {
|
||||||
|
RawExpression::Literal(Literal::GlobPattern).tagged(tag.into())
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn variable(inner: impl Into<Span>, outer: impl Into<Span>) -> Expression {
|
pub(crate) fn variable(inner: impl Into<Span>, outer: impl Into<Span>) -> Expression {
|
||||||
Tagged::from_simple_spanned_item(
|
Tagged::from_simple_spanned_item(
|
||||||
RawExpression::Variable(Variable::Other(inner.into())),
|
RawExpression::Variable(Variable::Other(inner.into())),
|
||||||
@ -238,6 +243,7 @@ pub enum Literal {
|
|||||||
Number(Number),
|
Number(Number),
|
||||||
Size(Number, Unit),
|
Size(Number, Unit),
|
||||||
String(Span),
|
String(Span),
|
||||||
|
GlobPattern,
|
||||||
Bare,
|
Bare,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -247,6 +253,7 @@ impl ToDebug for Tagged<&Literal> {
|
|||||||
Literal::Number(number) => write!(f, "{:?}", *number),
|
Literal::Number(number) => write!(f, "{:?}", *number),
|
||||||
Literal::Size(number, unit) => write!(f, "{:?}{:?}", *number, unit),
|
Literal::Size(number, unit) => write!(f, "{:?}{:?}", *number, unit),
|
||||||
Literal::String(span) => write!(f, "{}", span.slice(source)),
|
Literal::String(span) => write!(f, "{}", span.slice(source)),
|
||||||
|
Literal::GlobPattern => write!(f, "{}", self.span().slice(source)),
|
||||||
Literal::Bare => write!(f, "{}", self.span().slice(source)),
|
Literal::Bare => write!(f, "{}", self.span().slice(source)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -259,6 +266,7 @@ impl Literal {
|
|||||||
Literal::Size(..) => "size",
|
Literal::Size(..) => "size",
|
||||||
Literal::String(..) => "string",
|
Literal::String(..) => "string",
|
||||||
Literal::Bare => "string",
|
Literal::Bare => "string",
|
||||||
|
Literal::GlobPattern => "pattern",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use crate::context::Context;
|
use crate::context::Context;
|
||||||
use crate::errors::ShellError;
|
use crate::errors::ShellError;
|
||||||
use crate::parser::{hir, RawToken, Token};
|
use crate::parser::{hir, RawToken, Token};
|
||||||
|
use crate::TaggedItem;
|
||||||
use crate::Text;
|
use crate::Text;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
@ -20,6 +21,7 @@ pub fn baseline_parse_single_token(
|
|||||||
RawToken::Variable(span) => hir::Expression::variable(span, token.span()),
|
RawToken::Variable(span) => hir::Expression::variable(span, token.span()),
|
||||||
RawToken::ExternalCommand(span) => hir::Expression::external_command(span, token.span()),
|
RawToken::ExternalCommand(span) => hir::Expression::external_command(span, token.span()),
|
||||||
RawToken::ExternalWord => return Err(ShellError::invalid_external_word(token.span())),
|
RawToken::ExternalWord => return Err(ShellError::invalid_external_word(token.span())),
|
||||||
|
RawToken::GlobPattern => hir::Expression::pattern(token.span()),
|
||||||
RawToken::Bare => hir::Expression::bare(token.span()),
|
RawToken::Bare => hir::Expression::bare(token.span()),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -40,6 +42,12 @@ pub fn baseline_parse_token_as_number(
|
|||||||
hir::Expression::size(number.to_number(source), unit, token.span())
|
hir::Expression::size(number.to_number(source), unit, token.span())
|
||||||
}
|
}
|
||||||
RawToken::Bare => hir::Expression::bare(token.span()),
|
RawToken::Bare => hir::Expression::bare(token.span()),
|
||||||
|
RawToken::GlobPattern => {
|
||||||
|
return Err(ShellError::type_error(
|
||||||
|
"Number",
|
||||||
|
"glob pattern".to_string().tagged(token.tag()),
|
||||||
|
))
|
||||||
|
}
|
||||||
RawToken::String(span) => hir::Expression::string(span, token.span()),
|
RawToken::String(span) => hir::Expression::string(span, token.span()),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -58,6 +66,12 @@ pub fn baseline_parse_token_as_string(
|
|||||||
RawToken::Number(_) => hir::Expression::bare(token.span()),
|
RawToken::Number(_) => hir::Expression::bare(token.span()),
|
||||||
RawToken::Size(_, _) => hir::Expression::bare(token.span()),
|
RawToken::Size(_, _) => hir::Expression::bare(token.span()),
|
||||||
RawToken::Bare => hir::Expression::bare(token.span()),
|
RawToken::Bare => hir::Expression::bare(token.span()),
|
||||||
|
RawToken::GlobPattern => {
|
||||||
|
return Err(ShellError::type_error(
|
||||||
|
"String",
|
||||||
|
"glob pattern".tagged(token.tag()),
|
||||||
|
))
|
||||||
|
}
|
||||||
RawToken::String(span) => hir::Expression::string(span, token.span()),
|
RawToken::String(span) => hir::Expression::string(span, token.span()),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -80,6 +94,41 @@ pub fn baseline_parse_token_as_path(
|
|||||||
expand_path(token.span().slice(source), context),
|
expand_path(token.span().slice(source), context),
|
||||||
token.span(),
|
token.span(),
|
||||||
),
|
),
|
||||||
|
RawToken::GlobPattern => {
|
||||||
|
return Err(ShellError::type_error(
|
||||||
|
"Path",
|
||||||
|
"glob pattern".tagged(token.tag()),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
RawToken::String(span) => {
|
||||||
|
hir::Expression::file_path(expand_path(span.slice(source), context), token.span())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn baseline_parse_token_as_pattern(
|
||||||
|
token: &Token,
|
||||||
|
context: &Context,
|
||||||
|
source: &Text,
|
||||||
|
) -> Result<hir::Expression, ShellError> {
|
||||||
|
Ok(match *token.item() {
|
||||||
|
RawToken::Variable(span) if span.slice(source) == "it" => {
|
||||||
|
hir::Expression::it_variable(span, token.span())
|
||||||
|
}
|
||||||
|
RawToken::ExternalCommand(_) => {
|
||||||
|
return Err(ShellError::syntax_error(
|
||||||
|
"Invalid external command".to_string().tagged(token.tag()),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
RawToken::ExternalWord => return Err(ShellError::invalid_external_word(token.span())),
|
||||||
|
RawToken::Variable(span) => hir::Expression::variable(span, token.span()),
|
||||||
|
RawToken::Number(_) => hir::Expression::bare(token.span()),
|
||||||
|
RawToken::Size(_, _) => hir::Expression::bare(token.span()),
|
||||||
|
RawToken::GlobPattern => hir::Expression::pattern(token.span()),
|
||||||
|
RawToken::Bare => hir::Expression::file_path(
|
||||||
|
expand_path(token.span().slice(source), context),
|
||||||
|
token.span(),
|
||||||
|
),
|
||||||
RawToken::String(span) => {
|
RawToken::String(span) => {
|
||||||
hir::Expression::file_path(expand_path(span.slice(source), context), token.span())
|
hir::Expression::file_path(expand_path(span.slice(source), context), token.span())
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ use crate::parser::{
|
|||||||
hir,
|
hir,
|
||||||
hir::{
|
hir::{
|
||||||
baseline_parse_single_token, baseline_parse_token_as_number, baseline_parse_token_as_path,
|
baseline_parse_single_token, baseline_parse_token_as_number, baseline_parse_token_as_path,
|
||||||
baseline_parse_token_as_string,
|
baseline_parse_token_as_pattern, baseline_parse_token_as_string,
|
||||||
},
|
},
|
||||||
DelimitedNode, Delimiter, PathNode, RawToken, TokenNode,
|
DelimitedNode, Delimiter, PathNode, RawToken, TokenNode,
|
||||||
};
|
};
|
||||||
@ -43,6 +43,7 @@ pub enum SyntaxType {
|
|||||||
Variable,
|
Variable,
|
||||||
Number,
|
Number,
|
||||||
Path,
|
Path,
|
||||||
|
Pattern,
|
||||||
Binary,
|
Binary,
|
||||||
Block,
|
Block,
|
||||||
Boolean,
|
Boolean,
|
||||||
@ -59,6 +60,7 @@ impl std::fmt::Display for SyntaxType {
|
|||||||
SyntaxType::Variable => write!(f, "Variable"),
|
SyntaxType::Variable => write!(f, "Variable"),
|
||||||
SyntaxType::Number => write!(f, "Number"),
|
SyntaxType::Number => write!(f, "Number"),
|
||||||
SyntaxType::Path => write!(f, "Path"),
|
SyntaxType::Path => write!(f, "Path"),
|
||||||
|
SyntaxType::Pattern => write!(f, "Pattern"),
|
||||||
SyntaxType::Binary => write!(f, "Binary"),
|
SyntaxType::Binary => write!(f, "Binary"),
|
||||||
SyntaxType::Block => write!(f, "Block"),
|
SyntaxType::Block => write!(f, "Block"),
|
||||||
SyntaxType::Boolean => write!(f, "Boolean"),
|
SyntaxType::Boolean => write!(f, "Boolean"),
|
||||||
@ -90,6 +92,17 @@ pub fn baseline_parse_next_expr(
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
(SyntaxType::Pattern, TokenNode::Token(token)) => {
|
||||||
|
return baseline_parse_token_as_pattern(token, context, source)
|
||||||
|
}
|
||||||
|
|
||||||
|
(SyntaxType::Pattern, token) => {
|
||||||
|
return Err(ShellError::type_error(
|
||||||
|
"Path",
|
||||||
|
token.type_name().simple_spanned(token.span()),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
(SyntaxType::String, TokenNode::Token(token)) => {
|
(SyntaxType::String, TokenNode::Token(token)) => {
|
||||||
return baseline_parse_token_as_string(token, source);
|
return baseline_parse_token_as_string(token, source);
|
||||||
}
|
}
|
||||||
@ -315,6 +328,7 @@ pub fn baseline_parse_path(
|
|||||||
| RawToken::Size(..)
|
| RawToken::Size(..)
|
||||||
| RawToken::Variable(_)
|
| RawToken::Variable(_)
|
||||||
| RawToken::ExternalCommand(_)
|
| RawToken::ExternalCommand(_)
|
||||||
|
| RawToken::GlobPattern
|
||||||
| RawToken::ExternalWord => {
|
| RawToken::ExternalWord => {
|
||||||
return Err(ShellError::type_error(
|
return Err(ShellError::type_error(
|
||||||
"String",
|
"String",
|
||||||
|
@ -231,6 +231,29 @@ pub fn external(input: NomSpan) -> IResult<NomSpan, TokenNode> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn pattern(input: NomSpan) -> IResult<NomSpan, TokenNode> {
|
||||||
|
trace_step(input, "bare", move |input| {
|
||||||
|
let start = input.offset;
|
||||||
|
let (input, _) = take_while1(is_start_glob_char)(input)?;
|
||||||
|
let (input, _) = take_while(is_glob_char)(input)?;
|
||||||
|
|
||||||
|
let next_char = &input.fragment.chars().nth(0);
|
||||||
|
|
||||||
|
if let Some(next_char) = next_char {
|
||||||
|
if is_external_word_char(*next_char) {
|
||||||
|
return Err(nom::Err::Error(nom::error::make_error(
|
||||||
|
input,
|
||||||
|
nom::error::ErrorKind::TakeWhile1,
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let end = input.offset;
|
||||||
|
|
||||||
|
Ok((input, TokenTreeBuilder::spanned_pattern((start, end))))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub fn bare(input: NomSpan) -> IResult<NomSpan, TokenNode> {
|
pub fn bare(input: NomSpan) -> IResult<NomSpan, TokenNode> {
|
||||||
trace_step(input, "bare", move |input| {
|
trace_step(input, "bare", move |input| {
|
||||||
let start = input.offset;
|
let start = input.offset;
|
||||||
@ -240,7 +263,7 @@ pub fn bare(input: NomSpan) -> IResult<NomSpan, TokenNode> {
|
|||||||
let next_char = &input.fragment.chars().nth(0);
|
let next_char = &input.fragment.chars().nth(0);
|
||||||
|
|
||||||
if let Some(next_char) = next_char {
|
if let Some(next_char) = next_char {
|
||||||
if is_external_word_char(*next_char) {
|
if is_external_word_char(*next_char) || *next_char == '*' {
|
||||||
return Err(nom::Err::Error(nom::error::make_error(
|
return Err(nom::Err::Error(nom::error::make_error(
|
||||||
input,
|
input,
|
||||||
nom::error::ErrorKind::TakeWhile1,
|
nom::error::ErrorKind::TakeWhile1,
|
||||||
@ -395,6 +418,7 @@ pub fn leaf(input: NomSpan) -> IResult<NomSpan, TokenNode> {
|
|||||||
var,
|
var,
|
||||||
external,
|
external,
|
||||||
bare,
|
bare,
|
||||||
|
pattern,
|
||||||
external_word,
|
external_word,
|
||||||
))(input)?;
|
))(input)?;
|
||||||
|
|
||||||
@ -655,6 +679,14 @@ fn is_external_word_char(c: char) -> bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_start_glob_char(c: char) -> bool {
|
||||||
|
is_start_bare_char(c) || c == '*'
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_glob_char(c: char) -> bool {
|
||||||
|
is_bare_char(c) || c == '*'
|
||||||
|
}
|
||||||
|
|
||||||
fn is_start_bare_char(c: char) -> bool {
|
fn is_start_bare_char(c: char) -> bool {
|
||||||
match c {
|
match c {
|
||||||
'+' => false,
|
'+' => false,
|
||||||
@ -680,6 +712,7 @@ fn is_bare_char(c: char) -> bool {
|
|||||||
'-' => true,
|
'-' => true,
|
||||||
'=' => true,
|
'=' => true,
|
||||||
'~' => true,
|
'~' => true,
|
||||||
|
':' => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -152,6 +152,24 @@ impl TokenTreeBuilder {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn pattern(input: impl Into<String>) -> CurriedToken {
|
||||||
|
let input = input.into();
|
||||||
|
|
||||||
|
Box::new(move |b| {
|
||||||
|
let (start, end) = b.consume(&input);
|
||||||
|
b.pos = end;
|
||||||
|
|
||||||
|
TokenTreeBuilder::spanned_pattern((start, end))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn spanned_pattern(input: impl Into<Span>) -> TokenNode {
|
||||||
|
TokenNode::Token(Tagged::from_simple_spanned_item(
|
||||||
|
RawToken::Bare,
|
||||||
|
input.into(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn external_word(input: impl Into<String>) -> CurriedToken {
|
pub fn external_word(input: impl Into<String>) -> CurriedToken {
|
||||||
let input = input.into();
|
let input = input.into();
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ pub enum RawToken {
|
|||||||
Variable(Span),
|
Variable(Span),
|
||||||
ExternalCommand(Span),
|
ExternalCommand(Span),
|
||||||
ExternalWord,
|
ExternalWord,
|
||||||
|
GlobPattern,
|
||||||
Bare,
|
Bare,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,6 +54,7 @@ impl RawToken {
|
|||||||
RawToken::Variable(_) => "Variable",
|
RawToken::Variable(_) => "Variable",
|
||||||
RawToken::ExternalCommand(_) => "ExternalCommand",
|
RawToken::ExternalCommand(_) => "ExternalCommand",
|
||||||
RawToken::ExternalWord => "ExternalWord",
|
RawToken::ExternalWord => "ExternalWord",
|
||||||
|
RawToken::GlobPattern => "GlobPattern",
|
||||||
RawToken::Bare => "String",
|
RawToken::Bare => "String",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -123,6 +123,10 @@ fn paint_token_node(token_node: &TokenNode, line: &str) -> String {
|
|||||||
item: RawToken::Size(..),
|
item: RawToken::Size(..),
|
||||||
..
|
..
|
||||||
}) => Color::Purple.bold().paint(token_node.span().slice(line)),
|
}) => Color::Purple.bold().paint(token_node.span().slice(line)),
|
||||||
|
TokenNode::Token(Tagged {
|
||||||
|
item: RawToken::GlobPattern,
|
||||||
|
..
|
||||||
|
}) => Color::Cyan.normal().paint(token_node.span().slice(line)),
|
||||||
TokenNode::Token(Tagged {
|
TokenNode::Token(Tagged {
|
||||||
item: RawToken::String(..),
|
item: RawToken::String(..),
|
||||||
..
|
..
|
||||||
|
Loading…
Reference in New Issue
Block a user