Skip to content
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

AppSettings::AllowExternalSubcommands [sometimes] triggers suggestions #1169

Closed
yrashk opened this issue Feb 8, 2018 · 4 comments
Closed
Labels
A-parsing Area: Parser's logic and needs it changed somehow. C-enhancement Category: Raise on the bar on expectations E-easy Call for participation: Experience needed to fix: Easy / not much E-medium Call for participation: Experience needed to fix: Medium / intermediate

Comments

@yrashk
Copy link

yrashk commented Feb 8, 2018

Rust Version

rustc 1.23.0 (766bd11c8 2018-01-01)

Affected Version of clap

2.29.4

Expected Behavior Summary

The program executions to print:

# 1
subcommand: z
# 2
subcommand: te

Actual Behavior Summary

# 1
subcommand: z
# 2
error: The subcommand 'te' wasn't recognized
	Did you mean 'test'?

If you believe you received this message in error, try re-running with 'example -- te'

USAGE:
    example [SUBCOMMAND]

For more information try --help

Steps to Reproduce the issue

src/main.rs:

extern crate clap;

use clap::{App, AppSettings, SubCommand};

fn main() {
    let matches = App::new("My Super Program")
        .setting(AppSettings::AllowExternalSubcommands)
        .subcommand(SubCommand::with_name("test").about("controls testing features"))
        .get_matches();

    if let Some(_) = matches.subcommand_matches("test") {
        println!("pre-defined subcommand: test");
    } else {
        let (command, _) = matches.subcommand();
        println!("subcommand: {}", command);
    }

}

Run with

# 1
cargo run -- z
# 2
cargo run -- te

Debug output

$ cargo run -- te
   Compiling clap v2.29.4
   Compiling example v0.1.0 (file:///Users/yrashk/tmp/example)
    Finished dev [unoptimized + debuginfo] target(s) in 8.11 secs
     Running `target/debug/example te`
DEBUG:clap:Parser::add_subcommand: term_w=None, name=test
DEBUG:clap:Parser::propagate_settings: self=My Super Program, g_settings=AppFlags(
    (empty)
)
DEBUG:clap:Parser::propagate_settings: sc=test, settings=AppFlags(
    NEEDS_LONG_HELP | NEEDS_LONG_VERSION | NEEDS_SC_HELP | UTF8_NONE | COLOR_AUTO
), g_settings=AppFlags(
    (empty)
)
DEBUG:clap:Parser::propagate_settings: self=test, g_settings=AppFlags(
    (empty)
)
DEBUG:clap:Parser::get_matches_with;
DEBUG:clap:Parser::create_help_and_version;
DEBUG:clap:Parser::create_help_and_version: Building --help
DEBUG:clap:Parser::create_help_and_version: Building --version
DEBUG:clap:Parser::create_help_and_version: Building help
DEBUG:clap:Parser::get_matches_with: Begin parsing '"te"' ([116, 101])
DEBUG:clap:Parser::is_new_arg:"te":NotFound
DEBUG:clap:Parser::is_new_arg: arg_allows_tac=false
DEBUG:clap:Parser::is_new_arg: probably value
DEBUG:clap:Parser::is_new_arg: starts_new_arg=false
DEBUG:clap:Parser::possible_subcommand: arg="te"
DEBUG:clap:Parser::get_matches_with: possible_sc=false, sc=None
DEBUG:clap:usage::create_usage_with_title;
DEBUG:clap:usage::create_usage_no_title;
DEBUG:clap:usage::get_required_usage_from: reqs=[], extra=None
DEBUG:clap:usage::get_required_usage_from: after init desc_reqs=[]
DEBUG:clap:usage::get_required_usage_from: no more children
DEBUG:clap:usage::get_required_usage_from: final desc_reqs=[]
DEBUG:clap:usage::get_required_usage_from: args_in_groups=[]
DEBUG:clap:usage::needs_flags_tag;
DEBUG:clap:usage::needs_flags_tag:iter: f=hclap_help;
DEBUG:clap:usage::needs_flags_tag:iter: f=vclap_version;
DEBUG:clap:usage::needs_flags_tag: [FLAGS] not required
DEBUG:clap:usage::create_help_usage: usage=example [SUBCOMMAND]
DEBUG:clap:Parser::color;
DEBUG:clap:Parser::color: Color setting...Auto
DEBUG:clap:is_a_tty: stderr=true
DEBUG:clap:Colorizer::error;
DEBUG:clap:Colorizer::warning;
DEBUG:clap:Colorizer::good;
DEBUG:clap:Colorizer::good;
DEBUG:clap:Colorizer::good;
error: The subcommand 'te' wasn't recognized
	Did you mean 'test'?

If you believe you received this message in error, try re-running with 'example -- te'

USAGE:
    example [SUBCOMMAND]

For more information try --help
@kbknapp
Copy link
Member

kbknapp commented Feb 10, 2018

Currently the fix is to not compile the suggestions feature.

[dependencies.clap]
version = "2"
default-features = false
features = ["color", "wrap_help"] # assuming one would still want the other defaults

This is a hard one to solve generally for the masses because clap has to match incoming arguments to something and if they happen to be close enough to trigger a "possible subcommand" there's no way for clap to know if this is what this particular use case wanted or not.

A future fix would be to add a AppSettings::DontUseSuggestions which would only apply to the current (sub)command. Possibly also narrowed down at a later date with the ability to only not suggest on flags/options or subcommands. I'll mark this as a todo, or good first issue for someone.

I can look at adding it in v3 if no one has knocked it out by then.

@kbknapp kbknapp added A-parsing Area: Parser's logic and needs it changed somehow. C: errors C-enhancement Category: Raise on the bar on expectations E-medium Call for participation: Experience needed to fix: Medium / intermediate E-easy Call for participation: Experience needed to fix: Easy / not much labels Feb 10, 2018
@yrashk
Copy link
Author

yrashk commented Feb 10, 2018 via email

@kbknapp
Copy link
Member

kbknapp commented Feb 10, 2018

Awesome! If you'd like to try this issue, I'd suggest adding a new setting (by following the examples of all other settings) in src/app/settings.rs, then to actually use this setting, you'd probably check if this setting was used in src/app/parser.rs at the start of possible_subcommand and just return (false, None) if that setting was used.

I'd also add some tests to tests/app_settings.rs to ensure it's all working correctly.

@yrashk
Copy link
Author

yrashk commented Apr 5, 2018

It looks like 2.31.2 solves this issue (#1215), at least to some degree. I was just able to use it the way I intended to:

@yrashk yrashk closed this as completed Apr 5, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-parsing Area: Parser's logic and needs it changed somehow. C-enhancement Category: Raise on the bar on expectations E-easy Call for participation: Experience needed to fix: Easy / not much E-medium Call for participation: Experience needed to fix: Medium / intermediate
Projects
None yet
Development

No branches or pull requests

2 participants