Argu


1: 
2: 
3: 
4: 
5: 
6: 
// This block of code is omitted in the generated HTML documentation. Use
// it to define helpers that you do not want to show in the documentation.
#I "../../src/Argu/bin/Release/net45"
#r "Argu.dll"

open System

Tutorial

Introduction

The library is based on the simple observation that configuration parameters can be naturally described using discriminated unions. For instance:

1: 
2: 
3: 
4: 
5: 
type Arguments =
    | Working_Directory of path:string
    | Listener of host:string * port:int
    | Log_Level of level:int
    | Detach

Argu takes such discriminated unions and generates a corresponding argument parsing scheme. For example, a parser generated from the above template would take the following command line input

1: 
--working-directory /var/run --listener localhost 8080 --detach

and parse it into the list

1: 
[ Working_Directory "/var/run" ; Listener("localhost", 8080) ; Detach ]

Argu is also capable of reading the AppSettings section of an application's configuration file:

1: 
2: 
3: 
4: 
5: 
6: 
<appSettings>
    <add key="working directory" value="C:\temp" />
    <add key="listener" value="192.168.0.3, 2675" />
    <add key="log level" value="3" />
    <add key="detach" value="true" />
</appSettings>

Both XML configuration and command line arguments can be parsed at the same time. By default, command line parameters override their corresponding XML configuration.

Basic Usage

A minimal parser based on the above example can be created as follows:

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
open Argu

type CLIArguments =
    | Working_Directory of path:string
    | Listener of host:string * port:int
    | Data of base64:byte[]
    | Port of tcp_port:int
    | Log_Level of level:int
    | Detach
with
    interface IArgParserTemplate with
        member s.Usage =
            match s with
            | Working_Directory _ -> "specify a working directory."
            | Listener _ -> "specify a listener (hostname : port)."
            | Data _ -> "binary data in base64 encoding."
            | Port _ -> "specify a primary port."
            | Log_Level _ -> "set the log level."
            | Detach _ -> "detach daemon from console."

We extract the argument parser from the template using the following command:

1: 
let parser = ArgumentParser.Create<CLIArguments>(programName = "gadget.exe")

We can get the automatically generated usage string by typing

1: 
let usage = parser.PrintUsage()

giving

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
USAGE: gadget.exe [--help] [--working-directory <path>] [--listener <host> <port>] [--data <base64>]
                  [--port <tcp port>] [--log-level <level>] [--detach]

OPTIONS:

    --working-directory <path>
                          specify a working directory.
    --listener <host> <port>
                          specify a listener (hostname : port).
    --data <base64>       binary data in base64 encoding.
    --port <tcp port>     specify a primary port.
    --log-level <level>   set the log level.
    --detach              detach daemon from console.
    --help                display this list of options.

To parse a command line input:

1: 
let results = parser.Parse [| "--detach" ; "--listener" ; "localhost" ; "8080" |]

which gives

1: 
let all = results.GetAllResults() // [ Detach ; Listener ("localhost", 8080) ]

Querying Parameters

While getting a single list of all parsed results might be useful for some cases, it is more likely that you need to query the results for specific parameters:

1: 
2: 
let detach = results.Contains Detach
let listener = results.GetResults Listener

The following methods return the last observed result for given argument case

1: 
2: 
let dataOpt = results.TryGetResult Data
let logLevel = results.GetResult (Log_Level, defaultValue = 0)

Querying using quotations enables a simple and type safe way to deconstruct parse results into their constituent values.

Customization

The parsing behaviour of the configuration parameters can be customized by fixing attributes to the union cases:

1: 
2: 
3: 
4: 
5: 
6: 
type Argument =
    | [<Mandatory>] Cache_Path of path:string
    | [<NoCommandLine>] Connection_String of conn:string
    | [<Unique>] Listener of host:string * port:int
    | [<EqualsAssignment>] Assignment of value:string
    | [<AltCommandLine("-p")>] Primary_Port of tcp_port:int

In this case,

  • Mandatory: parser will fail if no configuration for this parameter is given.

  • NoCommandLine: restricts this parameter to the AppSettings section.

  • AltCommandLine: specifies an alternative command line switch.

  • EqualsAssignment : enforces --assignment=value and --assignment key=value CLI syntax.

  • Unique : parser will fail if CLI provides this argument more than once.

Many more attributes are also available, such as

  • First: Argument can only be placed at the beginning of the command line.

  • Hidden: do not display in the help usage string.

  • CustomAppSettings: sets a custom key name for AppSettings.

  • CustomAssignment: works like EqualsAssignment but with a custom separator string.

Please see the API Reference for a complete list of all attributes provided by Argu.

Supported Primitives

Arguments can specify the following primitives as parameters:

  • bool, byte and sbyte.
  • int, int16 and int64.
  • uint, uint16 and uint64.
  • char, string and guid.
  • float, double and decimal.
  • System.Numerics.BigInt.
  • byte[], which accepts base64 representations.

Optional and List parameters

Additionally, it is possible to specify argument parameters that are either optional or lists:

1: 
2: 
3: 
type VariadicParameters =
    | [<EqualsAssignment>] Enable_Logging of path:string option
    | Tcp_Ports of port:int list

which results in the following syntax:

1: 
2: 
3: 
4: 
5: 
6: 
7: 
USAGE: gadget.exe [--help] [--enable-logging[=<path>]] [--tcp-ports [<port>...]]

OPTIONS:

    --enable-logging[=<path>]  enable logging for the process; optionally path to the logfile can be specified.
    --tcp-ports [<port>...]    specify a list of TCP ports for the process.
    --help                     display this list of options.

Note that arguments that use optional or list must have precisely one parameter.

Enumeration parameters

Argu can also accept enumerations as parameters:

1: 
2: 
3: 
4: 
5: 
6: 
7: 
type MyEnum =
    | First  = 1
    | Second = 2
    | Third  = 3

type EnumArguments =
    | Get_Enum of MyEnum

which results in the syntax

1: 
2: 
3: 
4: 
5: 
6: 
7: 
USAGE: gadget.exe [--help] [--get-enum <first|second|third>]

OPTIONS:

    --get-enum <first|second|third>
                          specify either of 'first', 'second' or 'third'.
    --help                display this list of options.

Note that it is possible to specify F# unions instead of enumerations in this context, provided that these do not specify any parameters in any of their cases.

Main commands

Arguments carrying the MainCommand attribute can be used to specify the main set of arguments for the CLI. These arguments can be passed without the need to specify a switch identifier.

1: 
2: 
3: 
4: 
type WGetArguments =
    | Quiet
    | No_Check_Certificate
    | [<MainCommand; ExactlyOnce; Last>] Urls of url:string list

which generates the syntax

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
USAGE: wget [--help] [--quiet] [--no-check-certificate] <url>...

URLS:

    <url>...              List of urls to download from.

OPTIONS:

    --quiet               Turn off Wget's output.
    --no-check-certificate
                          Don't check the server certificate.
    --help                display this list of options.

SubCommands

As of Argu 3.0, it is possible to provide nested, contextual parsing. For example, consider this mock git CLI syntax:

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
[<CliPrefix(CliPrefix.Dash)>]
type CleanArgs =
    | D
    | F
    | X
with
    interface IArgParserTemplate with
        member this.Usage =
            match this with
            | D -> "Remove untracked directories in addition to untracked files"
            | F -> "Git clean will refuse to delete files or directories unless given -f."
            | X -> "Remove only files ignored by Git."
 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
and CommitArgs =
    | Amend
    | [<AltCommandLine("-p")>] Patch
    | [<AltCommandLine("-m")>] Message of msg:string
with
    interface IArgParserTemplate with
        member this.Usage =
            match this with
            | Amend -> "Replace the tip of the current branch by creating a new commit."
            | Patch -> "Use the interactive patch selection interface to chose which changes to commit."
            | Message _ -> "Use the given <msg> as the commit message. "
 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
and GitArgs =
    | Version
    | [<AltCommandLine("-v")>] Verbose
    | [<CliPrefix(CliPrefix.None)>] Clean of ParseResults<CleanArgs>
    | [<CliPrefix(CliPrefix.None)>] Commit of ParseResults<CommitArgs>
with
    interface IArgParserTemplate with
        member this.Usage =
            match this with
            | Version -> "Prints the Git suite version that the git program came from."
            | Verbose -> "Print a lot of output to stdout."
            | Clean _ -> "Remove untracked files from the working tree."
            | Commit _ -> "Record changes to the repository."

and the following console app entrypoint

1: 
2: 
3: 
4: 
5: 
6: 
7: 
//[<EntryPoint>]
let main argv =
    try
        parser.ParseCommandLine(inputs = argv, raiseOnUsage = true) |> ignore
    with e ->
        printfn "%s" e.Message
    0

which generates the following syntax on corresponding command and subcommand help requests:

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
USAGE: git [--help] [--version] [--verbose] [<subcommand> [<options>]]

SUBCOMMANDS:

    clean <options>       Remove untracked files from the working tree.
    commit <options>      Record changes to the repository.

    Use 'git <subcommand> --help' for additional information.

OPTIONS:

    --version             Prints the Git suite version that the git program came from.
    --verbose, -v         Print a lot of output to stdout.
    --help                display this list of options.

and for the subcommand:

1: 
2: 
3: 
4: 
5: 
6: 
7: 
8: 
USAGE: git commit [--help] [--amend] [--patch] [--message <msg>]

OPTIONS:

    --amend               Replace the tip of the current branch by creating a new commit.
    --patch, -p           Use the interactive patch selection interface to chose which changes to commit.
    --message, -m <msg>   Use the given <msg> as the commit message.
    --help                display this list of options.

This allows specifying parameters that are particular to a subcommand context. For instance, git clean -fdx parses correctly to [Clean [F; D; X]], however git -f or git commit -f will both result in a parse error:

1: 
ERROR: unrecognized argument: '-f'.

Inheriting parent arguments

Switches specified in the parent argument union do not automatically make it to the syntax of the child subcommand. For example the command

1: 
git clean --version

will result in parse error since Version is not a part of the subcommand syntax, but one of its parent syntax. It is possible to parent options visible inside subcommands by attaching the InheritAttribute to switches.

1: 
2: 
type GitArgs =
    | [<Inherit>] Version

which would make the aforementioned syntax valid.

Post Processing

It should be noted here that arbitrary unions are not supported by the parser. Union cases can only contain fields of primitive types. This means that user-defined parsers are not supported. For configuration inputs that are non-trivial, a post-process facility is provided.

1: 
2: 
3: 
4: 
5: 
6: 
let parsePort p =
    if p < 0 || p > int UInt16.MaxValue then
        failwith "invalid port number."
    else p

let ports = results.PostProcessResults (<@ Port @>, parsePort)

This construct is useful since error handling is delegated to the mechanisms of Argu.

Unparsing Support

Argu is convenient when it comes to automated process spawning:

1: 
2: 
3: 
4: 
5: 
open System.Diagnostics

let arguments = parser.PrintCommandLineArgumentsFlat [ Port 42 ; Working_Directory "temp" ]

Process.Start("foo.exe", arguments)

It can also be used to auto-generate a suitable AppSettings configuration file:

1: 
let xml = parser.PrintAppSettingsArguments [ Port 42 ; Working_Directory "/tmp" ]

which would yield the following:

1: 
2: 
3: 
4: 
5: 
6: 
7: 
8: 
9: 
<?xml version="1.0" encoding="utf-16"?>
<configuration>
  <appSettings>
    <!-- sets the port number. : port -->
    <add key="port" value="42" />
    <!-- sets the working directory. : path -->
    <add key="working directory" value="/tmp" />
  </appSettings>
</configuration>

More Examples

Check out the samples folder for CLI implementations that use Argu.

namespace System
type Arguments =
  | Working_Directory of path: string
  | Listener of host: string * port: int
  | Log_Level of level: int
  | Detach
union case Arguments.Working_Directory: path: string -> Arguments
Multiple items
val string : value:'T -> string

--------------------
type string = String
union case Arguments.Listener: host: string * port: int -> Arguments
Multiple items
val int : value:'T -> int (requires member op_Explicit)

--------------------
type int = int32

--------------------
type int<'Measure> = int
union case Arguments.Log_Level: level: int -> Arguments
union case Arguments.Detach: Arguments
namespace Argu
union case CLIArguments.Working_Directory: path: string -> CLIArguments
union case CLIArguments.Listener: host: string * port: int -> CLIArguments
Multiple items
union case CLIArguments.Data: base64: byte [] -> CLIArguments

--------------------
namespace System.Data

--------------------
namespace Microsoft.FSharp.Data
Multiple items
val byte : value:'T -> byte (requires member op_Explicit)

--------------------
type byte = Byte
union case CLIArguments.Port: tcp_port: int -> CLIArguments
union case CLIArguments.Log_Level: level: int -> CLIArguments
union case CLIArguments.Detach: CLIArguments
type IArgParserTemplate =
  interface
    abstract member Usage : string
  end
val s : CLIArguments
val parser : ArgumentParser<CLIArguments>
Multiple items
type ArgumentParser =
  private new : argInfo:UnionArgInfo * _programName:string * helpTextMessage:string option * _usageStringCharacterWidth:int * errorHandler:IExiter -> ArgumentParser
  abstract member Accept : visitor:IArgumentParserVisitor<'R> -> 'R
  member GetArgumentCases : unit -> ArgumentCaseInfo list
  member GetSubCommandParsers : unit -> ArgumentParser list
  member PrintCommandLineSyntax : ?programName:string * ?usageStringCharacterWidth:int -> string
  member PrintUsage : ?message:string * ?programName:string * ?hideSyntax:bool * ?usageStringCharacterWidth:int -> string
  member ErrorHandler : IExiter
  member HelpDescription : string
  member HelpFlags : string list
  member HelpTextMessage : string option
  ...

--------------------
type ArgumentParser<'Template (requires 'Template :> IArgParserTemplate)> =
  inherit ArgumentParser
  new : ?programName:string * ?helpTextMessage:string * ?usageStringCharacterWidth:int * ?errorHandler:IExiter * ?checkStructure:bool -> ArgumentParser<'Template>
  private new : argInfo:UnionArgInfo * _programName:string * helpTextMessage:string option * _usageStringCharacterWidth:int * errorHandler:IExiter -> ArgumentParser<'Template>
  override Accept : visitor:IArgumentParserVisitor<'a1> -> 'a1
  member GetArgumentCaseInfo : ctorExpr:Expr<('Fields -> 'Template)> -> ArgumentCaseInfo
  member GetArgumentCaseInfo : value:'Template -> ArgumentCaseInfo
  member GetSubCommandParser : expr:Expr<(ParseResults<'SubTemplate> -> 'Template)> -> ArgumentParser<'SubTemplate> (requires 'SubTemplate :> IArgParserTemplate)
  member GetTag : value:'Template -> int
  member Parse : ?inputs:string [] * ?configurationReader:IConfigurationReader * ?ignoreMissing:bool * ?ignoreUnrecognized:bool * ?raiseOnUsage:bool -> ParseResults<'Template>
  member ParseCommandLine : ?inputs:string [] * ?ignoreMissing:bool * ?ignoreUnrecognized:bool * ?raiseOnUsage:bool -> ParseResults<'Template>
  ...

--------------------
new : ?programName:string * ?helpTextMessage:string * ?usageStringCharacterWidth:int * ?errorHandler:IExiter * ?checkStructure:bool -> ArgumentParser<'Template>
static member ArgumentParser.Create : ?programName:string * ?helpTextMessage:string * ?usageStringCharacterWidth:int * ?errorHandler:IExiter * ?checkStructure:bool -> ArgumentParser<#IArgParserTemplate>
type CLIArguments =
  | Working_Directory of path: string
  | Listener of host: string * port: int
  | Data of base64: byte []
  | Port of tcp_port: int
  | Log_Level of level: int
  | Detach
    interface IArgParserTemplate
val usage : string
member ArgumentParser.PrintUsage : ?message:string * ?programName:string * ?hideSyntax:bool * ?usageStringCharacterWidth:int -> string
val results : ParseResults<CLIArguments>
member ArgumentParser.Parse : ?inputs:string [] * ?configurationReader:IConfigurationReader * ?ignoreMissing:bool * ?ignoreUnrecognized:bool * ?raiseOnUsage:bool -> ParseResults<'Template>
val all : CLIArguments list
member ParseResults.GetAllResults : ?source:ParseSource -> 'Template list
val detach : bool
member ParseResults.Contains : expr:Quotations.Expr<('Fields -> 'Template)> * ?source:ParseSource -> bool
member ParseResults.Contains : expr:Quotations.Expr<'Template> * ?source:ParseSource -> bool
val listener : (string * int) list
member ParseResults.GetResults : expr:Quotations.Expr<('Fields -> 'Template)> * ?source:ParseSource -> 'Fields list
member ParseResults.GetResults : expr:Quotations.Expr<'Template> * ?source:ParseSource -> 'Template list
val dataOpt : byte [] option
member ParseResults.TryGetResult : expr:Quotations.Expr<('Fields -> 'Template)> * ?source:ParseSource -> 'Fields option
member ParseResults.TryGetResult : expr:Quotations.Expr<'Template> * ?source:ParseSource -> 'Template option
val logLevel : int
member ParseResults.GetResult : expr:Quotations.Expr<('Fields -> 'Template)> * ?defaultValue:'Fields * ?source:ParseSource -> 'Fields
member ParseResults.GetResult : expr:Quotations.Expr<'Template> * ?defaultValue:'Template * ?source:ParseSource -> 'Template
type Argument =
  | Cache_Path of path: string
  | Connection_String of conn: string
  | Listener of host: string * port: int
  | Assignment of value: string
  | Primary_Port of tcp_port: int
Multiple items
type MandatoryAttribute =
  inherit Attribute
  new : unit -> MandatoryAttribute

--------------------
new : unit -> MandatoryAttribute
union case Argument.Cache_Path: path: string -> Argument
Multiple items
type NoCommandLineAttribute =
  inherit Attribute
  new : unit -> NoCommandLineAttribute

--------------------
new : unit -> NoCommandLineAttribute
union case Argument.Connection_String: conn: string -> Argument
Multiple items
type UniqueAttribute =
  inherit Attribute
  new : unit -> UniqueAttribute

--------------------
new : unit -> UniqueAttribute
union case Argument.Listener: host: string * port: int -> Argument
Multiple items
type EqualsAssignmentAttribute =
  inherit CustomAssignmentAttribute
  new : unit -> EqualsAssignmentAttribute

--------------------
new : unit -> EqualsAssignmentAttribute
union case Argument.Assignment: value: string -> Argument
Multiple items
type AltCommandLineAttribute =
  inherit Attribute
  new : [<ParamArray>] names:string [] -> AltCommandLineAttribute
  member Names : string []

--------------------
new : [<ParamArray>] names:string [] -> AltCommandLineAttribute
union case Argument.Primary_Port: tcp_port: int -> Argument
type VariadicParameters =
  | Enable_Logging of path: string option
  | Tcp_Ports of port: int list
union case VariadicParameters.Enable_Logging: path: string option -> VariadicParameters
type 'T option = Option<'T>
union case VariadicParameters.Tcp_Ports: port: int list -> VariadicParameters
type 'T list = List<'T>
type MyEnum =
  | First = 1
  | Second = 2
  | Third = 3
Multiple items
MyEnum.First: MyEnum = 1

--------------------
type FirstAttribute =
  inherit CliPositionAttribute
  new : unit -> FirstAttribute

--------------------
new : unit -> FirstAttribute
MyEnum.Second: MyEnum = 2
MyEnum.Third: MyEnum = 3
type EnumArguments = | Get_Enum of MyEnum
union case EnumArguments.Get_Enum: MyEnum -> EnumArguments
type WGetArguments =
  | Quiet
  | No_Check_Certificate
  | Urls of url: string list
union case WGetArguments.Quiet: WGetArguments
union case WGetArguments.No_Check_Certificate: WGetArguments
Multiple items
type MainCommandAttribute =
  inherit Attribute
  new : unit -> MainCommandAttribute
  new : argumentName:string -> MainCommandAttribute
  member ArgumentName : string

--------------------
new : unit -> MainCommandAttribute
new : argumentName:string -> MainCommandAttribute
Multiple items
type ExactlyOnceAttribute =
  inherit Attribute
  new : unit -> ExactlyOnceAttribute

--------------------
new : unit -> ExactlyOnceAttribute
Multiple items
type LastAttribute =
  inherit CliPositionAttribute
  new : unit -> LastAttribute

--------------------
new : unit -> LastAttribute
union case WGetArguments.Urls: url: string list -> WGetArguments
Multiple items
module CliPrefix

from Argu

--------------------
type CliPrefixAttribute =
  inherit Attribute
  new : prefix:string -> CliPrefixAttribute
  member Prefix : string

--------------------
new : prefix:string -> CliPrefixAttribute
val Dash : string
union case CleanArgs.D: CleanArgs
union case CleanArgs.F: CleanArgs
union case CleanArgs.X: CleanArgs
val this : CleanArgs
type CommitArgs =
  | Amend
  | Patch
  | Message of msg: string
    interface IArgParserTemplate
union case CommitArgs.Amend: CommitArgs
union case CommitArgs.Patch: CommitArgs
union case CommitArgs.Message: msg: string -> CommitArgs
val this : CommitArgs
type GitArgs =
  | Version
  | Verbose
  | Clean of ParseResults<CleanArgs>
  | Commit of ParseResults<CommitArgs>
    interface IArgParserTemplate
Multiple items
union case GitArgs.Version: GitArgs

--------------------
type Version =
  new : unit -> Version + 4 overloads
  member Build : int
  member Clone : unit -> obj
  member CompareTo : version:obj -> int + 1 overload
  member Equals : obj:obj -> bool + 1 overload
  member GetHashCode : unit -> int
  member Major : int
  member MajorRevision : int16
  member Minor : int
  member MinorRevision : int16
  ...

--------------------
Version() : Version
Version(version: string) : Version
Version(major: int, minor: int) : Version
Version(major: int, minor: int, build: int) : Version
Version(major: int, minor: int, build: int, revision: int) : Version
union case GitArgs.Verbose: GitArgs
val None : string
union case GitArgs.Clean: ParseResults<CleanArgs> -> GitArgs
type ParseResults<'Template (requires 'Template :> IArgParserTemplate)> =
  interface IParseResult
  private new : argInfo:UnionArgInfo * results:UnionParseResults * programName:string * description:string option * usageStringCharWidth:int * exiter:IExiter -> ParseResults<'Template>
  member Catch : f:(unit -> 'T) * ?errorCode:ErrorCode * ?showUsage:bool -> 'T
  member Contains : expr:Expr<('Fields -> 'Template)> * ?source:ParseSource -> bool
  member Contains : expr:Expr<'Template> * ?source:ParseSource -> bool
  member GetAllResults : ?source:ParseSource -> 'Template list
  member GetResult : expr:Expr<('Fields -> 'Template)> * ?defaultValue:'Fields * ?source:ParseSource -> 'Fields
  member GetResult : expr:Expr<'Template> * ?defaultValue:'Template * ?source:ParseSource -> 'Template
  member GetResults : expr:Expr<('Fields -> 'Template)> * ?source:ParseSource -> 'Fields list
  member GetResults : expr:Expr<'Template> * ?source:ParseSource -> 'Template list
  ...
type CleanArgs =
  | D
  | F
  | X
    interface IArgParserTemplate
union case GitArgs.Commit: ParseResults<CommitArgs> -> GitArgs
val this : GitArgs
val main : argv:string [] -> int
val argv : string []
member ArgumentParser.ParseCommandLine : ?inputs:string [] * ?ignoreMissing:bool * ?ignoreUnrecognized:bool * ?raiseOnUsage:bool -> ParseResults<'Template>
val ignore : value:'T -> unit
val e : exn
val printfn : format:Printf.TextWriterFormat<'T> -> 'T
property Exception.Message: string
type GitArgs = | Version
union case GitArgs.Version: GitArgs
val parsePort : p:int -> int
val p : int
type UInt16 =
  struct
    member CompareTo : value:obj -> int + 1 overload
    member Equals : obj:obj -> bool + 1 overload
    member GetHashCode : unit -> int
    member GetTypeCode : unit -> TypeCode
    member ToString : unit -> string + 3 overloads
    member TryFormat : destination:Span<char> * charsWritten:int * ?format:ReadOnlySpan<char> * ?provider:IFormatProvider -> bool
    static val MaxValue : uint16
    static val MinValue : uint16
    static member Parse : s:string -> uint16 + 4 overloads
    static member TryParse : s:string * result:uint16 -> bool + 3 overloads
  end
field uint16.MaxValue: uint16 = 65535us
val failwith : message:string -> 'T
val ports : int list
member ParseResults.PostProcessResults : expr:Quotations.Expr<('Field -> 'Template)> * parser:('Field -> 'R) * ?source:ParseSource -> 'R list
namespace System.Diagnostics
val arguments : string
member ArgumentParser.PrintCommandLineArgumentsFlat : args:'Template list -> string
Multiple items
type Process =
  inherit Component
  new : unit -> Process
  member BasePriority : int
  member BeginErrorReadLine : unit -> unit
  member BeginOutputReadLine : unit -> unit
  member CancelErrorRead : unit -> unit
  member CancelOutputRead : unit -> unit
  member Close : unit -> unit
  member CloseMainWindow : unit -> bool
  member EnableRaisingEvents : bool with get, set
  member ExitCode : int
  ...

--------------------
Process() : Process
Process.Start(startInfo: ProcessStartInfo) : Process
Process.Start(fileName: string) : Process
Process.Start(fileName: string, arguments: string) : Process
Process.Start(fileName: string, userName: string, password: Security.SecureString, domain: string) : Process
Process.Start(fileName: string, arguments: string, userName: string, password: Security.SecureString, domain: string) : Process
val xml : string
member ArgumentParser.PrintAppSettingsArguments : args:'Template list * ?printComments:bool -> string
Fork me on GitHub