1
1
mirror of https://github.com/casey/just.git synced 2024-11-22 18:34:06 +03:00
This commit is contained in:
Marc Addeo 2024-11-05 11:00:32 -05:00 committed by GitHub
commit 04adca563b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 176 additions and 32 deletions

8
src/alias_style.rs Normal file
View File

@ -0,0 +1,8 @@
use super::*;
#[derive(Debug, PartialEq, Clone, ValueEnum)]
pub(crate) enum AliasStyle {
Inline,
InlineLeft,
Recipe,
}

View File

@ -66,6 +66,10 @@ impl Color {
self.restyle(Style::new().fg(Blue)) self.restyle(Style::new().fg(Blue))
} }
pub(crate) fn alias(self) -> Self {
self.restyle(Style::new().fg(Purple))
}
pub(crate) fn error(self) -> Self { pub(crate) fn error(self) -> Self {
self.restyle(Style::new().fg(Red).bold()) self.restyle(Style::new().fg(Red).bold())
} }

View File

@ -9,6 +9,7 @@ use {
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub(crate) struct Config { pub(crate) struct Config {
pub(crate) alias_style: AliasStyle,
pub(crate) check: bool, pub(crate) check: bool,
pub(crate) color: Color, pub(crate) color: Color,
pub(crate) command_color: Option<ansi_term::Color>, pub(crate) command_color: Option<ansi_term::Color>,
@ -80,6 +81,7 @@ mod cmd {
} }
mod arg { mod arg {
pub(crate) const ALIAS_STYLE: &str = "ALIAS_STYLE";
pub(crate) const ARGUMENTS: &str = "ARGUMENTS"; pub(crate) const ARGUMENTS: &str = "ARGUMENTS";
pub(crate) const CHECK: &str = "CHECK"; pub(crate) const CHECK: &str = "CHECK";
pub(crate) const CHOOSER: &str = "CHOOSER"; pub(crate) const CHOOSER: &str = "CHOOSER";
@ -135,6 +137,16 @@ impl Config {
.placeholder(AnsiColor::Green.on_default()) .placeholder(AnsiColor::Green.on_default())
.usage(AnsiColor::Yellow.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(
Arg::new(arg::CHECK) Arg::new(arg::CHECK)
.long("check") .long("check")
@ -706,6 +718,10 @@ impl Config {
let explain = matches.get_flag(arg::EXPLAIN); let explain = matches.get_flag(arg::EXPLAIN);
Ok(Self { Ok(Self {
alias_style: matches
.get_one::<AliasStyle>(arg::ALIAS_STYLE)
.unwrap()
.clone(),
check: matches.get_flag(arg::CHECK), check: matches.get_flag(arg::CHECK),
color: (*matches.get_one::<UseColor>(arg::COLOR).unwrap()).into(), color: (*matches.get_one::<UseColor>(arg::COLOR).unwrap()).into(),
command_color: matches command_color: matches

View File

@ -6,16 +6,16 @@
pub(crate) use { pub(crate) use {
crate::{ crate::{
alias::Alias, analyzer::Analyzer, argument_parser::ArgumentParser, assignment::Assignment, alias::Alias, alias_style::AliasStyle, analyzer::Analyzer, argument_parser::ArgumentParser,
assignment_resolver::AssignmentResolver, ast::Ast, attribute::Attribute, binding::Binding, assignment::Assignment, assignment_resolver::AssignmentResolver, ast::Ast,
color::Color, color_display::ColorDisplay, command_color::CommandColor, attribute::Attribute, binding::Binding, color::Color, color_display::ColorDisplay,
command_ext::CommandExt, compilation::Compilation, compile_error::CompileError, command_color::CommandColor, command_ext::CommandExt, compilation::Compilation,
compile_error_kind::CompileErrorKind, compiler::Compiler, condition::Condition, compile_error::CompileError, compile_error_kind::CompileErrorKind, compiler::Compiler,
conditional_operator::ConditionalOperator, config::Config, config_error::ConfigError, condition::Condition, conditional_operator::ConditionalOperator, config::Config,
constants::constants, count::Count, delimiter::Delimiter, dependency::Dependency, config_error::ConfigError, constants::constants, count::Count, delimiter::Delimiter,
dump_format::DumpFormat, enclosure::Enclosure, error::Error, evaluator::Evaluator, dependency::Dependency, dump_format::DumpFormat, enclosure::Enclosure, error::Error,
execution_context::ExecutionContext, executor::Executor, expression::Expression, evaluator::Evaluator, execution_context::ExecutionContext, executor::Executor,
fragment::Fragment, function::Function, interpreter::Interpreter, expression::Expression, fragment::Fragment, function::Function, interpreter::Interpreter,
interrupt_guard::InterruptGuard, interrupt_handler::InterruptHandler, item::Item, interrupt_guard::InterruptGuard, interrupt_handler::InterruptHandler, item::Item,
justfile::Justfile, keyed::Keyed, keyword::Keyword, lexer::Lexer, line::Line, list::List, justfile::Justfile, keyed::Keyed, keyword::Keyword, lexer::Lexer, line::Line, list::List,
load_dotenv::load_dotenv, loader::Loader, module_path::ModulePath, name::Name, load_dotenv::load_dotenv, loader::Loader, module_path::ModulePath, name::Name,
@ -107,6 +107,7 @@ pub mod fuzzing;
pub mod summary; pub mod summary;
mod alias; mod alias;
mod alias_style;
mod analyzer; mod analyzer;
mod argument_parser; mod argument_parser;
mod assignment; mod assignment;

View File

@ -408,20 +408,49 @@ impl Subcommand {
config: &Config, config: &Config,
name: &str, name: &str,
doc: Option<&str>, doc: Option<&str>,
aliases: &[&str],
max_signature_width: usize, max_signature_width: usize,
signature_widths: &BTreeMap<&str, usize>, signature_widths: &BTreeMap<&str, usize>,
) { ) {
if let Some(doc) = doc { let doc = doc.unwrap_or_default();
if !doc.is_empty() && doc.lines().count() <= 1 { 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!( print!(
"{:padding$}{} {}", "{:padding$}{}",
"", "",
config.color.stdout().doc().paint("#"), config.color.stdout().doc().paint("#"),
config.color.stdout().doc().paint(doc),
padding = max_signature_width.saturating_sub(signature_widths[name]) + 1, 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!(); println!();
} }
@ -545,8 +574,14 @@ impl Subcommand {
if let Some(recipes) = recipe_groups.get(&group) { if let Some(recipes) = recipe_groups.get(&group) {
for recipe in recipes { 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()) 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() .enumerate()
{ {
let doc = if i == 0 { let doc = if i == 0 {
@ -576,6 +611,7 @@ impl Subcommand {
config, config,
name, name,
doc.as_deref(), doc.as_deref(),
aliases.get(recipe.name()).unwrap_or(&Vec::new()),
max_signature_width, max_signature_width,
&signature_widths, &signature_widths,
); );
@ -598,6 +634,7 @@ impl Subcommand {
config, config,
submodule.name(), submodule.name(),
submodule.doc.as_deref(), submodule.doc.as_deref(),
&Vec::new(),
max_signature_width, max_signature_width,
&signature_widths, &signature_widths,
); );

60
tests/alias_style.rs Normal file
View File

@ -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();
}

View File

@ -31,6 +31,7 @@ pub(crate) use {
#[macro_use] #[macro_use]
mod test; mod test;
mod alias_style;
mod allow_duplicate_recipes; mod allow_duplicate_recipes;
mod allow_duplicate_variables; mod allow_duplicate_variables;
mod assert_stdout; mod assert_stdout;

View File

@ -11,20 +11,40 @@ test! {
args: ("--list"), args: ("--list"),
stdout: " stdout: "
Available recipes: Available recipes:
foo foo # [aliases: f]
f # alias for `foo`
", ",
} }
#[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! { test! {
name: alias_listing_multiple_aliases, name: alias_listing_multiple_aliases,
justfile: "foo:\n echo foo\nalias f := foo\nalias fo := foo", justfile: "foo:\n echo foo\nalias f := foo\nalias fo := foo",
args: ("--list"), args: ("--list"),
stdout: " stdout: "
Available recipes: Available recipes:
foo foo # [aliases: f, fo]
f # alias for `foo`
fo # alias for `foo`
", ",
} }
@ -34,8 +54,7 @@ test! {
args: ("--list"), args: ("--list"),
stdout: " stdout: "
Available recipes: Available recipes:
foo PARAM='foo' foo PARAM='foo' # [aliases: f]
f PARAM='foo' # alias for `foo`
", ",
} }
@ -927,8 +946,7 @@ a:
stdout: r" stdout: r"
Available recipes: Available recipes:
a a
b b # [aliases: c]
c # alias for `b`
", ",
} }
@ -942,8 +960,7 @@ a:
args: ("--list", "--unsorted"), args: ("--list", "--unsorted"),
stdout: r" stdout: r"
Available recipes: Available recipes:
b b # [aliases: c]
c # alias for `b`
a a
", ",
} }