Commandline: After customizing help generation, hep VERB does not work

Created on 20 May 2020  路  15Comments  路  Source: commandlineparser/commandline

Did this

static async Task Main( string[] args )
{
    _logger.Info(CommandLine.Text.HeadingInfo.Default);

    var parser = new Parser(p => { p.AutoVersion = false; p.CaseInsensitiveEnumValues = true;  });
    var parserResult = parser.ParseArguments<SyncOptions, QueryOptions, TokenOptions>(args);
    await parserResult.MapResult(
            (SyncOptions opts) => SyncAsync(opts),
            (QueryOptions opts) => QueryAsync(opts),
            (TokenOptions opts) => ShowTokenAsync(opts),
            errors => Task.FromResult(DisplayHelp(parserResult, errors))
        )
        .ContinueWith(t => {
            if ( System.Diagnostics.Debugger.IsAttached )
            {
                Console.WriteLine("Press enter...");
                Console.ReadLine();
            }
        });
}

private static int DisplayHelp<T>( ParserResult<T> result, IEnumerable<Error> errs )
{
    var helpText = CommandLine.Text.HelpText.AutoBuild(result, h =>
    {
        h.AdditionalNewLineAfterOption = false;
        h.AddNewLineBetweenHelpSections = true;
        h.AddEnumValuesToHelpText = true;
        h.AutoVersion = false;
        h.Heading = CommandLine.Text.HeadingInfo.Empty;
        h.MaximumDisplayWidth = 110;
        h.AddVerbs(typeof(SyncOptions), typeof(QueryOptions), typeof(TokenOptions));
        return CommandLine.Text.HelpText.DefaultParsingErrorsHandler(result, h);
    }, e => e,
    true);
    Console.WriteLine(helpText);
    return 1;
}

Before this I could type MyProgram help VERB and it would tell me the same as MyProgram VERB minus errors section. Now this gives me only verb list, like if help lost its first argument. This does not work either: MyProgram VERB help but this does: MyProgram VERB --help.

Am I doing something wrong here?

question

Most helpful comment

Upgrade your example to the latest version (2.8+) and change your helptext class for the following and it should work

var helpText = HelpText.AutoBuild(result, h =>
{
    h.AdditionalNewLineAfterOption = false; //remove the extra newline between options
    h.Heading = "Myapp 2.0.0-beta"; //change header
    h.Copyright = "Copyright (c) 2019 Global.com"; //change copyrigt text
    return HelpText.DefaultParsingErrorsHandler(result, h);
}
//      , e => e); Remove this line 
); // add this one

All 15 comments

starting v2.7+, there is a new simplified overload method:

 private static int DisplayHelp<T>(ParserResult<T> result, IEnumerable<Error> errs)
        {
            var helpText = CommandLine.Text.HelpText.AutoBuild(result, h =>
            {
                h.AdditionalNewLineAfterOption = false;
                h.AddNewLineBetweenHelpSections = true;
                h.AddEnumValuesToHelpText = true;
                h.AutoVersion = false;
                h.Heading = CommandLine.Text.HeadingInfo.Empty;
                h.MaximumDisplayWidth = 110;
                //  h.AddVerbs(typeof(SyncOptions), typeof(QueryOptions), typeof(TokenOptions));
                return h;  // only h
            });
            Console.WriteLine(helpText);
            return 1;
        }

Let me know if this working with you

I was trying one of the examples on the FAQ section ([https://dotnetfiddle.net/IbwLbX]) and it seems that the help doesn't work for verbs. I was using the following list of options

new string[] { "help" }
            ,new string[] { "help clone" }
            ,new string[] { "help commit" }
            ,new string[] { "commit help" }
            ,new string[] { "clone help" }
            ,new string[] { "help clone" }
            ,new string[] { "clone -help" }
            ,new string[] { "clone --help" }
            ,new string[] { "clone -?" }
            ,new string[] { "?" }

But all of them fails except for the first one.
Which of them should work?

Since On .netfiddler I can't see the Error output, I modified the __YourMain method as follows

    static int __YourMain(string[] args)
    {
        int exitcode;
        var helpWriter = new StringWriter ();
        var parser = new CommandLine.Parser (with => with.HelpWriter = helpWriter);

        exitcode = parser.ParseArguments<CommitOptions,CloneOptions>(args)
            .MapResult(
            (CommitOptions opts) => RunCommitCommand(opts),
            (CloneOptions opts) => RunCloneCommand(opts), 
            //(AddOptions opts) => RunAddCommand(opts), 
            (parserErrors) => DisplayHelp (parserErrors, helpWriter)
        );
        //this works because there's a Dummy verb "NextVerbOptions" class
        //exitcode = CommandLine.Parser.Default
        //  .ParseArguments<CommitOptions,CloneOptions>(args)
        //  .MapResult(
        //  (CommitOptions opts) => RunCommitCommand(opts),
        //  (CloneOptions opts) => RunCloneCommand(opts), 
        //  //(AddOptions opts) => RunAddCommand(opts), 
        //  (parserErrors) => 1
        //);

        return exitcode;
    }


    static int DisplayHelp (IEnumerable<Error> errs, TextWriter helpWriter) {
        //if (errs.IsVersion () || errs.IsHelp ())
            Console.WriteLine (helpWriter.ToString ());
        //else
        //  Console.Error.WriteLine (helpWriter.ToString ());
        return 1;
    }

I'm doing something wrong or I'm missing something here?

@DkAngelito
Just modify args as:

new string[] { "--help" } // --help,  show help for non verb optons
,new string[] { "clone", "--help" } // clone --help , show help for clone verb
,new string[] { "clone", "git://github.com/commandlineparser/commandline.git" } 
,new string[] { "add","--help" }  //add --help , show help for add verb
,new string[] { "add", "addfile.cs" }
,new string[] { "commit", "-m", "initial commit" }
,new string[] { "push", "-f" }
,new string[] { "push", "--force" }
,new string[] { "push" }

The concatenated args is the actuall command line.
Wiki will be modified to a new modified version

I don't understand the above instructions. My heavily-cut adjustment from the example can be found here
(My actual code is using a set of verb classes, but the setup here is the same)

What do I "modify args as"?

My actual code is using a set of verb classes, but the setup here is the same

You should add VerbAttribute to your classes like:

[Verb("myverb")] //whatever name, here  verb is named 'myverb'
class Options
{
...
}

To display help for verbs use this syntax:

<MyVerbName> --help
# for the above verb, type:
myverb --help

I added a comment to explain args[]
I modified your code here and adding verb attribute, and it's working fine.

Hmm. I was trying to use the help auto-verb, is that not possible with a custom help text?

You can not customize auto generated help.

I don't want that, I want there to be the implicit "help" verb that uses the positional argument 0 as the verb to get help with.

i.e. help myverb gets auto translated to myverb --help

Do I just have to make this myself?

I don't want that, I want there to be the implicit "help" verb that uses the positional argument 0 as the verb to get help with.

i.e. help myverb gets auto translated to myverb --help

Do I just have to make this myself?

That works by default
you could try it

in this example from @moh-hassan
new string[] { "clone", "--help" }

would be equivalent to
new string[] { "help", "clone" }

That's what I'm saying is not working. Adjusting my example here, it just shows... nothing. Presumably because there is not help verb.

Upgrade your example to the latest version (2.8+) and change your helptext class for the following and it should work

var helpText = HelpText.AutoBuild(result, h =>
{
    h.AdditionalNewLineAfterOption = false; //remove the extra newline between options
    h.Heading = "Myapp 2.0.0-beta"; //change header
    h.Copyright = "Copyright (c) 2019 Global.com"; //change copyrigt text
    return HelpText.DefaultParsingErrorsHandler(result, h);
}
//      , e => e); Remove this line 
); // add this one

That worked!

Just gotta get the errors lines to stop repeating and I'm golden...

Hi @Tsaukpaetra

You need to change the return HelpText.DefaultParsingErrorsHandler(result, h); to just return h; as the AutoBuild will already call this method internally.

@DkAngelito Thank You!

// , e => e); Remove this line

This one line was what was throwing me off and I was banging my head on my keyboard. The overload with this should be marked obsolete and/or killed with fire. What a headache!

Did this

```
static async Task Main( string[] args )
{
_logger.Info(CommandLine.Text.HeadingInfo.Default);

var parser = new Parser(p => { p.AutoVersion = false; p.CaseInsensitiveEnumValues = true;  });
var parserResult = parser.ParseArguments<SyncOptions, QueryOptions, TokenOptions>(args);
await parserResult.MapResult(
        (SyncOptions opts) => SyncAsync(opts),
        (QueryOptions opts) => QueryAsync(opts),
        (TokenOptions opts) => ShowTokenAsync(opts),
        errors => Task.FromResult(DisplayHelp(parserResult, errors))
    )
    .ContinueWith(t => {
        if ( System.Diagnostics.Debugger.IsAttached )
        {
            Console.WriteLine("Press enter...");
            Console.ReadLine();
        }
    });

}

How you got that async to work? I cannot see any async/await support at all.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Silverwing1983 picture Silverwing1983  路  4Comments

ericnewton76 picture ericnewton76  路  4Comments

ppumkin picture ppumkin  路  4Comments

Valinwolf picture Valinwolf  路  3Comments

timotei picture timotei  路  4Comments