fsprojects / Argu

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

Question: attribute or possibility to customize casing of commands? #168

Closed njlr closed 2 years ago

njlr commented 2 years ago

Argu suggest declaring options like this:

type Arguments =
    | Working_Directory of path:string
    | Listener of host:string * port:int
    | Log_Level of level:int
    | Detach

But that does not agree with my linter.

Can I specify options like this:

type Arguments =
    | WorkingDirectory of path:string
    | Listener of host:string * port:int
    | LogLevel of level:int
    | Detach

And then tell Argu how to generate the names, for example using an annotation or even explicit names?


Explicit names via a static function:

type Arguments =
    | WorkingDirectory of path:string
    | Listener of host:string * port:int
    | LogLevel of level:int
    | Detach
    with 
      static member ArguName (x : Arguments) =
        match x with
        | WorkingDirectory _ -> "working-directory
        | Listener _ -> "listener"
        | LogLevel _ -> "log-level"
        | Detach -> 'detach"

Or via a parameter:

let generateCommandName = 
    function
    | WorkingDirectory _ -> "working-directory
    | Listener _ -> "listener"
    | LogLevel _ -> "log-level"
    | Detach -> 'detach"

let parser = ArgumentParser.Create<Arguments>(programName = "gadget.exe", generateCommandName)
bartelink commented 2 years ago

Does AltCommandLine as illustrated in https://fsprojects.github.io/Argu/tutorial.html#SubCommands fit the bill ?

njlr commented 2 years ago

I dug into the source-code and found CustomCommandLineAttribute, which is exactly what I was looking for!

#r "nuget: Argu, 6.1.1"

open Argu

type CLIArgument =
  | [<CustomCommandLine("--working-directory")>] WorkingDirectory of path : string
  interface IArgParserTemplate with
    member this.Usage =
      match this with
      | WorkingDirectory _ -> "Set the working directory"

let parser = ArgumentParser.Create<CLIArgument>(programName = "gadget.exe")

// ---------------

let examples =
  [
    [||]
    [| "--help" |]
    [| "--working-directory"; "a/b/c" |]
  ]

for example in examples do
  printfn "%A" example

  let pr = parser.Parse(example, raiseOnUsage = false)

  if pr.IsUsageRequested then
    printfn "%A" <| parser.PrintUsage()
  else
    printfn "%A" <| pr.GetAllResults()

  printfn "------"