### Root Command Builder Example Source: https://context7.com/jordanmarr/fsharp.systemcommandline/llms.txt Demonstrates creating and executing a root command with typed inputs and an action handler using FSharp.SystemCommandLine. The 'inputs' must precede 'setAction' for compile-time type checking. ```fsharp open System.IO open FSharp.SystemCommandLine open Input let unzip (zipFile: FileInfo, outputDirMaybe: DirectoryInfo option) = let outputDir = defaultArg outputDirMaybe zipFile.Directory printfn $"Unzipping {zipFile.Name} to {outputDir.FullName}..." [] let main argv = rootCommand argv { description "Unzips a .zip file" inputs ( argument "zipfile" |> desc "The file to unzip" |> validateFileExists, optionMaybe "--output" |> alias "-o" |> desc "The output directory" ) setAction unzip } ``` -------------------------------- ### Integrate with Microsoft.Extensions.Hosting Source: https://github.com/jordanmarr/fsharp.systemcommandline/blob/main/README.md Demonstrates how to integrate F# System.CommandLine with `Microsoft.Extensions.Hosting` for robust application bootstrapping, configuration, and dependency injection. This example uses Serilog for logging and reads settings from `appsettings.json`. It requires several NuGet packages. ```F# open System open System.IO open FSharp.SystemCommandLine open Input open Microsoft.Extensions.DependencyInjection open Microsoft.Extensions.Configuration open Microsoft.Extensions.Hosting open Microsoft.Extensions.Logging open Serilog let buildHost (argv: string[]) = Host.CreateDefaultBuilder(argv) .ConfigureHostConfiguration(fun configHost -> configHost.SetBasePath(Directory.GetCurrentDirectory()) |> ignore configHost.AddJsonFile("appsettings.json", optional = false) |> ignore ) .UseSerilog(fun hostingContext configureLogger -> configureLogger .MinimumLevel.Information() .Enrich.FromLogContext() .WriteTo.Console() .WriteTo.File( path = "logs/log.txt", rollingInterval = RollingInterval.Year ) |> ignore ) .Build() let export (logger: ILogger, connStr: string, outputDir: DirectoryInfo, startDate: DateTime, endDate: DateTime) = task { logger.Information($"Querying from {StartDate} to {EndDate}", startDate, endDate) // Do export stuff... } [] let main argv = let host = buildHost argv let cfg = host.Services.GetRequiredService() let logger = host.Services.GetRequiredService() |> Input.inject let connStr = Input.option "--connection-string" |> Input.alias "-c" |> Input.defaultValue (cfg["ConnectionStrings:DB"]) |> Input.desc "Database connection string" let outputDir = Input.option "--output-directory" |> Input.alias "-o" |> Input.defaultValue (DirectoryInfo(cfg["DefaultOutputDirectory"])) |> desc "Output directory folder." let startDate = Input.option "--start-date" |> Input.defaultValue (DateTime.Today.AddDays(-7)) |> desc "Start date (defaults to 1 week ago from today)" let endDate = Input.option "--end-date" |> Input.defaultValue DateTime.Today |> Input.desc "End date (defaults to today)" rootCommand argv { description "Data Export" inputs (logger, connStr, outputDir, startDate, endDate) setAction export } |> Async.AwaitTask |> Async.RunSynchronously ``` -------------------------------- ### Configure Parser and Invocation Settings Source: https://github.com/jordanmarr/fsharp.systemcommandline/blob/main/README.md Shows how to customize the parser and invocation behavior using `configureParser` and `configureInvocation`. This example disables the default token replacer to allow package names starting with '@'. ```fsharp module TokenReplacerExample open FSharp.SystemCommandLine open Input let app (package: string) = if package.StartsWith("@") then printfn "{package}" 0 else eprintfn "The package name does not start with a leading @" 1 [] let main argv = // The package option needs to accept strings that start with "@" symbol. // For example, "--package @shoelace-style/shoelace". // To accomplish this, we will need to modify the configuration below. let package = option "--package" |> alias "-p" |> desc "A package name that may have a leading '@' character." rootCommand argv { description "Can be called with a leading '@' package" configureParser (fun cfg -> // Override default token replacer to ignore `@` processing cfg.ResponseFileTokenReplacer <- null ) configureInvocation (fun cfg -> cfg.EnableDefaultExceptionHandler <- false ) inputs package setAction app } ``` -------------------------------- ### Create a 'list' Command in F# Source: https://github.com/jordanmarr/fsharp.systemcommandline/blob/main/README.md This example demonstrates creating a 'list' command using F# System.CommandLine. The command takes a directory as an argument and lists its files. It also shows how to integrate global options like logging. ```fsharp let listCmd = let action (ctx: ActionContext, dir: DirectoryInfo) = let options = Global.bind ctx if options.EnableLogging then printfn $"Logging enabled to {options.LogFile.FullName}" if dir.Exists then dir.EnumerateFiles() |> Seq.iter (fun f -> printfn "%s" f.FullName) else printfn $"{dir.FullName} does not exist." command "list" { description "lists contents of a directory" inputs ( Input.context, argument "directory" |> def (DirectoryInfo @"c:\default") ) setAction action addAlias "ls" } ``` -------------------------------- ### Create a 'migrate' Database Migration Command in F# Source: https://github.com/jordanmarr/fsharp.systemcommandline/blob/main/README.md This F# snippet defines a 'migrate' command for database migrations using EvolveDb. It accepts an environment string, retrieves the connection string, and logs the start of the migration process. This is a partial example, with the task body incomplete. ```fsharp let migrateCmd (logger: ILogger) = let action (env: string) = task { logger.Information($"Environment: {env}") logger.Information("Starting EvolveDb Migrate.") let! connStr = KeyVault.getConnectionString env ``` -------------------------------- ### F# Showing Help as Default Action Source: https://github.com/jordanmarr/fsharp.systemcommandline/blob/main/README.md Configures a F# command-line application to display help information by default when no specific commands are provided. This enhances user experience by guiding them on available commands and options. ```fsharp [] let main argv = rootCommand argv { description "Shows help by default." inputs Input.context helpAction addCommand helloCmd } ``` -------------------------------- ### Create a 'repair' Database Migration Command in F# Source: https://github.com/jordanmarr/fsharp.systemcommandline/blob/main/README.md This F# example defines a 'repair' command for database migrations using EvolveDb. It takes an environment string as input, retrieves a connection string from KeyVault, and uses the logger to provide feedback during the repair process. ```fsharp let repairCmd (logger: ILogger) = let action (env: string) = task { logger.Information($"Environment: {env}") logger.Information("Starting EvolveDb Repair (correcting checksums).") let! connStr = KeyVault.getConnectionString env use conn = new SqlConnection(connStr) let evolve = Evolve(conn, fun msg -> printfn "%s" msg) evolve.TransactionMode <- TransactionKind.CommitAll evolve.Locations <- [| "Scripts" |] evolve.IsEraseDisabled <- true evolve.MetadataTableName <- "_EvolveChangelog" evolve.Repair() } command "repair" { description "Corrects checksums in the database." inputs (argument "env" |> desc "The keyvault environment: [dev, beta, prod].") setAction action } ``` -------------------------------- ### Inject Dependencies into Action Handler Source: https://github.com/jordanmarr/fsharp.systemcommandline/blob/main/README.md Shows how to inject pre-resolved dependencies, such as loggers or database connections, into your action handler using `Input.inject`. This allows for cleaner separation of concerns and easier testing. The example uses Serilog for logging. ```F# open Serilog open FSharp.SystemCommandLine open Input [] let main argv = let logger = LoggerConfiguration() .WriteTo.Console() .CreateLogger() |> Input.inject let name = option "--name" |> desc "Your name" rootCommand argv { description "Greets a user" inputs (logger, name) setAction (fun (logger: ILogger, name) -> logger.Information("Hello, {Name}!", name) ) } ``` -------------------------------- ### Define Global Options for Child Commands Source: https://github.com/jordanmarr/fsharp.systemcommandline/blob/main/README.md Illustrates how to define global options that are available to all child commands within a command hierarchy. This is useful for settings that apply broadly, such as enabling logging. The example shows a simple `--enable-logging` option. ```F# module ProgramNestedSubCommands open System.IO open FSharp.SystemCommandLine open Input module Global = let enableLogging = option "--enable-logging" |> def false ``` -------------------------------- ### Group Commands with 'ioCmd' in F# Source: https://github.com/jordanmarr/fsharp.systemcommandline/blob/main/README.md This example shows how to group related commands, such as 'delete' and 'list', under a parent command named 'io' using F# System.CommandLine. This helps in organizing complex command-line applications. ```fsharp let ioCmd = command "io" { description "Contains IO related subcommands." noAction addCommands [ deleteCmd; listCmd ] } ``` -------------------------------- ### Use Custom File Existence Validator in Argument Definition (F#) Source: https://github.com/jordanmarr/fsharp.systemcommandline/blob/main/README.md An example of how to use the custom `validateFileExists` function when defining a command-line argument. This ensures that the 'zipfile' argument provided by the user points to a file that actually exists. ```fsharp let zipFile = argument "zipfile" |> desc "The file to unzip" |> validateFileExists ``` -------------------------------- ### Configure and Parse Command Line Arguments in F# Source: https://github.com/jordanmarr/fsharp.systemcommandline/blob/main/README.md This snippet demonstrates the entry point of an F# System.CommandLine application. It configures the command-line parser with global options and commands, then parses the arguments and invokes the appropriate action. ```fsharp [] let main (argv: string array) = let cfg = commandLineConfiguration { description "Sample app for System.CommandLine" noAction addGlobalOptions Global.options addCommand ioCmd } let parseResult = cfg.Parse(argv) // Get global option value from the parseResult let loggingEnabled = Global.enableLogging.GetValue parseResult printfn $"ROOT: Logging enabled: {loggingEnabled}" parseResult.Invoke() ``` -------------------------------- ### Build Host Configuration with Serilog in F# Source: https://github.com/jordanmarr/fsharp.systemcommandline/blob/main/README.md This F# code configures a host builder using Microsoft.Extensions.Hosting. It sets up JSON configuration and integrates Serilog for logging, writing logs to both the console and a file. ```fsharp let buildHost (argv: string[]) = Host.CreateDefaultBuilder(argv) .ConfigureHostConfiguration(fun configHost -> configHost.SetBasePath(Directory.GetCurrentDirectory()) |> ignore configHost.AddJsonFile("appsettings.json", optional = false) |> ignore ) .UseSerilog(fun hostingContext configureLogger -> configureLogger .MinimumLevel.Information() .Enrich.FromLogContext() .WriteTo.Console() .WriteTo.File( path = "logs/log.txt", rollingInterval = RollingInterval.Year ) |> ignore ) .Build() ``` -------------------------------- ### Define and Run a Root Command with Subcommands Source: https://github.com/jordanmarr/fsharp.systemcommandline/blob/main/README.md Defines a root command with a description, help action, and adds two subcommands: 'repair' and 'migrate'. The 'migrate' command has a description and an environment input. ```fsharp use conn = new SqlConnection(connStr) let evolve = Evolve(conn, fun msg -> printfn "%s" msg) evolve.TransactionMode <- TransactionKind.CommitAll evolve.Locations <- [| "Scripts" |] evolve.IsEraseDisabled <- true evolve.MetadataTableName <- "_EvolveChangelog" evolve.Migrate() command "migrate" { description "Migrates the database." inputs (argument "env" |> desc "The keyvault environment: [dev, beta, prod].") setAction action } [] let main argv = let host = buildHost argv let logger = host.Services.GetService() rootCommand argv { description "Database Migrations" inputs Input.context // Required input for helpAction helpAction // Show --help if no sub-command is called addCommand (fun () -> repairCmd logger) addCommand (fun () -> migrateCmd logger) } ``` -------------------------------- ### Define and Execute a Command-Line Application in F# Source: https://github.com/jordanmarr/fsharp.systemcommandline/blob/main/README.md This snippet demonstrates how to define a command-line application using FSharp.SystemCommandLine. It includes defining arguments, options, validation, and setting an action function. The `rootCommand` function orchestrates the command definition and execution. ```fsharp open System.IO open FSharp.SystemCommandLine open Input let unzip (zipFile: FileInfo, outputDirMaybe: DirectoryInfo option) = // Default to the zip file dir if None let outputDir = defaultArg outputDirMaybe zipFile.Directory printfn $"Unzipping {zipFile.Name} to {outputDir.FullName}..." [] let main argv = rootCommand argv { description "Unzips a .zip file" inputs ( argument "zipfile" |> desc "The file to unzip" |> validateFileExists |> validate (fun zipFile -> if zipFile.Length <= 500000 then Ok () else Error $"File cannot be bigger than 500 KB" ), optionMaybe "--output" |> alias "-o" |> desc "The output directory" |> validateDirectoryExists ) setAction unzip } ``` -------------------------------- ### Create Custom Input Functions with editOption and editArgument (F#) Source: https://github.com/jordanmarr/fsharp.systemcommandline/blob/main/README.md Demonstrates how to create custom input functions like `alias` and `desc` by composing existing functions using `editOption` and `editArgument`. These functions allow for concise configuration of command-line options and arguments. ```fsharp let alias (alias: string) (input: ActionInput<'T>) = input |> editOption (fun o -> o.Aliases.Add alias) let desc (description: string) (input: ActionInput<'T>) = input |> editOption (fun o -> o.Description <- description) |> editArgument (fun a -> a.Description <- description) ``` -------------------------------- ### Handle More Than 8 Inputs with ActionContext Source: https://github.com/jordanmarr/fsharp.systemcommandline/blob/main/README.md Demonstrates how to handle command handlers with more than eight inputs by manually parsing parameters from the ActionContext. This is useful when the default tuple limit is exceeded. It requires registering inputs in the command builder. ```F# module Program open FSharp.SystemCommandLine open Input module Parameters = let words = option "--word" |> alias "-w" |> desc "A list of words to be appended" let separator = optionMaybe "--separator" |> alias "-s" |> desc "A character that will separate the joined words." let app ctx = // Manually parse as many parameters as you need let words = Parameters.words.GetValue ctx.ParseResult let separator = Parameters.separator.GetValue ctx.ParseResult // Do work let separator = separator |> Option.defaultValue ", " System.String.Join(separator, words) |> printfn "Result: %s" 0 [] let main argv = rootCommand argv { description "Appends words together" inputs Input.context setAction app addInputs [ Parameters.words; Parameters.separator ] } ``` -------------------------------- ### Define and Bind Global Options in F# Source: https://github.com/jordanmarr/fsharp.systemcommandline/blob/main/README.md This snippet shows how to define global options like '--log-file' and 'enable-logging' using F# System.CommandLine. It demonstrates how to bind these options to a record type for easy access within command actions. ```fsharp let logFile = option "--log-file" |> def (FileInfo @"c:\temp\default.log") type Options = { EnableLogging: bool; LogFile: FileInfo } let options: ActionInput seq = [ enableLogging; logFile ] let bind (ctx: ActionContext) = { EnableLogging = enableLogging.GetValue ctx.ParseResult LogFile = logFile.GetValue ctx.ParseResult } ``` -------------------------------- ### Manually Invoke a Root Command Source: https://github.com/jordanmarr/fsharp.systemcommandline/blob/main/README.md Demonstrates how to manually invoke a root command using `ManualInvocation.rootCommand`. This approach does not take CLI arguments directly and requires explicit parsing and invocation. ```fsharp open FSharp.SystemCommandLine open Input open System.CommandLine.Parsing let app (words: string array, separator: string option) = let separator = defaultArg separator ", " System.String.Join(separator, words) |> printfn "Result: %s" 0 [] let main argv = let words = option "--word" |> alias "-w" |> desc "A list of words to be appended" let separator = optionMaybe "--separator" |> alias "-s" |> desc "A character that will separate the joined words." let cmd = ManualInvocation.rootCommand { description "Appends words together" inputs (words, separator) setAction app } let parseResult = cmd.Parse(argv) // parseResult.InvokeAsync() parseResult.Invoke() ``` -------------------------------- ### F# App with SubCommands using FSharp.SystemCommandLine Source: https://github.com/jordanmarr/fsharp.systemcommandline/blob/main/README.md Defines a command-line application with 'list' and 'delete' subcommands. The 'list' command enumerates files in a directory, while 'delete' removes a directory, with an option for recursive deletion. It utilizes FSharp.SystemCommandLine for command parsing and action handling. ```fsharp open System.IO open FSharp.SystemCommandLine open Input // Ex: fsm.exe list "c:\temp" let listCmd = let action (dir: DirectoryInfo) = if dir.Exists then dir.EnumerateFiles() |> Seq.iter (fun f -> printfn "%s" f.Name) else printfn $"{dir.FullName} does not exist." command "list" { description "lists contents of a directory" inputs (argument "dir" |> desc "The directory to list") setAction action } // Ex: fsm.exe delete "c:\temp" --recursive let deleteCmd = let action (dir: DirectoryInfo, recursive: bool) = if dir.Exists then if recursive then printfn $"Recursively deleting {dir.FullName}" else printfn $"Deleting {dir.FullName}" else printfn $"{dir.FullName} does not exist." let dir = argument "dir" |> desc "The directory to delete" let recursive = option "--recursive" |> def false command "delete" { description "deletes a directory" inputs (dir, recursive) setAction action } [] let main argv = rootCommand argv { description "File System Manager" noAction // if using async task sub commands: // noActionAsync addCommand listCmd addCommand deleteCmd } ``` -------------------------------- ### Define Optional CLI Options with Default None Source: https://context7.com/jordanmarr/fsharp.systemcommandline/llms.txt Shows how to create CLI options that can be omitted, defaulting to None, using FSharp.SystemCommandLine's Input.optionMaybe. This enables idiomatic F# optional handling in action handlers. ```fsharp open System.IO open FSharp.SystemCommandLine open Input let app (input: FileInfo, outputMaybe: DirectoryInfo option) = match outputMaybe with | Some dir -> printfn $"Output to: {dir.FullName}" | None -> printfn "Using default output" [] let main argv = rootCommand argv { description "Process files" inputs ( argument "input", optionMaybe "--output" |> alias "-o" |> desc "Output directory" ) setAction app } ``` -------------------------------- ### Define Required and Defaulted CLI Options Source: https://context7.com/jordanmarr/fsharp.systemcommandline/llms.txt Illustrates defining CLI options with specific types, aliases, descriptions, and default values using FSharp.SystemCommandLine's Input.option. Suitable for options that are always expected to have a value. ```fsharp open FSharp.SystemCommandLine open Input let verbose = option "--verbose" |> alias "-v" |> def false let count = option "--count" |> alias "-c" |> desc "Number of iterations" |> def 1 let name = option "--name" |> required |> desc "User name" ``` -------------------------------- ### Create Subcommands with Command Builder Source: https://context7.com/jordanmarr/fsharp.systemcommandline/llms.txt Creates named subcommands using the `command` builder. Parent commands use `noAction` when they only serve as containers for subcommands. ```fsharp open System.IO open FSharp.SystemCommandLine open Input let listCmd = let action (dir: DirectoryInfo) = if dir.Exists then dir.EnumerateFiles() |> Seq.iter (fun f -> printfn "%s" f.Name) else printfn $"{dir.FullName} does not exist." command "list" { description "Lists contents of a directory" inputs (argument "dir" |> desc "The directory to list") setAction action } let deleteCmd = let action (dir: DirectoryInfo, recursive: bool) = if dir.Exists then if recursive then printfn $"Recursively deleting {dir.FullName}" else printfn $"Deleting {dir.FullName}" else printfn $"{dir.FullName} does not exist." command "delete" { description "Deletes a directory" inputs ( argument "dir" |> desc "The directory to delete", option "--recursive" |> def false ) setAction action } [] let main argv = rootCommand argv { description "File System Manager" noAction addCommand listCmd addCommand deleteCmd } ``` -------------------------------- ### Inject Dependencies with Input.inject Source: https://context7.com/jordanmarr/fsharp.systemcommandline/llms.txt Wraps a pre-resolved dependency value for injection into the action inputs tuple. Useful for loggers, services, or configuration. ```fsharp open Serilog open FSharp.SystemCommandLine open Input [] let main argv = let logger = LoggerConfiguration() .WriteTo.Console() .CreateLogger() |> Input.inject let name = option "--name" |> desc "Your name" rootCommand argv { description "Greets a user" inputs (logger, name) setAction (fun (logger: ILogger, name) -> logger.Information("Hello, {Name}!", name) ) } ``` -------------------------------- ### Implement File Existence Validation with validate (F#) Source: https://github.com/jordanmarr/fsharp.systemcommandline/blob/main/README.md Shows how to implement a `validateFileExists` function using the existing `validate` function. This custom validator ensures that a provided file path corresponds to an existing file, returning an error message if it does not. ```fsharp let validateFileExists (input: ActionInput) = input |> Input.validate (fun file -> if file.Exists then Ok () else Error $("File '{file.FullName}' does not exist.") ) ``` -------------------------------- ### Define Optional Positional CLI Arguments Source: https://context7.com/jordanmarr/fsharp.systemcommandline/llms.txt Illustrates creating command-line arguments that can be omitted, defaulting to None, using FSharp.SystemCommandLine's Input.argumentMaybe. This allows for flexible handling of optional positional inputs. ```fsharp open FSharp.SystemCommandLine open Input let greet (name: string option) = match name with | Some n -> printfn $"Hello, {n}!" | None -> printfn "Hello, stranger!" [] let main argv = rootCommand argv { description "Greet someone" inputs (argumentMaybe "name" |> desc "Name to greet") setAction greet } ``` -------------------------------- ### Customizing Parser and Invocation in F# Source: https://context7.com/jordanmarr/fsharp.systemcommandline/llms.txt Shows how to customize the parser and invocation behavior of a command in F# using FSharp.SystemCommandLine. It utilizes `configureParser` to disable response file token replacement and `configureInvocation` to disable the default exception handler. The command takes a package name as input. ```fsharp open FSharp.SystemCommandLine open Input let app (package: string) = if package.StartsWith("@") then printfn $"{package}" 0 else eprintfn "Package name does not start with @" 1 [] let main argv = let package = option "--package" |> alias "-p" |> desc "Package name with optional @ prefix" rootCommand argv { description "Package manager" configureParser (fun cfg -> // Disable @ token replacement to allow @org/package names cfg.ResponseFileTokenReplacer <- null ) configureInvocation (fun cfg -> cfg.EnableDefaultExceptionHandler <- false ) inputs package setAction app } ``` -------------------------------- ### Create a 'delete' Command in F# Source: https://github.com/jordanmarr/fsharp.systemcommandline/blob/main/README.md This snippet illustrates creating a 'delete' command in F# System.CommandLine. The command accepts a directory argument and an optional '--recursive' flag. It includes logging integration and provides feedback on the deletion operation. ```fsharp let deleteCmd = let action (ctx: ActionContext, dir: DirectoryInfo, recursive: bool) = let options = Global.bind ctx if options.EnableLogging then printfn $"Logging enabled to {options.LogFile.FullName}" if dir.Exists then if recursive then printfn $"Recursively deleting {dir.FullName}" else printfn $"Deleting {dir.FullName}" else printfn $"{dir.FullName} does not exist." let dir = Input.argument "directory" |> def (DirectoryInfo @"c:\default") let recursive = Input.option "--recursive" |> def false command "delete" { description "deletes a directory" inputs (Input.context, dir, recursive) setAction action addAlias "del" } ``` -------------------------------- ### Define Positional CLI Arguments Source: https://context7.com/jordanmarr/fsharp.systemcommandline/llms.txt Demonstrates defining required positional command-line arguments using FSharp.SystemCommandLine's Input.argument. These arguments do not use dashes and are mandatory by default. ```fsharp open System.IO open FSharp.SystemCommandLine open Input let copy (source: FileInfo, destination: DirectoryInfo) = printfn $"Copying {source.Name} to {destination.FullName}" [] let main argv = rootCommand argv { description "Copy a file" inputs ( argument "source" |> desc "Source file" |> validateFileExists, argument "destination" |> desc "Destination directory" ) setAction copy } ``` -------------------------------- ### F# Input Property Modifiers for CLI Options Source: https://context7.com/jordanmarr/fsharp.systemcommandline/llms.txt Illustrates various input property modifiers available in FSharp.SystemCommandLine for configuring command-line options and arguments. This includes setting aliases, default values, descriptions, validation rules, and custom parsing logic. ```fsharp open System.IO open FSharp.SystemCommandLine open Input // Option with alias and default value let verbose = option "--verbose" |> alias "-v" |> def false |> desc "Enable verbose output" // Required option let config = option "--config" |> required |> desc "Configuration file path" // Option accepting only specific values let format = option "--format" |> acceptOnlyFromAmong ["json"; "xml"; "csv"] |> def "json" // Argument with file validation let inputFile = argument "input" |> desc "Input file" |> validateFileExists |> acceptLegalFilePathsOnly // Custom parsing with Result type let port = option "--port" |> tryParse (fun argResult -> match argResult.Tokens |> Seq.tryHead with | Some token -> match System.Int32.TryParse(token.Value) with | true, p when p > 0 && p < 65536 -> Ok p | _ -> Error "Port must be between 1 and 65535" | None -> Ok 8080 ) // Hidden option (not shown in help) let debug = option "--debug" |> hidden |> def false // Option with custom arity for multiple values let tags = option "--tag" |> alias "-t" |> arity OneOrMore ``` -------------------------------- ### Manual Invocation of RootCommand in F# Source: https://context7.com/jordanmarr/fsharp.systemcommandline/llms.txt Demonstrates how to manually parse and invoke a RootCommand in F# using FSharp.SystemCommandLine. This is useful when you need access to the ParseResult before invocation. It defines a command with words and an optional separator, then parses and invokes it. ```fsharp open FSharp.SystemCommandLine open Input let app (words: string array, separator: string option) = let separator = defaultArg separator ", " System.String.Join(separator, words) |> printfn "Result: %s" 0 [] let main argv = let cmd = ManualInvocation.rootCommand { description "Appends words together" inputs ( option "--word" |> alias "-w" |> desc "Words to append", optionMaybe "--separator" |> alias "-s" |> desc "Separator character" ) setAction app } let parseResult = cmd.Parse(argv) parseResult.Invoke() ``` -------------------------------- ### Implement Global Options with Recursive Modifier Source: https://context7.com/jordanmarr/fsharp.systemcommandline/llms.txt Creates options that apply recursively to all subcommands using the `recursive` modifier and manual binding via `ActionContext`. These options are defined in a module and added to the root command configuration. ```fsharp open System.IO open FSharp.SystemCommandLine open Input module Global = let enableLogging = option "--enable-logging" |> def false |> recursive let logFile = option "--log-file" |> def (FileInfo @"c:\temp\default.log") |> recursive type Options = { EnableLogging: bool; LogFile: FileInfo } let options: ActionInput seq = [ enableLogging; logFile ] let bind (ctx: ActionContext) = { EnableLogging = enableLogging.GetValue ctx.ParseResult LogFile = logFile.GetValue ctx.ParseResult } let listCmd = let action (ctx: ActionContext, dir: DirectoryInfo) = let options = Global.bind ctx if options.EnableLogging then printfn $"Logging enabled to {options.LogFile.FullName}" if dir.Exists then dir.EnumerateFiles() |> Seq.iter (fun f -> printfn "%s" f.FullName) command "list" { description "Lists contents of a directory" inputs (Input.context, argument "directory" |> def (DirectoryInfo @"c:\default")) setAction action addAlias "ls" } [] let main argv = let cfg = commandLineConfiguration { description "Sample app" noAction addGlobalOptions Global.options addCommand listCmd } cfg.Parse(argv).Invoke() ``` -------------------------------- ### Pass ActionContext to Handler Source: https://context7.com/jordanmarr/fsharp.systemcommandline/llms.txt Shows how to pass the ActionContext, containing ParseResult and CancellationToken, to an action handler using FSharp.SystemCommandLine. This is essential for asynchronous operations or when handling more than eight inputs. ```fsharp open System.Threading.Tasks open FSharp.SystemCommandLine open Input let app (ctx: ActionContext, words: string array, separator: string) = task { let cancel = ctx.CancellationToken // Use cancellation token for async work let result = System.String.Join(separator, words) printfn $"Result: {result}" } [] let main argv = rootCommand argv { description "Appends words together" inputs ( Input.context, option "--word" |> alias "-w" |> desc "Words to append", option "--separator" |> alias "-s" |> def ", " ) setAction app } |> Async.AwaitTask |> Async.RunSynchronously ``` -------------------------------- ### Validate Input with Input.validate Source: https://context7.com/jordanmarr/fsharp.systemcommandline/llms.txt Adds a validator that uses F#'s Result type to validate parsed values. Returns Ok () for valid input or Error "message" for invalid input. ```fsharp open System.IO open FSharp.SystemCommandLine open Input let processFile (file: FileInfo) = printfn $"Processing {file.Name}" [] let main argv = rootCommand argv { description "Process a file" inputs ( argument "file" |> desc "File to process" |> validateFileExists |> validate (fun file -> if file.Length <= 1_000_000L then Ok () else Error "File cannot be larger than 1 MB" ) ) setAction processFile } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.