Allow different names for ...rest (#3954)

* Allow different names for ...rest

* Resolves #3945

* This change requires an explicit name for the rest argument in `WholeStreamCommand`,
  which is why there are so many changed files.

* Remove redundant clone

* Add tests
This commit is contained in:
Hristo Filaretov
2021-08-26 19:58:53 +02:00
committed by GitHub
parent 88817a8f10
commit b8e2bdd6b1
97 changed files with 270 additions and 87 deletions

View File

@ -88,7 +88,7 @@ mod tests {
Signature::build("bundle add")
.switch("skip-install", "Adds the gem to the Gemfile but does not install it.", None)
.named("group", SyntaxShape::String, "Specify the group(s) for the added gem. Multiple groups should be separated by commas.", Some('g'))
.rest(SyntaxShape::Any, "options")
.rest("rest", SyntaxShape::Any, "options")
}
#[test]

View File

@ -1601,7 +1601,7 @@ fn parse_internal_command(
positional.push(arg);
current_positional += 1;
} else if let Some((rest_type, _)) = &signature.rest_positional {
} else if let Some((_, rest_type, _)) = &signature.rest_positional {
let (arg, err) = parse_arg(*rest_type, scope, &lite_cmd.parts[idx]);
if error.is_none() {
error = err;

View File

@ -185,20 +185,20 @@ pub fn parse_type_token(type_: &Token) -> (SyntaxShape, Option<ParseError>) {
}
}
pub(crate) fn parse_rest_name(name_token: &Token) -> Option<ParseError> {
pub(crate) fn parse_rest_name(name_token: &Token) -> (Spanned<String>, Option<ParseError>) {
return if let TokenContents::Baseline(name) = &name_token.contents {
if !name.starts_with("...") {
Some(parse_rest_name_err(name_token))
} else if !name.starts_with("...rest") {
Some(ParseError::mismatch(
"rest argument name to be 'rest'",
token_to_spanned_string(name_token),
))
} else {
None
match name.strip_prefix("...") {
Some(var_name) => (var_name.to_string().spanned(name_token.span), None),
None => (
"InternalError".to_string().spanned(name_token.span),
Some(parse_rest_name_err(name_token)),
),
}
} else {
Some(parse_rest_name_err(name_token))
(
"InternalError".to_string().spanned(name_token.span),
Some(parse_rest_name_err(name_token)),
)
};
fn parse_rest_name_err(token: &Token) -> ParseError {

View File

@ -231,7 +231,7 @@ fn parse_rest(
tokens: &[Token],
tokens_as_str: &Spanned<String>,
) -> (
Option<(SyntaxShape, Description)>,
Option<(String, SyntaxShape, Description)>,
usize,
Option<ParseError>,
) {
@ -251,7 +251,7 @@ fn parse_rest(
let mut type_ = SyntaxShape::Any;
let mut comment = "".to_string();
let error = parse_rest_name(&tokens[i]);
let (name, error) = parse_rest_name(&tokens[i]);
err = err.or(error);
i += 1;
@ -268,7 +268,7 @@ fn parse_rest(
comment = parsed_comment.unwrap_or_else(|| "".to_string());
}
(Some((type_, comment)), i, err)
(Some((name.item, type_, comment)), i, err)
}
fn parse_optional_type(tokens: &[Token]) -> (Option<SyntaxShape>, usize, Option<ParseError>) {
@ -352,7 +352,7 @@ fn to_signature(
name: &str,
params: Vec<Parameter>,
flags: Vec<Flag>,
rest: Option<(SyntaxShape, Description)>,
rest: Option<(String, SyntaxShape, Description)>,
) -> Signature {
let mut sign = Signature::new(name);

View File

@ -332,7 +332,23 @@ fn simple_def_with_rest_arg() {
assert!(err.is_none());
assert_eq!(
sign.rest_positional,
Some((SyntaxShape::Any, "".to_string()))
Some(("rest".to_string(), SyntaxShape::Any, "".to_string()))
);
}
#[test]
fn simple_def_with_rest_arg_other_name() {
let name = "my_func";
let sign = "[ ...paths:path # A pathological test]";
let (sign, err) = parse_signature(name, &sign.to_string().spanned_unknown());
assert!(err.is_none());
assert_eq!(
sign.rest_positional,
Some((
"paths".to_string(),
SyntaxShape::FilePath,
"A pathological test".to_string()
))
);
}
@ -344,7 +360,11 @@ fn simple_def_with_rest_arg_with_type_and_comment() {
assert!(err.is_none());
assert_eq!(
sign.rest_positional,
Some((SyntaxShape::FilePath, "My super cool rest arg".to_string()))
Some((
"rest".to_string(),
SyntaxShape::FilePath,
"My super cool rest arg".to_string()
))
);
}
@ -380,6 +400,10 @@ fn simple_def_with_param_flag_and_rest() {
);
assert_eq!(
sign.rest_positional,
Some((SyntaxShape::Table, "Another rest".to_string()))
Some((
"rest".to_string(),
SyntaxShape::Table,
"Another rest".to_string()
))
);
}