fsprojects / Argu

A declarative CLI argument parser for F#
https://fsprojects.github.io/Argu
MIT License
451 stars 75 forks source link

Adding an `Examples` section for `--help` #251

Open inwenis opened 1 month ago

inwenis commented 1 month ago

Is it possible for argu to print an Examples section when asked for --help?

bartelink commented 1 month ago

As far as I'm aware no such mechanism exists, but supporting it does seem like a useful addition In order to progress this, the next step would be to propose a mechanism

One factor is that any level in the hierarchy of subcommands could potentially have examples.

Don't have an idea off the top of my head as to how to incorporate it, i.e. whether a function would need to be supplied into the parse and/or render help functions, or whether something basic like checking the IsHelpRequested flag on a ArguParseException and using that to conditionally print a usage message might be enough for your needs and/or in general.

Best place to start is in the tests - they're effectively the reference section of the manual in terms of how to do stuff not explicitly called out in the tutorial.

(Assuming you can some up with a clean enough extension point that meets your needs, the idea does seem to make sense...)

inwenis commented 1 month ago

Thank you foe the answer. For now I ended up doing this:

let examples = """
EXAMPLE 1
    lorem ipsum dolor sit amet
"""

type CustomErrorHandler() =
    interface IExiter with
        member __.Name = "Exiter"
        member __.Exit (msg, code) =
            if code = ErrorCode.HelpText then
                printfn "%s" msg
                printfn "%s" examples
                exit 0
            else
              (ProcessExiter() :> IExiter).Exit(msg, code)

[<EntryPoint>]
let main argv =
  let parser = ArgumentParser.Create<CliArguments>(programName = "myTool", errorHandler = CustomErrorHandler())
  let results = parser.Parse argv
  ...
bartelink commented 1 month ago

Nice solution - I think it makes sense to keep the issue open for now as it would be nice for it to be first class in some way as examples are definitely a thing I know my tools could benefit from (a big improvement on putting it in my already-too-long READMEs!) nit: I tend to use eprintfn for the messages nit: doing an exit is a bit agressive - I tend to have a top level try/catch and throw to make sure stuff gets unwound, so ideally this should also be possible without a custom exiter - I can't think of a better idea than to make sure that the ArguParseException can expose the msg and the code, and I can do a try ... with :? ArguParseException as e when e.code = ErrorCode.HelpText -> eprintfn "%s" e.message; eprintfn "%s" Args.examples; return 1 nit: for F# 6 and later, the __ can be _ now!