Fix submodule recipe listing indentation (#2063)

This commit is contained in:
Casey Rodarmor 2024-05-20 00:25:18 -07:00 committed by GitHub
parent 9e658fba39
commit d6b2e6bad2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 135 additions and 88 deletions

View File

@ -29,13 +29,14 @@ pub(crate) use {
output::output, output_error::OutputError, parameter::Parameter, parameter_kind::ParameterKind, output::output, output_error::OutputError, parameter::Parameter, parameter_kind::ParameterKind,
parser::Parser, platform::Platform, platform_interface::PlatformInterface, position::Position, parser::Parser, platform::Platform, platform_interface::PlatformInterface, position::Position,
positional::Positional, ran::Ran, range_ext::RangeExt, recipe::Recipe, positional::Positional, ran::Ran, range_ext::RangeExt, recipe::Recipe,
recipe_context::RecipeContext, recipe_resolver::RecipeResolver, scope::Scope, search::Search, recipe_context::RecipeContext, recipe_resolver::RecipeResolver,
search_config::SearchConfig, search_error::SearchError, set::Set, setting::Setting, recipe_signature::RecipeSignature, scope::Scope, search::Search, search_config::SearchConfig,
settings::Settings, shebang::Shebang, shell::Shell, show_whitespace::ShowWhitespace, search_error::SearchError, set::Set, setting::Setting, settings::Settings, shebang::Shebang,
source::Source, string_kind::StringKind, string_literal::StringLiteral, subcommand::Subcommand, shell::Shell, show_whitespace::ShowWhitespace, source::Source, string_kind::StringKind,
suggestion::Suggestion, table::Table, thunk::Thunk, token::Token, token_kind::TokenKind, string_literal::StringLiteral, subcommand::Subcommand, suggestion::Suggestion, table::Table,
unresolved_dependency::UnresolvedDependency, unresolved_recipe::UnresolvedRecipe, thunk::Thunk, token::Token, token_kind::TokenKind, unresolved_dependency::UnresolvedDependency,
use_color::UseColor, variables::Variables, verbosity::Verbosity, warning::Warning, unresolved_recipe::UnresolvedRecipe, use_color::UseColor, variables::Variables,
verbosity::Verbosity, warning::Warning,
}, },
std::{ std::{
borrow::Cow, borrow::Cow,
@ -168,6 +169,7 @@ mod range_ext;
mod recipe; mod recipe;
mod recipe_context; mod recipe_context;
mod recipe_resolver; mod recipe_resolver;
mod recipe_signature;
mod run; mod run;
mod scope; mod scope;
mod search; mod search;

16
src/recipe_signature.rs Normal file
View File

@ -0,0 +1,16 @@
use super::*;
pub(crate) struct RecipeSignature<'a> {
pub(crate) name: &'a str,
pub(crate) recipe: &'a Recipe<'a>,
}
impl<'a> ColorDisplay for RecipeSignature<'a> {
fn fmt(&self, f: &mut Formatter, color: Color) -> fmt::Result {
write!(f, "{}", self.name)?;
for parameter in &self.recipe.parameters {
write!(f, " {}", parameter.color_display(color))?;
}
Ok(())
}
}

View File

@ -466,8 +466,12 @@ impl Subcommand {
fn list(config: &Config, level: usize, justfile: &Justfile) { fn list(config: &Config, level: usize, justfile: &Justfile) {
const MAX_WIDTH: usize = 50; const MAX_WIDTH: usize = 50;
if level == 0 {
print!("{}", config.list_heading);
}
// Construct a target to alias map. // Construct a target to alias map.
let mut recipe_aliases: BTreeMap<&str, Vec<&str>> = BTreeMap::new(); let mut recipe_aliases = BTreeMap::<&str, Vec<&str>>::new();
if !config.no_aliases { if !config.no_aliases {
for alias in justfile.aliases.values() { for alias in justfile.aliases.values() {
if alias.is_private() { if alias.is_private() {
@ -483,7 +487,7 @@ impl Subcommand {
} }
} }
let mut line_widths: BTreeMap<&str, usize> = BTreeMap::new(); let mut line_widths = BTreeMap::<&str, usize>::new();
for (name, recipe) in &justfile.recipes { for (name, recipe) in &justfile.recipes {
if !recipe.is_public() { if !recipe.is_public() {
@ -491,26 +495,24 @@ impl Subcommand {
} }
for name in iter::once(name).chain(recipe_aliases.get(name).unwrap_or(&Vec::new())) { for name in iter::once(name).chain(recipe_aliases.get(name).unwrap_or(&Vec::new())) {
let mut line_width = UnicodeWidthStr::width(*name); line_widths.insert(
name,
for parameter in &recipe.parameters { UnicodeWidthStr::width(
line_width += UnicodeWidthStr::width( RecipeSignature { name, recipe }
format!(" {}", parameter.color_display(Color::never())).as_str(), .color_display(Color::never())
.to_string()
.as_str(),
),
); );
} }
if line_width <= MAX_WIDTH {
line_widths.insert(name, line_width);
}
}
} }
let max_line_width = line_widths.values().copied().max().unwrap_or_default(); let max_line_width = line_widths
let doc_color = config.color.stdout().doc(); .values()
.filter(|line_width| **line_width <= MAX_WIDTH)
if level == 0 { .copied()
print!("{}", config.list_heading); .max()
} .unwrap_or_default();
for recipe in justfile.public_recipes(config.unsorted) { for recipe in justfile.public_recipes(config.unsorted) {
let name = recipe.name(); let name = recipe.name();
@ -519,10 +521,11 @@ impl Subcommand {
.chain(recipe_aliases.get(name).unwrap_or(&Vec::new())) .chain(recipe_aliases.get(name).unwrap_or(&Vec::new()))
.enumerate() .enumerate()
{ {
print!("{}{name}", config.list_prefix.repeat(level + 1)); print!(
for parameter in &recipe.parameters { "{}{}",
print!(" {}", parameter.color_display(config.color.stdout())); config.list_prefix.repeat(level + 1),
} RecipeSignature { name, recipe }.color_display(config.color.stdout())
);
let doc = match (i, recipe.doc) { let doc = match (i, recipe.doc) {
(0, Some(doc)) => Some(Cow::Borrowed(doc)), (0, Some(doc)) => Some(Cow::Borrowed(doc)),
@ -534,10 +537,9 @@ impl Subcommand {
print!( print!(
" {:padding$}{} {}", " {:padding$}{} {}",
"", "",
doc_color.paint("#"), config.color.stdout().doc().paint("#"),
doc_color.paint(&doc), config.color.stdout().doc().paint(&doc),
padding = max_line_width padding = max_line_width.saturating_sub(line_widths[name]),
.saturating_sub(line_widths.get(name).copied().unwrap_or(max_line_width))
); );
} }
@ -546,7 +548,7 @@ impl Subcommand {
} }
for (name, module) in &justfile.modules { for (name, module) in &justfile.modules {
println!(" {name}:"); println!("{}{name}:", config.list_prefix.repeat(level + 1));
Self::list(config, level + 1, module); Self::list(config, level + 1, module);
} }
} }

View File

@ -69,6 +69,7 @@ mod interrupts;
mod invocation_directory; mod invocation_directory;
mod json; mod json;
mod line_prefixes; mod line_prefixes;
mod list;
mod man; mod man;
mod misc; mod misc;
mod modules; mod modules;

79
tests/list.rs Normal file
View File

@ -0,0 +1,79 @@
use super::*;
#[test]
fn list_displays_recipes_in_submodules() {
Test::new()
.write("foo.just", "bar:\n @echo FOO")
.justfile(
"
mod foo
",
)
.test_round_trip(false)
.arg("--unstable")
.arg("--list")
.stdout(
"
Available recipes:
foo:
bar
",
)
.run();
}
#[test]
fn module_recipe_list_alignment_ignores_private_recipes() {
Test::new()
.write(
"foo.just",
"
# foos
foo:
@echo FOO
[private]
barbarbar:
@echo BAR
@_bazbazbaz:
@echo BAZ
",
)
.justfile("mod foo")
.test_round_trip(false)
.arg("--unstable")
.arg("--list")
.stdout(
"
Available recipes:
foo:
foo # foos
",
)
.run();
}
#[test]
fn nested_modules_are_properly_indented() {
Test::new()
.write("foo.just", "mod bar")
.write("bar.just", "baz:\n @echo FOO")
.justfile(
"
mod foo
",
)
.test_round_trip(false)
.arg("--unstable")
.arg("--list")
.stdout(
"
Available recipes:
foo:
bar:
baz
",
)
.run();
}

View File

@ -512,28 +512,6 @@ fn missing_optional_modules_do_not_conflict() {
.run(); .run();
} }
#[test]
fn list_displays_recipes_in_submodules() {
Test::new()
.write("foo.just", "bar:\n @echo FOO")
.justfile(
"
mod foo
",
)
.test_round_trip(false)
.arg("--unstable")
.arg("--list")
.stdout(
"
Available recipes:
foo:
bar
",
)
.run();
}
#[test] #[test]
fn root_dotenv_is_available_to_submodules() { fn root_dotenv_is_available_to_submodules() {
Test::new() Test::new()
@ -695,37 +673,6 @@ fn module_paths_beginning_with_tilde_are_expanded_to_homdir() {
.run(); .run();
} }
#[test]
fn module_recipe_list_alignment_ignores_private_recipes() {
Test::new()
.write(
"foo.just",
"
# foos
foo:
@echo FOO
[private]
barbarbar:
@echo BAR
@_bazbazbaz:
@echo BAZ
",
)
.justfile("mod foo")
.test_round_trip(false)
.arg("--unstable")
.arg("--list")
.stdout(
"Available recipes:
foo:
foo # foos
",
)
.run();
}
#[test] #[test]
fn recipes_with_same_name_are_both_run() { fn recipes_with_same_name_are_both_run() {
Test::new() Test::new()