Attribute shorthand

This commit is contained in:
Greg Shuflin 2024-06-06 11:45:00 -05:00
parent 38873dcb74
commit 393dbabc9b
5 changed files with 41 additions and 17 deletions

View File

@ -42,7 +42,7 @@ impl AttributeDiscriminant {
impl<'src> Attribute<'src> { impl<'src> Attribute<'src> {
pub(crate) fn new( pub(crate) fn new(
name: Name<'src>, name: Name<'src>,
argument: Option<StringLiteral<'src>>, mut arguments: Vec<StringLiteral<'src>>,
) -> CompileResult<'src, Self> { ) -> CompileResult<'src, Self> {
use AttributeDiscriminant::*; use AttributeDiscriminant::*;
@ -56,8 +56,7 @@ impl<'src> Attribute<'src> {
}) })
})?; })?;
let found = argument.as_ref().iter().count(); let found = arguments.len();
let range = discriminant.argument_range(); let range = discriminant.argument_range();
if !range.contains(&found) { if !range.contains(&found) {
@ -72,9 +71,9 @@ impl<'src> Attribute<'src> {
} }
Ok(match discriminant { Ok(match discriminant {
Confirm => Self::Confirm(argument), Confirm => Self::Confirm(arguments.pop()),
Doc => Self::Doc(argument), Doc => Self::Doc(arguments.pop()),
Group => Self::Group(argument.unwrap()), Group => Self::Group(arguments.pop().unwrap()),
Linux => Self::Linux, Linux => Self::Linux,
Macos => Self::Macos, Macos => Self::Macos,
NoCd => Self::NoCd, NoCd => Self::NoCd,

View File

@ -987,15 +987,29 @@ impl<'run, 'src> Parser<'run, 'src> {
loop { loop {
let name = self.parse_name()?; let name = self.parse_name()?;
let argument = if self.accepted(ParenL)? { let arguments: Vec<StringLiteral> = if self.next_is(Colon) {
let argument = self.parse_string_literal()?; self.presume(Colon)?;
self.expect(ParenR)?; let single_arg = self.parse_string_literal()?;
Some(argument) vec![single_arg]
} else if self.next_is(ParenL) {
self.presume(ParenL)?;
let mut args = Vec::new();
loop {
args.push(self.parse_string_literal()?);
if self.next_is(ParenR) {
self.presume(ParenR)?;
break;
}
if self.next_is(Comma) {
self.presume(Comma)?;
}
}
args
} else { } else {
None Vec::new()
}; };
let attribute = Attribute::new(name, argument)?; let attribute = Attribute::new(name, arguments)?;
if let Some(line) = attributes.get(&attribute) { if let Some(line) = attributes.get(&attribute) {
return Err(name.error(CompileErrorKind::DuplicateAttribute { return Err(name.error(CompileErrorKind::DuplicateAttribute {
@ -1158,6 +1172,18 @@ mod tests {
tree: (justfile (alias t test)), tree: (justfile (alias t test)),
} }
test! {
name: single_argument_attribute_shorthand,
text: "[group: 'some-group']\nalias t := test",
tree: (justfile (alias t test)),
}
test! {
name: single_argument_attribute_shorthand_multiple_same_line,
text: "[group: 'some-group', group: 'some-other-group']\nalias t := test",
tree: (justfile (alias t test)),
}
test! { test! {
name: aliases_multiple, name: aliases_multiple,
text: "alias t := test\nalias b := build", text: "alias t := test\nalias b := build",

View File

@ -72,7 +72,7 @@ fn multiple_attributes_one_line_error_message() {
) )
.stderr( .stderr(
" "
error: Expected ']', ',', or '(', but found identifier error: Expected ']', ':', ',', or '(', but found identifier
justfile:1:17 justfile:1:17
1 [macos, windows linux] 1 [macos, windows linux]

View File

@ -130,7 +130,7 @@ fn confirm_recipe_with_prompt_too_many_args() {
echo confirmed echo confirmed
", ",
) )
.stderr("error: Expected ')', but found ','\n ——▶ justfile:1:64\n\n1 │ [confirm(\"This is dangerous - are you sure you want to run it?\",\"this second argument is not supported\")]\n ^\n") .stderr("error: Attribute `confirm` got 2 arguments but takes at most 1 argument\n ——▶ justfile:1:2\n\n1 │ [confirm(\"This is dangerous - are you sure you want to run it?\",\"this second argument is not supported\")]\n^^^^^^^\n")
.stdout("") .stdout("")
.status(1) .status(1)
.run(); .run();

View File

@ -126,11 +126,10 @@ fn list_groups_with_custom_prefix() {
Test::new() Test::new()
.justfile( .justfile(
" "
[group('B')] [group: 'B']
foo: foo:
[group('A')] [group: 'A', group: 'B']
[group('B')]
bar: bar:
", ",
) )