Skip to content
Merged
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
7 changes: 4 additions & 3 deletions argv/src/complete.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,8 @@ pub fn for_name<'a>(
// Tree order last, and only as a fallback: two sibling commands may take a `tool` and mean
// different things by it, and the one the line reached is the one being asked about.
let reached = walk(spec.root.cmd, ctx.command_words_start());
let reached_meta = crate::help::find(spec, reached.cmd).map(|(_, meta)| meta);
let reached_meta =
crate::help::find(spec, reached.cmd).and_then(|(_, chain)| chain.last().copied());
let owner = if on(spec.root, name).is_some() {
spec.root
} else if let Some(meta) = reached_meta.filter(|meta| on(meta, name).is_some()) {
Expand Down Expand Up @@ -407,7 +408,7 @@ fn files_for(name: &str) -> Option<Files> {
/// for a word nothing is known about, and the `run=` completions a spec can declare.
pub fn complete<'a>(spec: &'a Spec<'a>, split: &Split) -> Completions<'a> {
let position = walk(spec.root.cmd, split.argv());
let meta = crate::help::find(spec, position.cmd).map(|(_, meta)| meta);
let meta = crate::help::find(spec, position.cmd).and_then(|(_, chain)| chain.last().copied());
let token = split.prefix.as_str();
let candidates = candidates(spec, split);

Expand Down Expand Up @@ -476,7 +477,7 @@ pub fn complete<'a>(spec: &'a Spec<'a>, split: &Split) -> Completions<'a> {
/// Just the candidates this CLI knows about, without the question of paths.
pub fn candidates<'a>(spec: &'a Spec<'a>, split: &Split) -> Vec<Candidate<'a>> {
let position = walk(spec.root.cmd, split.argv());
let meta = crate::help::find(spec, position.cmd).map(|(_, meta)| meta);
let meta = crate::help::find(spec, position.cmd).and_then(|(_, chain)| chain.last().copied());
let token = split.prefix.as_str();

let mut out = if position.flags_possible && token == "-" {
Expand Down
292 changes: 249 additions & 43 deletions argv/src/help.rs

Large diffs are not rendered by default.

33 changes: 20 additions & 13 deletions benches/gate/tests/help.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,20 @@ fn mise_spec() -> LibSpec {
/// Every command in the tree, as (path, metadata) — the path being what a user types.
fn walk<'a>(
path: Vec<&'a str>,
chain: Vec<&'a CommandMeta<'a>>,
meta: &'a CommandMeta<'a>,
out: &mut Vec<(Vec<&'a str>, &'a CommandMeta<'a>)>,
out: &mut Vec<(Vec<&'a str>, Vec<&'a CommandMeta<'a>>)>,
) {
out.push((path.clone(), meta));
// The chain and not just the command: a page lists what it inherits, which only the
// ancestors know.
let mut chain = chain;
chain.push(meta);
out.push((path.clone(), chain.clone()));
for sub in meta.subcommands {
// Aliases live in the parse table beside the canonical name; help names the command.
let mut child = path.clone();
child.push(sub.cmd.name);
walk(child, sub, out);
walk(child, chain.clone(), sub, out);
}
}

Expand All @@ -50,15 +55,17 @@ fn every_usage_line_matches_the_reference() {
let root = shadow_mise::Cli::spec().root;

let mut commands = Vec::new();
walk(vec!["mise"], root, &mut commands);
walk(vec!["mise"], Vec::new(), root, &mut commands);
assert!(
commands.len() > 200,
"the shadow should cover mise's whole tree, found {}",
commands.len()
);

let mut differences = Vec::new();
for (path, meta) in &commands {
for (path, chain) in &commands {
// The usage line is about the command itself; the chain is for what it inherits.
let meta = chain.last().expect("a command");
let ours = usage_line(path, meta);
// usage-lib's `usage()` omits the binary and starts at the command path, so the
// comparison puts it back — the same string the template writes after `Usage: `.
Expand Down Expand Up @@ -129,7 +136,7 @@ fn every_short_help_matches_the_reference() {
let root = shadow_mise::Cli::spec();

let mut commands = Vec::new();
walk(vec!["mise"], root.root, &mut commands);
walk(vec!["mise"], Vec::new(), root.root, &mut commands);

let mut differences = Vec::new();
for (path, meta) in &commands {
Expand Down Expand Up @@ -173,7 +180,7 @@ fn every_long_help_matches_the_reference() {
let root = shadow_mise::Cli::spec();

let mut commands = Vec::new();
walk(vec!["mise"], root.root, &mut commands);
walk(vec!["mise"], Vec::new(), root.root, &mut commands);

let mut differences = Vec::new();
for (path, meta) in &commands {
Expand Down Expand Up @@ -276,12 +283,12 @@ fn the_text_around_a_page_is_rendered_where_the_reference_puts_it() {
};

assert_eq!(
short_help(&SPEC, &["ex", "go"], &GO_META),
short_help(&SPEC, &["ex", "go"], &[&GO_META]),
usage::docs::cli::render_help(&spec, go, false),
"short form"
);
assert_eq!(
long_help(&SPEC, &["ex", "go"], &GO_META),
long_help(&SPEC, &["ex", "go"], &[&GO_META]),
usage::docs::cli::render_help(&spec, go, true),
"long form"
);
Expand Down Expand Up @@ -330,9 +337,9 @@ fn a_spec_can_surround_every_page_at_once() {

for long in [false, true] {
let ours = if long {
long_help(&SPEC, &["ex", "go"], &GO_META)
long_help(&SPEC, &["ex", "go"], &[&GO_META])
} else {
short_help(&SPEC, &["ex", "go"], &GO_META)
short_help(&SPEC, &["ex", "go"], &[&GO_META])
};
assert_eq!(
ours,
Expand Down Expand Up @@ -442,9 +449,9 @@ fn a_specs_examples_reach_a_page_that_has_none() {
let cmd = spec.cmd.subcommands.get(name).expect("in the spec");
for long in [false, true] {
let ours = if long {
long_help(&SPEC, &["ex", name], meta)
long_help(&SPEC, &["ex", name], &[meta])
} else {
short_help(&SPEC, &["ex", name], meta)
short_help(&SPEC, &["ex", name], &[meta])
};
assert_eq!(
ours,
Expand Down
Loading