diff --git a/src/alias_style.rs b/src/alias_style.rs new file mode 100644 index 00000000..ade5b2fe --- /dev/null +++ b/src/alias_style.rs @@ -0,0 +1,8 @@ +use super::*; + +#[derive(Debug, PartialEq, Clone, ValueEnum)] +pub(crate) enum AliasStyle { + Inline, + InlineLeft, + Recipe, +} diff --git a/src/color.rs b/src/color.rs index ccdf2185..cc454ea6 100644 --- a/src/color.rs +++ b/src/color.rs @@ -66,6 +66,10 @@ impl Color { self.restyle(Style::new().fg(Blue)) } + pub(crate) fn alias(self) -> Self { + self.restyle(Style::new().fg(Purple)) + } + pub(crate) fn error(self) -> Self { self.restyle(Style::new().fg(Red).bold()) } diff --git a/src/config.rs b/src/config.rs index d0b91d67..ca4c58e8 100644 --- a/src/config.rs +++ b/src/config.rs @@ -9,6 +9,7 @@ use { #[derive(Debug, PartialEq)] pub(crate) struct Config { + pub(crate) alias_style: AliasStyle, pub(crate) check: bool, pub(crate) color: Color, pub(crate) command_color: Option, @@ -80,6 +81,7 @@ mod cmd { } mod arg { + pub(crate) const ALIAS_STYLE: &str = "ALIAS_STYLE"; pub(crate) const ARGUMENTS: &str = "ARGUMENTS"; pub(crate) const CHECK: &str = "CHECK"; pub(crate) const CHOOSER: &str = "CHOOSER"; @@ -135,6 +137,16 @@ impl Config { .placeholder(AnsiColor::Green.on_default()) .usage(AnsiColor::Yellow.on_default()), ) + .arg( + Arg::new(arg::ALIAS_STYLE) + .long("alias-style") + .env("JUST_ALIAS_STYLE") + .action(ArgAction::Set) + .value_parser(clap::value_parser!(AliasStyle)) + .default_value("inline") + .help("Set the style that the list command will display aliases") + .conflicts_with(arg::NO_ALIASES), + ) .arg( Arg::new(arg::CHECK) .long("check") @@ -706,6 +718,10 @@ impl Config { let explain = matches.get_flag(arg::EXPLAIN); Ok(Self { + alias_style: matches + .get_one::(arg::ALIAS_STYLE) + .unwrap() + .clone(), check: matches.get_flag(arg::CHECK), color: (*matches.get_one::(arg::COLOR).unwrap()).into(), command_color: matches diff --git a/src/lib.rs b/src/lib.rs index 75e3332b..ad0ce0d0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,16 +6,16 @@ pub(crate) use { crate::{ - alias::Alias, analyzer::Analyzer, argument_parser::ArgumentParser, assignment::Assignment, - assignment_resolver::AssignmentResolver, ast::Ast, attribute::Attribute, binding::Binding, - color::Color, color_display::ColorDisplay, command_color::CommandColor, - command_ext::CommandExt, compilation::Compilation, compile_error::CompileError, - compile_error_kind::CompileErrorKind, compiler::Compiler, condition::Condition, - conditional_operator::ConditionalOperator, config::Config, config_error::ConfigError, - constants::constants, count::Count, delimiter::Delimiter, dependency::Dependency, - dump_format::DumpFormat, enclosure::Enclosure, error::Error, evaluator::Evaluator, - execution_context::ExecutionContext, executor::Executor, expression::Expression, - fragment::Fragment, function::Function, interpreter::Interpreter, + alias::Alias, alias_style::AliasStyle, analyzer::Analyzer, argument_parser::ArgumentParser, + assignment::Assignment, assignment_resolver::AssignmentResolver, ast::Ast, + attribute::Attribute, binding::Binding, color::Color, color_display::ColorDisplay, + command_color::CommandColor, command_ext::CommandExt, compilation::Compilation, + compile_error::CompileError, compile_error_kind::CompileErrorKind, compiler::Compiler, + condition::Condition, conditional_operator::ConditionalOperator, config::Config, + config_error::ConfigError, constants::constants, count::Count, delimiter::Delimiter, + dependency::Dependency, dump_format::DumpFormat, enclosure::Enclosure, error::Error, + evaluator::Evaluator, execution_context::ExecutionContext, executor::Executor, + expression::Expression, fragment::Fragment, function::Function, interpreter::Interpreter, interrupt_guard::InterruptGuard, interrupt_handler::InterruptHandler, item::Item, justfile::Justfile, keyed::Keyed, keyword::Keyword, lexer::Lexer, line::Line, list::List, load_dotenv::load_dotenv, loader::Loader, module_path::ModulePath, name::Name, @@ -107,6 +107,7 @@ pub mod fuzzing; pub mod summary; mod alias; +mod alias_style; mod analyzer; mod argument_parser; mod assignment; diff --git a/src/subcommand.rs b/src/subcommand.rs index b1f13592..687a7a3e 100644 --- a/src/subcommand.rs +++ b/src/subcommand.rs @@ -408,20 +408,49 @@ impl Subcommand { config: &Config, name: &str, doc: Option<&str>, + aliases: &[&str], max_signature_width: usize, signature_widths: &BTreeMap<&str, usize>, ) { - if let Some(doc) = doc { - if !doc.is_empty() && doc.lines().count() <= 1 { - print!( - "{:padding$}{} {}", - "", - config.color.stdout().doc().paint("#"), - config.color.stdout().doc().paint(doc), - padding = max_signature_width.saturating_sub(signature_widths[name]) + 1, - ); - } + let doc = doc.unwrap_or_default(); + let print_doc = !doc.is_empty() && doc.lines().count() <= 1; + let print_aliases = config.alias_style != AliasStyle::Recipe && !aliases.is_empty(); + + if print_doc || print_aliases { + print!( + "{:padding$}{}", + "", + config.color.stdout().doc().paint("#"), + padding = max_signature_width.saturating_sub(signature_widths[name]) + 1, + ); } + + let doc = print_doc.then_some(format!("{}", config.color.stdout().doc().paint(doc))); + let aliases = print_aliases.then_some(format!( + "{}", + config + .color + .stdout() + .alias() + .paint(&format!("[aliases: {}]", aliases.join(", "))) + )); + + let (left, right) = if config.alias_style == AliasStyle::InlineLeft { + (aliases, doc) + } else { + (doc, aliases) + }; + + if print_doc || print_aliases { + print!( + " {}", + [left, right] + .map(Option::unwrap_or_default) + .join(" ") + .trim() + ); + } + println!(); } @@ -545,8 +574,14 @@ impl Subcommand { if let Some(recipes) = recipe_groups.get(&group) { for recipe in recipes { + let recipe_alias_entries = if config.alias_style == AliasStyle::Recipe { + aliases.get(recipe.name()) + } else { + None + }; + for (i, name) in iter::once(&recipe.name()) - .chain(aliases.get(recipe.name()).unwrap_or(&Vec::new())) + .chain(recipe_alias_entries.unwrap_or(&Vec::new())) .enumerate() { let doc = if i == 0 { @@ -576,6 +611,7 @@ impl Subcommand { config, name, doc.as_deref(), + aliases.get(recipe.name()).unwrap_or(&Vec::new()), max_signature_width, &signature_widths, ); @@ -598,6 +634,7 @@ impl Subcommand { config, submodule.name(), submodule.doc.as_deref(), + &Vec::new(), max_signature_width, &signature_widths, ); diff --git a/tests/alias_style.rs b/tests/alias_style.rs new file mode 100644 index 00000000..1b2f94b2 --- /dev/null +++ b/tests/alias_style.rs @@ -0,0 +1,60 @@ +use super::*; + +#[test] +fn alias_style_inline() { + Test::new() + .justfile( + " + alias t := test1 + + # A test recipe + test1: + @echo 'test1' + + test2: + @echo 'test2' + ", + ) + .args(["--alias-style=inline", "--list"]) + .stdout("Available recipes:\n test1 # A test recipe [aliases: t]\n test2\n") + .run(); +} + +#[test] +fn alias_style_inline_left() { + Test::new() + .justfile( + " + alias t := test1 + + # A test recipe + test1: + @echo 'test1' + + test2: + @echo 'test2' + ", + ) + .args(["--alias-style=inline-left", "--list"]) + .stdout("Available recipes:\n test1 # [aliases: t] A test recipe\n test2\n") + .run(); +} + +#[test] +fn alias_style_recipe() { + Test::new() + .justfile( + " + alias t := test1 + + test1: + @echo 'test1' + + test2: + @echo 'test2' + ", + ) + .args(["--alias-style=recipe", "--list"]) + .stdout("Available recipes:\n test1\n t # alias for `test1`\n test2\n") + .run(); +} diff --git a/tests/lib.rs b/tests/lib.rs index 7c85460b..5d1d520b 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -31,6 +31,7 @@ pub(crate) use { #[macro_use] mod test; +mod alias_style; mod allow_duplicate_recipes; mod allow_duplicate_variables; mod assert_stdout; diff --git a/tests/misc.rs b/tests/misc.rs index 590c13cd..db2eb552 100644 --- a/tests/misc.rs +++ b/tests/misc.rs @@ -11,20 +11,40 @@ test! { args: ("--list"), stdout: " Available recipes: - foo - f # alias for `foo` + foo # [aliases: f] ", } +#[test] +fn alias_listing_with_doc() { + Test::new() + .justfile( + " + # foo command + foo: + echo foo + + alias f := foo + ", + ) + .arg("--list") + .stdout( + " + Available recipes: + foo # foo command [aliases: f] + ", + ) + .status(EXIT_SUCCESS) + .run(); +} + test! { name: alias_listing_multiple_aliases, justfile: "foo:\n echo foo\nalias f := foo\nalias fo := foo", args: ("--list"), stdout: " Available recipes: - foo - f # alias for `foo` - fo # alias for `foo` + foo # [aliases: f, fo] ", } @@ -34,8 +54,7 @@ test! { args: ("--list"), stdout: " Available recipes: - foo PARAM='foo' - f PARAM='foo' # alias for `foo` + foo PARAM='foo' # [aliases: f] ", } @@ -927,8 +946,7 @@ a: stdout: r" Available recipes: a - b - c # alias for `b` + b # [aliases: c] ", } @@ -942,8 +960,7 @@ a: args: ("--list", "--unsorted"), stdout: r" Available recipes: - b - c # alias for `b` + b # [aliases: c] a ", }