Skip to content

Improve cargo --list output (split output into sections) #12196

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 51 additions & 18 deletions src/bin/cargo/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use std::collections::HashMap;
use std::ffi::OsStr;
use std::ffi::OsString;
use std::fmt::Write;
use std::path::PathBuf;

use super::commands;
use super::list_commands;
Expand Down Expand Up @@ -128,39 +129,71 @@ Run with 'cargo -Z [FLAG] [COMMAND]'",
}

if expanded_args.flag("list") {
let mut builtins: Vec<(String, Option<String>)> = Vec::new();
let mut external: Vec<(String, PathBuf)> = Vec::new();
// (alias, source)
let mut aliases: Vec<(String, String)> = Vec::new();
drop_println!(config, "Installed Commands:");
for (name, command) in list_commands(config) {
let known_external_desc = KNOWN_EXTERNAL_COMMAND_DESCRIPTIONS.get(name.as_str());
match command {
CommandInfo::BuiltIn { about } => {
assert!(
known_external_desc.is_none(),
KNOWN_EXTERNAL_COMMAND_DESCRIPTIONS
.get(name.as_str())
.is_none(),
"KNOWN_EXTERNAL_COMMANDS shouldn't contain builtin \"{}\"",
name
);
let summary = about.unwrap_or_default();
let summary = summary.lines().next().unwrap_or(&summary); // display only the first line
drop_println!(config, " {:<20} {}", name, summary);
builtins.push((name, about));
// let summary = about.unwrap_or_default();
// let summary = summary.lines().next().unwrap_or(&summary); // display only the first line
// drop_println!(config, " {:<20} {}", name, summary);
}
CommandInfo::BuiltinAlias { to } => {
aliases.push((name, to));
}
CommandInfo::External { path } => {
if let Some(desc) = known_external_desc {
drop_println!(config, " {:<20} {}", name, desc);
} else if is_verbose {
drop_println!(config, " {:<20} {}", name, path.display());
} else {
drop_println!(config, " {}", name);
}
external.push((name, path));
}
CommandInfo::Alias { target } => {
drop_println!(
config,
" {:<20} alias: {}",
name,
target.iter().join(" ")
);
aliases.push((name, target.iter().join(" ")));
}
}
}

// If alias is a simple one (like b = build), display it along the original command

drop_println!(config, "====================\n Builtin commands:");
for (mut name, about) in builtins {
let summary = about.unwrap_or_default();
let summary = summary.lines().next().unwrap_or(&summary); // display only the first line
// If has an alias
if let Some(tuple) = aliases.iter().find(|x| x.1 == name) {
name.push_str(", ");
name.push_str(&tuple.0);
drop_println!(config, " {:<20} {}", name, summary);
} else {
drop_println!(config, " {:<20} {}", name, summary);
}
}

drop_println!(config, "====================\n External commands:");
for (name, path) in external {
let known_external_desc = KNOWN_EXTERNAL_COMMAND_DESCRIPTIONS.get(name.as_str());
if let Some(desc) = known_external_desc {
drop_println!(config, " {:<20} {}", name, desc);
} else if is_verbose {
drop_println!(config, " {:<20} {}", name, path.display());
} else {
drop_println!(config, " {}", name);
}
}

drop_println!(config, "====================\n Aliases:");
for (name, target) in aliases {
drop_println!(config, " {:<20} {}", name, target);
}

return Ok(());
}

Expand Down
20 changes: 10 additions & 10 deletions src/bin/cargo/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,18 +40,18 @@ fn main() {

/// Table for defining the aliases which come builtin in `Cargo`.
/// The contents are structured as: `(alias, aliased_command, description)`.
const BUILTIN_ALIASES: [(&str, &str, &str); 6] = [
("b", "build", "alias: build"),
("c", "check", "alias: check"),
("d", "doc", "alias: doc"),
("r", "run", "alias: run"),
("t", "test", "alias: test"),
("rm", "remove", "alias: remove"),
const BUILTIN_ALIASES: [(&str, &str); 6] = [
("b", "build"),
("c", "check"),
("d", "doc"),
("r", "run"),
("t", "test"),
("rm", "remove"),
];

/// Function which contains the list of all of the builtin aliases and it's
/// corresponding execs represented as &str.
fn builtin_aliases_execs(cmd: &str) -> Option<&(&str, &str, &str)> {
fn builtin_aliases_execs(cmd: &str) -> Option<&(&str, &str)> {
BUILTIN_ALIASES.iter().find(|alias| alias.0 == cmd)
}

Expand Down Expand Up @@ -126,8 +126,8 @@ fn list_commands(config: &Config) -> BTreeMap<String, CommandInfo> {
for command in &BUILTIN_ALIASES {
commands.insert(
command.0.to_string(),
CommandInfo::BuiltIn {
about: Some(command.2.to_string()),
CommandInfo::BuiltinAlias {
to: command.1.to_owned(),
},
);
}
Expand Down
1 change: 1 addition & 0 deletions src/cargo/util/command_prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -796,6 +796,7 @@ pub fn ignore_unknown<T: Default>(r: Result<T, clap::parser::MatchesError>) -> T
#[derive(PartialEq, Eq, PartialOrd, Ord)]
pub enum CommandInfo {
BuiltIn { about: Option<String> },
BuiltinAlias { to: String },
External { path: PathBuf },
Alias { target: StringOrVec },
}
23 changes: 13 additions & 10 deletions tests/testsuite/cargo_command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,25 +24,28 @@ fn path() -> Vec<PathBuf> {
fn list_commands_with_descriptions() {
let p = project().build();
p.cargo("--list")
.with_stdout_contains(
" build Compile a local package and all of its dependencies",
)
// Assert that `read-manifest` prints the right one-line description followed by another
// command, indented.
.with_stdout_contains(
" read-manifest Print a JSON representation of a Cargo.toml manifest.",
)
.with_stdout_contains("====================\n External commands:")
.with_stdout_contains("====================\n Aliases:")
.with_stdout_contains("====================\n Builtin commands:")
.with_stdout_contains(
" build, b Compile a local package and all of its dependencies",
)
.run();
}

#[cargo_test]
fn list_builtin_aliases_with_descriptions() {
let p = project().build();
p.cargo("--list")
.with_stdout_contains(" b alias: build")
.with_stdout_contains(" c alias: check")
.with_stdout_contains(" r alias: run")
.with_stdout_contains(" t alias: test")
.with_stdout_contains(" b build")
.with_stdout_contains(" c check")
.with_stdout_contains(" r run")
.with_stdout_contains(" t test")
.run();
}

Expand All @@ -60,8 +63,8 @@ fn list_custom_aliases_with_descriptions() {
.build();

p.cargo("--list")
.with_stdout_contains(" myaliasstr alias: foo --bar")
.with_stdout_contains(" myaliasvec alias: foo --bar")
.with_stdout_contains(" myaliasstr foo --bar")
.with_stdout_contains(" myaliasvec foo --bar")
.run();
}

Expand Down Expand Up @@ -236,7 +239,7 @@ error: no such command: `biuld`
.run();
cargo_process("--list")
.with_stdout_contains(
" build Compile a local package and all of its dependencies\n",
" build, b Compile a local package and all of its dependencies",
)
.with_stdout_contains(" biuld\n")
.run();
Expand Down