From 9ecfd2bef4bc9e6da70492b88d0fd13fde2d6a3b Mon Sep 17 00:00:00 2001 From: Casey Rodarmor Date: Fri, 21 Aug 2020 15:13:54 -0700 Subject: [PATCH] Add option to print recipes in source order (#669) Add an `--unsorted` flag, which makes `--list` and `--summary` print their entries in source order. --- completions/just.bash | 2 +- completions/just.elvish | 2 ++ completions/just.fish | 1 + completions/just.powershell | 2 ++ completions/just.zsh | 2 ++ src/common.rs | 2 +- src/config.rs | 57 ++++++++++++++++++++++++++++--------- src/justfile.rs | 14 +++++++++ src/recipe.rs | 4 +++ tests/integration.rs | 54 +++++++++++++++++++++++++++++++++++ 10 files changed, 125 insertions(+), 15 deletions(-) diff --git a/completions/just.bash b/completions/just.bash index 9f425c0c60..7d867fa7ef 100644 --- a/completions/just.bash +++ b/completions/just.bash @@ -20,7 +20,7 @@ _just() { case "${cmd}" in 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 ... " + 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 ... " if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/completions/just.elvish b/completions/just.elvish index a971615518..a823aac1f2 100644 --- a/completions/just.elvish +++ b/completions/just.elvish @@ -32,6 +32,8 @@ edit:completion:arg-completer[just] = [@words]{ cand -q 'Suppress all output' cand --quiet 'Suppress all output' 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 --verbose 'Use verbose output' cand --dump 'Print entire justfile' diff --git a/completions/just.fish b/completions/just.fish index 8dfce77c08..61d2e13b64 100644 --- a/completions/just.fish +++ b/completions/just.fish @@ -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" -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" -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" -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`' diff --git a/completions/just.powershell b/completions/just.powershell index 6c565cb8af..262c702aef 100644 --- a/completions/just.powershell +++ b/completions/just.powershell @@ -37,6 +37,8 @@ Register-ArgumentCompleter -Native -CommandName 'just' -ScriptBlock { [CompletionResult]::new('-q', 'q', [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('-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('--verbose', 'verbose', [CompletionResultType]::ParameterName, 'Use verbose output') [CompletionResult]::new('--dump', 'dump', [CompletionResultType]::ParameterName, 'Print entire justfile') diff --git a/completions/just.zsh b/completions/just.zsh index 7b7888b1b8..c7197861f5 100644 --- a/completions/just.zsh +++ b/completions/just.zsh @@ -33,6 +33,8 @@ _just() { '(--dry-run)-q[Suppress all output]' \ '(--dry-run)--quiet[Suppress all output]' \ '--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]' \ '*--verbose[Use verbose output]' \ '--dump[Print entire justfile]' \ diff --git a/src/common.rs b/src/common.rs index c9ddb1b246..1c688c57f0 100644 --- a/src/common.rs +++ b/src/common.rs @@ -31,7 +31,7 @@ pub(crate) use edit_distance::edit_distance; pub(crate) use libc::EXIT_FAILURE; pub(crate) use log::{info, warn}; pub(crate) use snafu::{ResultExt, Snafu}; -pub(crate) use unicode_width::UnicodeWidthChar; +pub(crate) use unicode_width::{UnicodeWidthChar, UnicodeWidthStr}; // modules pub(crate) use crate::{config_error, keyword, setting}; diff --git a/src/config.rs b/src/config.rs index 756e9ce2f2..8230a3b25a 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,7 +1,6 @@ use crate::common::*; use clap::{App, AppSettings, Arg, ArgGroup, ArgMatches, ArgSettings}; -use unicode_width::UnicodeWidthStr; pub(crate) const DEFAULT_SHELL: &str = "sh"; pub(crate) const DEFAULT_SHELL_ARG: &str = "-cu"; @@ -20,6 +19,7 @@ pub(crate) struct Config { pub(crate) shell_args: Vec, pub(crate) shell_present: bool, pub(crate) subcommand: Subcommand, + pub(crate) unsorted: bool, pub(crate) verbosity: Verbosity, } @@ -71,6 +71,7 @@ mod arg { pub(crate) const SET: &str = "SET"; pub(crate) const SHELL: &str = "SHELL"; pub(crate) const SHELL_ARG: &str = "SHELL-ARG"; + pub(crate) const UNSORTED: &str = "UNSORTED"; pub(crate) const VERBOSE: &str = "VERBOSE"; pub(crate) const WORKING_DIRECTORY: &str = "WORKING-DIRECTORY"; @@ -165,6 +166,12 @@ impl Config { .overrides_with(arg::SHELL_ARG) .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::with_name(arg::VERBOSE) .short("v") @@ -407,6 +414,7 @@ impl Config { quiet: matches.is_present(arg::QUIET), shell: matches.value_of(arg::SHELL).unwrap().to_owned(), load_dotenv: !matches.is_present(arg::NO_DOTENV), + unsorted: matches.is_present(arg::UNSORTED), color, invocation_directory, search_config, @@ -461,7 +469,7 @@ impl Config { overrides, } => self.run(justfile, &search, overrides, arguments), Show { ref name } => Self::show(&name, justfile), - Summary => Self::summary(justfile), + Summary => self.summary(justfile), Variables => Self::variables(justfile), Completions { .. } | Edit | Init => unreachable!(), } @@ -562,14 +570,14 @@ impl Config { let doc_color = self.color.stdout().doc(); println!("Available recipes:"); - for (name, recipe) in &justfile.recipes { + for recipe in justfile.recipes(self.unsorted) { + let name = recipe.name(); + if recipe.private { 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())) .enumerate() { @@ -599,7 +607,10 @@ impl Config { match (i, recipe.doc) { (0, Some(doc)) => print_doc(doc), (0, None) => (), - _ => print_doc(&alias_doc), + _ => { + let alias_doc = format!("alias for `{}`", recipe.name); + print_doc(&alias_doc); + }, } println!(); } @@ -646,17 +657,16 @@ impl Config { } } - fn summary(justfile: Justfile) -> Result<(), i32> { + fn summary(&self, justfile: Justfile) -> Result<(), i32> { if justfile.count() == 0 { eprintln!("Justfile contains no recipes."); } else { let summary = justfile - .recipes + .recipes(self.unsorted) .iter() - .filter(|&(_, recipe)| !recipe.private) - .map(|(name, _)| name) - .cloned() - .collect::>() + .filter(|recipe| recipe.public()) + .map(|recipe| recipe.name()) + .collect::>() .join(" "); println!("{}", summary); } @@ -707,6 +717,7 @@ FLAGS: --no-highlight Don't highlight echoed recipe lines in bold -q, --quiet Suppress all output --summary List names of available recipes + -u, --unsorted Return list and summary entries in source order --variables List names of variables -v, --verbose Use verbose output @@ -753,6 +764,7 @@ ARGS: $(shell_args: $shell_args:expr,)? $(shell_present: $shell_present:expr,)? $(subcommand: $subcommand:expr,)? + $(unsorted: $unsorted:expr,)? $(verbosity: $verbosity:expr,)? } => { #[test] @@ -772,6 +784,7 @@ ARGS: $(shell_args: $shell_args,)? $(shell_present: $shell_present,)? $(subcommand: $subcommand,)? + $(unsorted: $unsorted,)? $(verbosity: $verbosity,)? ..testing::config(&[]) }; @@ -936,6 +949,24 @@ ARGS: 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! { name: quiet_default, args: [], diff --git a/src/justfile.rs b/src/justfile.rs index f6383a1497..6eefe6030c 100644 --- a/src/justfile.rs +++ b/src/justfile.rs @@ -262,6 +262,20 @@ impl<'src> Justfile<'src> { ran.insert(invocation); Ok(()) } + + pub(crate) fn recipes(&self, source_order: bool) -> Vec<&Recipe> { + let mut recipes = self + .recipes + .values() + .map(AsRef::as_ref) + .collect::>>(); + + if source_order { + recipes.sort_by_key(|recipe| recipe.name.offset); + } + + recipes + } } impl<'src> Display for Justfile<'src> { diff --git a/src/recipe.rs b/src/recipe.rs index 2436e08369..c33477b7d3 100644 --- a/src/recipe.rs +++ b/src/recipe.rs @@ -64,6 +64,10 @@ impl<'src, D> Recipe<'src, D> { self.name.line } + pub(crate) fn public(&self) -> bool { + !self.private + } + pub(crate) fn run<'run>( &self, context: &RecipeContext<'src, 'run>, diff --git a/tests/integration.rs b/tests/integration.rs index b40cd04f81..a402ce2c3b 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -372,6 +372,28 @@ _y: 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! { name: select, 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! { name: show_suggestion, justfile: r#"