2

I'd like to use Spectre.Console in an F# console app. I'm trying to convert the Introduction example from C# to F#. Below is my attempt:

open System

open Spectre.Console.Cli

type AddSettings() =
    inherit CommandSettings()

    [<CommandArgument(0, "[PROJECT]")>]
    member val Project = "" with get, set

type AddPackageSettings() =
    inherit AddSettings()

    [<CommandArgument(0, "<PACKAGE_NAME>")>]
    member val PackageName = "" with get, set

    [<CommandOption("-v|--version <VERSION>")>]
    member val Version = "" with get, set

 type AddReferenceSettings() =
    inherit AddSettings()

    [<CommandArgument(0, "<PROJECT_REFERENCE>")>]
    member val ProjectReference = "" with get, set

type AddPackageCommand() =
    inherit Command<AddPackageSettings>()

    override _.Execute (context,  settings) = 0

type AddReferenceCommand() =
    inherit Command<AddReferenceSettings>()

    override _.Execute(context, settings) = 0


// Define a function to construct a message to print
let from whom =
    sprintf "from %s" whom

[<EntryPoint>]
let main argv =
    let message = from "F#" // Call the function
    let app = CommandApp()

    app.Configure(fun config ->
        config.AddBranch<AddSettings>("add", fun add ->
            add.AddCommand<AddPackageCommand>("package")
            add.AddCommand<AddReferenceCommand>("reference")
        )
    )

    app.Run(argv)

Unfortunately, I get the following compiler error:

The type 'AddPackageCommand' is not compatible with the type 'ICommandLimiter<AddSettings>'

The type 'AddPackageCommand' is not compatible with the type 'ICommandLimiter'

Thank you for any and all help.

lonix
  • 14,255
  • 23
  • 85
  • 176
Kurt Mueller
  • 3,173
  • 2
  • 29
  • 50
  • I'm using spectre.console.cli in fsharp for the cli in my repository (you might find the package SpectreCoff useful as well :)) https://github.com/EluciusFTW/SpectreCoff – EluciusFTW Jan 22 '23 at 08:54

1 Answers1

3

Here's how I solved that issue:

  1. Explicitly add interface ICommandLimiter<AddSettings> to the Command subclasses that use inheritance in the settings from AddSettings.
  2. Change the AddBranch call to infer the generic argument by only annotating the IConfigurator's type: config.AddBranch("add", fun (add: IConfigurator<AddSettings>) -> ....
open System

open Spectre.Console.Cli

type AddSettings() =
    inherit CommandSettings()

    [<CommandArgument(0, "[PROJECT]")>]
    member val Project = "" with get, set

type AddPackageSettings() =
    inherit AddSettings()

    [<CommandArgument(0, "<PACKAGE_NAME>")>]
    member val PackageName = "" with get, set

    [<CommandOption("-v|--version <VERSION>")>]
    member val Version = "" with get, set

 type AddReferenceSettings() =
    inherit AddSettings()

    [<CommandArgument(0, "<PROJECT_REFERENCE>")>]
    member val ProjectReference = "" with get, set

type AddPackageCommand() =
    inherit Command<AddPackageSettings>()

    interface ICommandLimiter<AddSettings>

    override _.Execute (context,  settings) = 0

type AddReferenceCommand() =
    inherit Command<AddReferenceSettings>()

    interface ICommandLimiter<AddSettings>

    override _.Execute(context, settings) = 0


// Define a function to construct a message to print
let from whom =
    sprintf "from %s" whom

[<EntryPoint>]
let main argv =
    let message = from "F#" // Call the function
    let app = CommandApp()

    app.Configure(fun config ->
        config.AddBranch("add", fun (add: IConfigurator<AddSettings>) ->
            add.AddCommand<AddPackageCommand>("package") |> ignore
            add.AddCommand<AddReferenceCommand>("reference") |> ignore
        )
    )

    app.Run(argv)
bddckr
  • 1,393
  • 13
  • 11