Add --fmt
subcommand (#837)
This commit is contained in:
parent
39e76488b5
commit
8677492d56
@ -20,7 +20,7 @@ _just() {
|
||||
|
||||
case "${cmd}" in
|
||||
just)
|
||||
opts=" -q -u -v -e -l -h -V -f -d -c -s --dry-run --highlight --no-dotenv --no-highlight --quiet --shell-command --clear-shell-args --unsorted --verbose --choose --dump --edit --evaluate --init --list --summary --variables --help --version --chooser --color --list-heading --list-prefix --justfile --set --shell --shell-arg --working-directory --command --completions --show <ARGUMENTS>... "
|
||||
opts=" -q -u -v -e -l -h -V -f -d -c -s --dry-run --highlight --no-dotenv --no-highlight --quiet --shell-command --clear-shell-args --unsorted --verbose --choose --dump --edit --evaluate --fmt --init --list --summary --variables --help --version --chooser --color --list-heading --list-prefix --justfile --set --shell --shell-arg --working-directory --command --completions --show <ARGUMENTS>... "
|
||||
if [[ ${cur} == -* ]] ; then
|
||||
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
|
||||
return 0
|
||||
|
@ -47,6 +47,7 @@ edit:completion:arg-completer[just] = [@words]{
|
||||
cand -e 'Edit justfile with editor given by $VISUAL or $EDITOR, falling back to `vim`'
|
||||
cand --edit 'Edit justfile with editor given by $VISUAL or $EDITOR, falling back to `vim`'
|
||||
cand --evaluate 'Evaluate and print all variables. If a variable name is given as an argument, only print that variable''s value.'
|
||||
cand --fmt 'Format and overwrite justfile'
|
||||
cand --init 'Initialize new justfile in project root'
|
||||
cand -l 'List available recipes and their arguments'
|
||||
cand --list 'List available recipes and their arguments'
|
||||
|
@ -34,6 +34,7 @@ complete -c just -n "__fish_use_subcommand" -l choose -d 'Select one or more rec
|
||||
complete -c just -n "__fish_use_subcommand" -l dump -d 'Print entire justfile'
|
||||
complete -c just -n "__fish_use_subcommand" -s e -l edit -d 'Edit justfile with editor given by $VISUAL or $EDITOR, falling back to `vim`'
|
||||
complete -c just -n "__fish_use_subcommand" -l evaluate -d 'Evaluate and print all variables. If a variable name is given as an argument, only print that variable\'s value.'
|
||||
complete -c just -n "__fish_use_subcommand" -l fmt -d 'Format and overwrite justfile'
|
||||
complete -c just -n "__fish_use_subcommand" -l init -d 'Initialize new justfile in project root'
|
||||
complete -c just -n "__fish_use_subcommand" -s l -l list -d 'List available recipes and their arguments'
|
||||
complete -c just -n "__fish_use_subcommand" -l summary -d 'List names of available recipes'
|
||||
|
@ -52,6 +52,7 @@ Register-ArgumentCompleter -Native -CommandName 'just' -ScriptBlock {
|
||||
[CompletionResult]::new('-e', 'e', [CompletionResultType]::ParameterName, 'Edit justfile with editor given by $VISUAL or $EDITOR, falling back to `vim`')
|
||||
[CompletionResult]::new('--edit', 'edit', [CompletionResultType]::ParameterName, 'Edit justfile with editor given by $VISUAL or $EDITOR, falling back to `vim`')
|
||||
[CompletionResult]::new('--evaluate', 'evaluate', [CompletionResultType]::ParameterName, 'Evaluate and print all variables. If a variable name is given as an argument, only print that variable''s value.')
|
||||
[CompletionResult]::new('--fmt', 'fmt', [CompletionResultType]::ParameterName, 'Format and overwrite justfile')
|
||||
[CompletionResult]::new('--init', 'init', [CompletionResultType]::ParameterName, 'Initialize new justfile in project root')
|
||||
[CompletionResult]::new('-l', 'l', [CompletionResultType]::ParameterName, 'List available recipes and their arguments')
|
||||
[CompletionResult]::new('--list', 'list', [CompletionResultType]::ParameterName, 'List available recipes and their arguments')
|
||||
|
@ -48,6 +48,7 @@ _just() {
|
||||
'-e[Edit justfile with editor given by $VISUAL or $EDITOR, falling back to `vim`]' \
|
||||
'--edit[Edit justfile with editor given by $VISUAL or $EDITOR, falling back to `vim`]' \
|
||||
'--evaluate[Evaluate and print all variables. If a variable name is given as an argument, only print that variable'\''s value.]' \
|
||||
'--fmt[Format and overwrite justfile]' \
|
||||
'--init[Initialize new justfile in project root]' \
|
||||
'-l[List available recipes and their arguments]' \
|
||||
'--list[List available recipes and their arguments]' \
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::common::*;
|
||||
|
||||
/// An alias, e.g. `name := target`
|
||||
#[derive(Debug, PartialEq)]
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub(crate) struct Alias<'src, T = Rc<Recipe<'src>>> {
|
||||
pub(crate) name: Name<'src>,
|
||||
pub(crate) target: T,
|
||||
|
@ -29,6 +29,7 @@ impl<'src> Analyzer<'src> {
|
||||
self.analyze_assignment(&assignment)?;
|
||||
self.assignments.insert(assignment);
|
||||
},
|
||||
Item::Comment(_) => (),
|
||||
Item::Recipe(recipe) => {
|
||||
self.analyze_recipe(&recipe)?;
|
||||
self.recipes.insert(recipe);
|
||||
|
@ -2,3 +2,12 @@ use crate::common::*;
|
||||
|
||||
/// An assignment, e.g `foo := bar`
|
||||
pub(crate) type Assignment<'src> = Binding<'src, Expression<'src>>;
|
||||
|
||||
impl<'src> Display for Assignment<'src> {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
|
||||
if self.export {
|
||||
write!(f, "export ")?;
|
||||
}
|
||||
write!(f, "{} := {}", self.name, self.value)
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::common::*;
|
||||
|
||||
/// A binding of `name` to `value`
|
||||
#[derive(Debug, PartialEq)]
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub(crate) struct Binding<'src, V = String> {
|
||||
/// Export binding as an environment variable to child processes
|
||||
pub(crate) export: bool,
|
||||
|
@ -5,9 +5,10 @@ pub(crate) use std::{
|
||||
env,
|
||||
ffi::{OsStr, OsString},
|
||||
fmt::{self, Debug, Display, Formatter},
|
||||
fs,
|
||||
fs::{self, File},
|
||||
io::{self, Cursor, Write},
|
||||
iter::{self, FromIterator},
|
||||
mem,
|
||||
ops::{Index, Range, RangeInclusive},
|
||||
path::{Path, PathBuf},
|
||||
process::{self, Command, Stdio},
|
||||
@ -45,21 +46,21 @@ pub(crate) use crate::{
|
||||
alias::Alias, analyzer::Analyzer, assignment::Assignment,
|
||||
assignment_resolver::AssignmentResolver, binding::Binding, color::Color,
|
||||
compilation_error::CompilationError, compilation_error_kind::CompilationErrorKind,
|
||||
compiler::Compiler, config::Config, config_error::ConfigError, count::Count,
|
||||
delimiter::Delimiter, dependency::Dependency, enclosure::Enclosure, evaluator::Evaluator,
|
||||
expression::Expression, fragment::Fragment, function::Function,
|
||||
function_context::FunctionContext, interrupt_guard::InterruptGuard,
|
||||
interrupt_handler::InterruptHandler, item::Item, justfile::Justfile, keyword::Keyword,
|
||||
lexer::Lexer, line::Line, list::List, load_error::LoadError, module::Module, name::Name,
|
||||
output_error::OutputError, parameter::Parameter, parameter_kind::ParameterKind, parser::Parser,
|
||||
platform::Platform, position::Position, positional::Positional, recipe::Recipe,
|
||||
recipe_context::RecipeContext, recipe_resolver::RecipeResolver, runtime_error::RuntimeError,
|
||||
scope::Scope, search::Search, search_config::SearchConfig, search_error::SearchError, set::Set,
|
||||
setting::Setting, settings::Settings, shebang::Shebang, show_whitespace::ShowWhitespace,
|
||||
string_kind::StringKind, string_literal::StringLiteral, subcommand::Subcommand,
|
||||
suggestion::Suggestion, table::Table, thunk::Thunk, token::Token, token_kind::TokenKind,
|
||||
unresolved_dependency::UnresolvedDependency, unresolved_recipe::UnresolvedRecipe,
|
||||
use_color::UseColor, variables::Variables, verbosity::Verbosity, warning::Warning,
|
||||
config::Config, config_error::ConfigError, count::Count, delimiter::Delimiter,
|
||||
dependency::Dependency, enclosure::Enclosure, evaluator::Evaluator, expression::Expression,
|
||||
fragment::Fragment, function::Function, function_context::FunctionContext,
|
||||
interrupt_guard::InterruptGuard, interrupt_handler::InterruptHandler, item::Item,
|
||||
justfile::Justfile, keyword::Keyword, lexer::Lexer, line::Line, list::List,
|
||||
load_error::LoadError, module::Module, name::Name, output_error::OutputError,
|
||||
parameter::Parameter, parameter_kind::ParameterKind, parser::Parser, platform::Platform,
|
||||
position::Position, positional::Positional, recipe::Recipe, recipe_context::RecipeContext,
|
||||
recipe_resolver::RecipeResolver, runtime_error::RuntimeError, scope::Scope, search::Search,
|
||||
search_config::SearchConfig, search_error::SearchError, set::Set, setting::Setting,
|
||||
settings::Settings, shebang::Shebang, show_whitespace::ShowWhitespace, string_kind::StringKind,
|
||||
string_literal::StringLiteral, subcommand::Subcommand, suggestion::Suggestion, table::Table,
|
||||
thunk::Thunk, token::Token, token_kind::TokenKind, unresolved_dependency::UnresolvedDependency,
|
||||
unresolved_recipe::UnresolvedRecipe, use_color::UseColor, variables::Variables,
|
||||
verbosity::Verbosity, warning::Warning,
|
||||
};
|
||||
|
||||
// type aliases
|
||||
|
@ -38,6 +38,7 @@ mod cmd {
|
||||
pub(crate) const DUMP: &str = "DUMP";
|
||||
pub(crate) const EDIT: &str = "EDIT";
|
||||
pub(crate) const EVALUATE: &str = "EVALUATE";
|
||||
pub(crate) const FORMAT: &str = "FORMAT";
|
||||
pub(crate) const INIT: &str = "INIT";
|
||||
pub(crate) const LIST: &str = "LIST";
|
||||
pub(crate) const SHOW: &str = "SHOW";
|
||||
@ -52,6 +53,7 @@ mod cmd {
|
||||
DUMP,
|
||||
EDIT,
|
||||
EVALUATE,
|
||||
FORMAT,
|
||||
INIT,
|
||||
LIST,
|
||||
SHOW,
|
||||
@ -63,6 +65,7 @@ mod cmd {
|
||||
COMPLETIONS,
|
||||
DUMP,
|
||||
EDIT,
|
||||
FORMAT,
|
||||
INIT,
|
||||
LIST,
|
||||
SHOW,
|
||||
@ -266,6 +269,11 @@ impl Config {
|
||||
"Evaluate and print all variables. If a variable name is given as an argument, only print \
|
||||
that variable's value.",
|
||||
))
|
||||
.arg(
|
||||
Arg::with_name(cmd::FORMAT)
|
||||
.long("fmt")
|
||||
.help("Format and overwrite justfile"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name(cmd::INIT)
|
||||
.long("init")
|
||||
@ -442,6 +450,8 @@ impl Config {
|
||||
Subcommand::Summary
|
||||
} else if matches.is_present(cmd::DUMP) {
|
||||
Subcommand::Dump
|
||||
} else if matches.is_present(cmd::FORMAT) {
|
||||
Subcommand::Format
|
||||
} else if matches.is_present(cmd::INIT) {
|
||||
Subcommand::Init
|
||||
} else if matches.is_present(cmd::LIST) {
|
||||
@ -539,7 +549,9 @@ impl Config {
|
||||
})
|
||||
.eprint(self.color)?;
|
||||
|
||||
let justfile = Compiler::compile(&src).eprint(self.color)?;
|
||||
let tokens = Lexer::lex(&src).eprint(self.color)?;
|
||||
let ast = Parser::parse(&tokens).eprint(self.color)?;
|
||||
let justfile = Analyzer::analyze(ast.clone()).eprint(self.color)?;
|
||||
|
||||
if self.verbosity.loud() {
|
||||
for warning in &justfile.warnings {
|
||||
@ -555,8 +567,9 @@ impl Config {
|
||||
Choose { overrides, chooser } =>
|
||||
self.choose(justfile, &search, overrides, chooser.as_deref())?,
|
||||
Command { overrides, .. } => self.run(justfile, &search, overrides, &[])?,
|
||||
Dump => Self::dump(justfile),
|
||||
Dump => Self::dump(ast)?,
|
||||
Evaluate { overrides, .. } => self.run(justfile, &search, overrides, &[])?,
|
||||
Format => self.format(ast, &search)?,
|
||||
List => self.list(justfile),
|
||||
Run {
|
||||
arguments,
|
||||
@ -676,8 +689,9 @@ impl Config {
|
||||
self.run(justfile, search, overrides, &recipes)
|
||||
}
|
||||
|
||||
fn dump(justfile: Justfile) {
|
||||
println!("{}", justfile);
|
||||
fn dump(ast: Module) -> Result<(), i32> {
|
||||
print!("{}", ast);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn edit(&self, search: &Search) -> Result<(), i32> {
|
||||
@ -713,6 +727,24 @@ impl Config {
|
||||
}
|
||||
}
|
||||
|
||||
fn format(&self, ast: Module, search: &Search) -> Result<(), i32> {
|
||||
if let Err(error) = File::open(&search.justfile).and_then(|mut file| write!(file, "{}", ast)) {
|
||||
if self.verbosity.loud() {
|
||||
eprintln!(
|
||||
"Failed to write justfile to `{}`: {}",
|
||||
search.justfile.display(),
|
||||
error
|
||||
);
|
||||
}
|
||||
Err(EXIT_FAILURE)
|
||||
} else {
|
||||
if self.verbosity.loud() {
|
||||
eprintln!("Wrote justfile to `{}`", search.justfile.display());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn init(&self) -> Result<(), i32> {
|
||||
let search =
|
||||
Search::init(&self.search_config, &self.invocation_directory).eprint(self.color)?;
|
||||
@ -920,6 +952,7 @@ FLAGS:
|
||||
--evaluate Evaluate and print all variables. If a variable name is given as an \
|
||||
argument, only print
|
||||
that variable's value.
|
||||
--fmt Format and overwrite justfile
|
||||
--highlight Highlight echoed recipe lines in bold
|
||||
--init Initialize new justfile in project root
|
||||
-l, --list List available recipes and their arguments
|
||||
@ -1315,6 +1348,11 @@ ARGS:
|
||||
args: ["--list", "--dump"],
|
||||
}
|
||||
|
||||
error! {
|
||||
name: subcommand_conflict_fmt,
|
||||
args: ["--list", "--fmt"],
|
||||
}
|
||||
|
||||
error! {
|
||||
name: subcommand_conflict_init,
|
||||
args: ["--list", "--init"],
|
||||
@ -1661,6 +1699,16 @@ ARGS:
|
||||
},
|
||||
}
|
||||
|
||||
error! {
|
||||
name: fmt_arguments,
|
||||
args: ["--fmt", "bar"],
|
||||
error: ConfigError::SubcommandArguments { subcommand, arguments },
|
||||
check: {
|
||||
assert_eq!(subcommand, cmd::FORMAT);
|
||||
assert_eq!(arguments, &["bar"]);
|
||||
},
|
||||
}
|
||||
|
||||
error! {
|
||||
name: init_arguments,
|
||||
args: ["--init", "bar"],
|
||||
|
@ -6,7 +6,7 @@ use crate::common::*;
|
||||
/// parenthetical groups).
|
||||
///
|
||||
/// The parser parses both values and expressions into `Expression`s.
|
||||
#[derive(PartialEq, Debug)]
|
||||
#[derive(PartialEq, Debug, Clone)]
|
||||
pub(crate) enum Expression<'src> {
|
||||
/// `contents`
|
||||
Backtick {
|
||||
@ -45,7 +45,7 @@ impl<'src> Expression<'src> {
|
||||
impl<'src> Display for Expression<'src> {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
|
||||
match self {
|
||||
Expression::Backtick { contents, .. } => write!(f, "`{}`", contents),
|
||||
Expression::Backtick { token, .. } => write!(f, "{}", token.lexeme()),
|
||||
Expression::Concatination { lhs, rhs } => write!(f, "{} + {}", lhs, rhs),
|
||||
Expression::Conditional {
|
||||
lhs,
|
||||
@ -55,7 +55,7 @@ impl<'src> Display for Expression<'src> {
|
||||
inverted,
|
||||
} => write!(
|
||||
f,
|
||||
"if {} {} {} {{ {} }} else {{ {} }} ",
|
||||
"if {} {} {} {{ {} }} else {{ {} }}",
|
||||
lhs,
|
||||
if *inverted { "!=" } else { "==" },
|
||||
rhs,
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::common::*;
|
||||
|
||||
/// A line fragment consisting either of…
|
||||
#[derive(PartialEq, Debug)]
|
||||
#[derive(PartialEq, Debug, Clone)]
|
||||
pub(crate) enum Fragment<'src> {
|
||||
/// …raw text…
|
||||
Text { token: Token<'src> },
|
||||
|
15
src/item.rs
15
src/item.rs
@ -1,10 +1,23 @@
|
||||
use crate::common::*;
|
||||
|
||||
/// A single top-level item
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) enum Item<'src> {
|
||||
Alias(Alias<'src, Name<'src>>),
|
||||
Assignment(Assignment<'src>),
|
||||
Comment(&'src str),
|
||||
Recipe(UnresolvedRecipe<'src>),
|
||||
Set(Set<'src>),
|
||||
}
|
||||
|
||||
impl<'src> Display for Item<'src> {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Item::Alias(alias) => write!(f, "{}", alias),
|
||||
Item::Assignment(assignment) => write!(f, "{}", assignment),
|
||||
Item::Comment(comment) => write!(f, "{}", comment),
|
||||
Item::Recipe(recipe) => write!(f, "{}", recipe),
|
||||
Item::Set(set) => write!(f, "{}", set),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -802,7 +802,7 @@ goodbye := \"y\"
|
||||
hello a b c: x y z
|
||||
#! blah
|
||||
#blarg
|
||||
{{foo + bar}}abc{{goodbye + \"x\"}}xyz
|
||||
{{ foo + bar }}abc{{ goodbye + \"x\" }}xyz
|
||||
1
|
||||
2
|
||||
3
|
||||
@ -828,7 +828,7 @@ install:
|
||||
|
||||
install:
|
||||
#!/bin/sh
|
||||
if [[ -f {{practicum}} ]]; then
|
||||
if [[ -f {{ practicum }} ]]; then
|
||||
\treturn
|
||||
fi",
|
||||
}
|
||||
@ -869,7 +869,7 @@ c := a + b + a + b",
|
||||
r#"a:
|
||||
echo {{ `echo hello` + "blarg" }} {{ `echo bob` }}"#,
|
||||
r#"a:
|
||||
echo {{`echo hello` + "blarg"}} {{`echo bob`}}"#,
|
||||
echo {{ `echo hello` + "blarg" }} {{ `echo bob` }}"#,
|
||||
}
|
||||
|
||||
test! {
|
||||
@ -895,7 +895,7 @@ c := a + b + a + b",
|
||||
"a b c:
|
||||
{{b}} {{c}}",
|
||||
"a b c:
|
||||
{{b}} {{c}}",
|
||||
{{ b }} {{ c }}",
|
||||
}
|
||||
|
||||
test! {
|
||||
@ -908,7 +908,7 @@ a:
|
||||
"x := arch()
|
||||
|
||||
a:
|
||||
{{os()}} {{os_family()}}",
|
||||
{{ os() }} {{ os_family() }}",
|
||||
}
|
||||
|
||||
test! {
|
||||
@ -921,7 +921,7 @@ a:
|
||||
r#"x := env_var('foo')
|
||||
|
||||
a:
|
||||
{{env_var_or_default('foo' + 'bar', 'baz')}} {{env_var(env_var("baz"))}}"#,
|
||||
{{ env_var_or_default('foo' + 'bar', 'baz') }} {{ env_var(env_var("baz")) }}"#,
|
||||
}
|
||||
|
||||
test! {
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::common::*;
|
||||
|
||||
/// A single line in a recipe body, consisting of any number of `Fragment`s.
|
||||
#[derive(Debug, PartialEq)]
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub(crate) struct Line<'src> {
|
||||
pub(crate) fragments: Vec<Fragment<'src>>,
|
||||
}
|
||||
|
@ -7,10 +7,30 @@ use crate::common::*;
|
||||
/// Not all successful parses result in valid justfiles, so additional
|
||||
/// consistency checks and name resolution are performed by the `Analyzer`,
|
||||
/// which produces a `Justfile` from a `Module`.
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct Module<'src> {
|
||||
/// Items in the justfile
|
||||
pub(crate) items: Vec<Item<'src>>,
|
||||
/// Non-fatal warnings encountered during parsing
|
||||
pub(crate) warnings: Vec<Warning>,
|
||||
}
|
||||
|
||||
impl<'src> Display for Module<'src> {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
|
||||
let mut iter = self.items.iter().peekable();
|
||||
|
||||
while let Some(item) = iter.next() {
|
||||
writeln!(f, "{}", item)?;
|
||||
|
||||
if let Some(next_item) = iter.peek() {
|
||||
if matches!(item, Item::Recipe(_))
|
||||
|| mem::discriminant(item) != mem::discriminant(next_item)
|
||||
{
|
||||
writeln!(f)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ impl<'src> Node<'src> for Item<'src> {
|
||||
match self {
|
||||
Item::Alias(alias) => alias.tree(),
|
||||
Item::Assignment(assignment) => assignment.tree(),
|
||||
Item::Comment(comment) => comment.tree(),
|
||||
Item::Recipe(recipe) => recipe.tree(),
|
||||
Item::Set(set) => set.tree(),
|
||||
}
|
||||
@ -210,3 +211,9 @@ impl<'src> Node<'src> for Warning {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'src> Node<'src> for str {
|
||||
fn tree(&self) -> Tree<'src> {
|
||||
Tree::atom("comment").push(["\"", self, "\""].concat())
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::common::*;
|
||||
|
||||
/// A single function parameter
|
||||
#[derive(PartialEq, Debug)]
|
||||
#[derive(PartialEq, Debug, Clone)]
|
||||
pub(crate) struct Parameter<'src> {
|
||||
/// The parameter name
|
||||
pub(crate) name: Name<'src>,
|
||||
@ -16,6 +16,9 @@ pub(crate) struct Parameter<'src> {
|
||||
impl<'src> Display for Parameter<'src> {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
|
||||
let color = Color::fmt(f);
|
||||
if self.export {
|
||||
write!(f, "$")?;
|
||||
}
|
||||
if let Some(prefix) = self.kind.prefix() {
|
||||
write!(f, "{}", color.annotation().paint(prefix))?;
|
||||
}
|
||||
|
@ -296,17 +296,34 @@ impl<'tokens, 'src> Parser<'tokens, 'src> {
|
||||
|
||||
/// Parse a justfile, consumes self
|
||||
fn parse_justfile(mut self) -> CompilationResult<'src, Module<'src>> {
|
||||
fn pop_doc_comment<'src>(
|
||||
items: &mut Vec<Item<'src>>,
|
||||
eol_since_last_comment: bool,
|
||||
) -> Option<&'src str> {
|
||||
if !eol_since_last_comment {
|
||||
if let Some(Item::Comment(contents)) = items.last() {
|
||||
let doc = Some(contents[1..].trim_start());
|
||||
items.pop();
|
||||
return doc;
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
let mut items = Vec::new();
|
||||
|
||||
let mut doc = None;
|
||||
let mut eol_since_last_comment = false;
|
||||
|
||||
loop {
|
||||
let next = self.next()?;
|
||||
|
||||
if let Some(comment) = self.accept(Comment)? {
|
||||
doc = Some(comment.lexeme()[1..].trim());
|
||||
items.push(Item::Comment(comment.lexeme().trim_end()));
|
||||
self.expect_eol()?;
|
||||
eol_since_last_comment = false;
|
||||
} else if self.accepted(Eol)? {
|
||||
eol_since_last_comment = true;
|
||||
} else if self.accepted(Eof)? {
|
||||
break;
|
||||
} else if self.next_is(Identifier) {
|
||||
@ -317,6 +334,7 @@ impl<'tokens, 'src> Parser<'tokens, 'src> {
|
||||
} else if self.next_are(&[Identifier, Identifier, ColonEquals]) {
|
||||
items.push(Item::Alias(self.parse_alias()?));
|
||||
} else {
|
||||
let doc = pop_doc_comment(&mut items, eol_since_last_comment);
|
||||
items.push(Item::Recipe(self.parse_recipe(doc, false)?));
|
||||
},
|
||||
Some(Keyword::Export) =>
|
||||
@ -326,6 +344,7 @@ impl<'tokens, 'src> Parser<'tokens, 'src> {
|
||||
self.presume_keyword(Keyword::Export)?;
|
||||
items.push(Item::Assignment(self.parse_assignment(true)?));
|
||||
} else {
|
||||
let doc = pop_doc_comment(&mut items, eol_since_last_comment);
|
||||
items.push(Item::Recipe(self.parse_recipe(doc, false)?));
|
||||
},
|
||||
Some(Keyword::Set) =>
|
||||
@ -335,6 +354,7 @@ impl<'tokens, 'src> Parser<'tokens, 'src> {
|
||||
{
|
||||
items.push(Item::Set(self.parse_set()?));
|
||||
} else {
|
||||
let doc = pop_doc_comment(&mut items, eol_since_last_comment);
|
||||
items.push(Item::Recipe(self.parse_recipe(doc, false)?));
|
||||
},
|
||||
_ =>
|
||||
@ -343,18 +363,16 @@ impl<'tokens, 'src> Parser<'tokens, 'src> {
|
||||
} else if self.next_are(&[Identifier, ColonEquals]) {
|
||||
items.push(Item::Assignment(self.parse_assignment(false)?));
|
||||
} else {
|
||||
let doc = pop_doc_comment(&mut items, eol_since_last_comment);
|
||||
items.push(Item::Recipe(self.parse_recipe(doc, false)?));
|
||||
},
|
||||
}
|
||||
} else if self.accepted(At)? {
|
||||
let doc = pop_doc_comment(&mut items, eol_since_last_comment);
|
||||
items.push(Item::Recipe(self.parse_recipe(doc, true)?));
|
||||
} else {
|
||||
return Err(self.unexpected_token()?);
|
||||
}
|
||||
|
||||
if next.kind != Comment {
|
||||
doc = None;
|
||||
}
|
||||
}
|
||||
|
||||
if self.next != self.tokens.len() {
|
||||
@ -1097,11 +1115,17 @@ mod tests {
|
||||
test! {
|
||||
name: comment,
|
||||
text: "# foo",
|
||||
tree: (justfile),
|
||||
tree: (justfile (comment "# foo")),
|
||||
}
|
||||
|
||||
test! {
|
||||
name: comment_alias,
|
||||
name: comment_before_alias,
|
||||
text: "# foo\nalias x := y",
|
||||
tree: (justfile (comment "# foo") (alias x y)),
|
||||
}
|
||||
|
||||
test! {
|
||||
name: comment_after_alias,
|
||||
text: "alias x := y # foo",
|
||||
tree: (justfile (alias x y)),
|
||||
}
|
||||
@ -1166,7 +1190,7 @@ mod tests {
|
||||
x := y
|
||||
bar:
|
||||
",
|
||||
tree: (justfile (assignment x y) (recipe bar)),
|
||||
tree: (justfile (comment "# foo") (assignment x y) (recipe bar)),
|
||||
}
|
||||
|
||||
test! {
|
||||
@ -1176,7 +1200,7 @@ mod tests {
|
||||
|
||||
bar:
|
||||
",
|
||||
tree: (justfile (recipe bar)),
|
||||
tree: (justfile (comment "# foo") (recipe bar)),
|
||||
}
|
||||
|
||||
test! {
|
||||
|
@ -23,7 +23,7 @@ fn error_from_signal(
|
||||
}
|
||||
|
||||
/// A recipe, e.g. `foo: bar baz`
|
||||
#[derive(PartialEq, Debug)]
|
||||
#[derive(PartialEq, Debug, Clone)]
|
||||
pub(crate) struct Recipe<'src, D = Dependency<'src>> {
|
||||
pub(crate) dependencies: Vec<D>,
|
||||
pub(crate) doc: Option<&'src str>,
|
||||
@ -314,7 +314,7 @@ impl<'src, D> Keyed<'src> for Recipe<'src, D> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'src> Display for Recipe<'src> {
|
||||
impl<'src, D: Display> Display for Recipe<'src, D> {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
|
||||
if let Some(doc) = self.doc {
|
||||
writeln!(f, "# {}", doc)?;
|
||||
@ -344,7 +344,7 @@ impl<'src> Display for Recipe<'src> {
|
||||
}
|
||||
match fragment {
|
||||
Fragment::Text { token } => write!(f, "{}", token.lexeme())?,
|
||||
Fragment::Interpolation { expression, .. } => write!(f, "{{{{{}}}}}", expression)?,
|
||||
Fragment::Interpolation { expression, .. } => write!(f, "{{{{ {} }}}}", expression)?,
|
||||
}
|
||||
}
|
||||
if i + 1 < self.body.len() {
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::common::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct Set<'src> {
|
||||
pub(crate) name: Name<'src>,
|
||||
pub(crate) value: Setting<'src>,
|
||||
@ -11,3 +11,9 @@ impl<'src> Keyed<'src> for Set<'src> {
|
||||
self.name.lexeme()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'src> Display for Set<'src> {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
|
||||
write!(f, "set {} := {}", self.name, self.value)
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::common::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) enum Setting<'src> {
|
||||
DotenvLoad(bool),
|
||||
Export(bool),
|
||||
@ -8,8 +8,31 @@ pub(crate) enum Setting<'src> {
|
||||
Shell(Shell<'src>),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub(crate) struct Shell<'src> {
|
||||
pub(crate) command: StringLiteral<'src>,
|
||||
pub(crate) arguments: Vec<StringLiteral<'src>>,
|
||||
}
|
||||
|
||||
impl<'src> Display for Setting<'src> {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
|
||||
match self {
|
||||
Setting::DotenvLoad(value) => write!(f, "{}", value),
|
||||
Setting::Export(value) => write!(f, "{}", value),
|
||||
Setting::PositionalArguments(value) => write!(f, "{}", value),
|
||||
Setting::Shell(shell) => write!(f, "{}", shell),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'src> Display for Shell<'src> {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
|
||||
write!(f, "[{}", self.command)?;
|
||||
|
||||
for argument in &self.arguments {
|
||||
write!(f, ", {}", argument)?;
|
||||
}
|
||||
|
||||
write!(f, "]")
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::common::*;
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
#[derive(PartialEq, Debug, Clone)]
|
||||
pub(crate) struct StringLiteral<'src> {
|
||||
pub(crate) kind: StringKind,
|
||||
pub(crate) raw: &'src str,
|
||||
|
@ -20,6 +20,7 @@ pub(crate) enum Subcommand {
|
||||
overrides: BTreeMap<String, String>,
|
||||
variable: Option<String>,
|
||||
},
|
||||
Format,
|
||||
Init,
|
||||
List,
|
||||
Run {
|
||||
|
@ -1,5 +1,6 @@
|
||||
use crate::common::*;
|
||||
|
||||
use crate::compiler::Compiler;
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
pub(crate) fn compile(text: &str) -> Justfile {
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::common::*;
|
||||
|
||||
#[derive(Derivative)]
|
||||
#[derivative(Debug, PartialEq = "feature_allow_slow_enum")]
|
||||
#[derivative(Debug, Clone, PartialEq = "feature_allow_slow_enum")]
|
||||
pub(crate) enum Thunk<'src> {
|
||||
Nullary {
|
||||
name: Name<'src>,
|
||||
|
@ -1,7 +1,23 @@
|
||||
use crate::common::*;
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
#[derive(PartialEq, Debug, Clone)]
|
||||
pub(crate) struct UnresolvedDependency<'src> {
|
||||
pub(crate) recipe: Name<'src>,
|
||||
pub(crate) arguments: Vec<Expression<'src>>,
|
||||
}
|
||||
|
||||
impl<'src> Display for UnresolvedDependency<'src> {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
|
||||
if self.arguments.is_empty() {
|
||||
write!(f, "{}", self.recipe)
|
||||
} else {
|
||||
write!(f, "({}", self.recipe)?;
|
||||
|
||||
for argument in &self.arguments {
|
||||
write!(f, " {}", argument)?;
|
||||
}
|
||||
|
||||
write!(f, ")")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::common::*;
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub(crate) enum Warning {
|
||||
// Remove this on 2021-07-01.
|
||||
#[allow(dead_code)]
|
||||
|
@ -33,7 +33,7 @@ test! {
|
||||
USAGE:
|
||||
just{} --color <COLOR> --shell <SHELL> --shell-arg <SHELL-ARG>... \
|
||||
<--choose|--command <COMMAND>|--completions <SHELL>|--dump|--edit|\
|
||||
--evaluate|--init|--list|--show <RECIPE>|--summary|--variables>
|
||||
--evaluate|--fmt|--init|--list|--show <RECIPE>|--summary|--variables>
|
||||
|
||||
For more information try --help
|
||||
", EXE_SUFFIX),
|
||||
|
@ -149,10 +149,10 @@ test! {
|
||||
echo {{ a }}
|
||||
",
|
||||
args: ("--dump"),
|
||||
stdout: format!("
|
||||
a := if '' == '' {{ '' }} else {{ '' }}{}
|
||||
stdout: "
|
||||
a := if '' == '' { '' } else { '' }
|
||||
|
||||
foo:
|
||||
echo {{{{a}}}}
|
||||
", " ").as_str(),
|
||||
echo {{ a }}
|
||||
",
|
||||
}
|
||||
|
891
tests/fmt.rs
Normal file
891
tests/fmt.rs
Normal file
@ -0,0 +1,891 @@
|
||||
test! {
|
||||
name: alias_good,
|
||||
justfile: "
|
||||
alias f := foo
|
||||
|
||||
foo:
|
||||
echo foo
|
||||
",
|
||||
args: ("--dump"),
|
||||
stdout: "
|
||||
alias f := foo
|
||||
|
||||
foo:
|
||||
echo foo
|
||||
",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: alias_fix_indent,
|
||||
justfile: "
|
||||
alias f:= foo
|
||||
|
||||
foo:
|
||||
echo foo
|
||||
",
|
||||
args: ("--dump"),
|
||||
stdout: "
|
||||
alias f := foo
|
||||
|
||||
foo:
|
||||
echo foo
|
||||
",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: assignment_singlequote,
|
||||
justfile: "
|
||||
foo := 'foo'
|
||||
",
|
||||
args: ("--dump"),
|
||||
stdout: "
|
||||
foo := 'foo'
|
||||
",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: assignment_doublequote,
|
||||
justfile: r#"
|
||||
foo := "foo"
|
||||
"#,
|
||||
args: ("--dump"),
|
||||
stdout: r#"
|
||||
foo := "foo"
|
||||
"#,
|
||||
}
|
||||
|
||||
test! {
|
||||
name: assignment_indented_singlequote,
|
||||
justfile: "
|
||||
foo := '''
|
||||
foo
|
||||
'''
|
||||
",
|
||||
args: ("--dump"),
|
||||
stdout: r"
|
||||
foo := '''
|
||||
foo
|
||||
'''
|
||||
",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: assignment_indented_doublequote,
|
||||
justfile: r#"
|
||||
foo := """
|
||||
foo
|
||||
"""
|
||||
"#,
|
||||
args: ("--dump"),
|
||||
stdout: r#"
|
||||
foo := """
|
||||
foo
|
||||
"""
|
||||
"#,
|
||||
}
|
||||
|
||||
test! {
|
||||
name: assignment_backtick,
|
||||
justfile: "
|
||||
foo := `foo`
|
||||
",
|
||||
args: ("--dump"),
|
||||
stdout: "
|
||||
foo := `foo`
|
||||
",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: assignment_indented_backtick,
|
||||
justfile: "
|
||||
foo := ```
|
||||
foo
|
||||
```
|
||||
",
|
||||
args: ("--dump"),
|
||||
stdout: "
|
||||
foo := ```
|
||||
foo
|
||||
```
|
||||
",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: assignment_name,
|
||||
justfile: "
|
||||
bar := 'bar'
|
||||
foo := bar
|
||||
",
|
||||
args: ("--dump"),
|
||||
stdout: "
|
||||
bar := 'bar'
|
||||
foo := bar
|
||||
",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: assignment_parenthized_expression,
|
||||
justfile: "
|
||||
foo := ('foo')
|
||||
",
|
||||
args: ("--dump"),
|
||||
stdout: "
|
||||
foo := ('foo')
|
||||
",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: assignment_export,
|
||||
justfile: "
|
||||
export foo := 'foo'
|
||||
",
|
||||
args: ("--dump"),
|
||||
stdout: "
|
||||
export foo := 'foo'
|
||||
",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: assignment_concat_values,
|
||||
justfile: "
|
||||
foo := 'foo' + 'bar'
|
||||
",
|
||||
args: ("--dump"),
|
||||
stdout: "
|
||||
foo := 'foo' + 'bar'
|
||||
",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: assignment_if_oneline,
|
||||
justfile: "
|
||||
foo := if 'foo' == 'foo' { 'foo' } else { 'bar' }
|
||||
",
|
||||
args: ("--dump"),
|
||||
stdout: "
|
||||
foo := if 'foo' == 'foo' { 'foo' } else { 'bar' }
|
||||
",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: assignment_if_multiline,
|
||||
justfile: "
|
||||
foo := if 'foo' != 'foo' {
|
||||
'foo'
|
||||
} else {
|
||||
'bar'
|
||||
}
|
||||
",
|
||||
args: ("--dump"),
|
||||
stdout: "
|
||||
foo := if 'foo' != 'foo' { 'foo' } else { 'bar' }
|
||||
",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: assignment_nullary_function,
|
||||
justfile: "
|
||||
foo := arch()
|
||||
",
|
||||
args: ("--dump"),
|
||||
stdout: "
|
||||
foo := arch()
|
||||
",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: assignment_unary_function,
|
||||
justfile: "
|
||||
foo := env_var('foo')
|
||||
",
|
||||
args: ("--dump"),
|
||||
stdout: "
|
||||
foo := env_var('foo')
|
||||
",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: assignment_binary_function,
|
||||
justfile: "
|
||||
foo := env_var_or_default('foo', 'bar')
|
||||
",
|
||||
args: ("--dump"),
|
||||
stdout: "
|
||||
foo := env_var_or_default('foo', 'bar')
|
||||
",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: recipe_ordinary,
|
||||
justfile: "
|
||||
foo:
|
||||
echo bar
|
||||
",
|
||||
args: ("--dump"),
|
||||
stdout: "
|
||||
foo:
|
||||
echo bar
|
||||
",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: recipe_with_docstring,
|
||||
justfile: "
|
||||
# bar
|
||||
foo:
|
||||
echo bar
|
||||
",
|
||||
args: ("--dump"),
|
||||
stdout: "
|
||||
# bar
|
||||
foo:
|
||||
echo bar
|
||||
",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: recipe_with_comments_in_body,
|
||||
justfile: "
|
||||
foo:
|
||||
# bar
|
||||
echo bar
|
||||
",
|
||||
args: ("--dump"),
|
||||
stdout: "
|
||||
foo:
|
||||
# bar
|
||||
echo bar
|
||||
",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: recipe_body_is_comment,
|
||||
justfile: "
|
||||
foo:
|
||||
# bar
|
||||
",
|
||||
args: ("--dump"),
|
||||
stdout: "
|
||||
foo:
|
||||
# bar
|
||||
",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: recipe_several_commands,
|
||||
justfile: "
|
||||
foo:
|
||||
echo bar
|
||||
echo baz
|
||||
",
|
||||
args: ("--dump"),
|
||||
stdout: "
|
||||
foo:
|
||||
echo bar
|
||||
echo baz
|
||||
",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: recipe_quiet,
|
||||
justfile: "
|
||||
@foo:
|
||||
echo bar
|
||||
",
|
||||
args: ("--dump"),
|
||||
stdout: "
|
||||
@foo:
|
||||
echo bar
|
||||
",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: recipe_quiet_command,
|
||||
justfile: "
|
||||
foo:
|
||||
@echo bar
|
||||
",
|
||||
args: ("--dump"),
|
||||
stdout: "
|
||||
foo:
|
||||
@echo bar
|
||||
",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: recipe_quiet_comment,
|
||||
justfile: "
|
||||
foo:
|
||||
@# bar
|
||||
",
|
||||
args: ("--dump"),
|
||||
stdout: "
|
||||
foo:
|
||||
@# bar
|
||||
",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: recipe_ignore_errors,
|
||||
justfile: "
|
||||
foo:
|
||||
-echo foo
|
||||
",
|
||||
args: ("--dump"),
|
||||
stdout: "
|
||||
foo:
|
||||
-echo foo
|
||||
",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: recipe_parameter,
|
||||
justfile: "
|
||||
foo BAR:
|
||||
echo foo
|
||||
",
|
||||
args: ("--dump"),
|
||||
stdout: "
|
||||
foo BAR:
|
||||
echo foo
|
||||
",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: recipe_parameter_default,
|
||||
justfile: "
|
||||
foo BAR='bar':
|
||||
echo foo
|
||||
",
|
||||
args: ("--dump"),
|
||||
stdout: "
|
||||
foo BAR='bar':
|
||||
echo foo
|
||||
",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: recipe_parameter_envar,
|
||||
justfile: "
|
||||
foo $BAR:
|
||||
echo foo
|
||||
",
|
||||
args: ("--dump"),
|
||||
stdout: "
|
||||
foo $BAR:
|
||||
echo foo
|
||||
",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: recipe_parameter_default_envar,
|
||||
justfile: "
|
||||
foo $BAR='foo':
|
||||
echo foo
|
||||
",
|
||||
args: ("--dump"),
|
||||
stdout: "
|
||||
foo $BAR='foo':
|
||||
echo foo
|
||||
",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: recipe_parameter_concat,
|
||||
justfile: "
|
||||
foo BAR=('bar' + 'baz'):
|
||||
echo foo
|
||||
",
|
||||
args: ("--dump"),
|
||||
stdout: "
|
||||
foo BAR=('bar' + 'baz'):
|
||||
echo foo
|
||||
",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: recipe_parameters,
|
||||
justfile: "
|
||||
foo BAR BAZ:
|
||||
echo foo
|
||||
",
|
||||
args: ("--dump"),
|
||||
stdout: "
|
||||
foo BAR BAZ:
|
||||
echo foo
|
||||
",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: recipe_parameters_envar,
|
||||
justfile: "
|
||||
foo $BAR $BAZ:
|
||||
echo foo
|
||||
",
|
||||
args: ("--dump"),
|
||||
stdout: "
|
||||
foo $BAR $BAZ:
|
||||
echo foo
|
||||
",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: recipe_variadic_plus,
|
||||
justfile: "
|
||||
foo +BAR:
|
||||
echo foo
|
||||
",
|
||||
args: ("--dump"),
|
||||
stdout: "
|
||||
foo +BAR:
|
||||
echo foo
|
||||
",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: recipe_variadic_star,
|
||||
justfile: "
|
||||
foo *BAR:
|
||||
echo foo
|
||||
",
|
||||
args: ("--dump"),
|
||||
stdout: "
|
||||
foo *BAR:
|
||||
echo foo
|
||||
",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: recipe_positional_variadic,
|
||||
justfile: "
|
||||
foo BAR *BAZ:
|
||||
echo foo
|
||||
",
|
||||
args: ("--dump"),
|
||||
stdout: "
|
||||
foo BAR *BAZ:
|
||||
echo foo
|
||||
",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: recipe_variadic_default,
|
||||
justfile: "
|
||||
foo +BAR='bar':
|
||||
echo foo
|
||||
",
|
||||
args: ("--dump"),
|
||||
stdout: "
|
||||
foo +BAR='bar':
|
||||
echo foo
|
||||
",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: recipe_parameter_in_body,
|
||||
justfile: "
|
||||
foo BAR:
|
||||
echo {{ BAR }}
|
||||
",
|
||||
args: ("--dump"),
|
||||
stdout: "
|
||||
foo BAR:
|
||||
echo {{ BAR }}
|
||||
",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: recipe_parameter_conditional,
|
||||
justfile: "
|
||||
foo BAR:
|
||||
echo {{ if 'foo' == 'foo' { 'foo' } else { 'bar' } }}
|
||||
",
|
||||
args: ("--dump"),
|
||||
stdout: "
|
||||
foo BAR:
|
||||
echo {{ if 'foo' == 'foo' { 'foo' } else { 'bar' } }}
|
||||
",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: recipe_escaped_braces,
|
||||
justfile: "
|
||||
foo BAR:
|
||||
echo '{{{{BAR}}}}'
|
||||
",
|
||||
args: ("--dump"),
|
||||
stdout: "
|
||||
foo BAR:
|
||||
echo '{{{{BAR}}}}'
|
||||
",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: recipe_assignment_in_body,
|
||||
justfile: "
|
||||
bar := 'bar'
|
||||
|
||||
foo:
|
||||
echo $bar
|
||||
",
|
||||
args: ("--dump"),
|
||||
stdout: "
|
||||
bar := 'bar'
|
||||
|
||||
foo:
|
||||
echo $bar
|
||||
",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: recipe_dependency,
|
||||
justfile: "
|
||||
bar:
|
||||
echo bar
|
||||
|
||||
foo: bar
|
||||
echo foo
|
||||
",
|
||||
args: ("--dump"),
|
||||
stdout: "
|
||||
bar:
|
||||
echo bar
|
||||
|
||||
foo: bar
|
||||
echo foo
|
||||
",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: recipe_dependency_param,
|
||||
justfile: "
|
||||
bar BAR:
|
||||
echo bar
|
||||
|
||||
foo: (bar 'bar')
|
||||
echo foo
|
||||
",
|
||||
args: ("--dump"),
|
||||
stdout: "
|
||||
bar BAR:
|
||||
echo bar
|
||||
|
||||
foo: (bar 'bar')
|
||||
echo foo
|
||||
",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: recipe_dependency_params,
|
||||
justfile: "
|
||||
bar BAR BAZ:
|
||||
echo bar
|
||||
|
||||
foo: (bar 'bar' 'baz')
|
||||
echo foo
|
||||
",
|
||||
args: ("--dump"),
|
||||
stdout: "
|
||||
bar BAR BAZ:
|
||||
echo bar
|
||||
|
||||
foo: (bar 'bar' 'baz')
|
||||
echo foo
|
||||
",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: recipe_dependencies,
|
||||
justfile: "
|
||||
bar:
|
||||
echo bar
|
||||
|
||||
baz:
|
||||
echo baz
|
||||
|
||||
foo: baz bar
|
||||
echo foo
|
||||
",
|
||||
args: ("--dump"),
|
||||
stdout: "
|
||||
bar:
|
||||
echo bar
|
||||
|
||||
baz:
|
||||
echo baz
|
||||
|
||||
foo: baz bar
|
||||
echo foo
|
||||
",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: recipe_dependencies_params,
|
||||
justfile: "
|
||||
bar BAR:
|
||||
echo bar
|
||||
|
||||
baz BAZ:
|
||||
echo baz
|
||||
|
||||
foo: (baz 'baz') (bar 'bar')
|
||||
echo foo
|
||||
",
|
||||
args: ("--dump"),
|
||||
stdout: "
|
||||
bar BAR:
|
||||
echo bar
|
||||
|
||||
baz BAZ:
|
||||
echo baz
|
||||
|
||||
foo: (baz 'baz') (bar 'bar')
|
||||
echo foo
|
||||
",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: set_true_explicit,
|
||||
justfile: "
|
||||
set export := true
|
||||
",
|
||||
args: ("--dump"),
|
||||
stdout: "
|
||||
set export := true
|
||||
",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: set_true_implicit,
|
||||
justfile: "
|
||||
set export
|
||||
",
|
||||
args: ("--dump"),
|
||||
stdout: "
|
||||
set export := true
|
||||
",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: set_false,
|
||||
justfile: "
|
||||
set export := false
|
||||
",
|
||||
args: ("--dump"),
|
||||
stdout: "
|
||||
set export := false
|
||||
",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: set_shell,
|
||||
justfile: r#"
|
||||
set shell := ['sh', "-c"]
|
||||
"#,
|
||||
args: ("--dump"),
|
||||
stdout: r#"
|
||||
set shell := ['sh', "-c"]
|
||||
"#,
|
||||
}
|
||||
|
||||
test! {
|
||||
name: comment,
|
||||
justfile: "
|
||||
# foo
|
||||
",
|
||||
args: ("--dump"),
|
||||
stdout: "
|
||||
# foo
|
||||
",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: comment_multiline,
|
||||
justfile: "
|
||||
# foo
|
||||
# bar
|
||||
",
|
||||
args: ("--dump"),
|
||||
stdout: "
|
||||
# foo
|
||||
# bar
|
||||
",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: comment_leading,
|
||||
justfile: "
|
||||
# foo
|
||||
|
||||
foo := 'bar'
|
||||
",
|
||||
args: ("--dump"),
|
||||
stdout: "
|
||||
# foo
|
||||
|
||||
foo := 'bar'
|
||||
",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: comment_trailing,
|
||||
justfile: "
|
||||
foo := 'bar'
|
||||
|
||||
# foo
|
||||
",
|
||||
args: ("--dump"),
|
||||
stdout: "
|
||||
foo := 'bar'
|
||||
|
||||
# foo
|
||||
",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: comment_before_recipe,
|
||||
justfile: "
|
||||
# foo
|
||||
|
||||
foo:
|
||||
echo foo
|
||||
",
|
||||
args: ("--dump"),
|
||||
stdout: "
|
||||
# foo
|
||||
|
||||
foo:
|
||||
echo foo
|
||||
",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: comment_before_docstring_recipe,
|
||||
justfile: "
|
||||
# bar
|
||||
|
||||
# foo
|
||||
foo:
|
||||
echo foo
|
||||
",
|
||||
args: ("--dump"),
|
||||
stdout: "
|
||||
# bar
|
||||
|
||||
# foo
|
||||
foo:
|
||||
echo foo
|
||||
",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: group_recipies,
|
||||
justfile: "
|
||||
foo:
|
||||
echo foo
|
||||
bar:
|
||||
echo bar
|
||||
",
|
||||
args: ("--dump"),
|
||||
stdout: "
|
||||
foo:
|
||||
echo foo
|
||||
|
||||
bar:
|
||||
echo bar
|
||||
",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: group_aliases,
|
||||
justfile: "
|
||||
alias f := foo
|
||||
|
||||
alias b := bar
|
||||
|
||||
foo:
|
||||
echo foo
|
||||
|
||||
bar:
|
||||
echo bar
|
||||
",
|
||||
args: ("--dump"),
|
||||
stdout: "
|
||||
alias f := foo
|
||||
alias b := bar
|
||||
|
||||
foo:
|
||||
echo foo
|
||||
|
||||
bar:
|
||||
echo bar
|
||||
",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: group_assignments,
|
||||
justfile: "
|
||||
foo := 'foo'
|
||||
bar := 'bar'
|
||||
",
|
||||
args: ("--dump"),
|
||||
stdout: "
|
||||
foo := 'foo'
|
||||
bar := 'bar'
|
||||
",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: group_sets,
|
||||
justfile: "
|
||||
set export := true
|
||||
set positional-arguments := true
|
||||
",
|
||||
args: ("--dump"),
|
||||
stdout: "
|
||||
set export := true
|
||||
set positional-arguments := true
|
||||
",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: group_comments,
|
||||
justfile: "
|
||||
# foo
|
||||
|
||||
# bar
|
||||
",
|
||||
args: ("--dump"),
|
||||
stdout: "
|
||||
# foo
|
||||
# bar
|
||||
",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: separate_recipes_aliases,
|
||||
justfile: "
|
||||
alias f := foo
|
||||
foo:
|
||||
echo foo
|
||||
",
|
||||
args: ("--dump"),
|
||||
stdout: "
|
||||
alias f := foo
|
||||
|
||||
foo:
|
||||
echo foo
|
||||
",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: no_trailing_newline,
|
||||
justfile: "
|
||||
foo:
|
||||
echo foo",
|
||||
args: ("--dump"),
|
||||
stdout: "
|
||||
foo:
|
||||
echo foo
|
||||
",
|
||||
}
|
@ -14,6 +14,7 @@ mod error_messages;
|
||||
mod evaluate;
|
||||
mod examples;
|
||||
mod export;
|
||||
mod fmt;
|
||||
mod init;
|
||||
mod interrupts;
|
||||
mod invocation_directory;
|
||||
|
@ -265,7 +265,7 @@ recipe:
|
||||
args: ("--show", "recipe"),
|
||||
stdout: r#"
|
||||
recipe:
|
||||
echo {{hello + "bar" + bar}}
|
||||
echo {{ hello + "bar" + bar }}
|
||||
"#,
|
||||
}
|
||||
|
||||
|
@ -75,7 +75,7 @@ impl<'a> Test<'a> {
|
||||
|
||||
let mut justfile_path = tmp.path().to_path_buf();
|
||||
justfile_path.push("justfile");
|
||||
fs::write(justfile_path, justfile).unwrap();
|
||||
fs::write(&justfile_path, justfile).unwrap();
|
||||
|
||||
let mut dotenv_path = tmp.path().to_path_buf();
|
||||
dotenv_path.push(".env");
|
||||
|
Loading…
Reference in New Issue
Block a user