Use stable rustfmt instead of nightly (#967)
This commit is contained in:
parent
ca2b596c90
commit
629c75ff04
12
.github/workflows/build.yaml
vendored
12
.github/workflows/build.yaml
vendored
@ -80,7 +80,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Install Rust Toolchain
|
- name: Install Rust Toolchain
|
||||||
run: |
|
run: |
|
||||||
rustup component add clippy
|
rustup component add clippy rustfmt
|
||||||
rustup target add ${{ matrix.target }}
|
rustup target add ${{ matrix.target }}
|
||||||
rustup default "`cat rust-toolchain`-${{ matrix.target }}"
|
rustup default "`cat rust-toolchain`-${{ matrix.target }}"
|
||||||
|
|
||||||
@ -108,16 +108,8 @@ jobs:
|
|||||||
- name: Clippy
|
- name: Clippy
|
||||||
run: cargo clippy --all --all-targets --all-features
|
run: cargo clippy --all --all-targets --all-features
|
||||||
|
|
||||||
- name: Install Rustfmt Toolchain
|
|
||||||
uses: actions-rs/toolchain@v1
|
|
||||||
with:
|
|
||||||
toolchain: nightly
|
|
||||||
target: ${{ matrix.target }}
|
|
||||||
profile: minimal
|
|
||||||
components: rustfmt
|
|
||||||
|
|
||||||
- name: Format
|
- name: Format
|
||||||
run: cargo +nightly fmt --all -- --check
|
run: cargo fmt --all -- --check
|
||||||
|
|
||||||
- name: Completion Scripts
|
- name: Completion Scripts
|
||||||
if: ${{ matrix.os != 'windows-2016' }}
|
if: ${{ matrix.os != 'windows-2016' }}
|
||||||
|
3
justfile
3
justfile
@ -31,7 +31,7 @@ build:
|
|||||||
cargo lbuild
|
cargo lbuild
|
||||||
|
|
||||||
fmt:
|
fmt:
|
||||||
cargo +nightly fmt --all
|
cargo fmt --all
|
||||||
|
|
||||||
watch +COMMAND='ltest':
|
watch +COMMAND='ltest':
|
||||||
cargo watch --clear --exec "{{COMMAND}}"
|
cargo watch --clear --exec "{{COMMAND}}"
|
||||||
@ -94,7 +94,6 @@ install:
|
|||||||
install-dev-deps:
|
install-dev-deps:
|
||||||
rustup install nightly
|
rustup install nightly
|
||||||
rustup update nightly
|
rustup update nightly
|
||||||
rustup run nightly cargo install clippy
|
|
||||||
cargo +nightly install cargo-fuzz
|
cargo +nightly install cargo-fuzz
|
||||||
cargo install cargo-check
|
cargo install cargo-check
|
||||||
cargo install cargo-limit
|
cargo install cargo-limit
|
||||||
|
27
rustfmt.toml
27
rustfmt.toml
@ -1,21 +1,6 @@
|
|||||||
comment_width = 80
|
edition = "2018"
|
||||||
edition = "2018"
|
max_width = 100
|
||||||
error_on_line_overflow = true
|
newline_style = "Unix"
|
||||||
error_on_unformatted = true
|
tab_spaces = 2
|
||||||
format_code_in_doc_comments = true
|
use_field_init_shorthand = true
|
||||||
format_macro_bodies = true
|
use_try_shorthand = true
|
||||||
format_strings = true
|
|
||||||
imports_granularity = "Crate"
|
|
||||||
match_arm_blocks = false
|
|
||||||
match_block_trailing_comma = true
|
|
||||||
max_width = 100
|
|
||||||
newline_style = "Unix"
|
|
||||||
normalize_comments = true
|
|
||||||
overflow_delimited_expr = true
|
|
||||||
reorder_impl_items = true
|
|
||||||
struct_field_align_threshold = 20
|
|
||||||
tab_spaces = 2
|
|
||||||
unstable_features = true
|
|
||||||
use_field_init_shorthand = true
|
|
||||||
use_try_shorthand = true
|
|
||||||
wrap_comments = true
|
|
||||||
|
@ -3,7 +3,7 @@ use crate::common::*;
|
|||||||
/// An alias, e.g. `name := target`
|
/// An alias, e.g. `name := target`
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub(crate) struct Alias<'src, T = Rc<Recipe<'src>>> {
|
pub(crate) struct Alias<'src, T = Rc<Recipe<'src>>> {
|
||||||
pub(crate) name: Name<'src>,
|
pub(crate) name: Name<'src>,
|
||||||
pub(crate) target: T,
|
pub(crate) target: T,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,10 +4,10 @@ use CompileErrorKind::*;
|
|||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub(crate) struct Analyzer<'src> {
|
pub(crate) struct Analyzer<'src> {
|
||||||
recipes: Table<'src, UnresolvedRecipe<'src>>,
|
recipes: Table<'src, UnresolvedRecipe<'src>>,
|
||||||
assignments: Table<'src, Assignment<'src>>,
|
assignments: Table<'src, Assignment<'src>>,
|
||||||
aliases: Table<'src, Alias<'src, Name<'src>>>,
|
aliases: Table<'src, Alias<'src, Name<'src>>>,
|
||||||
sets: Table<'src, Set<'src>>,
|
sets: Table<'src, Set<'src>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'src> Analyzer<'src> {
|
impl<'src> Analyzer<'src> {
|
||||||
@ -21,20 +21,20 @@ impl<'src> Analyzer<'src> {
|
|||||||
Item::Alias(alias) => {
|
Item::Alias(alias) => {
|
||||||
self.analyze_alias(&alias)?;
|
self.analyze_alias(&alias)?;
|
||||||
self.aliases.insert(alias);
|
self.aliases.insert(alias);
|
||||||
},
|
}
|
||||||
Item::Assignment(assignment) => {
|
Item::Assignment(assignment) => {
|
||||||
self.analyze_assignment(&assignment)?;
|
self.analyze_assignment(&assignment)?;
|
||||||
self.assignments.insert(assignment);
|
self.assignments.insert(assignment);
|
||||||
},
|
}
|
||||||
Item::Comment(_) => (),
|
Item::Comment(_) => (),
|
||||||
Item::Recipe(recipe) => {
|
Item::Recipe(recipe) => {
|
||||||
self.analyze_recipe(&recipe)?;
|
self.analyze_recipe(&recipe)?;
|
||||||
self.recipes.insert(recipe);
|
self.recipes.insert(recipe);
|
||||||
},
|
}
|
||||||
Item::Set(set) => {
|
Item::Set(set) => {
|
||||||
self.analyze_set(&set)?;
|
self.analyze_set(&set)?;
|
||||||
self.sets.insert(set);
|
self.sets.insert(set);
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,17 +65,17 @@ impl<'src> Analyzer<'src> {
|
|||||||
match set.value {
|
match set.value {
|
||||||
Setting::DotenvLoad(dotenv_load) => {
|
Setting::DotenvLoad(dotenv_load) => {
|
||||||
settings.dotenv_load = Some(dotenv_load);
|
settings.dotenv_load = Some(dotenv_load);
|
||||||
},
|
}
|
||||||
Setting::Export(export) => {
|
Setting::Export(export) => {
|
||||||
settings.export = export;
|
settings.export = export;
|
||||||
},
|
}
|
||||||
Setting::PositionalArguments(positional_arguments) => {
|
Setting::PositionalArguments(positional_arguments) => {
|
||||||
settings.positional_arguments = positional_arguments;
|
settings.positional_arguments = positional_arguments;
|
||||||
},
|
}
|
||||||
Setting::Shell(shell) => {
|
Setting::Shell(shell) => {
|
||||||
assert!(settings.shell.is_none());
|
assert!(settings.shell.is_none());
|
||||||
settings.shell = Some(shell);
|
settings.shell = Some(shell);
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,7 +92,7 @@ impl<'src> Analyzer<'src> {
|
|||||||
if let Some(original) = self.recipes.get(recipe.name.lexeme()) {
|
if let Some(original) = self.recipes.get(recipe.name.lexeme()) {
|
||||||
return Err(recipe.name.token().error(DuplicateRecipe {
|
return Err(recipe.name.token().error(DuplicateRecipe {
|
||||||
recipe: original.name(),
|
recipe: original.name(),
|
||||||
first: original.line_number(),
|
first: original.line_number(),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,7 +102,7 @@ impl<'src> Analyzer<'src> {
|
|||||||
for parameter in &recipe.parameters {
|
for parameter in &recipe.parameters {
|
||||||
if parameters.contains(parameter.name.lexeme()) {
|
if parameters.contains(parameter.name.lexeme()) {
|
||||||
return Err(parameter.name.token().error(DuplicateParameter {
|
return Err(parameter.name.token().error(DuplicateParameter {
|
||||||
recipe: recipe.name.lexeme(),
|
recipe: recipe.name.lexeme(),
|
||||||
parameter: parameter.name.lexeme(),
|
parameter: parameter.name.lexeme(),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
@ -166,7 +166,7 @@ impl<'src> Analyzer<'src> {
|
|||||||
if let Some(original) = self.sets.get(set.name.lexeme()) {
|
if let Some(original) = self.sets.get(set.name.lexeme()) {
|
||||||
return Err(set.name.error(DuplicateSet {
|
return Err(set.name.error(DuplicateSet {
|
||||||
setting: original.name.lexeme(),
|
setting: original.name.lexeme(),
|
||||||
first: original.name.line,
|
first: original.name.line,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,7 +181,7 @@ impl<'src> Analyzer<'src> {
|
|||||||
// Make sure the alias doesn't conflict with any recipe
|
// Make sure the alias doesn't conflict with any recipe
|
||||||
if let Some(recipe) = recipes.get(alias.name.lexeme()) {
|
if let Some(recipe) = recipes.get(alias.name.lexeme()) {
|
||||||
return Err(token.error(AliasShadowsRecipe {
|
return Err(token.error(AliasShadowsRecipe {
|
||||||
alias: alias.name.lexeme(),
|
alias: alias.name.lexeme(),
|
||||||
recipe_line: recipe.line_number(),
|
recipe_line: recipe.line_number(),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
@ -190,7 +190,7 @@ impl<'src> Analyzer<'src> {
|
|||||||
match recipes.get(alias.target.lexeme()) {
|
match recipes.get(alias.target.lexeme()) {
|
||||||
Some(target) => Ok(alias.resolve(Rc::clone(target))),
|
Some(target) => Ok(alias.resolve(Rc::clone(target))),
|
||||||
None => Err(token.error(UnknownAliasTarget {
|
None => Err(token.error(UnknownAliasTarget {
|
||||||
alias: alias.name.lexeme(),
|
alias: alias.name.lexeme(),
|
||||||
target: alias.target.lexeme(),
|
target: alias.target.lexeme(),
|
||||||
})),
|
})),
|
||||||
}
|
}
|
||||||
|
@ -4,8 +4,8 @@ use CompileErrorKind::*;
|
|||||||
|
|
||||||
pub(crate) struct AssignmentResolver<'src: 'run, 'run> {
|
pub(crate) struct AssignmentResolver<'src: 'run, 'run> {
|
||||||
assignments: &'run Table<'src, Assignment<'src>>,
|
assignments: &'run Table<'src, Assignment<'src>>,
|
||||||
stack: Vec<&'src str>,
|
stack: Vec<&'src str>,
|
||||||
evaluated: BTreeSet<&'src str>,
|
evaluated: BTreeSet<&'src str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'src: 'run, 'run> AssignmentResolver<'src, 'run> {
|
impl<'src: 'run, 'run> AssignmentResolver<'src, 'run> {
|
||||||
@ -38,12 +38,12 @@ impl<'src: 'run, 'run> AssignmentResolver<'src, 'run> {
|
|||||||
} else {
|
} else {
|
||||||
let message = format!("attempted to resolve unknown assignment `{}`", name);
|
let message = format!("attempted to resolve unknown assignment `{}`", name);
|
||||||
let token = Token {
|
let token = Token {
|
||||||
src: "",
|
src: "",
|
||||||
offset: 0,
|
offset: 0,
|
||||||
line: 0,
|
line: 0,
|
||||||
column: 0,
|
column: 0,
|
||||||
length: 0,
|
length: 0,
|
||||||
kind: TokenKind::Unspecified,
|
kind: TokenKind::Unspecified,
|
||||||
};
|
};
|
||||||
return Err(CompileError {
|
return Err(CompileError {
|
||||||
kind: Internal { message },
|
kind: Internal { message },
|
||||||
@ -74,26 +74,26 @@ impl<'src: 'run, 'run> AssignmentResolver<'src, 'run> {
|
|||||||
} else {
|
} else {
|
||||||
Err(name.token().error(UndefinedVariable { variable }))
|
Err(name.token().error(UndefinedVariable { variable }))
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Expression::Call { thunk } => match thunk {
|
Expression::Call { thunk } => match thunk {
|
||||||
Thunk::Nullary { .. } => Ok(()),
|
Thunk::Nullary { .. } => Ok(()),
|
||||||
Thunk::Unary { arg, .. } => self.resolve_expression(arg),
|
Thunk::Unary { arg, .. } => self.resolve_expression(arg),
|
||||||
Thunk::Binary { args: [a, b], .. } => {
|
Thunk::Binary { args: [a, b], .. } => {
|
||||||
self.resolve_expression(a)?;
|
self.resolve_expression(a)?;
|
||||||
self.resolve_expression(b)
|
self.resolve_expression(b)
|
||||||
},
|
}
|
||||||
Thunk::Ternary {
|
Thunk::Ternary {
|
||||||
args: [a, b, c], ..
|
args: [a, b, c], ..
|
||||||
} => {
|
} => {
|
||||||
self.resolve_expression(a)?;
|
self.resolve_expression(a)?;
|
||||||
self.resolve_expression(b)?;
|
self.resolve_expression(b)?;
|
||||||
self.resolve_expression(c)
|
self.resolve_expression(c)
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
Expression::Concatination { lhs, rhs } => {
|
Expression::Concatination { lhs, rhs } => {
|
||||||
self.resolve_expression(lhs)?;
|
self.resolve_expression(lhs)?;
|
||||||
self.resolve_expression(rhs)
|
self.resolve_expression(rhs)
|
||||||
},
|
}
|
||||||
Expression::Conditional {
|
Expression::Conditional {
|
||||||
lhs,
|
lhs,
|
||||||
rhs,
|
rhs,
|
||||||
@ -105,7 +105,7 @@ impl<'src: 'run, 'run> AssignmentResolver<'src, 'run> {
|
|||||||
self.resolve_expression(rhs)?;
|
self.resolve_expression(rhs)?;
|
||||||
self.resolve_expression(then)?;
|
self.resolve_expression(then)?;
|
||||||
self.resolve_expression(otherwise)
|
self.resolve_expression(otherwise)
|
||||||
},
|
}
|
||||||
Expression::StringLiteral { .. } | Expression::Backtick { .. } => Ok(()),
|
Expression::StringLiteral { .. } | Expression::Backtick { .. } => Ok(()),
|
||||||
Expression::Group { contents } => self.resolve_expression(contents),
|
Expression::Group { contents } => self.resolve_expression(contents),
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ use crate::common::*;
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub(crate) struct Ast<'src> {
|
pub(crate) struct Ast<'src> {
|
||||||
/// Items in the justfile
|
/// Items in the justfile
|
||||||
pub(crate) items: Vec<Item<'src>>,
|
pub(crate) items: Vec<Item<'src>>,
|
||||||
/// Non-fatal warnings encountered during parsing
|
/// Non-fatal warnings encountered during parsing
|
||||||
pub(crate) warnings: Vec<Warning>,
|
pub(crate) warnings: Vec<Warning>,
|
||||||
}
|
}
|
||||||
|
@ -6,9 +6,9 @@ pub(crate) struct Binding<'src, V = String> {
|
|||||||
/// Export binding as an environment variable to child processes
|
/// Export binding as an environment variable to child processes
|
||||||
pub(crate) export: bool,
|
pub(crate) export: bool,
|
||||||
/// Binding name
|
/// Binding name
|
||||||
pub(crate) name: Name<'src>,
|
pub(crate) name: Name<'src>,
|
||||||
/// Binding value
|
/// Binding value
|
||||||
pub(crate) value: V,
|
pub(crate) value: V,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'src, V> Keyed<'src> for Binding<'src, V> {
|
impl<'src, V> Keyed<'src> for Binding<'src, V> {
|
||||||
|
@ -6,8 +6,8 @@ use atty::Stream;
|
|||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||||
pub(crate) struct Color {
|
pub(crate) struct Color {
|
||||||
use_color: UseColor,
|
use_color: UseColor,
|
||||||
atty: bool,
|
atty: bool,
|
||||||
style: Style,
|
style: Style,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Color {
|
impl Color {
|
||||||
@ -120,8 +120,8 @@ impl Default for Color {
|
|||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
use_color: UseColor::Auto,
|
use_color: UseColor::Auto,
|
||||||
atty: false,
|
atty: false,
|
||||||
style: Style::new(),
|
style: Style::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ use crate::common::*;
|
|||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub(crate) struct CompileError<'src> {
|
pub(crate) struct CompileError<'src> {
|
||||||
pub(crate) token: Token<'src>,
|
pub(crate) token: Token<'src>,
|
||||||
pub(crate) kind: CompileErrorKind<'src>,
|
pub(crate) kind: CompileErrorKind<'src>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'src> CompileError<'src> {
|
impl<'src> CompileError<'src> {
|
||||||
@ -26,11 +26,11 @@ impl Display for CompileError<'_> {
|
|||||||
alias,
|
alias,
|
||||||
recipe_line.ordinal(),
|
recipe_line.ordinal(),
|
||||||
)?;
|
)?;
|
||||||
},
|
}
|
||||||
BacktickShebang => {
|
BacktickShebang => {
|
||||||
write!(f, "Backticks may not start with `#!`")?;
|
write!(f, "Backticks may not start with `#!`")?;
|
||||||
},
|
}
|
||||||
CircularRecipeDependency { recipe, ref circle } =>
|
CircularRecipeDependency { recipe, ref circle } => {
|
||||||
if circle.len() == 2 {
|
if circle.len() == 2 {
|
||||||
write!(f, "Recipe `{}` depends on itself", recipe)?;
|
write!(f, "Recipe `{}` depends on itself", recipe)?;
|
||||||
} else {
|
} else {
|
||||||
@ -40,11 +40,12 @@ impl Display for CompileError<'_> {
|
|||||||
recipe,
|
recipe,
|
||||||
circle.join(" -> ")
|
circle.join(" -> ")
|
||||||
)?;
|
)?;
|
||||||
},
|
}
|
||||||
|
}
|
||||||
CircularVariableDependency {
|
CircularVariableDependency {
|
||||||
variable,
|
variable,
|
||||||
ref circle,
|
ref circle,
|
||||||
} =>
|
} => {
|
||||||
if circle.len() == 2 {
|
if circle.len() == 2 {
|
||||||
write!(f, "Variable `{}` is defined in terms of itself", variable)?;
|
write!(f, "Variable `{}` is defined in terms of itself", variable)?;
|
||||||
} else {
|
} else {
|
||||||
@ -54,7 +55,8 @@ impl Display for CompileError<'_> {
|
|||||||
variable,
|
variable,
|
||||||
circle.join(" -> ")
|
circle.join(" -> ")
|
||||||
)?;
|
)?;
|
||||||
},
|
}
|
||||||
|
}
|
||||||
DependencyArgumentCountMismatch {
|
DependencyArgumentCountMismatch {
|
||||||
dependency,
|
dependency,
|
||||||
found,
|
found,
|
||||||
@ -77,7 +79,7 @@ impl Display for CompileError<'_> {
|
|||||||
} else {
|
} else {
|
||||||
write!(f, "at most {} {}", max, Count("argument", *max))?;
|
write!(f, "at most {} {}", max, Count("argument", *max))?;
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
DeprecatedEquals => {
|
DeprecatedEquals => {
|
||||||
writeln!(
|
writeln!(
|
||||||
f,
|
f,
|
||||||
@ -87,7 +89,7 @@ impl Display for CompileError<'_> {
|
|||||||
f,
|
f,
|
||||||
"Please see this issue for more details: https://github.com/casey/just/issues/379"
|
"Please see this issue for more details: https://github.com/casey/just/issues/379"
|
||||||
)?;
|
)?;
|
||||||
},
|
}
|
||||||
DuplicateAlias { alias, first } => {
|
DuplicateAlias { alias, first } => {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
@ -96,14 +98,14 @@ impl Display for CompileError<'_> {
|
|||||||
first.ordinal(),
|
first.ordinal(),
|
||||||
self.token.line.ordinal(),
|
self.token.line.ordinal(),
|
||||||
)?;
|
)?;
|
||||||
},
|
}
|
||||||
DuplicateParameter { recipe, parameter } => {
|
DuplicateParameter { recipe, parameter } => {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"Recipe `{}` has duplicate parameter `{}`",
|
"Recipe `{}` has duplicate parameter `{}`",
|
||||||
recipe, parameter
|
recipe, parameter
|
||||||
)?;
|
)?;
|
||||||
},
|
}
|
||||||
DuplicateRecipe { recipe, first } => {
|
DuplicateRecipe { recipe, first } => {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
@ -112,7 +114,7 @@ impl Display for CompileError<'_> {
|
|||||||
first.ordinal(),
|
first.ordinal(),
|
||||||
self.token.line.ordinal()
|
self.token.line.ordinal()
|
||||||
)?;
|
)?;
|
||||||
},
|
}
|
||||||
DuplicateSet { setting, first } => {
|
DuplicateSet { setting, first } => {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
@ -121,10 +123,10 @@ impl Display for CompileError<'_> {
|
|||||||
first.ordinal(),
|
first.ordinal(),
|
||||||
self.token.line.ordinal(),
|
self.token.line.ordinal(),
|
||||||
)?;
|
)?;
|
||||||
},
|
}
|
||||||
DuplicateVariable { variable } => {
|
DuplicateVariable { variable } => {
|
||||||
write!(f, "Variable `{}` has multiple definitions", variable)?;
|
write!(f, "Variable `{}` has multiple definitions", variable)?;
|
||||||
},
|
}
|
||||||
ExpectedKeyword { expected, found } => write!(
|
ExpectedKeyword { expected, found } => write!(
|
||||||
f,
|
f,
|
||||||
"Expected keyword {} but found identifier `{}`",
|
"Expected keyword {} but found identifier `{}`",
|
||||||
@ -133,7 +135,7 @@ impl Display for CompileError<'_> {
|
|||||||
)?,
|
)?,
|
||||||
ExtraLeadingWhitespace => {
|
ExtraLeadingWhitespace => {
|
||||||
write!(f, "Recipe line has extra leading whitespace")?;
|
write!(f, "Recipe line has extra leading whitespace")?;
|
||||||
},
|
}
|
||||||
FunctionArgumentCountMismatch {
|
FunctionArgumentCountMismatch {
|
||||||
function,
|
function,
|
||||||
found,
|
found,
|
||||||
@ -147,7 +149,7 @@ impl Display for CompileError<'_> {
|
|||||||
Count("argument", *found),
|
Count("argument", *found),
|
||||||
expected
|
expected
|
||||||
)?;
|
)?;
|
||||||
},
|
}
|
||||||
InconsistentLeadingWhitespace { expected, found } => {
|
InconsistentLeadingWhitespace { expected, found } => {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
@ -156,7 +158,7 @@ impl Display for CompileError<'_> {
|
|||||||
ShowWhitespace(expected),
|
ShowWhitespace(expected),
|
||||||
ShowWhitespace(found)
|
ShowWhitespace(found)
|
||||||
)?;
|
)?;
|
||||||
},
|
}
|
||||||
Internal { ref message } => {
|
Internal { ref message } => {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
@ -164,7 +166,7 @@ impl Display for CompileError<'_> {
|
|||||||
consider filing an issue: https://github.com/casey/just/issues/new",
|
consider filing an issue: https://github.com/casey/just/issues/new",
|
||||||
message
|
message
|
||||||
)?;
|
)?;
|
||||||
},
|
}
|
||||||
InvalidEscapeSequence { character } => {
|
InvalidEscapeSequence { character } => {
|
||||||
let representation = match character {
|
let representation = match character {
|
||||||
'`' => r"\`".to_owned(),
|
'`' => r"\`".to_owned(),
|
||||||
@ -174,7 +176,7 @@ impl Display for CompileError<'_> {
|
|||||||
_ => character.escape_default().collect(),
|
_ => character.escape_default().collect(),
|
||||||
};
|
};
|
||||||
write!(f, "`\\{}` is not a valid escape sequence", representation)?;
|
write!(f, "`\\{}` is not a valid escape sequence", representation)?;
|
||||||
},
|
}
|
||||||
MismatchedClosingDelimiter {
|
MismatchedClosingDelimiter {
|
||||||
open,
|
open,
|
||||||
open_line,
|
open_line,
|
||||||
@ -187,7 +189,7 @@ impl Display for CompileError<'_> {
|
|||||||
open.open(),
|
open.open(),
|
||||||
open_line.ordinal(),
|
open_line.ordinal(),
|
||||||
)?;
|
)?;
|
||||||
},
|
}
|
||||||
MixedLeadingWhitespace { whitespace } => {
|
MixedLeadingWhitespace { whitespace } => {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
@ -195,73 +197,73 @@ impl Display for CompileError<'_> {
|
|||||||
consist of tabs or spaces, but not both",
|
consist of tabs or spaces, but not both",
|
||||||
ShowWhitespace(whitespace)
|
ShowWhitespace(whitespace)
|
||||||
)?;
|
)?;
|
||||||
},
|
}
|
||||||
ParameterFollowsVariadicParameter { parameter } => {
|
ParameterFollowsVariadicParameter { parameter } => {
|
||||||
write!(f, "Parameter `{}` follows variadic parameter", parameter)?;
|
write!(f, "Parameter `{}` follows variadic parameter", parameter)?;
|
||||||
},
|
}
|
||||||
ParameterShadowsVariable { parameter } => {
|
ParameterShadowsVariable { parameter } => {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"Parameter `{}` shadows variable of the same name",
|
"Parameter `{}` shadows variable of the same name",
|
||||||
parameter
|
parameter
|
||||||
)?;
|
)?;
|
||||||
},
|
}
|
||||||
RequiredParameterFollowsDefaultParameter { parameter } => {
|
RequiredParameterFollowsDefaultParameter { parameter } => {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"Non-default parameter `{}` follows default parameter",
|
"Non-default parameter `{}` follows default parameter",
|
||||||
parameter
|
parameter
|
||||||
)?;
|
)?;
|
||||||
},
|
}
|
||||||
UndefinedVariable { variable } => {
|
UndefinedVariable { variable } => {
|
||||||
write!(f, "Variable `{}` not defined", variable)?;
|
write!(f, "Variable `{}` not defined", variable)?;
|
||||||
},
|
}
|
||||||
UnexpectedCharacter { expected } => {
|
UnexpectedCharacter { expected } => {
|
||||||
write!(f, "Expected character `{}`", expected)?;
|
write!(f, "Expected character `{}`", expected)?;
|
||||||
},
|
}
|
||||||
UnexpectedClosingDelimiter { close } => {
|
UnexpectedClosingDelimiter { close } => {
|
||||||
write!(f, "Unexpected closing delimiter `{}`", close.close())?;
|
write!(f, "Unexpected closing delimiter `{}`", close.close())?;
|
||||||
},
|
}
|
||||||
UnexpectedEndOfToken { expected } => {
|
UnexpectedEndOfToken { expected } => {
|
||||||
write!(f, "Expected character `{}` but found end-of-file", expected)?;
|
write!(f, "Expected character `{}` but found end-of-file", expected)?;
|
||||||
},
|
}
|
||||||
UnexpectedToken {
|
UnexpectedToken {
|
||||||
ref expected,
|
ref expected,
|
||||||
found,
|
found,
|
||||||
} => {
|
} => {
|
||||||
write!(f, "Expected {}, but found {}", List::or(expected), found)?;
|
write!(f, "Expected {}, but found {}", List::or(expected), found)?;
|
||||||
},
|
}
|
||||||
UnknownAliasTarget { alias, target } => {
|
UnknownAliasTarget { alias, target } => {
|
||||||
write!(f, "Alias `{}` has an unknown target `{}`", alias, target)?;
|
write!(f, "Alias `{}` has an unknown target `{}`", alias, target)?;
|
||||||
},
|
}
|
||||||
UnknownDependency { recipe, unknown } => {
|
UnknownDependency { recipe, unknown } => {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"Recipe `{}` has unknown dependency `{}`",
|
"Recipe `{}` has unknown dependency `{}`",
|
||||||
recipe, unknown
|
recipe, unknown
|
||||||
)?;
|
)?;
|
||||||
},
|
}
|
||||||
UnknownFunction { function } => {
|
UnknownFunction { function } => {
|
||||||
write!(f, "Call to unknown function `{}`", function)?;
|
write!(f, "Call to unknown function `{}`", function)?;
|
||||||
},
|
}
|
||||||
UnknownSetting { setting } => {
|
UnknownSetting { setting } => {
|
||||||
write!(f, "Unknown setting `{}`", setting)?;
|
write!(f, "Unknown setting `{}`", setting)?;
|
||||||
},
|
}
|
||||||
UnknownStartOfToken => {
|
UnknownStartOfToken => {
|
||||||
write!(f, "Unknown start of token:")?;
|
write!(f, "Unknown start of token:")?;
|
||||||
},
|
}
|
||||||
UnpairedCarriageReturn => {
|
UnpairedCarriageReturn => {
|
||||||
write!(f, "Unpaired carriage return")?;
|
write!(f, "Unpaired carriage return")?;
|
||||||
},
|
}
|
||||||
UnterminatedBacktick => {
|
UnterminatedBacktick => {
|
||||||
write!(f, "Unterminated backtick")?;
|
write!(f, "Unterminated backtick")?;
|
||||||
},
|
}
|
||||||
UnterminatedInterpolation => {
|
UnterminatedInterpolation => {
|
||||||
write!(f, "Unterminated interpolation")?;
|
write!(f, "Unterminated interpolation")?;
|
||||||
},
|
}
|
||||||
UnterminatedString => {
|
UnterminatedString => {
|
||||||
write!(f, "Unterminated string")?;
|
write!(f, "Unterminated string")?;
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -3,7 +3,7 @@ use crate::common::*;
|
|||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub(crate) enum CompileErrorKind<'src> {
|
pub(crate) enum CompileErrorKind<'src> {
|
||||||
AliasShadowsRecipe {
|
AliasShadowsRecipe {
|
||||||
alias: &'src str,
|
alias: &'src str,
|
||||||
recipe_line: usize,
|
recipe_line: usize,
|
||||||
},
|
},
|
||||||
BacktickShebang,
|
BacktickShebang,
|
||||||
@ -13,13 +13,13 @@ pub(crate) enum CompileErrorKind<'src> {
|
|||||||
},
|
},
|
||||||
CircularVariableDependency {
|
CircularVariableDependency {
|
||||||
variable: &'src str,
|
variable: &'src str,
|
||||||
circle: Vec<&'src str>,
|
circle: Vec<&'src str>,
|
||||||
},
|
},
|
||||||
DependencyArgumentCountMismatch {
|
DependencyArgumentCountMismatch {
|
||||||
dependency: &'src str,
|
dependency: &'src str,
|
||||||
found: usize,
|
found: usize,
|
||||||
min: usize,
|
min: usize,
|
||||||
max: usize,
|
max: usize,
|
||||||
},
|
},
|
||||||
DeprecatedEquals,
|
DeprecatedEquals,
|
||||||
DuplicateAlias {
|
DuplicateAlias {
|
||||||
@ -27,33 +27,33 @@ pub(crate) enum CompileErrorKind<'src> {
|
|||||||
first: usize,
|
first: usize,
|
||||||
},
|
},
|
||||||
DuplicateParameter {
|
DuplicateParameter {
|
||||||
recipe: &'src str,
|
recipe: &'src str,
|
||||||
parameter: &'src str,
|
parameter: &'src str,
|
||||||
},
|
},
|
||||||
DuplicateRecipe {
|
DuplicateRecipe {
|
||||||
recipe: &'src str,
|
recipe: &'src str,
|
||||||
first: usize,
|
first: usize,
|
||||||
},
|
},
|
||||||
DuplicateSet {
|
DuplicateSet {
|
||||||
setting: &'src str,
|
setting: &'src str,
|
||||||
first: usize,
|
first: usize,
|
||||||
},
|
},
|
||||||
DuplicateVariable {
|
DuplicateVariable {
|
||||||
variable: &'src str,
|
variable: &'src str,
|
||||||
},
|
},
|
||||||
ExpectedKeyword {
|
ExpectedKeyword {
|
||||||
expected: Vec<Keyword>,
|
expected: Vec<Keyword>,
|
||||||
found: &'src str,
|
found: &'src str,
|
||||||
},
|
},
|
||||||
ExtraLeadingWhitespace,
|
ExtraLeadingWhitespace,
|
||||||
FunctionArgumentCountMismatch {
|
FunctionArgumentCountMismatch {
|
||||||
function: &'src str,
|
function: &'src str,
|
||||||
found: usize,
|
found: usize,
|
||||||
expected: usize,
|
expected: usize,
|
||||||
},
|
},
|
||||||
InconsistentLeadingWhitespace {
|
InconsistentLeadingWhitespace {
|
||||||
expected: &'src str,
|
expected: &'src str,
|
||||||
found: &'src str,
|
found: &'src str,
|
||||||
},
|
},
|
||||||
Internal {
|
Internal {
|
||||||
message: String,
|
message: String,
|
||||||
@ -62,8 +62,8 @@ pub(crate) enum CompileErrorKind<'src> {
|
|||||||
character: char,
|
character: char,
|
||||||
},
|
},
|
||||||
MismatchedClosingDelimiter {
|
MismatchedClosingDelimiter {
|
||||||
close: Delimiter,
|
close: Delimiter,
|
||||||
open: Delimiter,
|
open: Delimiter,
|
||||||
open_line: usize,
|
open_line: usize,
|
||||||
},
|
},
|
||||||
MixedLeadingWhitespace {
|
MixedLeadingWhitespace {
|
||||||
@ -92,14 +92,14 @@ pub(crate) enum CompileErrorKind<'src> {
|
|||||||
},
|
},
|
||||||
UnexpectedToken {
|
UnexpectedToken {
|
||||||
expected: Vec<TokenKind>,
|
expected: Vec<TokenKind>,
|
||||||
found: TokenKind,
|
found: TokenKind,
|
||||||
},
|
},
|
||||||
UnknownAliasTarget {
|
UnknownAliasTarget {
|
||||||
alias: &'src str,
|
alias: &'src str,
|
||||||
target: &'src str,
|
target: &'src str,
|
||||||
},
|
},
|
||||||
UnknownDependency {
|
UnknownDependency {
|
||||||
recipe: &'src str,
|
recipe: &'src str,
|
||||||
unknown: &'src str,
|
unknown: &'src str,
|
||||||
},
|
},
|
||||||
UnknownFunction {
|
UnknownFunction {
|
||||||
|
@ -14,24 +14,24 @@ pub(crate) const DEFAULT_SHELL_ARG: &str = "-cu";
|
|||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub(crate) struct Config {
|
pub(crate) struct Config {
|
||||||
pub(crate) color: Color,
|
pub(crate) color: Color,
|
||||||
pub(crate) dry_run: bool,
|
pub(crate) dry_run: bool,
|
||||||
pub(crate) highlight: bool,
|
pub(crate) highlight: bool,
|
||||||
pub(crate) invocation_directory: PathBuf,
|
pub(crate) invocation_directory: PathBuf,
|
||||||
pub(crate) list_heading: String,
|
pub(crate) list_heading: String,
|
||||||
pub(crate) list_prefix: String,
|
pub(crate) list_prefix: String,
|
||||||
pub(crate) load_dotenv: bool,
|
pub(crate) load_dotenv: bool,
|
||||||
pub(crate) search_config: SearchConfig,
|
pub(crate) search_config: SearchConfig,
|
||||||
pub(crate) shell: String,
|
pub(crate) shell: String,
|
||||||
pub(crate) shell_args: Vec<String>,
|
pub(crate) shell_args: Vec<String>,
|
||||||
pub(crate) shell_command: bool,
|
pub(crate) shell_command: bool,
|
||||||
pub(crate) shell_present: bool,
|
pub(crate) shell_present: bool,
|
||||||
pub(crate) subcommand: Subcommand,
|
pub(crate) subcommand: Subcommand,
|
||||||
pub(crate) unsorted: bool,
|
pub(crate) unsorted: bool,
|
||||||
pub(crate) unstable: bool,
|
pub(crate) unstable: bool,
|
||||||
pub(crate) dotenv_filename: Option<String>,
|
pub(crate) dotenv_filename: Option<String>,
|
||||||
pub(crate) dotenv_path: Option<PathBuf>,
|
pub(crate) dotenv_path: Option<PathBuf>,
|
||||||
pub(crate) verbosity: Verbosity,
|
pub(crate) verbosity: Verbosity,
|
||||||
}
|
}
|
||||||
|
|
||||||
mod cmd {
|
mod cmd {
|
||||||
@ -416,15 +416,17 @@ impl Config {
|
|||||||
match (justfile, working_directory) {
|
match (justfile, working_directory) {
|
||||||
(None, None) => SearchConfig::FromInvocationDirectory,
|
(None, None) => SearchConfig::FromInvocationDirectory,
|
||||||
(Some(justfile), None) => SearchConfig::WithJustfile { justfile },
|
(Some(justfile), None) => SearchConfig::WithJustfile { justfile },
|
||||||
(Some(justfile), Some(working_directory)) =>
|
(Some(justfile), Some(working_directory)) => {
|
||||||
SearchConfig::WithJustfileAndWorkingDirectory {
|
SearchConfig::WithJustfileAndWorkingDirectory {
|
||||||
justfile,
|
justfile,
|
||||||
working_directory,
|
working_directory,
|
||||||
},
|
}
|
||||||
(None, Some(_)) =>
|
}
|
||||||
|
(None, Some(_)) => {
|
||||||
return Err(ConfigError::internal(
|
return Err(ConfigError::internal(
|
||||||
"--working-directory set without --justfile",
|
"--working-directory set without --justfile",
|
||||||
)),
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -432,26 +434,26 @@ impl Config {
|
|||||||
for subcommand in cmd::ARGLESS {
|
for subcommand in cmd::ARGLESS {
|
||||||
if matches.is_present(subcommand) {
|
if matches.is_present(subcommand) {
|
||||||
match (!overrides.is_empty(), !positional.arguments.is_empty()) {
|
match (!overrides.is_empty(), !positional.arguments.is_empty()) {
|
||||||
(false, false) => {},
|
(false, false) => {}
|
||||||
(true, false) => {
|
(true, false) => {
|
||||||
return Err(ConfigError::SubcommandOverrides {
|
return Err(ConfigError::SubcommandOverrides {
|
||||||
subcommand,
|
subcommand,
|
||||||
overrides,
|
overrides,
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
(false, true) => {
|
(false, true) => {
|
||||||
return Err(ConfigError::SubcommandArguments {
|
return Err(ConfigError::SubcommandArguments {
|
||||||
arguments: positional.arguments,
|
arguments: positional.arguments,
|
||||||
subcommand,
|
subcommand,
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
(true, true) => {
|
(true, true) => {
|
||||||
return Err(ConfigError::SubcommandOverridesAndArguments {
|
return Err(ConfigError::SubcommandOverridesAndArguments {
|
||||||
arguments: positional.arguments,
|
arguments: positional.arguments,
|
||||||
subcommand,
|
subcommand,
|
||||||
overrides,
|
overrides,
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -497,7 +499,7 @@ impl Config {
|
|||||||
if positional.arguments.len() > 1 {
|
if positional.arguments.len() > 1 {
|
||||||
return Err(ConfigError::SubcommandArguments {
|
return Err(ConfigError::SubcommandArguments {
|
||||||
subcommand: cmd::EVALUATE,
|
subcommand: cmd::EVALUATE,
|
||||||
arguments: positional
|
arguments: positional
|
||||||
.arguments
|
.arguments
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.skip(1)
|
.skip(1)
|
||||||
|
@ -23,7 +23,7 @@ pub(crate) enum ConfigError {
|
|||||||
))]
|
))]
|
||||||
SubcommandArguments {
|
SubcommandArguments {
|
||||||
subcommand: &'static str,
|
subcommand: &'static str,
|
||||||
arguments: Vec<String>,
|
arguments: Vec<String>,
|
||||||
},
|
},
|
||||||
#[snafu(display(
|
#[snafu(display(
|
||||||
"`--{}` used with unexpected overrides: {}",
|
"`--{}` used with unexpected overrides: {}",
|
||||||
@ -32,7 +32,7 @@ pub(crate) enum ConfigError {
|
|||||||
))]
|
))]
|
||||||
SubcommandOverrides {
|
SubcommandOverrides {
|
||||||
subcommand: &'static str,
|
subcommand: &'static str,
|
||||||
overrides: BTreeMap<String, String>,
|
overrides: BTreeMap<String, String>,
|
||||||
},
|
},
|
||||||
#[snafu(display(
|
#[snafu(display(
|
||||||
"`--{}` used with unexpected overrides: {}; and arguments: {}",
|
"`--{}` used with unexpected overrides: {}; and arguments: {}",
|
||||||
@ -42,8 +42,8 @@ pub(crate) enum ConfigError {
|
|||||||
]
|
]
|
||||||
SubcommandOverridesAndArguments {
|
SubcommandOverridesAndArguments {
|
||||||
subcommand: &'static str,
|
subcommand: &'static str,
|
||||||
overrides: BTreeMap<String, String>,
|
overrides: BTreeMap<String, String>,
|
||||||
arguments: Vec<String>,
|
arguments: Vec<String>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ use crate::common::*;
|
|||||||
|
|
||||||
#[derive(PartialEq, Debug)]
|
#[derive(PartialEq, Debug)]
|
||||||
pub(crate) struct Dependency<'src> {
|
pub(crate) struct Dependency<'src> {
|
||||||
pub(crate) recipe: Rc<Recipe<'src>>,
|
pub(crate) recipe: Rc<Recipe<'src>>,
|
||||||
pub(crate) arguments: Vec<Expression<'src>>,
|
pub(crate) arguments: Vec<Expression<'src>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ use crate::common::*;
|
|||||||
|
|
||||||
pub struct Enclosure<T: Display> {
|
pub struct Enclosure<T: Display> {
|
||||||
enclosure: &'static str,
|
enclosure: &'static str,
|
||||||
value: T,
|
value: T,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Display> Enclosure<T> {
|
impl<T: Display> Enclosure<T> {
|
||||||
|
151
src/error.rs
151
src/error.rs
@ -3,48 +3,48 @@ use crate::common::*;
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) enum Error<'src> {
|
pub(crate) enum Error<'src> {
|
||||||
ArgumentCountMismatch {
|
ArgumentCountMismatch {
|
||||||
recipe: &'src str,
|
recipe: &'src str,
|
||||||
parameters: Vec<Parameter<'src>>,
|
parameters: Vec<Parameter<'src>>,
|
||||||
found: usize,
|
found: usize,
|
||||||
min: usize,
|
min: usize,
|
||||||
max: usize,
|
max: usize,
|
||||||
},
|
},
|
||||||
Backtick {
|
Backtick {
|
||||||
token: Token<'src>,
|
token: Token<'src>,
|
||||||
output_error: OutputError,
|
output_error: OutputError,
|
||||||
},
|
},
|
||||||
ChooserInvoke {
|
ChooserInvoke {
|
||||||
shell_binary: String,
|
shell_binary: String,
|
||||||
shell_arguments: String,
|
shell_arguments: String,
|
||||||
chooser: OsString,
|
chooser: OsString,
|
||||||
io_error: io::Error,
|
io_error: io::Error,
|
||||||
},
|
},
|
||||||
ChooserRead {
|
ChooserRead {
|
||||||
chooser: OsString,
|
chooser: OsString,
|
||||||
io_error: io::Error,
|
io_error: io::Error,
|
||||||
},
|
},
|
||||||
ChooserStatus {
|
ChooserStatus {
|
||||||
chooser: OsString,
|
chooser: OsString,
|
||||||
status: ExitStatus,
|
status: ExitStatus,
|
||||||
},
|
},
|
||||||
ChooserWrite {
|
ChooserWrite {
|
||||||
chooser: OsString,
|
chooser: OsString,
|
||||||
io_error: io::Error,
|
io_error: io::Error,
|
||||||
},
|
},
|
||||||
Code {
|
Code {
|
||||||
recipe: &'src str,
|
recipe: &'src str,
|
||||||
line_number: Option<usize>,
|
line_number: Option<usize>,
|
||||||
code: i32,
|
code: i32,
|
||||||
},
|
},
|
||||||
CommandInvoke {
|
CommandInvoke {
|
||||||
binary: OsString,
|
binary: OsString,
|
||||||
arguments: Vec<OsString>,
|
arguments: Vec<OsString>,
|
||||||
io_error: io::Error,
|
io_error: io::Error,
|
||||||
},
|
},
|
||||||
CommandStatus {
|
CommandStatus {
|
||||||
binary: OsString,
|
binary: OsString,
|
||||||
arguments: Vec<OsString>,
|
arguments: Vec<OsString>,
|
||||||
status: ExitStatus,
|
status: ExitStatus,
|
||||||
},
|
},
|
||||||
Compile {
|
Compile {
|
||||||
compile_error: CompileError<'src>,
|
compile_error: CompileError<'src>,
|
||||||
@ -53,18 +53,18 @@ pub(crate) enum Error<'src> {
|
|||||||
config_error: ConfigError,
|
config_error: ConfigError,
|
||||||
},
|
},
|
||||||
Cygpath {
|
Cygpath {
|
||||||
recipe: &'src str,
|
recipe: &'src str,
|
||||||
output_error: OutputError,
|
output_error: OutputError,
|
||||||
},
|
},
|
||||||
DefaultRecipeRequiresArguments {
|
DefaultRecipeRequiresArguments {
|
||||||
recipe: &'src str,
|
recipe: &'src str,
|
||||||
min_arguments: usize,
|
min_arguments: usize,
|
||||||
},
|
},
|
||||||
Dotenv {
|
Dotenv {
|
||||||
dotenv_error: dotenv::Error,
|
dotenv_error: dotenv::Error,
|
||||||
},
|
},
|
||||||
EditorInvoke {
|
EditorInvoke {
|
||||||
editor: OsString,
|
editor: OsString,
|
||||||
io_error: io::Error,
|
io_error: io::Error,
|
||||||
},
|
},
|
||||||
EditorStatus {
|
EditorStatus {
|
||||||
@ -72,12 +72,12 @@ pub(crate) enum Error<'src> {
|
|||||||
status: ExitStatus,
|
status: ExitStatus,
|
||||||
},
|
},
|
||||||
EvalUnknownVariable {
|
EvalUnknownVariable {
|
||||||
variable: String,
|
variable: String,
|
||||||
suggestion: Option<Suggestion<'src>>,
|
suggestion: Option<Suggestion<'src>>,
|
||||||
},
|
},
|
||||||
FunctionCall {
|
FunctionCall {
|
||||||
function: Name<'src>,
|
function: Name<'src>,
|
||||||
message: String,
|
message: String,
|
||||||
},
|
},
|
||||||
InitExists {
|
InitExists {
|
||||||
justfile: PathBuf,
|
justfile: PathBuf,
|
||||||
@ -86,11 +86,11 @@ pub(crate) enum Error<'src> {
|
|||||||
message: String,
|
message: String,
|
||||||
},
|
},
|
||||||
Io {
|
Io {
|
||||||
recipe: &'src str,
|
recipe: &'src str,
|
||||||
io_error: io::Error,
|
io_error: io::Error,
|
||||||
},
|
},
|
||||||
Load {
|
Load {
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
io_error: io::Error,
|
io_error: io::Error,
|
||||||
},
|
},
|
||||||
NoChoosableRecipes,
|
NoChoosableRecipes,
|
||||||
@ -99,29 +99,29 @@ pub(crate) enum Error<'src> {
|
|||||||
search_error: SearchError,
|
search_error: SearchError,
|
||||||
},
|
},
|
||||||
Shebang {
|
Shebang {
|
||||||
recipe: &'src str,
|
recipe: &'src str,
|
||||||
command: String,
|
command: String,
|
||||||
argument: Option<String>,
|
argument: Option<String>,
|
||||||
io_error: io::Error,
|
io_error: io::Error,
|
||||||
},
|
},
|
||||||
Signal {
|
Signal {
|
||||||
recipe: &'src str,
|
recipe: &'src str,
|
||||||
line_number: Option<usize>,
|
line_number: Option<usize>,
|
||||||
signal: i32,
|
signal: i32,
|
||||||
},
|
},
|
||||||
TmpdirIo {
|
TmpdirIo {
|
||||||
recipe: &'src str,
|
recipe: &'src str,
|
||||||
io_error: io::Error,
|
io_error: io::Error,
|
||||||
},
|
},
|
||||||
Unknown {
|
Unknown {
|
||||||
recipe: &'src str,
|
recipe: &'src str,
|
||||||
line_number: Option<usize>,
|
line_number: Option<usize>,
|
||||||
},
|
},
|
||||||
UnknownOverrides {
|
UnknownOverrides {
|
||||||
overrides: Vec<String>,
|
overrides: Vec<String>,
|
||||||
},
|
},
|
||||||
UnknownRecipes {
|
UnknownRecipes {
|
||||||
recipes: Vec<String>,
|
recipes: Vec<String>,
|
||||||
suggestion: Option<Suggestion<'src>>,
|
suggestion: Option<Suggestion<'src>>,
|
||||||
},
|
},
|
||||||
Unstable {
|
Unstable {
|
||||||
@ -204,7 +204,7 @@ impl<'src> ColorDisplay for Error<'src> {
|
|||||||
min,
|
min,
|
||||||
max,
|
max,
|
||||||
..
|
..
|
||||||
} =>
|
} => {
|
||||||
if min == max {
|
if min == max {
|
||||||
let expected = min;
|
let expected = min;
|
||||||
write!(
|
write!(
|
||||||
@ -234,17 +234,18 @@ impl<'src> ColorDisplay for Error<'src> {
|
|||||||
Count("argument", *found),
|
Count("argument", *found),
|
||||||
max
|
max
|
||||||
)?;
|
)?;
|
||||||
},
|
}
|
||||||
|
}
|
||||||
Backtick { output_error, .. } => match output_error {
|
Backtick { output_error, .. } => match output_error {
|
||||||
OutputError::Code(code) => {
|
OutputError::Code(code) => {
|
||||||
write!(f, "Backtick failed with exit code {}", code)?;
|
write!(f, "Backtick failed with exit code {}", code)?;
|
||||||
},
|
}
|
||||||
OutputError::Signal(signal) => {
|
OutputError::Signal(signal) => {
|
||||||
write!(f, "Backtick was terminated by signal {}", signal)?;
|
write!(f, "Backtick was terminated by signal {}", signal)?;
|
||||||
},
|
}
|
||||||
OutputError::Unknown => {
|
OutputError::Unknown => {
|
||||||
write!(f, "Backtick failed for an unknown reason")?;
|
write!(f, "Backtick failed for an unknown reason")?;
|
||||||
},
|
}
|
||||||
OutputError::Io(io_error) => {
|
OutputError::Io(io_error) => {
|
||||||
match io_error.kind() {
|
match io_error.kind() {
|
||||||
io::ErrorKind::NotFound => write!(
|
io::ErrorKind::NotFound => write!(
|
||||||
@ -263,14 +264,14 @@ impl<'src> ColorDisplay for Error<'src> {
|
|||||||
io_error
|
io_error
|
||||||
),
|
),
|
||||||
}?;
|
}?;
|
||||||
},
|
}
|
||||||
OutputError::Utf8(utf8_error) => {
|
OutputError::Utf8(utf8_error) => {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"Backtick succeeded but stdout was not utf8: {}",
|
"Backtick succeeded but stdout was not utf8: {}",
|
||||||
utf8_error
|
utf8_error
|
||||||
)?;
|
)?;
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
ChooserInvoke {
|
ChooserInvoke {
|
||||||
shell_binary,
|
shell_binary,
|
||||||
@ -286,7 +287,7 @@ impl<'src> ColorDisplay for Error<'src> {
|
|||||||
chooser.to_string_lossy(),
|
chooser.to_string_lossy(),
|
||||||
io_error,
|
io_error,
|
||||||
)?;
|
)?;
|
||||||
},
|
}
|
||||||
ChooserRead { chooser, io_error } => {
|
ChooserRead { chooser, io_error } => {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
@ -294,7 +295,7 @@ impl<'src> ColorDisplay for Error<'src> {
|
|||||||
chooser.to_string_lossy(),
|
chooser.to_string_lossy(),
|
||||||
io_error
|
io_error
|
||||||
)?;
|
)?;
|
||||||
},
|
}
|
||||||
ChooserStatus { chooser, status } => {
|
ChooserStatus { chooser, status } => {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
@ -302,7 +303,7 @@ impl<'src> ColorDisplay for Error<'src> {
|
|||||||
chooser.to_string_lossy(),
|
chooser.to_string_lossy(),
|
||||||
status
|
status
|
||||||
)?;
|
)?;
|
||||||
},
|
}
|
||||||
ChooserWrite { chooser, io_error } => {
|
ChooserWrite { chooser, io_error } => {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
@ -310,12 +311,12 @@ impl<'src> ColorDisplay for Error<'src> {
|
|||||||
chooser.to_string_lossy(),
|
chooser.to_string_lossy(),
|
||||||
io_error
|
io_error
|
||||||
)?;
|
)?;
|
||||||
},
|
}
|
||||||
Code {
|
Code {
|
||||||
recipe,
|
recipe,
|
||||||
line_number,
|
line_number,
|
||||||
code,
|
code,
|
||||||
} =>
|
} => {
|
||||||
if let Some(n) = line_number {
|
if let Some(n) = line_number {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
@ -324,7 +325,8 @@ impl<'src> ColorDisplay for Error<'src> {
|
|||||||
)?;
|
)?;
|
||||||
} else {
|
} else {
|
||||||
write!(f, "Recipe `{}` failed with exit code {}", recipe, code)?;
|
write!(f, "Recipe `{}` failed with exit code {}", recipe, code)?;
|
||||||
},
|
}
|
||||||
|
}
|
||||||
CommandInvoke {
|
CommandInvoke {
|
||||||
binary,
|
binary,
|
||||||
arguments,
|
arguments,
|
||||||
@ -340,7 +342,7 @@ impl<'src> ColorDisplay for Error<'src> {
|
|||||||
.join(" "),
|
.join(" "),
|
||||||
io_error,
|
io_error,
|
||||||
)?;
|
)?;
|
||||||
},
|
}
|
||||||
CommandStatus {
|
CommandStatus {
|
||||||
binary,
|
binary,
|
||||||
arguments,
|
arguments,
|
||||||
@ -356,7 +358,7 @@ impl<'src> ColorDisplay for Error<'src> {
|
|||||||
.join(" "),
|
.join(" "),
|
||||||
status,
|
status,
|
||||||
)?;
|
)?;
|
||||||
},
|
}
|
||||||
Compile { compile_error } => Display::fmt(compile_error, f)?,
|
Compile { compile_error } => Display::fmt(compile_error, f)?,
|
||||||
Config { config_error } => Display::fmt(config_error, f)?,
|
Config { config_error } => Display::fmt(config_error, f)?,
|
||||||
Cygpath {
|
Cygpath {
|
||||||
@ -370,7 +372,7 @@ impl<'src> ColorDisplay for Error<'src> {
|
|||||||
path",
|
path",
|
||||||
code, recipe
|
code, recipe
|
||||||
)?;
|
)?;
|
||||||
},
|
}
|
||||||
OutputError::Signal(signal) => {
|
OutputError::Signal(signal) => {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
@ -378,7 +380,7 @@ impl<'src> ColorDisplay for Error<'src> {
|
|||||||
path",
|
path",
|
||||||
signal, recipe
|
signal, recipe
|
||||||
)?;
|
)?;
|
||||||
},
|
}
|
||||||
OutputError::Unknown => {
|
OutputError::Unknown => {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
@ -386,7 +388,7 @@ impl<'src> ColorDisplay for Error<'src> {
|
|||||||
interpreter path",
|
interpreter path",
|
||||||
recipe
|
recipe
|
||||||
)?;
|
)?;
|
||||||
},
|
}
|
||||||
OutputError::Io(io_error) => {
|
OutputError::Io(io_error) => {
|
||||||
match io_error.kind() {
|
match io_error.kind() {
|
||||||
io::ErrorKind::NotFound => write!(
|
io::ErrorKind::NotFound => write!(
|
||||||
@ -403,7 +405,7 @@ impl<'src> ColorDisplay for Error<'src> {
|
|||||||
),
|
),
|
||||||
_ => write!(f, "Could not run `cygpath` executable:\n{}", io_error),
|
_ => write!(f, "Could not run `cygpath` executable:\n{}", io_error),
|
||||||
}?;
|
}?;
|
||||||
},
|
}
|
||||||
OutputError::Utf8(utf8_error) => {
|
OutputError::Utf8(utf8_error) => {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
@ -411,7 +413,7 @@ impl<'src> ColorDisplay for Error<'src> {
|
|||||||
not utf8: {}",
|
not utf8: {}",
|
||||||
recipe, utf8_error
|
recipe, utf8_error
|
||||||
)?;
|
)?;
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
DefaultRecipeRequiresArguments {
|
DefaultRecipeRequiresArguments {
|
||||||
recipe,
|
recipe,
|
||||||
@ -424,10 +426,10 @@ impl<'src> ColorDisplay for Error<'src> {
|
|||||||
min_arguments,
|
min_arguments,
|
||||||
Count("argument", *min_arguments),
|
Count("argument", *min_arguments),
|
||||||
)?;
|
)?;
|
||||||
},
|
}
|
||||||
Dotenv { dotenv_error } => {
|
Dotenv { dotenv_error } => {
|
||||||
write!(f, "Failed to load environment file: {}", dotenv_error)?;
|
write!(f, "Failed to load environment file: {}", dotenv_error)?;
|
||||||
},
|
}
|
||||||
EditorInvoke { editor, io_error } => {
|
EditorInvoke { editor, io_error } => {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
@ -435,7 +437,7 @@ impl<'src> ColorDisplay for Error<'src> {
|
|||||||
editor.to_string_lossy(),
|
editor.to_string_lossy(),
|
||||||
io_error
|
io_error
|
||||||
)?;
|
)?;
|
||||||
},
|
}
|
||||||
EditorStatus { editor, status } => {
|
EditorStatus { editor, status } => {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
@ -443,7 +445,7 @@ impl<'src> ColorDisplay for Error<'src> {
|
|||||||
editor.to_string_lossy(),
|
editor.to_string_lossy(),
|
||||||
status
|
status
|
||||||
)?;
|
)?;
|
||||||
},
|
}
|
||||||
EvalUnknownVariable {
|
EvalUnknownVariable {
|
||||||
variable,
|
variable,
|
||||||
suggestion,
|
suggestion,
|
||||||
@ -452,7 +454,7 @@ impl<'src> ColorDisplay for Error<'src> {
|
|||||||
if let Some(suggestion) = *suggestion {
|
if let Some(suggestion) = *suggestion {
|
||||||
write!(f, "\n{}", suggestion)?;
|
write!(f, "\n{}", suggestion)?;
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
FunctionCall { function, message } => {
|
FunctionCall { function, message } => {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
@ -460,10 +462,10 @@ impl<'src> ColorDisplay for Error<'src> {
|
|||||||
function.lexeme(),
|
function.lexeme(),
|
||||||
message
|
message
|
||||||
)?;
|
)?;
|
||||||
},
|
}
|
||||||
InitExists { justfile } => {
|
InitExists { justfile } => {
|
||||||
write!(f, "Justfile `{}` already exists", justfile.display())?;
|
write!(f, "Justfile `{}` already exists", justfile.display())?;
|
||||||
},
|
}
|
||||||
Internal { message } => {
|
Internal { message } => {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
@ -471,7 +473,7 @@ impl<'src> ColorDisplay for Error<'src> {
|
|||||||
consider filing an issue: https://github.com/casey/just/issues/new",
|
consider filing an issue: https://github.com/casey/just/issues/new",
|
||||||
message
|
message
|
||||||
)?;
|
)?;
|
||||||
},
|
}
|
||||||
Io { recipe, io_error } => {
|
Io { recipe, io_error } => {
|
||||||
match io_error.kind() {
|
match io_error.kind() {
|
||||||
io::ErrorKind::NotFound => write!(
|
io::ErrorKind::NotFound => write!(
|
||||||
@ -490,7 +492,7 @@ impl<'src> ColorDisplay for Error<'src> {
|
|||||||
recipe, io_error
|
recipe, io_error
|
||||||
),
|
),
|
||||||
}?;
|
}?;
|
||||||
},
|
}
|
||||||
Load { io_error, path } => {
|
Load { io_error, path } => {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
@ -498,20 +500,20 @@ impl<'src> ColorDisplay for Error<'src> {
|
|||||||
path.display(),
|
path.display(),
|
||||||
io_error
|
io_error
|
||||||
)?;
|
)?;
|
||||||
},
|
}
|
||||||
NoChoosableRecipes => {
|
NoChoosableRecipes => {
|
||||||
write!(f, "Justfile contains no choosable recipes.")?;
|
write!(f, "Justfile contains no choosable recipes.")?;
|
||||||
},
|
}
|
||||||
NoRecipes => {
|
NoRecipes => {
|
||||||
write!(f, "Justfile contains no recipes.")?;
|
write!(f, "Justfile contains no recipes.")?;
|
||||||
},
|
}
|
||||||
Search { search_error } => Display::fmt(search_error, f)?,
|
Search { search_error } => Display::fmt(search_error, f)?,
|
||||||
Shebang {
|
Shebang {
|
||||||
recipe,
|
recipe,
|
||||||
command,
|
command,
|
||||||
argument,
|
argument,
|
||||||
io_error,
|
io_error,
|
||||||
} =>
|
} => {
|
||||||
if let Some(argument) = argument {
|
if let Some(argument) = argument {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
@ -524,12 +526,13 @@ impl<'src> ColorDisplay for Error<'src> {
|
|||||||
"Recipe `{}` with shebang `#!{}` execution error: {}",
|
"Recipe `{}` with shebang `#!{}` execution error: {}",
|
||||||
recipe, command, io_error
|
recipe, command, io_error
|
||||||
)?;
|
)?;
|
||||||
},
|
}
|
||||||
|
}
|
||||||
Signal {
|
Signal {
|
||||||
recipe,
|
recipe,
|
||||||
line_number,
|
line_number,
|
||||||
signal,
|
signal,
|
||||||
} =>
|
} => {
|
||||||
if let Some(n) = line_number {
|
if let Some(n) = line_number {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
@ -538,7 +541,8 @@ impl<'src> ColorDisplay for Error<'src> {
|
|||||||
)?;
|
)?;
|
||||||
} else {
|
} else {
|
||||||
write!(f, "Recipe `{}` was terminated by signal {}", recipe, signal)?;
|
write!(f, "Recipe `{}` was terminated by signal {}", recipe, signal)?;
|
||||||
},
|
}
|
||||||
|
}
|
||||||
TmpdirIo { recipe, io_error } => write!(
|
TmpdirIo { recipe, io_error } => write!(
|
||||||
f,
|
f,
|
||||||
"Recipe `{}` could not be run because of an IO error while trying to create a temporary \
|
"Recipe `{}` could not be run because of an IO error while trying to create a temporary \
|
||||||
@ -548,7 +552,7 @@ impl<'src> ColorDisplay for Error<'src> {
|
|||||||
Unknown {
|
Unknown {
|
||||||
recipe,
|
recipe,
|
||||||
line_number,
|
line_number,
|
||||||
} =>
|
} => {
|
||||||
if let Some(n) = line_number {
|
if let Some(n) = line_number {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
@ -557,7 +561,8 @@ impl<'src> ColorDisplay for Error<'src> {
|
|||||||
)?;
|
)?;
|
||||||
} else {
|
} else {
|
||||||
write!(f, "Recipe `{}` failed for an unknown reason", recipe)?;
|
write!(f, "Recipe `{}` failed for an unknown reason", recipe)?;
|
||||||
},
|
}
|
||||||
|
}
|
||||||
UnknownOverrides { overrides } => {
|
UnknownOverrides { overrides } => {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
@ -565,7 +570,7 @@ impl<'src> ColorDisplay for Error<'src> {
|
|||||||
Count("Variable", overrides.len()),
|
Count("Variable", overrides.len()),
|
||||||
List::and_ticked(overrides),
|
List::and_ticked(overrides),
|
||||||
)?;
|
)?;
|
||||||
},
|
}
|
||||||
UnknownRecipes {
|
UnknownRecipes {
|
||||||
recipes,
|
recipes,
|
||||||
suggestion,
|
suggestion,
|
||||||
@ -579,14 +584,14 @@ impl<'src> ColorDisplay for Error<'src> {
|
|||||||
if let Some(suggestion) = *suggestion {
|
if let Some(suggestion) = *suggestion {
|
||||||
write!(f, "\n{}", suggestion)?;
|
write!(f, "\n{}", suggestion)?;
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Unstable { message } => {
|
Unstable { message } => {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"{} Invoke `just` with the `--unstable` flag to enable unstable features.",
|
"{} Invoke `just` with the `--unstable` flag to enable unstable features.",
|
||||||
message
|
message
|
||||||
)?;
|
)?;
|
||||||
},
|
}
|
||||||
WriteJustfile { justfile, io_error } => {
|
WriteJustfile { justfile, io_error } => {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
@ -594,7 +599,7 @@ impl<'src> ColorDisplay for Error<'src> {
|
|||||||
justfile.display(),
|
justfile.display(),
|
||||||
io_error
|
io_error
|
||||||
)?;
|
)?;
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
write!(f, "{}", color.message().suffix())?;
|
write!(f, "{}", color.message().suffix())?;
|
||||||
|
@ -2,11 +2,11 @@ use crate::common::*;
|
|||||||
|
|
||||||
pub(crate) struct Evaluator<'src: 'run, 'run> {
|
pub(crate) struct Evaluator<'src: 'run, 'run> {
|
||||||
assignments: Option<&'run Table<'src, Assignment<'src>>>,
|
assignments: Option<&'run Table<'src, Assignment<'src>>>,
|
||||||
config: &'run Config,
|
config: &'run Config,
|
||||||
dotenv: &'run BTreeMap<String, String>,
|
dotenv: &'run BTreeMap<String, String>,
|
||||||
scope: Scope<'src, 'run>,
|
scope: Scope<'src, 'run>,
|
||||||
settings: &'run Settings<'run>,
|
settings: &'run Settings<'run>,
|
||||||
search: &'run Search,
|
search: &'run Search,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'src, 'run> Evaluator<'src, 'run> {
|
impl<'src, 'run> Evaluator<'src, 'run> {
|
||||||
@ -64,22 +64,23 @@ impl<'src, 'run> Evaluator<'src, 'run> {
|
|||||||
message: format!("attempted to evaluate undefined variable `{}`", variable),
|
message: format!("attempted to evaluate undefined variable `{}`", variable),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Expression::Call { thunk } => {
|
Expression::Call { thunk } => {
|
||||||
use Thunk::*;
|
use Thunk::*;
|
||||||
|
|
||||||
let context = FunctionContext {
|
let context = FunctionContext {
|
||||||
dotenv: self.dotenv,
|
dotenv: self.dotenv,
|
||||||
invocation_directory: &self.config.invocation_directory,
|
invocation_directory: &self.config.invocation_directory,
|
||||||
search: self.search,
|
search: self.search,
|
||||||
};
|
};
|
||||||
|
|
||||||
match thunk {
|
match thunk {
|
||||||
Nullary { name, function, .. } =>
|
Nullary { name, function, .. } => {
|
||||||
function(&context).map_err(|message| Error::FunctionCall {
|
function(&context).map_err(|message| Error::FunctionCall {
|
||||||
function: *name,
|
function: *name,
|
||||||
message,
|
message,
|
||||||
}),
|
})
|
||||||
|
}
|
||||||
Unary {
|
Unary {
|
||||||
name,
|
name,
|
||||||
function,
|
function,
|
||||||
@ -121,16 +122,18 @@ impl<'src, 'run> Evaluator<'src, 'run> {
|
|||||||
message,
|
message,
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Expression::StringLiteral { string_literal } => Ok(string_literal.cooked.clone()),
|
Expression::StringLiteral { string_literal } => Ok(string_literal.cooked.clone()),
|
||||||
Expression::Backtick { contents, token } =>
|
Expression::Backtick { contents, token } => {
|
||||||
if self.config.dry_run {
|
if self.config.dry_run {
|
||||||
Ok(format!("`{}`", contents))
|
Ok(format!("`{}`", contents))
|
||||||
} else {
|
} else {
|
||||||
Ok(self.run_backtick(contents, token)?)
|
Ok(self.run_backtick(contents, token)?)
|
||||||
},
|
}
|
||||||
Expression::Concatination { lhs, rhs } =>
|
}
|
||||||
Ok(self.evaluate_expression(lhs)? + &self.evaluate_expression(rhs)?),
|
Expression::Concatination { lhs, rhs } => {
|
||||||
|
Ok(self.evaluate_expression(lhs)? + &self.evaluate_expression(rhs)?)
|
||||||
|
}
|
||||||
Expression::Conditional {
|
Expression::Conditional {
|
||||||
lhs,
|
lhs,
|
||||||
rhs,
|
rhs,
|
||||||
@ -146,7 +149,7 @@ impl<'src, 'run> Evaluator<'src, 'run> {
|
|||||||
} else {
|
} else {
|
||||||
self.evaluate_expression(otherwise)
|
self.evaluate_expression(otherwise)
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Expression::Group { contents } => self.evaluate_expression(contents),
|
Expression::Group { contents } => self.evaluate_expression(contents),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -192,10 +195,10 @@ impl<'src, 'run> Evaluator<'src, 'run> {
|
|||||||
} else {
|
} else {
|
||||||
evaluated += &lexeme;
|
evaluated += &lexeme;
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Fragment::Interpolation { expression } => {
|
Fragment::Interpolation { expression } => {
|
||||||
evaluated += &self.evaluate_expression(expression)?;
|
evaluated += &self.evaluate_expression(expression)?;
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(evaluated)
|
Ok(evaluated)
|
||||||
|
@ -11,7 +11,7 @@ pub(crate) enum Expression<'src> {
|
|||||||
/// `contents`
|
/// `contents`
|
||||||
Backtick {
|
Backtick {
|
||||||
contents: String,
|
contents: String,
|
||||||
token: Token<'src>,
|
token: Token<'src>,
|
||||||
},
|
},
|
||||||
/// `name(arguments)`
|
/// `name(arguments)`
|
||||||
Call { thunk: Thunk<'src> },
|
Call { thunk: Thunk<'src> },
|
||||||
@ -22,11 +22,11 @@ pub(crate) enum Expression<'src> {
|
|||||||
},
|
},
|
||||||
/// `if lhs == rhs { then } else { otherwise }`
|
/// `if lhs == rhs { then } else { otherwise }`
|
||||||
Conditional {
|
Conditional {
|
||||||
lhs: Box<Expression<'src>>,
|
lhs: Box<Expression<'src>>,
|
||||||
rhs: Box<Expression<'src>>,
|
rhs: Box<Expression<'src>>,
|
||||||
then: Box<Expression<'src>>,
|
then: Box<Expression<'src>>,
|
||||||
otherwise: Box<Expression<'src>>,
|
otherwise: Box<Expression<'src>>,
|
||||||
inverted: bool,
|
inverted: bool,
|
||||||
},
|
},
|
||||||
/// `(contents)`
|
/// `(contents)`
|
||||||
Group { contents: Box<Expression<'src>> },
|
Group { contents: Box<Expression<'src>> },
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use crate::common::*;
|
use crate::common::*;
|
||||||
|
|
||||||
pub(crate) struct FunctionContext<'run> {
|
pub(crate) struct FunctionContext<'run> {
|
||||||
pub(crate) dotenv: &'run BTreeMap<String, String>,
|
pub(crate) dotenv: &'run BTreeMap<String, String>,
|
||||||
pub(crate) invocation_directory: &'run Path,
|
pub(crate) invocation_directory: &'run Path,
|
||||||
pub(crate) search: &'run Search,
|
pub(crate) search: &'run Search,
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
use crate::common::*;
|
use crate::common::*;
|
||||||
|
|
||||||
pub(crate) struct InterruptHandler {
|
pub(crate) struct InterruptHandler {
|
||||||
blocks: u32,
|
blocks: u32,
|
||||||
interrupted: bool,
|
interrupted: bool,
|
||||||
verbosity: Verbosity,
|
verbosity: Verbosity,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InterruptHandler {
|
impl InterruptHandler {
|
||||||
@ -29,15 +29,15 @@ impl InterruptHandler {
|
|||||||
.color_display(Color::auto().stderr())
|
.color_display(Color::auto().stderr())
|
||||||
);
|
);
|
||||||
std::process::exit(EXIT_FAILURE);
|
std::process::exit(EXIT_FAILURE);
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
blocks: 0,
|
blocks: 0,
|
||||||
interrupted: false,
|
interrupted: false,
|
||||||
verbosity: Verbosity::default(),
|
verbosity: Verbosity::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,11 +2,11 @@ use crate::common::*;
|
|||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub(crate) struct Justfile<'src> {
|
pub(crate) struct Justfile<'src> {
|
||||||
pub(crate) recipes: Table<'src, Rc<Recipe<'src>>>,
|
pub(crate) recipes: Table<'src, Rc<Recipe<'src>>>,
|
||||||
pub(crate) assignments: Table<'src, Assignment<'src>>,
|
pub(crate) assignments: Table<'src, Assignment<'src>>,
|
||||||
pub(crate) aliases: Table<'src, Alias<'src>>,
|
pub(crate) aliases: Table<'src, Alias<'src>>,
|
||||||
pub(crate) settings: Settings<'src>,
|
pub(crate) settings: Settings<'src>,
|
||||||
pub(crate) warnings: Vec<Warning>,
|
pub(crate) warnings: Vec<Warning>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'src> Justfile<'src> {
|
impl<'src> Justfile<'src> {
|
||||||
@ -33,16 +33,19 @@ impl<'src> Justfile<'src> {
|
|||||||
.recipes
|
.recipes
|
||||||
.keys()
|
.keys()
|
||||||
.map(|name| {
|
.map(|name| {
|
||||||
(edit_distance(name, input), Suggestion {
|
(
|
||||||
name,
|
edit_distance(name, input),
|
||||||
target: None,
|
Suggestion { name, target: None },
|
||||||
})
|
)
|
||||||
})
|
})
|
||||||
.chain(self.aliases.iter().map(|(name, alias)| {
|
.chain(self.aliases.iter().map(|(name, alias)| {
|
||||||
(edit_distance(name, input), Suggestion {
|
(
|
||||||
name,
|
edit_distance(name, input),
|
||||||
target: Some(alias.target.name.lexeme()),
|
Suggestion {
|
||||||
})
|
name,
|
||||||
|
target: Some(alias.target.name.lexeme()),
|
||||||
|
},
|
||||||
|
)
|
||||||
}))
|
}))
|
||||||
.filter(|(distance, _suggestion)| distance < &3)
|
.filter(|(distance, _suggestion)| distance < &3)
|
||||||
.collect::<Vec<(usize, Suggestion)>>();
|
.collect::<Vec<(usize, Suggestion)>>();
|
||||||
@ -59,10 +62,10 @@ impl<'src> Justfile<'src> {
|
|||||||
.assignments
|
.assignments
|
||||||
.keys()
|
.keys()
|
||||||
.map(|name| {
|
.map(|name| {
|
||||||
(edit_distance(name, input), Suggestion {
|
(
|
||||||
name,
|
edit_distance(name, input),
|
||||||
target: None,
|
Suggestion { name, target: None },
|
||||||
})
|
)
|
||||||
})
|
})
|
||||||
.filter(|(distance, _suggestion)| distance < &3)
|
.filter(|(distance, _suggestion)| distance < &3)
|
||||||
.collect::<Vec<(usize, Suggestion)>>();
|
.collect::<Vec<(usize, Suggestion)>>();
|
||||||
@ -168,7 +171,7 @@ impl<'src> Justfile<'src> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
},
|
}
|
||||||
Subcommand::Evaluate { variable, .. } => {
|
Subcommand::Evaluate { variable, .. } => {
|
||||||
if let Some(variable) = variable {
|
if let Some(variable) = variable {
|
||||||
if let Some(value) = scope.value(variable) {
|
if let Some(value) = scope.value(variable) {
|
||||||
@ -176,7 +179,7 @@ impl<'src> Justfile<'src> {
|
|||||||
} else {
|
} else {
|
||||||
return Err(Error::EvalUnknownVariable {
|
return Err(Error::EvalUnknownVariable {
|
||||||
suggestion: self.suggest_variable(&variable),
|
suggestion: self.suggest_variable(&variable),
|
||||||
variable: variable.clone(),
|
variable: variable.clone(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -197,8 +200,8 @@ impl<'src> Justfile<'src> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
},
|
}
|
||||||
_ => {},
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
let argvec: Vec<&str> = if !arguments.is_empty() {
|
let argvec: Vec<&str> = if !arguments.is_empty() {
|
||||||
@ -231,11 +234,11 @@ impl<'src> Justfile<'src> {
|
|||||||
let argument_count = cmp::min(tail.len(), recipe.max_arguments());
|
let argument_count = cmp::min(tail.len(), recipe.max_arguments());
|
||||||
if !argument_range.range_contains(&argument_count) {
|
if !argument_range.range_contains(&argument_count) {
|
||||||
return Err(Error::ArgumentCountMismatch {
|
return Err(Error::ArgumentCountMismatch {
|
||||||
recipe: recipe.name(),
|
recipe: recipe.name(),
|
||||||
parameters: recipe.parameters.clone(),
|
parameters: recipe.parameters.clone(),
|
||||||
found: tail.len(),
|
found: tail.len(),
|
||||||
min: recipe.min_arguments(),
|
min: recipe.min_arguments(),
|
||||||
max: recipe.max_arguments(),
|
max: recipe.max_arguments(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
grouped.push((recipe, &tail[0..argument_count]));
|
grouped.push((recipe, &tail[0..argument_count]));
|
||||||
|
69
src/lexer.rs
69
src/lexer.rs
@ -13,27 +13,27 @@ use TokenKind::*;
|
|||||||
/// bad.
|
/// bad.
|
||||||
pub(crate) struct Lexer<'src> {
|
pub(crate) struct Lexer<'src> {
|
||||||
/// Source text
|
/// Source text
|
||||||
src: &'src str,
|
src: &'src str,
|
||||||
/// Char iterator
|
/// Char iterator
|
||||||
chars: Chars<'src>,
|
chars: Chars<'src>,
|
||||||
/// Tokens
|
/// Tokens
|
||||||
tokens: Vec<Token<'src>>,
|
tokens: Vec<Token<'src>>,
|
||||||
/// Current token start
|
/// Current token start
|
||||||
token_start: Position,
|
token_start: Position,
|
||||||
/// Current token end
|
/// Current token end
|
||||||
token_end: Position,
|
token_end: Position,
|
||||||
/// Next character to be lexed
|
/// Next character to be lexed
|
||||||
next: Option<char>,
|
next: Option<char>,
|
||||||
/// Next indent will start a recipe body
|
/// Next indent will start a recipe body
|
||||||
recipe_body_pending: bool,
|
recipe_body_pending: bool,
|
||||||
/// Inside recipe body
|
/// Inside recipe body
|
||||||
recipe_body: bool,
|
recipe_body: bool,
|
||||||
/// Indentation stack
|
/// Indentation stack
|
||||||
indentation: Vec<&'src str>,
|
indentation: Vec<&'src str>,
|
||||||
/// Interpolation token start stack
|
/// Interpolation token start stack
|
||||||
interpolation_stack: Vec<Token<'src>>,
|
interpolation_stack: Vec<Token<'src>>,
|
||||||
/// Current open delimiters
|
/// Current open delimiters
|
||||||
open_delimiters: Vec<(Delimiter, usize)>,
|
open_delimiters: Vec<(Delimiter, usize)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'src> Lexer<'src> {
|
impl<'src> Lexer<'src> {
|
||||||
@ -50,7 +50,7 @@ impl<'src> Lexer<'src> {
|
|||||||
let start = Position {
|
let start = Position {
|
||||||
offset: 0,
|
offset: 0,
|
||||||
column: 0,
|
column: 0,
|
||||||
line: 0,
|
line: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
Lexer {
|
Lexer {
|
||||||
@ -86,7 +86,7 @@ impl<'src> Lexer<'src> {
|
|||||||
self.next = self.chars.next();
|
self.next = self.chars.next();
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
}
|
||||||
None => Err(self.internal_error("Lexer advanced past end of text")),
|
None => Err(self.internal_error("Lexer advanced past end of text")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -202,12 +202,12 @@ impl<'src> Lexer<'src> {
|
|||||||
fn internal_error(&self, message: impl Into<String>) -> CompileError<'src> {
|
fn internal_error(&self, message: impl Into<String>) -> CompileError<'src> {
|
||||||
// Use `self.token_end` as the location of the error
|
// Use `self.token_end` as the location of the error
|
||||||
let token = Token {
|
let token = Token {
|
||||||
src: self.src,
|
src: self.src,
|
||||||
offset: self.token_end.offset,
|
offset: self.token_end.offset,
|
||||||
line: self.token_end.line,
|
line: self.token_end.line,
|
||||||
column: self.token_end.column,
|
column: self.token_end.column,
|
||||||
length: 0,
|
length: 0,
|
||||||
kind: Unspecified,
|
kind: Unspecified,
|
||||||
};
|
};
|
||||||
CompileError {
|
CompileError {
|
||||||
kind: CompileErrorKind::Internal {
|
kind: CompileErrorKind::Internal {
|
||||||
@ -226,11 +226,12 @@ impl<'src> Lexer<'src> {
|
|||||||
UnterminatedString | UnterminatedBacktick => {
|
UnterminatedString | UnterminatedBacktick => {
|
||||||
let kind = match StringKind::from_token_start(self.lexeme()) {
|
let kind = match StringKind::from_token_start(self.lexeme()) {
|
||||||
Some(kind) => kind,
|
Some(kind) => kind,
|
||||||
None =>
|
None => {
|
||||||
return self.internal_error("Lexer::error: expected string or backtick token start"),
|
return self.internal_error("Lexer::error: expected string or backtick token start")
|
||||||
|
}
|
||||||
};
|
};
|
||||||
kind.delimiter().len()
|
kind.delimiter().len()
|
||||||
},
|
}
|
||||||
// highlight the full token
|
// highlight the full token
|
||||||
_ => self.lexeme().len(),
|
_ => self.lexeme().len(),
|
||||||
};
|
};
|
||||||
@ -250,7 +251,7 @@ impl<'src> Lexer<'src> {
|
|||||||
fn unterminated_interpolation_error(interpolation_start: Token<'src>) -> CompileError<'src> {
|
fn unterminated_interpolation_error(interpolation_start: Token<'src>) -> CompileError<'src> {
|
||||||
CompileError {
|
CompileError {
|
||||||
token: interpolation_start,
|
token: interpolation_start,
|
||||||
kind: UnterminatedInterpolation,
|
kind: UnterminatedInterpolation,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -304,7 +305,7 @@ impl<'src> Lexer<'src> {
|
|||||||
} else {
|
} else {
|
||||||
self.lex_normal(first)?;
|
self.lex_normal(first)?;
|
||||||
};
|
};
|
||||||
},
|
}
|
||||||
None => break,
|
None => break,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -411,7 +412,7 @@ impl<'src> Lexer<'src> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
}
|
||||||
Continue => {
|
Continue => {
|
||||||
if !self.indentation().is_empty() {
|
if !self.indentation().is_empty() {
|
||||||
for _ in self.indentation().chars() {
|
for _ in self.indentation().chars() {
|
||||||
@ -422,7 +423,7 @@ impl<'src> Lexer<'src> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
}
|
||||||
Decrease => {
|
Decrease => {
|
||||||
while self.indentation() != whitespace {
|
while self.indentation() != whitespace {
|
||||||
self.lex_dedent();
|
self.lex_dedent();
|
||||||
@ -437,14 +438,14 @@ impl<'src> Lexer<'src> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
}
|
||||||
Mixed { whitespace } => {
|
Mixed { whitespace } => {
|
||||||
for _ in whitespace.chars() {
|
for _ in whitespace.chars() {
|
||||||
self.advance()?;
|
self.advance()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(self.error(MixedLeadingWhitespace { whitespace }))
|
Err(self.error(MixedLeadingWhitespace { whitespace }))
|
||||||
},
|
}
|
||||||
Inconsistent => {
|
Inconsistent => {
|
||||||
for _ in whitespace.chars() {
|
for _ in whitespace.chars() {
|
||||||
self.advance()?;
|
self.advance()?;
|
||||||
@ -452,9 +453,9 @@ impl<'src> Lexer<'src> {
|
|||||||
|
|
||||||
Err(self.error(InconsistentLeadingWhitespace {
|
Err(self.error(InconsistentLeadingWhitespace {
|
||||||
expected: self.indentation(),
|
expected: self.indentation(),
|
||||||
found: whitespace,
|
found: whitespace,
|
||||||
}))
|
}))
|
||||||
},
|
}
|
||||||
Increase => {
|
Increase => {
|
||||||
while self.next_is_whitespace() {
|
while self.next_is_whitespace() {
|
||||||
self.advance()?;
|
self.advance()?;
|
||||||
@ -472,7 +473,7 @@ impl<'src> Lexer<'src> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -504,7 +505,7 @@ impl<'src> Lexer<'src> {
|
|||||||
_ => {
|
_ => {
|
||||||
self.advance()?;
|
self.advance()?;
|
||||||
Err(self.error(UnknownStartOfToken))
|
Err(self.error(UnknownStartOfToken))
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -585,7 +586,7 @@ impl<'src> Lexer<'src> {
|
|||||||
.interpolation_stack
|
.interpolation_stack
|
||||||
.push(self.tokens[self.tokens.len() - 1]);
|
.push(self.tokens[self.tokens.len() - 1]);
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
}
|
||||||
EndOfFile => Ok(()),
|
EndOfFile => Ok(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -644,11 +645,12 @@ impl<'src> Lexer<'src> {
|
|||||||
BracketR => self.close_delimiter(Bracket)?,
|
BracketR => self.close_delimiter(Bracket)?,
|
||||||
ParenL => self.open_delimiter(Paren),
|
ParenL => self.open_delimiter(Paren),
|
||||||
ParenR => self.close_delimiter(Paren)?,
|
ParenR => self.close_delimiter(Paren)?,
|
||||||
_ =>
|
_ => {
|
||||||
return Err(self.internal_error(format!(
|
return Err(self.internal_error(format!(
|
||||||
"Lexer::lex_delimiter called with non-delimiter token: `{}`",
|
"Lexer::lex_delimiter called with non-delimiter token: `{}`",
|
||||||
kind,
|
kind,
|
||||||
))),
|
)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Emit the delimiter token
|
// Emit the delimiter token
|
||||||
@ -947,8 +949,9 @@ mod tests {
|
|||||||
Dedent | Eof => "",
|
Dedent | Eof => "",
|
||||||
|
|
||||||
// Variable lexemes
|
// Variable lexemes
|
||||||
Text | StringToken | Backtick | Identifier | Comment | Unspecified =>
|
Text | StringToken | Backtick | Identifier | Comment | Unspecified => {
|
||||||
panic!("Token {:?} has no default lexeme", kind),
|
panic!("Token {:?} has no default lexeme", kind)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -992,7 +995,7 @@ mod tests {
|
|||||||
kind,
|
kind,
|
||||||
};
|
};
|
||||||
assert_eq!(have, want);
|
assert_eq!(have, want);
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
10
src/list.rs
10
src/list.rs
@ -5,21 +5,21 @@ use crate::common::*;
|
|||||||
|
|
||||||
pub struct List<T: Display, I: Iterator<Item = T> + Clone> {
|
pub struct List<T: Display, I: Iterator<Item = T> + Clone> {
|
||||||
conjunction: &'static str,
|
conjunction: &'static str,
|
||||||
values: I,
|
values: I,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Display, I: Iterator<Item = T> + Clone> List<T, I> {
|
impl<T: Display, I: Iterator<Item = T> + Clone> List<T, I> {
|
||||||
pub fn or<II: IntoIterator<Item = T, IntoIter = I>>(values: II) -> List<T, I> {
|
pub fn or<II: IntoIterator<Item = T, IntoIter = I>>(values: II) -> List<T, I> {
|
||||||
List {
|
List {
|
||||||
conjunction: "or",
|
conjunction: "or",
|
||||||
values: values.into_iter(),
|
values: values.into_iter(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn and<II: IntoIterator<Item = T, IntoIter = I>>(values: II) -> List<T, I> {
|
pub fn and<II: IntoIterator<Item = T, IntoIter = I>>(values: II) -> List<T, I> {
|
||||||
List {
|
List {
|
||||||
conjunction: "and",
|
conjunction: "and",
|
||||||
values: values.into_iter(),
|
values: values.into_iter(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,11 +68,11 @@ impl<T: Display, I: Iterator<Item = T> + Clone> Display for List<T, I> {
|
|||||||
write!(f, ", {}", c)?;
|
write!(f, ", {}", c)?;
|
||||||
current = Some(n);
|
current = Some(n);
|
||||||
next = values.next();
|
next = values.next();
|
||||||
},
|
}
|
||||||
(Some(c), None) => {
|
(Some(c), None) => {
|
||||||
write!(f, ", {} {}", self.conjunction, c)?;
|
write!(f, ", {} {}", self.conjunction, c)?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
},
|
}
|
||||||
_ => unreachable!("Iterator was fused, but returned Some after None"),
|
_ => unreachable!("Iterator was fused, but returned Some after None"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
14
src/name.rs
14
src/name.rs
@ -6,9 +6,9 @@ use crate::common::*;
|
|||||||
pub(crate) struct Name<'src> {
|
pub(crate) struct Name<'src> {
|
||||||
pub(crate) offset: usize,
|
pub(crate) offset: usize,
|
||||||
pub(crate) length: usize,
|
pub(crate) length: usize,
|
||||||
pub(crate) line: usize,
|
pub(crate) line: usize,
|
||||||
pub(crate) column: usize,
|
pub(crate) column: usize,
|
||||||
pub(crate) src: &'src str,
|
pub(crate) src: &'src str,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'src> Name<'src> {
|
impl<'src> Name<'src> {
|
||||||
@ -20,12 +20,12 @@ impl<'src> Name<'src> {
|
|||||||
/// Turn this name back into a token
|
/// Turn this name back into a token
|
||||||
pub(crate) fn token(&self) -> Token<'src> {
|
pub(crate) fn token(&self) -> Token<'src> {
|
||||||
Token {
|
Token {
|
||||||
kind: TokenKind::Identifier,
|
kind: TokenKind::Identifier,
|
||||||
offset: self.offset,
|
offset: self.offset,
|
||||||
length: self.length,
|
length: self.length,
|
||||||
line: self.line,
|
line: self.line,
|
||||||
column: self.column,
|
column: self.column,
|
||||||
src: self.src,
|
src: self.src,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,9 +34,9 @@ impl<'src> Name<'src> {
|
|||||||
Name {
|
Name {
|
||||||
offset: token.offset,
|
offset: token.offset,
|
||||||
length: token.length,
|
length: token.length,
|
||||||
line: token.line,
|
line: token.line,
|
||||||
column: token.column,
|
column: token.column,
|
||||||
src: token.src,
|
src: token.src,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
17
src/node.rs
17
src/node.rs
@ -71,7 +71,7 @@ impl<'src> Node<'src> for Expression<'src> {
|
|||||||
tree.push_mut(then.tree());
|
tree.push_mut(then.tree());
|
||||||
tree.push_mut(otherwise.tree());
|
tree.push_mut(otherwise.tree());
|
||||||
tree
|
tree
|
||||||
},
|
}
|
||||||
Expression::Call { thunk } => {
|
Expression::Call { thunk } => {
|
||||||
use Thunk::*;
|
use Thunk::*;
|
||||||
|
|
||||||
@ -82,14 +82,14 @@ impl<'src> Node<'src> for Expression<'src> {
|
|||||||
Unary { name, arg, .. } => {
|
Unary { name, arg, .. } => {
|
||||||
tree.push_mut(name.lexeme());
|
tree.push_mut(name.lexeme());
|
||||||
tree.push_mut(arg.tree());
|
tree.push_mut(arg.tree());
|
||||||
},
|
}
|
||||||
Binary {
|
Binary {
|
||||||
name, args: [a, b], ..
|
name, args: [a, b], ..
|
||||||
} => {
|
} => {
|
||||||
tree.push_mut(name.lexeme());
|
tree.push_mut(name.lexeme());
|
||||||
tree.push_mut(a.tree());
|
tree.push_mut(a.tree());
|
||||||
tree.push_mut(b.tree());
|
tree.push_mut(b.tree());
|
||||||
},
|
}
|
||||||
Ternary {
|
Ternary {
|
||||||
name,
|
name,
|
||||||
args: [a, b, c],
|
args: [a, b, c],
|
||||||
@ -99,11 +99,11 @@ impl<'src> Node<'src> for Expression<'src> {
|
|||||||
tree.push_mut(a.tree());
|
tree.push_mut(a.tree());
|
||||||
tree.push_mut(b.tree());
|
tree.push_mut(b.tree());
|
||||||
tree.push_mut(c.tree());
|
tree.push_mut(c.tree());
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tree
|
tree
|
||||||
},
|
}
|
||||||
Expression::Variable { name } => Tree::atom(name.lexeme()),
|
Expression::Variable { name } => Tree::atom(name.lexeme()),
|
||||||
Expression::StringLiteral {
|
Expression::StringLiteral {
|
||||||
string_literal: StringLiteral { cooked, .. },
|
string_literal: StringLiteral { cooked, .. },
|
||||||
@ -213,14 +213,15 @@ impl<'src> Node<'src> for Set<'src> {
|
|||||||
set.push_mut(self.name.lexeme().replace('-', "_"));
|
set.push_mut(self.name.lexeme().replace('-', "_"));
|
||||||
|
|
||||||
match &self.value {
|
match &self.value {
|
||||||
DotenvLoad(value) | Export(value) | PositionalArguments(value) =>
|
DotenvLoad(value) | Export(value) | PositionalArguments(value) => {
|
||||||
set.push_mut(value.to_string()),
|
set.push_mut(value.to_string());
|
||||||
|
}
|
||||||
Shell(setting::Shell { command, arguments }) => {
|
Shell(setting::Shell { command, arguments }) => {
|
||||||
set.push_mut(Tree::string(&command.cooked));
|
set.push_mut(Tree::string(&command.cooked));
|
||||||
for argument in arguments {
|
for argument in arguments {
|
||||||
set.push_mut(Tree::string(&argument.cooked));
|
set.push_mut(Tree::string(&argument.cooked));
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
set
|
set
|
||||||
|
@ -28,7 +28,7 @@ pub(crate) fn output(mut command: Command) -> Result<String, OutputError> {
|
|||||||
.to_owned(),
|
.to_owned(),
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Err(io_error) => Err(OutputError::Io(io_error)),
|
Err(io_error) => Err(OutputError::Io(io_error)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,13 +4,13 @@ use crate::common::*;
|
|||||||
#[derive(PartialEq, Debug, Clone)]
|
#[derive(PartialEq, Debug, Clone)]
|
||||||
pub(crate) struct Parameter<'src> {
|
pub(crate) struct Parameter<'src> {
|
||||||
/// The parameter name
|
/// The parameter name
|
||||||
pub(crate) name: Name<'src>,
|
pub(crate) name: Name<'src>,
|
||||||
/// The kind of parameter
|
/// The kind of parameter
|
||||||
pub(crate) kind: ParameterKind,
|
pub(crate) kind: ParameterKind,
|
||||||
/// An optional default expression
|
/// An optional default expression
|
||||||
pub(crate) default: Option<Expression<'src>>,
|
pub(crate) default: Option<Expression<'src>>,
|
||||||
/// Export parameter as environment variable
|
/// Export parameter as environment variable
|
||||||
pub(crate) export: bool,
|
pub(crate) export: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'src> ColorDisplay for Parameter<'src> {
|
impl<'src> ColorDisplay for Parameter<'src> {
|
||||||
|
@ -27,9 +27,9 @@ use TokenKind::*;
|
|||||||
/// contents of the set is printed in the resultant error message.
|
/// contents of the set is printed in the resultant error message.
|
||||||
pub(crate) struct Parser<'tokens, 'src> {
|
pub(crate) struct Parser<'tokens, 'src> {
|
||||||
/// Source tokens
|
/// Source tokens
|
||||||
tokens: &'tokens [Token<'src>],
|
tokens: &'tokens [Token<'src>],
|
||||||
/// Index of the next un-parsed token
|
/// Index of the next un-parsed token
|
||||||
next: usize,
|
next: usize,
|
||||||
/// Current expected tokens
|
/// Current expected tokens
|
||||||
expected: BTreeSet<TokenKind>,
|
expected: BTreeSet<TokenKind>,
|
||||||
}
|
}
|
||||||
@ -58,7 +58,7 @@ impl<'tokens, 'src> Parser<'tokens, 'src> {
|
|||||||
fn unexpected_token(&self) -> CompileResult<'src, CompileError<'src>> {
|
fn unexpected_token(&self) -> CompileResult<'src, CompileError<'src>> {
|
||||||
self.error(CompileErrorKind::UnexpectedToken {
|
self.error(CompileErrorKind::UnexpectedToken {
|
||||||
expected: self.expected.iter().cloned().collect::<Vec<TokenKind>>(),
|
expected: self.expected.iter().cloned().collect::<Vec<TokenKind>>(),
|
||||||
found: self.next()?.kind,
|
found: self.next()?.kind,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,10 +101,11 @@ impl<'tokens, 'src> Parser<'tokens, 'src> {
|
|||||||
let mut rest = self.rest();
|
let mut rest = self.rest();
|
||||||
for kind in kinds {
|
for kind in kinds {
|
||||||
match rest.next() {
|
match rest.next() {
|
||||||
Some(token) =>
|
Some(token) => {
|
||||||
if token.kind != *kind {
|
if token.kind != *kind {
|
||||||
return false;
|
return false;
|
||||||
},
|
}
|
||||||
|
}
|
||||||
None => return false,
|
None => return false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -322,22 +323,27 @@ impl<'tokens, 'src> Parser<'tokens, 'src> {
|
|||||||
break;
|
break;
|
||||||
} else if self.next_is(Identifier) {
|
} else if self.next_is(Identifier) {
|
||||||
match Keyword::from_lexeme(next.lexeme()) {
|
match Keyword::from_lexeme(next.lexeme()) {
|
||||||
Some(Keyword::Alias) if self.next_are(&[Identifier, Identifier, Equals]) =>
|
Some(Keyword::Alias) if self.next_are(&[Identifier, Identifier, Equals]) => {
|
||||||
return Err(self.get(2)?.error(CompileErrorKind::DeprecatedEquals)),
|
return Err(self.get(2)?.error(CompileErrorKind::DeprecatedEquals))
|
||||||
Some(Keyword::Alias) if self.next_are(&[Identifier, Identifier, ColonEquals]) =>
|
}
|
||||||
items.push(Item::Alias(self.parse_alias()?)),
|
Some(Keyword::Alias) if self.next_are(&[Identifier, Identifier, ColonEquals]) => {
|
||||||
Some(Keyword::Export) if self.next_are(&[Identifier, Identifier, Equals]) =>
|
items.push(Item::Alias(self.parse_alias()?));
|
||||||
return Err(self.get(2)?.error(CompileErrorKind::DeprecatedEquals)),
|
}
|
||||||
|
Some(Keyword::Export) if self.next_are(&[Identifier, Identifier, Equals]) => {
|
||||||
|
return Err(self.get(2)?.error(CompileErrorKind::DeprecatedEquals))
|
||||||
|
}
|
||||||
Some(Keyword::Export) if self.next_are(&[Identifier, Identifier, ColonEquals]) => {
|
Some(Keyword::Export) if self.next_are(&[Identifier, Identifier, ColonEquals]) => {
|
||||||
self.presume_keyword(Keyword::Export)?;
|
self.presume_keyword(Keyword::Export)?;
|
||||||
items.push(Item::Assignment(self.parse_assignment(true)?));
|
items.push(Item::Assignment(self.parse_assignment(true)?));
|
||||||
},
|
}
|
||||||
Some(Keyword::Set)
|
Some(Keyword::Set)
|
||||||
if self.next_are(&[Identifier, Identifier, ColonEquals])
|
if self.next_are(&[Identifier, Identifier, ColonEquals])
|
||||||
|| self.next_are(&[Identifier, Identifier, Eol])
|
|| self.next_are(&[Identifier, Identifier, Eol])
|
||||||
|| self.next_are(&[Identifier, Identifier, Eof]) =>
|
|| self.next_are(&[Identifier, Identifier, Eof]) =>
|
||||||
items.push(Item::Set(self.parse_set()?)),
|
{
|
||||||
_ =>
|
items.push(Item::Set(self.parse_set()?));
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
if self.next_are(&[Identifier, Equals]) {
|
if self.next_are(&[Identifier, Equals]) {
|
||||||
return Err(self.get(1)?.error(CompileErrorKind::DeprecatedEquals));
|
return Err(self.get(1)?.error(CompileErrorKind::DeprecatedEquals));
|
||||||
} else if self.next_are(&[Identifier, ColonEquals]) {
|
} else if self.next_are(&[Identifier, ColonEquals]) {
|
||||||
@ -345,7 +351,8 @@ impl<'tokens, 'src> Parser<'tokens, 'src> {
|
|||||||
} else {
|
} else {
|
||||||
let doc = pop_doc_comment(&mut items, eol_since_last_comment);
|
let doc = pop_doc_comment(&mut items, eol_since_last_comment);
|
||||||
items.push(Item::Recipe(self.parse_recipe(doc, false)?));
|
items.push(Item::Recipe(self.parse_recipe(doc, false)?));
|
||||||
},
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if self.accepted(At)? {
|
} else if self.accepted(At)? {
|
||||||
let doc = pop_doc_comment(&mut items, eol_since_last_comment);
|
let doc = pop_doc_comment(&mut items, eol_since_last_comment);
|
||||||
@ -516,13 +523,13 @@ impl<'tokens, 'src> Parser<'tokens, 'src> {
|
|||||||
'r' => cooked.push('\r'),
|
'r' => cooked.push('\r'),
|
||||||
't' => cooked.push('\t'),
|
't' => cooked.push('\t'),
|
||||||
'\\' => cooked.push('\\'),
|
'\\' => cooked.push('\\'),
|
||||||
'\n' => {},
|
'\n' => {}
|
||||||
'"' => cooked.push('"'),
|
'"' => cooked.push('"'),
|
||||||
other => {
|
other => {
|
||||||
return Err(
|
return Err(
|
||||||
token.error(CompileErrorKind::InvalidEscapeSequence { character: other }),
|
token.error(CompileErrorKind::InvalidEscapeSequence { character: other }),
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
escape = false;
|
escape = false;
|
||||||
} else if c == '\\' {
|
} else if c == '\\' {
|
||||||
@ -715,7 +722,7 @@ impl<'tokens, 'src> Parser<'tokens, 'src> {
|
|||||||
} else {
|
} else {
|
||||||
return Err(identifier.error(CompileErrorKind::ExpectedKeyword {
|
return Err(identifier.error(CompileErrorKind::ExpectedKeyword {
|
||||||
expected: vec![Keyword::True, Keyword::False],
|
expected: vec![Keyword::True, Keyword::False],
|
||||||
found: identifier.lexeme(),
|
found: identifier.lexeme(),
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -859,7 +866,7 @@ mod tests {
|
|||||||
kind,
|
kind,
|
||||||
};
|
};
|
||||||
assert_eq!(have, want);
|
assert_eq!(have, want);
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,5 +3,5 @@
|
|||||||
pub(crate) struct Position {
|
pub(crate) struct Position {
|
||||||
pub(crate) offset: usize,
|
pub(crate) offset: usize,
|
||||||
pub(crate) column: usize,
|
pub(crate) column: usize,
|
||||||
pub(crate) line: usize,
|
pub(crate) line: usize,
|
||||||
}
|
}
|
||||||
|
@ -29,11 +29,11 @@ use crate::common::*;
|
|||||||
#[cfg_attr(test, derive(PartialEq, Debug))]
|
#[cfg_attr(test, derive(PartialEq, Debug))]
|
||||||
pub struct Positional {
|
pub struct Positional {
|
||||||
/// Overrides from values of the form `[a-zA-Z_][a-zA-Z0-9_-]*=.*`
|
/// Overrides from values of the form `[a-zA-Z_][a-zA-Z0-9_-]*=.*`
|
||||||
pub overrides: Vec<(String, String)>,
|
pub overrides: Vec<(String, String)>,
|
||||||
/// An argument equal to '.', '..', or ending with `/`
|
/// An argument equal to '.', '..', or ending with `/`
|
||||||
pub search_directory: Option<String>,
|
pub search_directory: Option<String>,
|
||||||
/// Everything else
|
/// Everything else
|
||||||
pub arguments: Vec<String>,
|
pub arguments: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Positional {
|
impl Positional {
|
||||||
|
@ -21,15 +21,15 @@ fn error_from_signal(recipe: &str, line_number: Option<usize>, exit_status: Exit
|
|||||||
/// A recipe, e.g. `foo: bar baz`
|
/// A recipe, e.g. `foo: bar baz`
|
||||||
#[derive(PartialEq, Debug, Clone)]
|
#[derive(PartialEq, Debug, Clone)]
|
||||||
pub(crate) struct Recipe<'src, D = Dependency<'src>> {
|
pub(crate) struct Recipe<'src, D = Dependency<'src>> {
|
||||||
pub(crate) body: Vec<Line<'src>>,
|
pub(crate) body: Vec<Line<'src>>,
|
||||||
pub(crate) dependencies: Vec<D>,
|
pub(crate) dependencies: Vec<D>,
|
||||||
pub(crate) doc: Option<&'src str>,
|
pub(crate) doc: Option<&'src str>,
|
||||||
pub(crate) name: Name<'src>,
|
pub(crate) name: Name<'src>,
|
||||||
pub(crate) parameters: Vec<Parameter<'src>>,
|
pub(crate) parameters: Vec<Parameter<'src>>,
|
||||||
pub(crate) private: bool,
|
pub(crate) private: bool,
|
||||||
pub(crate) quiet: bool,
|
pub(crate) quiet: bool,
|
||||||
pub(crate) shebang: bool,
|
pub(crate) shebang: bool,
|
||||||
pub(crate) priors: usize,
|
pub(crate) priors: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'src, D> Recipe<'src, D> {
|
impl<'src, D> Recipe<'src, D> {
|
||||||
@ -116,7 +116,7 @@ impl<'src, D> Recipe<'src, D> {
|
|||||||
.prefix("just")
|
.prefix("just")
|
||||||
.tempdir()
|
.tempdir()
|
||||||
.map_err(|error| Error::TmpdirIo {
|
.map_err(|error| Error::TmpdirIo {
|
||||||
recipe: self.name(),
|
recipe: self.name(),
|
||||||
io_error: error,
|
io_error: error,
|
||||||
})?;
|
})?;
|
||||||
let mut path = tmp.path().to_path_buf();
|
let mut path = tmp.path().to_path_buf();
|
||||||
@ -125,7 +125,7 @@ impl<'src, D> Recipe<'src, D> {
|
|||||||
|
|
||||||
{
|
{
|
||||||
let mut f = fs::File::create(&path).map_err(|error| Error::TmpdirIo {
|
let mut f = fs::File::create(&path).map_err(|error| Error::TmpdirIo {
|
||||||
recipe: self.name(),
|
recipe: self.name(),
|
||||||
io_error: error,
|
io_error: error,
|
||||||
})?;
|
})?;
|
||||||
let mut text = String::new();
|
let mut text = String::new();
|
||||||
@ -153,14 +153,14 @@ impl<'src, D> Recipe<'src, D> {
|
|||||||
|
|
||||||
f.write_all(text.as_bytes())
|
f.write_all(text.as_bytes())
|
||||||
.map_err(|error| Error::TmpdirIo {
|
.map_err(|error| Error::TmpdirIo {
|
||||||
recipe: self.name(),
|
recipe: self.name(),
|
||||||
io_error: error,
|
io_error: error,
|
||||||
})?;
|
})?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// make the script executable
|
// make the script executable
|
||||||
Platform::set_execute_permission(&path).map_err(|error| Error::TmpdirIo {
|
Platform::set_execute_permission(&path).map_err(|error| Error::TmpdirIo {
|
||||||
recipe: self.name(),
|
recipe: self.name(),
|
||||||
io_error: error,
|
io_error: error,
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
@ -181,7 +181,7 @@ impl<'src, D> Recipe<'src, D> {
|
|||||||
|
|
||||||
// run it!
|
// run it!
|
||||||
match InterruptHandler::guard(|| command.status()) {
|
match InterruptHandler::guard(|| command.status()) {
|
||||||
Ok(exit_status) =>
|
Ok(exit_status) => {
|
||||||
if let Some(code) = exit_status.code() {
|
if let Some(code) = exit_status.code() {
|
||||||
if code != 0 {
|
if code != 0 {
|
||||||
return Err(Error::Code {
|
return Err(Error::Code {
|
||||||
@ -192,7 +192,8 @@ impl<'src, D> Recipe<'src, D> {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(error_from_signal(self.name(), None, exit_status));
|
return Err(error_from_signal(self.name(), None, exit_status));
|
||||||
},
|
}
|
||||||
|
}
|
||||||
Err(io_error) => {
|
Err(io_error) => {
|
||||||
return Err(Error::Shebang {
|
return Err(Error::Shebang {
|
||||||
recipe: self.name(),
|
recipe: self.name(),
|
||||||
@ -200,7 +201,7 @@ impl<'src, D> Recipe<'src, D> {
|
|||||||
argument: shebang.argument.map(String::from),
|
argument: shebang.argument.map(String::from),
|
||||||
io_error,
|
io_error,
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
let mut lines = self.body.iter().peekable();
|
let mut lines = self.body.iter().peekable();
|
||||||
@ -274,7 +275,7 @@ impl<'src, D> Recipe<'src, D> {
|
|||||||
cmd.export(context.settings, dotenv, &scope);
|
cmd.export(context.settings, dotenv, &scope);
|
||||||
|
|
||||||
match InterruptHandler::guard(|| cmd.status()) {
|
match InterruptHandler::guard(|| cmd.status()) {
|
||||||
Ok(exit_status) =>
|
Ok(exit_status) => {
|
||||||
if let Some(code) = exit_status.code() {
|
if let Some(code) = exit_status.code() {
|
||||||
if code != 0 && !infallable_command {
|
if code != 0 && !infallable_command {
|
||||||
return Err(Error::Code {
|
return Err(Error::Code {
|
||||||
@ -289,13 +290,14 @@ impl<'src, D> Recipe<'src, D> {
|
|||||||
Some(line_number),
|
Some(line_number),
|
||||||
exit_status,
|
exit_status,
|
||||||
));
|
));
|
||||||
},
|
}
|
||||||
|
}
|
||||||
Err(io_error) => {
|
Err(io_error) => {
|
||||||
return Err(Error::Io {
|
return Err(Error::Io {
|
||||||
recipe: self.name(),
|
recipe: self.name(),
|
||||||
io_error,
|
io_error,
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
use crate::common::*;
|
use crate::common::*;
|
||||||
|
|
||||||
pub(crate) struct RecipeContext<'src: 'run, 'run> {
|
pub(crate) struct RecipeContext<'src: 'run, 'run> {
|
||||||
pub(crate) config: &'run Config,
|
pub(crate) config: &'run Config,
|
||||||
pub(crate) scope: Scope<'src, 'run>,
|
pub(crate) scope: Scope<'src, 'run>,
|
||||||
pub(crate) search: &'run Search,
|
pub(crate) search: &'run Search,
|
||||||
pub(crate) settings: &'run Settings<'src>,
|
pub(crate) settings: &'run Settings<'src>,
|
||||||
}
|
}
|
||||||
|
@ -4,8 +4,8 @@ use CompileErrorKind::*;
|
|||||||
|
|
||||||
pub(crate) struct RecipeResolver<'src: 'run, 'run> {
|
pub(crate) struct RecipeResolver<'src: 'run, 'run> {
|
||||||
unresolved_recipes: Table<'src, UnresolvedRecipe<'src>>,
|
unresolved_recipes: Table<'src, UnresolvedRecipe<'src>>,
|
||||||
resolved_recipes: Table<'src, Rc<Recipe<'src>>>,
|
resolved_recipes: Table<'src, Rc<Recipe<'src>>>,
|
||||||
assignments: &'run Table<'src, Assignment<'src>>,
|
assignments: &'run Table<'src, Assignment<'src>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'src: 'run, 'run> RecipeResolver<'src, 'run> {
|
impl<'src: 'run, 'run> RecipeResolver<'src, 'run> {
|
||||||
@ -107,7 +107,7 @@ impl<'src: 'run, 'run> RecipeResolver<'src, 'run> {
|
|||||||
} else {
|
} else {
|
||||||
// dependency is unknown
|
// dependency is unknown
|
||||||
return Err(dependency.recipe.error(UnknownDependency {
|
return Err(dependency.recipe.error(UnknownDependency {
|
||||||
recipe: recipe.name(),
|
recipe: recipe.name(),
|
||||||
unknown: name,
|
unknown: name,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
@ -2,21 +2,21 @@ use crate::common::*;
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct Scope<'src: 'run, 'run> {
|
pub(crate) struct Scope<'src: 'run, 'run> {
|
||||||
parent: Option<&'run Scope<'src, 'run>>,
|
parent: Option<&'run Scope<'src, 'run>>,
|
||||||
bindings: Table<'src, Binding<'src, String>>,
|
bindings: Table<'src, Binding<'src, String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'src, 'run> Scope<'src, 'run> {
|
impl<'src, 'run> Scope<'src, 'run> {
|
||||||
pub(crate) fn child(&'run self) -> Scope<'src, 'run> {
|
pub(crate) fn child(&'run self) -> Scope<'src, 'run> {
|
||||||
Scope {
|
Scope {
|
||||||
parent: Some(self),
|
parent: Some(self),
|
||||||
bindings: Table::new(),
|
bindings: Table::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn new() -> Scope<'src, 'run> {
|
pub(crate) fn new() -> Scope<'src, 'run> {
|
||||||
Scope {
|
Scope {
|
||||||
parent: None,
|
parent: None,
|
||||||
bindings: Table::new(),
|
bindings: Table::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ const JUSTFILE_NAMES: &[&str] = &["justfile", ".justfile"];
|
|||||||
const PROJECT_ROOT_CHILDREN: &[&str] = &[".bzr", ".git", ".hg", ".svn", "_darcs"];
|
const PROJECT_ROOT_CHILDREN: &[&str] = &[".bzr", ".git", ".hg", ".svn", "_darcs"];
|
||||||
|
|
||||||
pub(crate) struct Search {
|
pub(crate) struct Search {
|
||||||
pub(crate) justfile: PathBuf,
|
pub(crate) justfile: PathBuf,
|
||||||
pub(crate) working_directory: PathBuf,
|
pub(crate) working_directory: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -26,7 +26,7 @@ impl Search {
|
|||||||
justfile,
|
justfile,
|
||||||
working_directory,
|
working_directory,
|
||||||
})
|
})
|
||||||
},
|
}
|
||||||
|
|
||||||
SearchConfig::FromSearchDirectory { search_directory } => {
|
SearchConfig::FromSearchDirectory { search_directory } => {
|
||||||
let search_directory = Self::clean(invocation_directory, search_directory);
|
let search_directory = Self::clean(invocation_directory, search_directory);
|
||||||
@ -39,7 +39,7 @@ impl Search {
|
|||||||
justfile,
|
justfile,
|
||||||
working_directory,
|
working_directory,
|
||||||
})
|
})
|
||||||
},
|
}
|
||||||
|
|
||||||
SearchConfig::WithJustfile { justfile } => {
|
SearchConfig::WithJustfile { justfile } => {
|
||||||
let justfile = Self::clean(invocation_directory, justfile);
|
let justfile = Self::clean(invocation_directory, justfile);
|
||||||
@ -50,13 +50,13 @@ impl Search {
|
|||||||
justfile,
|
justfile,
|
||||||
working_directory,
|
working_directory,
|
||||||
})
|
})
|
||||||
},
|
}
|
||||||
|
|
||||||
SearchConfig::WithJustfileAndWorkingDirectory {
|
SearchConfig::WithJustfileAndWorkingDirectory {
|
||||||
justfile,
|
justfile,
|
||||||
working_directory,
|
working_directory,
|
||||||
} => Ok(Self {
|
} => Ok(Self {
|
||||||
justfile: Self::clean(invocation_directory, justfile),
|
justfile: Self::clean(invocation_directory, justfile),
|
||||||
working_directory: Self::clean(invocation_directory, working_directory),
|
working_directory: Self::clean(invocation_directory, working_directory),
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
@ -76,7 +76,7 @@ impl Search {
|
|||||||
justfile,
|
justfile,
|
||||||
working_directory,
|
working_directory,
|
||||||
})
|
})
|
||||||
},
|
}
|
||||||
|
|
||||||
SearchConfig::FromSearchDirectory { search_directory } => {
|
SearchConfig::FromSearchDirectory { search_directory } => {
|
||||||
let search_directory = Self::clean(invocation_directory, search_directory);
|
let search_directory = Self::clean(invocation_directory, search_directory);
|
||||||
@ -89,7 +89,7 @@ impl Search {
|
|||||||
justfile,
|
justfile,
|
||||||
working_directory,
|
working_directory,
|
||||||
})
|
})
|
||||||
},
|
}
|
||||||
|
|
||||||
SearchConfig::WithJustfile { justfile } => {
|
SearchConfig::WithJustfile { justfile } => {
|
||||||
let justfile = Self::clean(invocation_directory, justfile);
|
let justfile = Self::clean(invocation_directory, justfile);
|
||||||
@ -100,13 +100,13 @@ impl Search {
|
|||||||
justfile,
|
justfile,
|
||||||
working_directory,
|
working_directory,
|
||||||
})
|
})
|
||||||
},
|
}
|
||||||
|
|
||||||
SearchConfig::WithJustfileAndWorkingDirectory {
|
SearchConfig::WithJustfileAndWorkingDirectory {
|
||||||
justfile,
|
justfile,
|
||||||
working_directory,
|
working_directory,
|
||||||
} => Ok(Self {
|
} => Ok(Self {
|
||||||
justfile: Self::clean(invocation_directory, justfile),
|
justfile: Self::clean(invocation_directory, justfile),
|
||||||
working_directory: Self::clean(invocation_directory, working_directory),
|
working_directory: Self::clean(invocation_directory, working_directory),
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
@ -206,7 +206,7 @@ mod tests {
|
|||||||
fn not_found() {
|
fn not_found() {
|
||||||
let tmp = testing::tempdir();
|
let tmp = testing::tempdir();
|
||||||
match Search::justfile(tmp.path()) {
|
match Search::justfile(tmp.path()) {
|
||||||
Err(SearchError::NotFound) => {},
|
Err(SearchError::NotFound) => {}
|
||||||
_ => panic!("No justfile found error was expected"),
|
_ => panic!("No justfile found error was expected"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -226,7 +226,7 @@ mod tests {
|
|||||||
fs::write(&path, "default:\n\techo ok").unwrap();
|
fs::write(&path, "default:\n\techo ok").unwrap();
|
||||||
path.pop();
|
path.pop();
|
||||||
match Search::justfile(path.as_path()) {
|
match Search::justfile(path.as_path()) {
|
||||||
Err(SearchError::MultipleCandidates { .. }) => {},
|
Err(SearchError::MultipleCandidates { .. }) => {}
|
||||||
_ => panic!("Multiple candidates error was expected"),
|
_ => panic!("Multiple candidates error was expected"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -301,7 +301,7 @@ mod tests {
|
|||||||
path.pop();
|
path.pop();
|
||||||
path.push(DEFAULT_JUSTFILE_NAME);
|
path.push(DEFAULT_JUSTFILE_NAME);
|
||||||
assert_eq!(found_path, path);
|
assert_eq!(found_path, path);
|
||||||
},
|
}
|
||||||
Err(err) => panic!("No errors were expected: {}", err),
|
Err(err) => panic!("No errors were expected: {}", err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ pub(crate) enum SearchConfig {
|
|||||||
WithJustfile { justfile: PathBuf },
|
WithJustfile { justfile: PathBuf },
|
||||||
/// Use user-specified justfile and working directory.
|
/// Use user-specified justfile and working directory.
|
||||||
WithJustfileAndWorkingDirectory {
|
WithJustfileAndWorkingDirectory {
|
||||||
justfile: PathBuf,
|
justfile: PathBuf,
|
||||||
working_directory: PathBuf,
|
working_directory: PathBuf,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ pub(crate) enum SearchError {
|
|||||||
))]
|
))]
|
||||||
Io {
|
Io {
|
||||||
directory: PathBuf,
|
directory: PathBuf,
|
||||||
io_error: io::Error,
|
io_error: io::Error,
|
||||||
},
|
},
|
||||||
#[snafu(display("Justfile path had no parent: {}", path.display()))]
|
#[snafu(display("Justfile path had no parent: {}", path.display()))]
|
||||||
JustfileHadNoParent { path: PathBuf },
|
JustfileHadNoParent { path: PathBuf },
|
||||||
|
@ -2,7 +2,7 @@ use crate::common::*;
|
|||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub(crate) struct Set<'src> {
|
pub(crate) struct Set<'src> {
|
||||||
pub(crate) name: Name<'src>,
|
pub(crate) name: Name<'src>,
|
||||||
pub(crate) value: Setting<'src>,
|
pub(crate) value: Setting<'src>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ pub(crate) enum Setting<'src> {
|
|||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub(crate) struct Shell<'src> {
|
pub(crate) struct Shell<'src> {
|
||||||
pub(crate) command: StringLiteral<'src>,
|
pub(crate) command: StringLiteral<'src>,
|
||||||
pub(crate) arguments: Vec<StringLiteral<'src>>,
|
pub(crate) arguments: Vec<StringLiteral<'src>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,19 +2,19 @@ use crate::common::*;
|
|||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub(crate) struct Settings<'src> {
|
pub(crate) struct Settings<'src> {
|
||||||
pub(crate) dotenv_load: Option<bool>,
|
pub(crate) dotenv_load: Option<bool>,
|
||||||
pub(crate) export: bool,
|
pub(crate) export: bool,
|
||||||
pub(crate) positional_arguments: bool,
|
pub(crate) positional_arguments: bool,
|
||||||
pub(crate) shell: Option<setting::Shell<'src>>,
|
pub(crate) shell: Option<setting::Shell<'src>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'src> Settings<'src> {
|
impl<'src> Settings<'src> {
|
||||||
pub(crate) fn new() -> Settings<'src> {
|
pub(crate) fn new() -> Settings<'src> {
|
||||||
Settings {
|
Settings {
|
||||||
dotenv_load: None,
|
dotenv_load: None,
|
||||||
export: false,
|
export: false,
|
||||||
positional_arguments: false,
|
positional_arguments: false,
|
||||||
shell: None,
|
shell: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub(crate) struct Shebang<'line> {
|
pub(crate) struct Shebang<'line> {
|
||||||
pub(crate) interpreter: &'line str,
|
pub(crate) interpreter: &'line str,
|
||||||
pub(crate) argument: Option<&'line str>,
|
pub(crate) argument: Option<&'line str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'line> Shebang<'line> {
|
impl<'line> Shebang<'line> {
|
||||||
|
@ -3,7 +3,7 @@ use crate::common::*;
|
|||||||
#[derive(Debug, PartialEq, Clone, Copy, Ord, PartialOrd, Eq)]
|
#[derive(Debug, PartialEq, Clone, Copy, Ord, PartialOrd, Eq)]
|
||||||
pub(crate) struct StringKind {
|
pub(crate) struct StringKind {
|
||||||
delimiter: StringDelimiter,
|
delimiter: StringDelimiter,
|
||||||
indented: bool,
|
indented: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone, Copy, Ord, PartialOrd, Eq)]
|
#[derive(Debug, PartialEq, Clone, Copy, Ord, PartialOrd, Eq)]
|
||||||
@ -57,8 +57,9 @@ impl StringKind {
|
|||||||
|
|
||||||
pub(crate) fn unterminated_error_kind(self) -> CompileErrorKind<'static> {
|
pub(crate) fn unterminated_error_kind(self) -> CompileErrorKind<'static> {
|
||||||
match self.delimiter {
|
match self.delimiter {
|
||||||
StringDelimiter::QuoteDouble | StringDelimiter::QuoteSingle =>
|
StringDelimiter::QuoteDouble | StringDelimiter::QuoteSingle => {
|
||||||
CompileErrorKind::UnterminatedString,
|
CompileErrorKind::UnterminatedString
|
||||||
|
}
|
||||||
StringDelimiter::Backtick => CompileErrorKind::UnterminatedBacktick,
|
StringDelimiter::Backtick => CompileErrorKind::UnterminatedBacktick,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,8 @@ use crate::common::*;
|
|||||||
|
|
||||||
#[derive(PartialEq, Debug, Clone)]
|
#[derive(PartialEq, Debug, Clone)]
|
||||||
pub(crate) struct StringLiteral<'src> {
|
pub(crate) struct StringLiteral<'src> {
|
||||||
pub(crate) kind: StringKind,
|
pub(crate) kind: StringKind,
|
||||||
pub(crate) raw: &'src str,
|
pub(crate) raw: &'src str,
|
||||||
pub(crate) cooked: String,
|
pub(crate) cooked: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,11 +7,11 @@ pub(crate) enum Subcommand {
|
|||||||
Changelog,
|
Changelog,
|
||||||
Choose {
|
Choose {
|
||||||
overrides: BTreeMap<String, String>,
|
overrides: BTreeMap<String, String>,
|
||||||
chooser: Option<String>,
|
chooser: Option<String>,
|
||||||
},
|
},
|
||||||
Command {
|
Command {
|
||||||
arguments: Vec<OsString>,
|
arguments: Vec<OsString>,
|
||||||
binary: OsString,
|
binary: OsString,
|
||||||
overrides: BTreeMap<String, String>,
|
overrides: BTreeMap<String, String>,
|
||||||
},
|
},
|
||||||
Completions {
|
Completions {
|
||||||
@ -21,7 +21,7 @@ pub(crate) enum Subcommand {
|
|||||||
Edit,
|
Edit,
|
||||||
Evaluate {
|
Evaluate {
|
||||||
overrides: BTreeMap<String, String>,
|
overrides: BTreeMap<String, String>,
|
||||||
variable: Option<String>,
|
variable: Option<String>,
|
||||||
},
|
},
|
||||||
Format,
|
Format,
|
||||||
Init,
|
Init,
|
||||||
@ -45,10 +45,10 @@ impl Subcommand {
|
|||||||
Changelog => {
|
Changelog => {
|
||||||
Self::changelog();
|
Self::changelog();
|
||||||
return Ok(());
|
return Ok(());
|
||||||
},
|
}
|
||||||
Completions { shell } => return Self::completions(&shell),
|
Completions { shell } => return Self::completions(&shell),
|
||||||
Init => return Self::init(config),
|
Init => return Self::init(config),
|
||||||
_ => {},
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
let search = Search::find(&config.search_config, &config.invocation_directory)?;
|
let search = Search::find(&config.search_config, &config.invocation_directory)?;
|
||||||
@ -70,8 +70,9 @@ impl Subcommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
Choose { overrides, chooser } =>
|
Choose { overrides, chooser } => {
|
||||||
Self::choose(config, justfile, &search, overrides, chooser.as_deref())?,
|
Self::choose(config, justfile, &search, overrides, chooser.as_deref())?;
|
||||||
|
}
|
||||||
Command { overrides, .. } => justfile.run(config, &search, overrides, &[])?,
|
Command { overrides, .. } => justfile.run(config, &search, overrides, &[])?,
|
||||||
Dump => Self::dump(ast),
|
Dump => Self::dump(ast),
|
||||||
Evaluate { overrides, .. } => justfile.run(config, &search, overrides, &[])?,
|
Evaluate { overrides, .. } => justfile.run(config, &search, overrides, &[])?,
|
||||||
@ -135,7 +136,7 @@ impl Subcommand {
|
|||||||
chooser,
|
chooser,
|
||||||
io_error,
|
io_error,
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
for recipe in recipes {
|
for recipe in recipes {
|
||||||
@ -153,7 +154,7 @@ impl Subcommand {
|
|||||||
Ok(output) => output,
|
Ok(output) => output,
|
||||||
Err(io_error) => {
|
Err(io_error) => {
|
||||||
return Err(Error::ChooserRead { io_error, chooser });
|
return Err(Error::ChooserRead { io_error, chooser });
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if !output.status.success() {
|
if !output.status.success() {
|
||||||
@ -200,23 +201,26 @@ impl Subcommand {
|
|||||||
let mut script = String::from_utf8(buffer).expect("Clap completion not UTF-8");
|
let mut script = String::from_utf8(buffer).expect("Clap completion not UTF-8");
|
||||||
|
|
||||||
match shell {
|
match shell {
|
||||||
Shell::Bash =>
|
Shell::Bash => {
|
||||||
for (needle, replacement) in completions::BASH_COMPLETION_REPLACEMENTS {
|
for (needle, replacement) in completions::BASH_COMPLETION_REPLACEMENTS {
|
||||||
replace(&mut script, needle, replacement)?;
|
replace(&mut script, needle, replacement)?;
|
||||||
},
|
}
|
||||||
|
}
|
||||||
Shell::Fish => {
|
Shell::Fish => {
|
||||||
script.insert_str(0, completions::FISH_RECIPE_COMPLETIONS);
|
script.insert_str(0, completions::FISH_RECIPE_COMPLETIONS);
|
||||||
},
|
}
|
||||||
Shell::PowerShell =>
|
Shell::PowerShell => {
|
||||||
for (needle, replacement) in completions::POWERSHELL_COMPLETION_REPLACEMENTS {
|
for (needle, replacement) in completions::POWERSHELL_COMPLETION_REPLACEMENTS {
|
||||||
replace(&mut script, needle, replacement)?;
|
replace(&mut script, needle, replacement)?;
|
||||||
},
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Shell::Zsh =>
|
Shell::Zsh => {
|
||||||
for (needle, replacement) in completions::ZSH_COMPLETION_REPLACEMENTS {
|
for (needle, replacement) in completions::ZSH_COMPLETION_REPLACEMENTS {
|
||||||
replace(&mut script, needle, replacement)?;
|
replace(&mut script, needle, replacement)?;
|
||||||
},
|
}
|
||||||
Shell::Elvish => {},
|
}
|
||||||
|
Shell::Elvish => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("{}", script.trim());
|
println!("{}", script.trim());
|
||||||
@ -363,7 +367,7 @@ impl Subcommand {
|
|||||||
_ => {
|
_ => {
|
||||||
let alias_doc = format!("alias for `{}`", recipe.name);
|
let alias_doc = format!("alias for `{}`", recipe.name);
|
||||||
print_doc(&alias_doc);
|
print_doc(&alias_doc);
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
println!();
|
println!();
|
||||||
}
|
}
|
||||||
@ -381,7 +385,7 @@ impl Subcommand {
|
|||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(Error::UnknownRecipes {
|
Err(Error::UnknownRecipes {
|
||||||
recipes: vec![name.to_owned()],
|
recipes: vec![name.to_owned()],
|
||||||
suggestion: justfile.suggest_recipe(name),
|
suggestion: justfile.suggest_recipe(name),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ use crate::common::*;
|
|||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
pub(crate) struct Suggestion<'src> {
|
pub(crate) struct Suggestion<'src> {
|
||||||
pub(crate) name: &'src str,
|
pub(crate) name: &'src str,
|
||||||
pub(crate) target: Option<&'src str>,
|
pub(crate) target: Option<&'src str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ pub fn summary(path: &Path) -> Result<Result<Summary, String>, io::Error> {
|
|||||||
#[derive(Eq, PartialEq, Hash, Ord, PartialOrd, Debug, Clone)]
|
#[derive(Eq, PartialEq, Hash, Ord, PartialOrd, Debug, Clone)]
|
||||||
pub struct Summary {
|
pub struct Summary {
|
||||||
pub assignments: BTreeMap<String, Assignment>,
|
pub assignments: BTreeMap<String, Assignment>,
|
||||||
pub recipes: BTreeMap<String, Recipe>,
|
pub recipes: BTreeMap<String, Recipe>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Summary {
|
impl Summary {
|
||||||
@ -51,7 +51,7 @@ impl Summary {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Summary {
|
Summary {
|
||||||
recipes: justfile
|
recipes: justfile
|
||||||
.recipes
|
.recipes
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(name, recipe)| {
|
.map(|(name, recipe)| {
|
||||||
@ -72,13 +72,13 @@ impl Summary {
|
|||||||
|
|
||||||
#[derive(Eq, PartialEq, Hash, Ord, PartialOrd, Debug, Clone)]
|
#[derive(Eq, PartialEq, Hash, Ord, PartialOrd, Debug, Clone)]
|
||||||
pub struct Recipe {
|
pub struct Recipe {
|
||||||
pub aliases: Vec<String>,
|
pub aliases: Vec<String>,
|
||||||
pub dependencies: Vec<Dependency>,
|
pub dependencies: Vec<Dependency>,
|
||||||
pub lines: Vec<Line>,
|
pub lines: Vec<Line>,
|
||||||
pub private: bool,
|
pub private: bool,
|
||||||
pub quiet: bool,
|
pub quiet: bool,
|
||||||
pub shebang: bool,
|
pub shebang: bool,
|
||||||
pub parameters: Vec<Parameter>,
|
pub parameters: Vec<Parameter>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Recipe {
|
impl Recipe {
|
||||||
@ -101,16 +101,16 @@ impl Recipe {
|
|||||||
|
|
||||||
#[derive(Eq, PartialEq, Hash, Ord, PartialOrd, Debug, Clone)]
|
#[derive(Eq, PartialEq, Hash, Ord, PartialOrd, Debug, Clone)]
|
||||||
pub struct Parameter {
|
pub struct Parameter {
|
||||||
pub kind: ParameterKind,
|
pub kind: ParameterKind,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub default: Option<Expression>,
|
pub default: Option<Expression>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parameter {
|
impl Parameter {
|
||||||
fn new(parameter: &full::Parameter) -> Parameter {
|
fn new(parameter: &full::Parameter) -> Parameter {
|
||||||
Parameter {
|
Parameter {
|
||||||
kind: ParameterKind::new(parameter.kind),
|
kind: ParameterKind::new(parameter.kind),
|
||||||
name: parameter.name.lexeme().to_owned(),
|
name: parameter.name.lexeme().to_owned(),
|
||||||
default: parameter.default.as_ref().map(Expression::new),
|
default: parameter.default.as_ref().map(Expression::new),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -167,14 +167,14 @@ impl Fragment {
|
|||||||
|
|
||||||
#[derive(Eq, PartialEq, Hash, Ord, PartialOrd, Debug, Clone)]
|
#[derive(Eq, PartialEq, Hash, Ord, PartialOrd, Debug, Clone)]
|
||||||
pub struct Assignment {
|
pub struct Assignment {
|
||||||
pub exported: bool,
|
pub exported: bool,
|
||||||
pub expression: Expression,
|
pub expression: Expression,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Assignment {
|
impl Assignment {
|
||||||
fn new(assignment: &full::Assignment) -> Assignment {
|
fn new(assignment: &full::Assignment) -> Assignment {
|
||||||
Assignment {
|
Assignment {
|
||||||
exported: assignment.export,
|
exported: assignment.export,
|
||||||
expression: Expression::new(&assignment.value),
|
expression: Expression::new(&assignment.value),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -186,7 +186,7 @@ pub enum Expression {
|
|||||||
command: String,
|
command: String,
|
||||||
},
|
},
|
||||||
Call {
|
Call {
|
||||||
name: String,
|
name: String,
|
||||||
arguments: Vec<Expression>,
|
arguments: Vec<Expression>,
|
||||||
},
|
},
|
||||||
Concatination {
|
Concatination {
|
||||||
@ -194,11 +194,11 @@ pub enum Expression {
|
|||||||
rhs: Box<Expression>,
|
rhs: Box<Expression>,
|
||||||
},
|
},
|
||||||
Conditional {
|
Conditional {
|
||||||
lhs: Box<Expression>,
|
lhs: Box<Expression>,
|
||||||
rhs: Box<Expression>,
|
rhs: Box<Expression>,
|
||||||
then: Box<Expression>,
|
then: Box<Expression>,
|
||||||
otherwise: Box<Expression>,
|
otherwise: Box<Expression>,
|
||||||
inverted: bool,
|
inverted: bool,
|
||||||
},
|
},
|
||||||
String {
|
String {
|
||||||
text: String,
|
text: String,
|
||||||
@ -217,17 +217,17 @@ impl Expression {
|
|||||||
},
|
},
|
||||||
Call { thunk } => match thunk {
|
Call { thunk } => match thunk {
|
||||||
full::Thunk::Nullary { name, .. } => Expression::Call {
|
full::Thunk::Nullary { name, .. } => Expression::Call {
|
||||||
name: name.lexeme().to_owned(),
|
name: name.lexeme().to_owned(),
|
||||||
arguments: Vec::new(),
|
arguments: Vec::new(),
|
||||||
},
|
},
|
||||||
full::Thunk::Unary { name, arg, .. } => Expression::Call {
|
full::Thunk::Unary { name, arg, .. } => Expression::Call {
|
||||||
name: name.lexeme().to_owned(),
|
name: name.lexeme().to_owned(),
|
||||||
arguments: vec![Expression::new(arg)],
|
arguments: vec![Expression::new(arg)],
|
||||||
},
|
},
|
||||||
full::Thunk::Binary {
|
full::Thunk::Binary {
|
||||||
name, args: [a, b], ..
|
name, args: [a, b], ..
|
||||||
} => Expression::Call {
|
} => Expression::Call {
|
||||||
name: name.lexeme().to_owned(),
|
name: name.lexeme().to_owned(),
|
||||||
arguments: vec![Expression::new(a), Expression::new(b)],
|
arguments: vec![Expression::new(a), Expression::new(b)],
|
||||||
},
|
},
|
||||||
full::Thunk::Ternary {
|
full::Thunk::Ternary {
|
||||||
@ -235,7 +235,7 @@ impl Expression {
|
|||||||
args: [a, b, c],
|
args: [a, b, c],
|
||||||
..
|
..
|
||||||
} => Expression::Call {
|
} => Expression::Call {
|
||||||
name: name.lexeme().to_owned(),
|
name: name.lexeme().to_owned(),
|
||||||
arguments: vec![Expression::new(a), Expression::new(b), Expression::new(c)],
|
arguments: vec![Expression::new(a), Expression::new(b), Expression::new(c)],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -250,11 +250,11 @@ impl Expression {
|
|||||||
then,
|
then,
|
||||||
otherwise,
|
otherwise,
|
||||||
} => Expression::Conditional {
|
} => Expression::Conditional {
|
||||||
lhs: Box::new(Expression::new(lhs)),
|
lhs: Box::new(Expression::new(lhs)),
|
||||||
rhs: Box::new(Expression::new(rhs)),
|
rhs: Box::new(Expression::new(rhs)),
|
||||||
then: Box::new(Expression::new(then)),
|
then: Box::new(Expression::new(then)),
|
||||||
otherwise: Box::new(Expression::new(otherwise)),
|
otherwise: Box::new(Expression::new(otherwise)),
|
||||||
inverted: *inverted,
|
inverted: *inverted,
|
||||||
},
|
},
|
||||||
StringLiteral { string_literal } => Expression::String {
|
StringLiteral { string_literal } => Expression::String {
|
||||||
text: string_literal.cooked.clone(),
|
text: string_literal.cooked.clone(),
|
||||||
@ -269,14 +269,14 @@ impl Expression {
|
|||||||
|
|
||||||
#[derive(Eq, PartialEq, Hash, Ord, PartialOrd, Debug, Clone)]
|
#[derive(Eq, PartialEq, Hash, Ord, PartialOrd, Debug, Clone)]
|
||||||
pub struct Dependency {
|
pub struct Dependency {
|
||||||
pub recipe: String,
|
pub recipe: String,
|
||||||
pub arguments: Vec<Expression>,
|
pub arguments: Vec<Expression>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Dependency {
|
impl Dependency {
|
||||||
fn new(dependency: &full::Dependency) -> Dependency {
|
fn new(dependency: &full::Dependency) -> Dependency {
|
||||||
Dependency {
|
Dependency {
|
||||||
recipe: dependency.recipe.name().to_owned(),
|
recipe: dependency.recipe.name().to_owned(),
|
||||||
arguments: dependency.arguments.iter().map(Expression::new).collect(),
|
arguments: dependency.arguments.iter().map(Expression::new).collect(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -82,7 +82,7 @@ pub(crate) fn analysis_error(
|
|||||||
kind,
|
kind,
|
||||||
};
|
};
|
||||||
assert_eq!(have, want);
|
assert_eq!(have, want);
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
20
src/thunk.rs
20
src/thunk.rs
@ -4,27 +4,27 @@ use crate::common::*;
|
|||||||
#[derivative(Debug, Clone, PartialEq = "feature_allow_slow_enum")]
|
#[derivative(Debug, Clone, PartialEq = "feature_allow_slow_enum")]
|
||||||
pub(crate) enum Thunk<'src> {
|
pub(crate) enum Thunk<'src> {
|
||||||
Nullary {
|
Nullary {
|
||||||
name: Name<'src>,
|
name: Name<'src>,
|
||||||
#[derivative(Debug = "ignore", PartialEq = "ignore")]
|
#[derivative(Debug = "ignore", PartialEq = "ignore")]
|
||||||
function: fn(&FunctionContext) -> Result<String, String>,
|
function: fn(&FunctionContext) -> Result<String, String>,
|
||||||
},
|
},
|
||||||
Unary {
|
Unary {
|
||||||
name: Name<'src>,
|
name: Name<'src>,
|
||||||
#[derivative(Debug = "ignore", PartialEq = "ignore")]
|
#[derivative(Debug = "ignore", PartialEq = "ignore")]
|
||||||
function: fn(&FunctionContext, &str) -> Result<String, String>,
|
function: fn(&FunctionContext, &str) -> Result<String, String>,
|
||||||
arg: Box<Expression<'src>>,
|
arg: Box<Expression<'src>>,
|
||||||
},
|
},
|
||||||
Binary {
|
Binary {
|
||||||
name: Name<'src>,
|
name: Name<'src>,
|
||||||
#[derivative(Debug = "ignore", PartialEq = "ignore")]
|
#[derivative(Debug = "ignore", PartialEq = "ignore")]
|
||||||
function: fn(&FunctionContext, &str, &str) -> Result<String, String>,
|
function: fn(&FunctionContext, &str, &str) -> Result<String, String>,
|
||||||
args: [Box<Expression<'src>>; 2],
|
args: [Box<Expression<'src>>; 2],
|
||||||
},
|
},
|
||||||
Ternary {
|
Ternary {
|
||||||
name: Name<'src>,
|
name: Name<'src>,
|
||||||
#[derivative(Debug = "ignore", PartialEq = "ignore")]
|
#[derivative(Debug = "ignore", PartialEq = "ignore")]
|
||||||
function: fn(&FunctionContext, &str, &str, &str) -> Result<String, String>,
|
function: fn(&FunctionContext, &str, &str, &str) -> Result<String, String>,
|
||||||
args: [Box<Expression<'src>>; 3],
|
args: [Box<Expression<'src>>; 3],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,7 +52,7 @@ impl<'src> Thunk<'src> {
|
|||||||
args: [a, b],
|
args: [a, b],
|
||||||
name,
|
name,
|
||||||
})
|
})
|
||||||
},
|
}
|
||||||
(Function::Ternary(function), 3) => {
|
(Function::Ternary(function), 3) => {
|
||||||
let c = Box::new(arguments.pop().unwrap());
|
let c = Box::new(arguments.pop().unwrap());
|
||||||
let b = Box::new(arguments.pop().unwrap());
|
let b = Box::new(arguments.pop().unwrap());
|
||||||
@ -62,10 +62,10 @@ impl<'src> Thunk<'src> {
|
|||||||
args: [a, b, c],
|
args: [a, b, c],
|
||||||
name,
|
name,
|
||||||
})
|
})
|
||||||
},
|
}
|
||||||
_ => Err(name.error(CompileErrorKind::FunctionArgumentCountMismatch {
|
_ => Err(name.error(CompileErrorKind::FunctionArgumentCountMismatch {
|
||||||
function: name.lexeme(),
|
function: name.lexeme(),
|
||||||
found: arguments.len(),
|
found: arguments.len(),
|
||||||
expected: function.argc(),
|
expected: function.argc(),
|
||||||
})),
|
})),
|
||||||
}
|
}
|
||||||
|
13
src/token.rs
13
src/token.rs
@ -4,10 +4,10 @@ use crate::common::*;
|
|||||||
pub(crate) struct Token<'src> {
|
pub(crate) struct Token<'src> {
|
||||||
pub(crate) offset: usize,
|
pub(crate) offset: usize,
|
||||||
pub(crate) length: usize,
|
pub(crate) length: usize,
|
||||||
pub(crate) line: usize,
|
pub(crate) line: usize,
|
||||||
pub(crate) column: usize,
|
pub(crate) column: usize,
|
||||||
pub(crate) src: &'src str,
|
pub(crate) src: &'src str,
|
||||||
pub(crate) kind: TokenKind,
|
pub(crate) kind: TokenKind,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'src> Token<'src> {
|
impl<'src> Token<'src> {
|
||||||
@ -65,15 +65,16 @@ impl<'src> ColorDisplay for Token<'src> {
|
|||||||
space_width.max(1),
|
space_width.max(1),
|
||||||
color.suffix()
|
color.suffix()
|
||||||
)?;
|
)?;
|
||||||
},
|
}
|
||||||
None =>
|
None => {
|
||||||
if self.offset != self.src.len() {
|
if self.offset != self.src.len() {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"internal error: Error has invalid line number: {}",
|
"internal error: Error has invalid line number: {}",
|
||||||
line_number
|
line_number
|
||||||
)?;
|
)?;
|
||||||
},
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -37,37 +37,41 @@ pub(crate) enum TokenKind {
|
|||||||
impl Display for TokenKind {
|
impl Display for TokenKind {
|
||||||
fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
|
fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
|
||||||
use TokenKind::*;
|
use TokenKind::*;
|
||||||
write!(f, "{}", match *self {
|
write!(
|
||||||
AmpersandAmpersand => "'&&'",
|
f,
|
||||||
Asterisk => "'*'",
|
"{}",
|
||||||
At => "'@'",
|
match *self {
|
||||||
Backtick => "backtick",
|
AmpersandAmpersand => "'&&'",
|
||||||
BangEquals => "'!='",
|
Asterisk => "'*'",
|
||||||
BraceL => "'{'",
|
At => "'@'",
|
||||||
BraceR => "'}'",
|
Backtick => "backtick",
|
||||||
BracketL => "'['",
|
BangEquals => "'!='",
|
||||||
BracketR => "']'",
|
BraceL => "'{'",
|
||||||
Colon => "':'",
|
BraceR => "'}'",
|
||||||
ColonEquals => "':='",
|
BracketL => "'['",
|
||||||
Comma => "','",
|
BracketR => "']'",
|
||||||
Comment => "comment",
|
Colon => "':'",
|
||||||
Dedent => "dedent",
|
ColonEquals => "':='",
|
||||||
Dollar => "'$'",
|
Comma => "','",
|
||||||
Eof => "end of file",
|
Comment => "comment",
|
||||||
Eol => "end of line",
|
Dedent => "dedent",
|
||||||
Equals => "'='",
|
Dollar => "'$'",
|
||||||
EqualsEquals => "'=='",
|
Eof => "end of file",
|
||||||
Identifier => "identifier",
|
Eol => "end of line",
|
||||||
Indent => "indent",
|
Equals => "'='",
|
||||||
InterpolationEnd => "'}}'",
|
EqualsEquals => "'=='",
|
||||||
InterpolationStart => "'{{'",
|
Identifier => "identifier",
|
||||||
ParenL => "'('",
|
Indent => "indent",
|
||||||
ParenR => "')'",
|
InterpolationEnd => "'}}'",
|
||||||
Plus => "'+'",
|
InterpolationStart => "'{{'",
|
||||||
StringToken => "string",
|
ParenL => "'('",
|
||||||
Text => "command text",
|
ParenR => "')'",
|
||||||
Unspecified => "unspecified",
|
Plus => "'+'",
|
||||||
Whitespace => "whitespace",
|
StringToken => "string",
|
||||||
})
|
Text => "command text",
|
||||||
|
Unspecified => "unspecified",
|
||||||
|
Whitespace => "whitespace",
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -92,7 +92,7 @@ impl<'text> Tree<'text> {
|
|||||||
Tree::List(mut children) => {
|
Tree::List(mut children) => {
|
||||||
children.push(tree.into());
|
children.push(tree.into());
|
||||||
Tree::List(children)
|
Tree::List(children)
|
||||||
},
|
}
|
||||||
Tree::Atom(text) => Tree::List(vec![Tree::Atom(text), tree.into()]),
|
Tree::Atom(text) => Tree::List(vec![Tree::Atom(text), tree.into()]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -137,7 +137,7 @@ impl Display for Tree<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
write!(f, ")")
|
write!(f, ")")
|
||||||
},
|
}
|
||||||
Tree::Atom(text) => write!(f, "{}", text),
|
Tree::Atom(text) => write!(f, "{}", text),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ use crate::common::*;
|
|||||||
|
|
||||||
#[derive(PartialEq, Debug, Clone)]
|
#[derive(PartialEq, Debug, Clone)]
|
||||||
pub(crate) struct UnresolvedDependency<'src> {
|
pub(crate) struct UnresolvedDependency<'src> {
|
||||||
pub(crate) recipe: Name<'src>,
|
pub(crate) recipe: Name<'src>,
|
||||||
pub(crate) arguments: Vec<Expression<'src>>,
|
pub(crate) arguments: Vec<Expression<'src>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,9 +26,9 @@ impl<'src> UnresolvedRecipe<'src> {
|
|||||||
.recipe
|
.recipe
|
||||||
.error(CompileErrorKind::DependencyArgumentCountMismatch {
|
.error(CompileErrorKind::DependencyArgumentCountMismatch {
|
||||||
dependency: unresolved.recipe.lexeme(),
|
dependency: unresolved.recipe.lexeme(),
|
||||||
found: unresolved.arguments.len(),
|
found: unresolved.arguments.len(),
|
||||||
min: resolved.min_arguments(),
|
min: resolved.min_arguments(),
|
||||||
max: resolved.max_arguments(),
|
max: resolved.max_arguments(),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -39,7 +39,7 @@ impl<'src> UnresolvedRecipe<'src> {
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.zip(resolved)
|
.zip(resolved)
|
||||||
.map(|(unresolved, resolved)| Dependency {
|
.map(|(unresolved, resolved)| Dependency {
|
||||||
recipe: resolved,
|
recipe: resolved,
|
||||||
arguments: unresolved.arguments,
|
arguments: unresolved.arguments,
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
@ -31,17 +31,17 @@ impl<'expression, 'src> Iterator for Variables<'expression, 'src> {
|
|||||||
self.stack.push(then);
|
self.stack.push(then);
|
||||||
self.stack.push(otherwise);
|
self.stack.push(otherwise);
|
||||||
self.next()
|
self.next()
|
||||||
},
|
}
|
||||||
Some(Expression::Variable { name, .. }) => Some(name.token()),
|
Some(Expression::Variable { name, .. }) => Some(name.token()),
|
||||||
Some(Expression::Concatination { lhs, rhs }) => {
|
Some(Expression::Concatination { lhs, rhs }) => {
|
||||||
self.stack.push(lhs);
|
self.stack.push(lhs);
|
||||||
self.stack.push(rhs);
|
self.stack.push(rhs);
|
||||||
self.next()
|
self.next()
|
||||||
},
|
}
|
||||||
Some(Expression::Group { contents }) => {
|
Some(Expression::Group { contents }) => {
|
||||||
self.stack.push(contents);
|
self.stack.push(contents);
|
||||||
self.next()
|
self.next()
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@ adding the following line to your shell rc file:
|
|||||||
export JUST_SUPPRESS_DOTENV_LOAD_WARNING=1
|
export JUST_SUPPRESS_DOTENV_LOAD_WARNING=1
|
||||||
|
|
||||||
See https://github.com/casey/just/issues/469 for more details.")?;
|
See https://github.com/casey/just/issues/469 for more details.")?;
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
write!(f, "{}", message.suffix())?;
|
write!(f, "{}", message.suffix())?;
|
||||||
|
Loading…
Reference in New Issue
Block a user