Add option to print recipes in source order (#669)

Add an `--unsorted` flag, which makes `--list` and `--summary` print
their entries in source order.
This commit is contained in:
Casey Rodarmor 2020-08-21 15:13:54 -07:00 committed by GitHub
parent 75898e29b6
commit 9ecfd2bef4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 125 additions and 15 deletions

View File

@ -20,7 +20,7 @@ _just() {
case "${cmd}" in case "${cmd}" in
just) just)
opts=" -q -v -e -l -h -V -f -d -s --dry-run --highlight --no-dotenv --no-highlight --quiet --clear-shell-args --verbose --dump --edit --evaluate --init --list --summary --variables --help --version --color --justfile --set --shell --shell-arg --working-directory --completions --show <ARGUMENTS>... " opts=" -q -u -v -e -l -h -V -f -d -s --dry-run --highlight --no-dotenv --no-highlight --quiet --clear-shell-args --unsorted --verbose --dump --edit --evaluate --init --list --summary --variables --help --version --color --justfile --set --shell --shell-arg --working-directory --completions --show <ARGUMENTS>... "
if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0 return 0

View File

@ -32,6 +32,8 @@ edit:completion:arg-completer[just] = [@words]{
cand -q 'Suppress all output' cand -q 'Suppress all output'
cand --quiet 'Suppress all output' cand --quiet 'Suppress all output'
cand --clear-shell-args 'Clear shell arguments' cand --clear-shell-args 'Clear shell arguments'
cand -u 'Return list and summary entries in source order'
cand --unsorted 'Return list and summary entries in source order'
cand -v 'Use verbose output' cand -v 'Use verbose output'
cand --verbose 'Use verbose output' cand --verbose 'Use verbose output'
cand --dump 'Print entire justfile' cand --dump 'Print entire justfile'

View File

@ -23,6 +23,7 @@ complete -c just -n "__fish_use_subcommand" -l no-dotenv -d 'Don\'t load `.env`
complete -c just -n "__fish_use_subcommand" -l no-highlight -d 'Don\'t highlight echoed recipe lines in bold' complete -c just -n "__fish_use_subcommand" -l no-highlight -d 'Don\'t highlight echoed recipe lines in bold'
complete -c just -n "__fish_use_subcommand" -s q -l quiet -d 'Suppress all output' complete -c just -n "__fish_use_subcommand" -s q -l quiet -d 'Suppress all output'
complete -c just -n "__fish_use_subcommand" -l clear-shell-args -d 'Clear shell arguments' complete -c just -n "__fish_use_subcommand" -l clear-shell-args -d 'Clear shell arguments'
complete -c just -n "__fish_use_subcommand" -s u -l unsorted -d 'Return list and summary entries in source order'
complete -c just -n "__fish_use_subcommand" -s v -l verbose -d 'Use verbose output' complete -c just -n "__fish_use_subcommand" -s v -l verbose -d 'Use verbose output'
complete -c just -n "__fish_use_subcommand" -l dump -d 'Print entire justfile' 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" -s e -l edit -d 'Edit justfile with editor given by $VISUAL or $EDITOR, falling back to `vim`'

View File

@ -37,6 +37,8 @@ Register-ArgumentCompleter -Native -CommandName 'just' -ScriptBlock {
[CompletionResult]::new('-q', 'q', [CompletionResultType]::ParameterName, 'Suppress all output') [CompletionResult]::new('-q', 'q', [CompletionResultType]::ParameterName, 'Suppress all output')
[CompletionResult]::new('--quiet', 'quiet', [CompletionResultType]::ParameterName, 'Suppress all output') [CompletionResult]::new('--quiet', 'quiet', [CompletionResultType]::ParameterName, 'Suppress all output')
[CompletionResult]::new('--clear-shell-args', 'clear-shell-args', [CompletionResultType]::ParameterName, 'Clear shell arguments') [CompletionResult]::new('--clear-shell-args', 'clear-shell-args', [CompletionResultType]::ParameterName, 'Clear shell arguments')
[CompletionResult]::new('-u', 'u', [CompletionResultType]::ParameterName, 'Return list and summary entries in source order')
[CompletionResult]::new('--unsorted', 'unsorted', [CompletionResultType]::ParameterName, 'Return list and summary entries in source order')
[CompletionResult]::new('-v', 'v', [CompletionResultType]::ParameterName, 'Use verbose output') [CompletionResult]::new('-v', 'v', [CompletionResultType]::ParameterName, 'Use verbose output')
[CompletionResult]::new('--verbose', 'verbose', [CompletionResultType]::ParameterName, 'Use verbose output') [CompletionResult]::new('--verbose', 'verbose', [CompletionResultType]::ParameterName, 'Use verbose output')
[CompletionResult]::new('--dump', 'dump', [CompletionResultType]::ParameterName, 'Print entire justfile') [CompletionResult]::new('--dump', 'dump', [CompletionResultType]::ParameterName, 'Print entire justfile')

View File

@ -33,6 +33,8 @@ _just() {
'(--dry-run)-q[Suppress all output]' \ '(--dry-run)-q[Suppress all output]' \
'(--dry-run)--quiet[Suppress all output]' \ '(--dry-run)--quiet[Suppress all output]' \
'--clear-shell-args[Clear shell arguments]' \ '--clear-shell-args[Clear shell arguments]' \
'-u[Return list and summary entries in source order]' \
'--unsorted[Return list and summary entries in source order]' \
'*-v[Use verbose output]' \ '*-v[Use verbose output]' \
'*--verbose[Use verbose output]' \ '*--verbose[Use verbose output]' \
'--dump[Print entire justfile]' \ '--dump[Print entire justfile]' \

View File

@ -31,7 +31,7 @@ pub(crate) use edit_distance::edit_distance;
pub(crate) use libc::EXIT_FAILURE; pub(crate) use libc::EXIT_FAILURE;
pub(crate) use log::{info, warn}; pub(crate) use log::{info, warn};
pub(crate) use snafu::{ResultExt, Snafu}; pub(crate) use snafu::{ResultExt, Snafu};
pub(crate) use unicode_width::UnicodeWidthChar; pub(crate) use unicode_width::{UnicodeWidthChar, UnicodeWidthStr};
// modules // modules
pub(crate) use crate::{config_error, keyword, setting}; pub(crate) use crate::{config_error, keyword, setting};

View File

@ -1,7 +1,6 @@
use crate::common::*; use crate::common::*;
use clap::{App, AppSettings, Arg, ArgGroup, ArgMatches, ArgSettings}; use clap::{App, AppSettings, Arg, ArgGroup, ArgMatches, ArgSettings};
use unicode_width::UnicodeWidthStr;
pub(crate) const DEFAULT_SHELL: &str = "sh"; pub(crate) const DEFAULT_SHELL: &str = "sh";
pub(crate) const DEFAULT_SHELL_ARG: &str = "-cu"; pub(crate) const DEFAULT_SHELL_ARG: &str = "-cu";
@ -20,6 +19,7 @@ pub(crate) struct Config {
pub(crate) shell_args: Vec<String>, pub(crate) shell_args: Vec<String>,
pub(crate) shell_present: bool, pub(crate) shell_present: bool,
pub(crate) subcommand: Subcommand, pub(crate) subcommand: Subcommand,
pub(crate) unsorted: bool,
pub(crate) verbosity: Verbosity, pub(crate) verbosity: Verbosity,
} }
@ -71,6 +71,7 @@ mod arg {
pub(crate) const SET: &str = "SET"; pub(crate) const SET: &str = "SET";
pub(crate) const SHELL: &str = "SHELL"; pub(crate) const SHELL: &str = "SHELL";
pub(crate) const SHELL_ARG: &str = "SHELL-ARG"; pub(crate) const SHELL_ARG: &str = "SHELL-ARG";
pub(crate) const UNSORTED: &str = "UNSORTED";
pub(crate) const VERBOSE: &str = "VERBOSE"; pub(crate) const VERBOSE: &str = "VERBOSE";
pub(crate) const WORKING_DIRECTORY: &str = "WORKING-DIRECTORY"; pub(crate) const WORKING_DIRECTORY: &str = "WORKING-DIRECTORY";
@ -165,6 +166,12 @@ impl Config {
.overrides_with(arg::SHELL_ARG) .overrides_with(arg::SHELL_ARG)
.help("Clear shell arguments"), .help("Clear shell arguments"),
) )
.arg(
Arg::with_name(arg::UNSORTED)
.long("unsorted")
.short("u")
.help("Return list and summary entries in source order"),
)
.arg( .arg(
Arg::with_name(arg::VERBOSE) Arg::with_name(arg::VERBOSE)
.short("v") .short("v")
@ -407,6 +414,7 @@ impl Config {
quiet: matches.is_present(arg::QUIET), quiet: matches.is_present(arg::QUIET),
shell: matches.value_of(arg::SHELL).unwrap().to_owned(), shell: matches.value_of(arg::SHELL).unwrap().to_owned(),
load_dotenv: !matches.is_present(arg::NO_DOTENV), load_dotenv: !matches.is_present(arg::NO_DOTENV),
unsorted: matches.is_present(arg::UNSORTED),
color, color,
invocation_directory, invocation_directory,
search_config, search_config,
@ -461,7 +469,7 @@ impl Config {
overrides, overrides,
} => self.run(justfile, &search, overrides, arguments), } => self.run(justfile, &search, overrides, arguments),
Show { ref name } => Self::show(&name, justfile), Show { ref name } => Self::show(&name, justfile),
Summary => Self::summary(justfile), Summary => self.summary(justfile),
Variables => Self::variables(justfile), Variables => Self::variables(justfile),
Completions { .. } | Edit | Init => unreachable!(), Completions { .. } | Edit | Init => unreachable!(),
} }
@ -562,14 +570,14 @@ impl Config {
let doc_color = self.color.stdout().doc(); let doc_color = self.color.stdout().doc();
println!("Available recipes:"); println!("Available recipes:");
for (name, recipe) in &justfile.recipes { for recipe in justfile.recipes(self.unsorted) {
let name = recipe.name();
if recipe.private { if recipe.private {
continue; continue;
} }
let alias_doc = format!("alias for `{}`", recipe.name); for (i, name) in iter::once(&name)
for (i, name) in iter::once(name)
.chain(recipe_aliases.get(name).unwrap_or(&Vec::new())) .chain(recipe_aliases.get(name).unwrap_or(&Vec::new()))
.enumerate() .enumerate()
{ {
@ -599,7 +607,10 @@ impl Config {
match (i, recipe.doc) { match (i, recipe.doc) {
(0, Some(doc)) => print_doc(doc), (0, Some(doc)) => print_doc(doc),
(0, None) => (), (0, None) => (),
_ => print_doc(&alias_doc), _ => {
let alias_doc = format!("alias for `{}`", recipe.name);
print_doc(&alias_doc);
},
} }
println!(); println!();
} }
@ -646,17 +657,16 @@ impl Config {
} }
} }
fn summary(justfile: Justfile) -> Result<(), i32> { fn summary(&self, justfile: Justfile) -> Result<(), i32> {
if justfile.count() == 0 { if justfile.count() == 0 {
eprintln!("Justfile contains no recipes."); eprintln!("Justfile contains no recipes.");
} else { } else {
let summary = justfile let summary = justfile
.recipes .recipes(self.unsorted)
.iter() .iter()
.filter(|&(_, recipe)| !recipe.private) .filter(|recipe| recipe.public())
.map(|(name, _)| name) .map(|recipe| recipe.name())
.cloned() .collect::<Vec<&str>>()
.collect::<Vec<_>>()
.join(" "); .join(" ");
println!("{}", summary); println!("{}", summary);
} }
@ -707,6 +717,7 @@ FLAGS:
--no-highlight Don't highlight echoed recipe lines in bold --no-highlight Don't highlight echoed recipe lines in bold
-q, --quiet Suppress all output -q, --quiet Suppress all output
--summary List names of available recipes --summary List names of available recipes
-u, --unsorted Return list and summary entries in source order
--variables List names of variables --variables List names of variables
-v, --verbose Use verbose output -v, --verbose Use verbose output
@ -753,6 +764,7 @@ ARGS:
$(shell_args: $shell_args:expr,)? $(shell_args: $shell_args:expr,)?
$(shell_present: $shell_present:expr,)? $(shell_present: $shell_present:expr,)?
$(subcommand: $subcommand:expr,)? $(subcommand: $subcommand:expr,)?
$(unsorted: $unsorted:expr,)?
$(verbosity: $verbosity:expr,)? $(verbosity: $verbosity:expr,)?
} => { } => {
#[test] #[test]
@ -772,6 +784,7 @@ ARGS:
$(shell_args: $shell_args,)? $(shell_args: $shell_args,)?
$(shell_present: $shell_present,)? $(shell_present: $shell_present,)?
$(subcommand: $subcommand,)? $(subcommand: $subcommand,)?
$(unsorted: $unsorted,)?
$(verbosity: $verbosity,)? $(verbosity: $verbosity,)?
..testing::config(&[]) ..testing::config(&[])
}; };
@ -936,6 +949,24 @@ ARGS:
highlight: false, highlight: false,
} }
test! {
name: unsorted_default,
args: [],
unsorted: false,
}
test! {
name: unsorted_long,
args: ["--unsorted"],
unsorted: true,
}
test! {
name: unsorted_short,
args: ["-u"],
unsorted: true,
}
test! { test! {
name: quiet_default, name: quiet_default,
args: [], args: [],

View File

@ -262,6 +262,20 @@ impl<'src> Justfile<'src> {
ran.insert(invocation); ran.insert(invocation);
Ok(()) Ok(())
} }
pub(crate) fn recipes(&self, source_order: bool) -> Vec<&Recipe<Dependency>> {
let mut recipes = self
.recipes
.values()
.map(AsRef::as_ref)
.collect::<Vec<&Recipe<Dependency>>>();
if source_order {
recipes.sort_by_key(|recipe| recipe.name.offset);
}
recipes
}
} }
impl<'src> Display for Justfile<'src> { impl<'src> Display for Justfile<'src> {

View File

@ -64,6 +64,10 @@ impl<'src, D> Recipe<'src, D> {
self.name.line self.name.line
} }
pub(crate) fn public(&self) -> bool {
!self.private
}
pub(crate) fn run<'run>( pub(crate) fn run<'run>(
&self, &self,
context: &RecipeContext<'src, 'run>, context: &RecipeContext<'src, 'run>,

View File

@ -372,6 +372,28 @@ _y:
stdout: "a b c d\n", stdout: "a b c d\n",
} }
test! {
name: summary_sorted,
justfile: "
b:
c:
a:
",
args: ("--summary"),
stdout: "a b c\n",
}
test! {
name: summary_unsorted,
justfile: "
b:
c:
a:
",
args: ("--summary", "--unsorted"),
stdout: "b c a\n",
}
test! { test! {
name: select, name: select,
justfile: "b: justfile: "b:
@ -1235,6 +1257,38 @@ _private-recipe:
"#, "#,
} }
test! {
name: list_sorted,
justfile: r#"
alias c := b
b:
a:
"#,
args: ("--list"),
stdout: r#"
Available recipes:
a
b
c # alias for `b`
"#,
}
test! {
name: list_unsorted,
justfile: r#"
alias c := b
b:
a:
"#,
args: ("--list", "--unsorted"),
stdout: r#"
Available recipes:
b
c # alias for `b`
a
"#,
}
test! { test! {
name: show_suggestion, name: show_suggestion,
justfile: r#" justfile: r#"