Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add --fmt subcommand #837

Merged
merged 28 commits into from
Jun 8, 2021
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
8af6116
Add `--fmt` subcommand
vglfr May 23, 2021
91afc5a
Fix lint in src/module.rs
vglfr May 24, 2021
8c9d027
Fix `Display` for UnresolvedRecipe
vglfr May 24, 2021
a048fdf
Rollback Cargo.lock
vglfr May 25, 2021
d61adea
Add integration tests for `--fmt`
vglfr May 27, 2021
54db8fc
Add autocompletions for `--fmt`
vglfr May 27, 2021
8f5d6b3
Merge remote-tracking branch 'upstream/master' into fmt-command
vglfr May 27, 2021
46ff598
Fix nightly autoformat
vglfr May 27, 2021
007978f
Merge branch 'master' into fmt-command
vglfr May 28, 2021
b74cdb2
Fix completions
vglfr May 28, 2021
e8b9fb3
Use `--fmt` format for `--dump`
vglfr May 29, 2021
a132987
Fix formatting
casey May 29, 2021
bc5c24f
Assorted fixes
vglfr Jun 1, 2021
f77a806
Fix formatting
vglfr Jun 1, 2021
636a0cf
Merge branch 'master' into fmt-command
casey Jun 2, 2021
2db31f5
Refactoring & trailing newline test
vglfr Jun 2, 2021
a470c8f
Merge branch 'master' into fmt-command
vglfr Jun 4, 2021
c6f8dee
Formatting fixes
vglfr Jun 4, 2021
c81e32d
Merge branch 'master' into fmt-command
vglfr Jun 8, 2021
1d13d51
Avoid creating temporary string
casey Jun 8, 2021
ba6532a
Help message wording
casey Jun 8, 2021
5c5488d
Fix compilation and regenerate completion scripts
casey Jun 8, 2021
98e0d2a
Fix config test
casey Jun 8, 2021
3454d1b
Refactor doc comment handling
casey Jun 8, 2021
8062d5f
Refactor refactoring
casey Jun 8, 2021
9a89a6d
Remove let
casey Jun 8, 2021
a7958ee
Fix clippy lints
casey Jun 8, 2021
b5755a1
Placate clippy
casey Jun 8, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion completions/just.bash
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ _just() {

case "${cmd}" in
just)
opts=" -q -u -v -e -l -h -V -f -d -c -s --dry-run --highlight --no-dotenv --no-highlight --quiet --shell-command --clear-shell-args --unsorted --verbose --choose --dump --edit --evaluate --init --list --summary --variables --help --version --chooser --color --list-heading --list-prefix --justfile --set --shell --shell-arg --working-directory --command --completions --show <ARGUMENTS>... "
opts=" -q -u -v -e -l -h -V -f -d -c -s --dry-run --highlight --no-dotenv --no-highlight --quiet --shell-command --clear-shell-args --unsorted --verbose --choose --dump --edit --evaluate --fmt --init --list --summary --variables --help --version --chooser --color --list-heading --list-prefix --justfile --set --shell --shell-arg --working-directory --command --completions --show <ARGUMENTS>... "
if [[ ${cur} == -* ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
Expand Down
1 change: 1 addition & 0 deletions completions/just.elvish
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ edit:completion:arg-completer[just] = [@words]{
cand -e 'Edit justfile with editor given by $VISUAL or $EDITOR, falling back to `vim`'
cand --edit 'Edit justfile with editor given by $VISUAL or $EDITOR, falling back to `vim`'
cand --evaluate 'Evaluate and print all variables. If a variable name is given as an argument, only print that variable''s value.'
cand --fmt 'Format justfile and overwrite it in-place'
cand --init 'Initialize new justfile in project root'
cand -l 'List available recipes and their arguments'
cand --list 'List available recipes and their arguments'
Expand Down
1 change: 1 addition & 0 deletions completions/just.fish
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ complete -c just -n "__fish_use_subcommand" -l choose -d 'Select one or more rec
complete -c just -n "__fish_use_subcommand" -l dump -d 'Print entire justfile'
complete -c just -n "__fish_use_subcommand" -s e -l edit -d 'Edit justfile with editor given by $VISUAL or $EDITOR, falling back to `vim`'
complete -c just -n "__fish_use_subcommand" -l evaluate -d 'Evaluate and print all variables. If a variable name is given as an argument, only print that variable\'s value.'
complete -c just -n "__fish_use_subcommand" -l fmt -d 'Format justfile and overwrite it in-place'
complete -c just -n "__fish_use_subcommand" -l init -d 'Initialize new justfile in project root'
complete -c just -n "__fish_use_subcommand" -s l -l list -d 'List available recipes and their arguments'
complete -c just -n "__fish_use_subcommand" -l summary -d 'List names of available recipes'
Expand Down
1 change: 1 addition & 0 deletions completions/just.powershell
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ Register-ArgumentCompleter -Native -CommandName 'just' -ScriptBlock {
[CompletionResult]::new('-e', 'e', [CompletionResultType]::ParameterName, 'Edit justfile with editor given by $VISUAL or $EDITOR, falling back to `vim`')
[CompletionResult]::new('--edit', 'edit', [CompletionResultType]::ParameterName, 'Edit justfile with editor given by $VISUAL or $EDITOR, falling back to `vim`')
[CompletionResult]::new('--evaluate', 'evaluate', [CompletionResultType]::ParameterName, 'Evaluate and print all variables. If a variable name is given as an argument, only print that variable''s value.')
[CompletionResult]::new('--fmt', 'fmt', [CompletionResultType]::ParameterName, 'Format justfile and overwrite it in-place')
[CompletionResult]::new('--init', 'init', [CompletionResultType]::ParameterName, 'Initialize new justfile in project root')
[CompletionResult]::new('-l', 'l', [CompletionResultType]::ParameterName, 'List available recipes and their arguments')
[CompletionResult]::new('--list', 'list', [CompletionResultType]::ParameterName, 'List available recipes and their arguments')
Expand Down
1 change: 1 addition & 0 deletions completions/just.zsh
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ _just() {
'-e[Edit justfile with editor given by $VISUAL or $EDITOR, falling back to `vim`]' \
'--edit[Edit justfile with editor given by $VISUAL or $EDITOR, falling back to `vim`]' \
'--evaluate[Evaluate and print all variables. If a variable name is given as an argument, only print that variable'\''s value.]' \
'--fmt[Format justfile and overwrite it in-place]' \
'--init[Initialize new justfile in project root]' \
'-l[List available recipes and their arguments]' \
'--list[List available recipes and their arguments]' \
Expand Down
2 changes: 1 addition & 1 deletion src/alias.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::common::*;

/// An alias, e.g. `name := target`
#[derive(Debug, PartialEq)]
#[derive(Debug, PartialEq, Clone)]
pub(crate) struct Alias<'src, T = Rc<Recipe<'src>>> {
pub(crate) name: Name<'src>,
pub(crate) target: T,
Expand Down
1 change: 1 addition & 0 deletions src/analyzer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ impl<'src> Analyzer<'src> {
self.analyze_assignment(&assignment)?;
self.assignments.insert(assignment);
},
Item::Comment(_) => (),
Item::Recipe(recipe) => {
self.analyze_recipe(&recipe)?;
self.recipes.insert(recipe);
Expand Down
9 changes: 9 additions & 0 deletions src/assignment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,12 @@ use crate::common::*;

/// An assignment, e.g `foo := bar`
pub(crate) type Assignment<'src> = Binding<'src, Expression<'src>>;

impl<'src> Display for Assignment<'src> {
fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
if self.export {
write!(f, "export ")?;
}
write!(f, "{} := {}", self.name, self.value)
}
}
2 changes: 1 addition & 1 deletion src/binding.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::common::*;

/// A binding of `name` to `value`
#[derive(Debug, PartialEq)]
#[derive(Debug, Clone, PartialEq)]
pub(crate) struct Binding<'src, V = String> {
/// Export binding as an environment variable to child processes
pub(crate) export: bool,
Expand Down
31 changes: 16 additions & 15 deletions src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ pub(crate) use std::{
fs,
io::{self, Cursor, Write},
iter::{self, FromIterator},
mem,
ops::{Index, Range, RangeInclusive},
path::{Path, PathBuf},
process::{self, Command, Stdio},
Expand Down Expand Up @@ -45,21 +46,21 @@ pub(crate) use crate::{
alias::Alias, analyzer::Analyzer, assignment::Assignment,
assignment_resolver::AssignmentResolver, binding::Binding, color::Color,
compilation_error::CompilationError, compilation_error_kind::CompilationErrorKind,
compiler::Compiler, config::Config, config_error::ConfigError, count::Count,
delimiter::Delimiter, dependency::Dependency, enclosure::Enclosure, evaluator::Evaluator,
expression::Expression, fragment::Fragment, function::Function,
function_context::FunctionContext, interrupt_guard::InterruptGuard,
interrupt_handler::InterruptHandler, item::Item, justfile::Justfile, keyword::Keyword,
lexer::Lexer, line::Line, list::List, load_error::LoadError, module::Module, name::Name,
output_error::OutputError, parameter::Parameter, parameter_kind::ParameterKind, parser::Parser,
platform::Platform, position::Position, positional::Positional, recipe::Recipe,
recipe_context::RecipeContext, recipe_resolver::RecipeResolver, runtime_error::RuntimeError,
scope::Scope, search::Search, search_config::SearchConfig, search_error::SearchError, set::Set,
setting::Setting, settings::Settings, shebang::Shebang, show_whitespace::ShowWhitespace,
string_kind::StringKind, string_literal::StringLiteral, subcommand::Subcommand,
suggestion::Suggestion, table::Table, thunk::Thunk, token::Token, token_kind::TokenKind,
unresolved_dependency::UnresolvedDependency, unresolved_recipe::UnresolvedRecipe,
use_color::UseColor, variables::Variables, verbosity::Verbosity, warning::Warning,
config::Config, config_error::ConfigError, count::Count, delimiter::Delimiter,
dependency::Dependency, enclosure::Enclosure, evaluator::Evaluator, expression::Expression,
fragment::Fragment, function::Function, function_context::FunctionContext,
interrupt_guard::InterruptGuard, interrupt_handler::InterruptHandler, item::Item,
justfile::Justfile, keyword::Keyword, lexer::Lexer, line::Line, list::List,
load_error::LoadError, module::Module, name::Name, output_error::OutputError,
parameter::Parameter, parameter_kind::ParameterKind, parser::Parser, platform::Platform,
position::Position, positional::Positional, recipe::Recipe, recipe_context::RecipeContext,
recipe_resolver::RecipeResolver, runtime_error::RuntimeError, scope::Scope, search::Search,
search_config::SearchConfig, search_error::SearchError, set::Set, setting::Setting,
settings::Settings, shebang::Shebang, show_whitespace::ShowWhitespace, string_kind::StringKind,
string_literal::StringLiteral, subcommand::Subcommand, suggestion::Suggestion, table::Table,
thunk::Thunk, token::Token, token_kind::TokenKind, unresolved_dependency::UnresolvedDependency,
unresolved_recipe::UnresolvedRecipe, use_color::UseColor, variables::Variables,
verbosity::Verbosity, warning::Warning,
};

// type aliases
Expand Down
43 changes: 39 additions & 4 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ mod cmd {
pub(crate) const DUMP: &str = "DUMP";
pub(crate) const EDIT: &str = "EDIT";
pub(crate) const EVALUATE: &str = "EVALUATE";
pub(crate) const FORMAT: &str = "FORMAT";
pub(crate) const INIT: &str = "INIT";
pub(crate) const LIST: &str = "LIST";
pub(crate) const SHOW: &str = "SHOW";
Expand All @@ -52,6 +53,7 @@ mod cmd {
DUMP,
EDIT,
EVALUATE,
FORMAT,
INIT,
LIST,
SHOW,
Expand All @@ -63,6 +65,7 @@ mod cmd {
COMPLETIONS,
DUMP,
EDIT,
FORMAT,
INIT,
LIST,
SHOW,
Expand Down Expand Up @@ -266,6 +269,11 @@ impl Config {
"Evaluate and print all variables. If a variable name is given as an argument, only print \
that variable's value.",
))
.arg(
Arg::with_name(cmd::FORMAT)
.long("fmt")
.help("Format justfile and overwrite it in-place"),
)
.arg(
Arg::with_name(cmd::INIT)
.long("init")
Expand Down Expand Up @@ -442,6 +450,8 @@ impl Config {
Subcommand::Summary
} else if matches.is_present(cmd::DUMP) {
Subcommand::Dump
} else if matches.is_present(cmd::FORMAT) {
Subcommand::Format
} else if matches.is_present(cmd::INIT) {
Subcommand::Init
} else if matches.is_present(cmd::LIST) {
Expand Down Expand Up @@ -539,7 +549,9 @@ impl Config {
})
.eprint(self.color)?;

let justfile = Compiler::compile(&src).eprint(self.color)?;
let tokens = Lexer::lex(&src).eprint(self.color)?;
let ast = Parser::parse(&tokens).eprint(self.color)?;
let justfile = Analyzer::analyze(ast.clone()).eprint(self.color)?;

if self.verbosity.loud() {
for warning in &justfile.warnings {
Expand All @@ -555,8 +567,9 @@ impl Config {
Choose { overrides, chooser } =>
self.choose(justfile, &search, overrides, chooser.as_deref())?,
Command { overrides, .. } => self.run(justfile, &search, overrides, &[])?,
Dump => Self::dump(justfile),
Dump => Self::dump(ast)?,
Evaluate { overrides, .. } => self.run(justfile, &search, overrides, &[])?,
Format => Self::format(ast, &search)?,
List => self.list(justfile),
Run {
arguments,
Expand Down Expand Up @@ -676,8 +689,9 @@ impl Config {
self.run(justfile, search, overrides, &recipes)
}

fn dump(justfile: Justfile) {
println!("{}", justfile);
fn dump(ast: Module) -> Result<(), i32> {
print!("{}", ast);
Ok(())
}

pub(crate) fn edit(&self, search: &Search) -> Result<(), i32> {
Expand Down Expand Up @@ -713,6 +727,11 @@ impl Config {
}
}

fn format(ast: Module, search: &Search) -> Result<(), i32> {
fs::write(&search.justfile, ast.to_string()).unwrap();
Ok(())
}

pub(crate) fn init(&self) -> Result<(), i32> {
let search =
Search::init(&self.search_config, &self.invocation_directory).eprint(self.color)?;
Expand Down Expand Up @@ -920,6 +939,7 @@ FLAGS:
--evaluate Evaluate and print all variables. If a variable name is given as an \
argument, only print
that variable's value.
--fmt Format justfile and overwrite it in-place
--highlight Highlight echoed recipe lines in bold
--init Initialize new justfile in project root
-l, --list List available recipes and their arguments
Expand Down Expand Up @@ -1315,6 +1335,11 @@ ARGS:
args: ["--list", "--dump"],
}

error! {
name: subcommand_conflict_fmt,
args: ["--list", "--fmt"],
}

error! {
name: subcommand_conflict_init,
args: ["--list", "--init"],
Expand Down Expand Up @@ -1661,6 +1686,16 @@ ARGS:
},
}

error! {
name: fmt_arguments,
args: ["--fmt", "bar"],
error: ConfigError::SubcommandArguments { subcommand, arguments },
check: {
assert_eq!(subcommand, cmd::FORMAT);
assert_eq!(arguments, &["bar"]);
},
}

error! {
name: init_arguments,
args: ["--init", "bar"],
Expand Down
6 changes: 3 additions & 3 deletions src/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::common::*;
/// parenthetical groups).
///
/// The parser parses both values and expressions into `Expression`s.
#[derive(PartialEq, Debug)]
#[derive(PartialEq, Debug, Clone)]
pub(crate) enum Expression<'src> {
/// `contents`
Backtick {
Expand Down Expand Up @@ -45,7 +45,7 @@ impl<'src> Expression<'src> {
impl<'src> Display for Expression<'src> {
fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
match self {
Expression::Backtick { contents, .. } => write!(f, "`{}`", contents),
Expression::Backtick { token, .. } => write!(f, "{}", token.lexeme()),
Expression::Concatination { lhs, rhs } => write!(f, "{} + {}", lhs, rhs),
Expression::Conditional {
lhs,
Expand All @@ -55,7 +55,7 @@ impl<'src> Display for Expression<'src> {
inverted,
} => write!(
f,
"if {} {} {} {{ {} }} else {{ {} }} ",
"if {} {} {} {{ {} }} else {{ {} }}",
lhs,
if *inverted { "!=" } else { "==" },
rhs,
Expand Down
2 changes: 1 addition & 1 deletion src/fragment.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::common::*;

/// A line fragment consisting either of…
#[derive(PartialEq, Debug)]
#[derive(PartialEq, Debug, Clone)]
pub(crate) enum Fragment<'src> {
/// …raw text…
Text { token: Token<'src> },
Expand Down
15 changes: 14 additions & 1 deletion src/item.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,23 @@
use crate::common::*;

/// A single top-level item
#[derive(Debug)]
#[derive(Debug, Clone)]
pub(crate) enum Item<'src> {
Alias(Alias<'src, Name<'src>>),
Assignment(Assignment<'src>),
Comment(&'src str),
Recipe(UnresolvedRecipe<'src>),
Set(Set<'src>),
}

impl<'src> Display for Item<'src> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
Item::Alias(alias) => write!(f, "{}", alias),
Item::Assignment(assignment) => write!(f, "{}", assignment),
Item::Comment(comment) => write!(f, "{}", comment),
Item::Recipe(recipe) => write!(f, "{}", recipe),
Item::Set(set) => write!(f, "{}", set),
}
}
}
12 changes: 6 additions & 6 deletions src/justfile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -802,7 +802,7 @@ goodbye := \"y\"
hello a b c: x y z
#! blah
#blarg
{{foo + bar}}abc{{goodbye + \"x\"}}xyz
{{ foo + bar }}abc{{ goodbye + \"x\" }}xyz
1
2
3
Expand All @@ -828,7 +828,7 @@ install:

install:
#!/bin/sh
if [[ -f {{practicum}} ]]; then
if [[ -f {{ practicum }} ]]; then
\treturn
fi",
}
Expand Down Expand Up @@ -869,7 +869,7 @@ c := a + b + a + b",
r#"a:
echo {{ `echo hello` + "blarg" }} {{ `echo bob` }}"#,
r#"a:
echo {{`echo hello` + "blarg"}} {{`echo bob`}}"#,
echo {{ `echo hello` + "blarg" }} {{ `echo bob` }}"#,
}

test! {
Expand All @@ -895,7 +895,7 @@ c := a + b + a + b",
"a b c:
{{b}} {{c}}",
"a b c:
{{b}} {{c}}",
{{ b }} {{ c }}",
}

test! {
Expand All @@ -908,7 +908,7 @@ a:
"x := arch()

a:
{{os()}} {{os_family()}}",
{{ os() }} {{ os_family() }}",
}

test! {
Expand All @@ -921,7 +921,7 @@ a:
r#"x := env_var('foo')

a:
{{env_var_or_default('foo' + 'bar', 'baz')}} {{env_var(env_var("baz"))}}"#,
{{ env_var_or_default('foo' + 'bar', 'baz') }} {{ env_var(env_var("baz")) }}"#,
}

test! {
Expand Down
2 changes: 1 addition & 1 deletion src/line.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::common::*;

/// A single line in a recipe body, consisting of any number of `Fragment`s.
#[derive(Debug, PartialEq)]
#[derive(Debug, Clone, PartialEq)]
pub(crate) struct Line<'src> {
pub(crate) fragments: Vec<Fragment<'src>>,
}
Expand Down
Loading