Skip to content

Commit f2556ca

Browse files
authoredJul 21, 2020
Docs improvements (#979)
* docs updates * add linux-x64 rid to dotnet-suggest
1 parent 4c1f1df commit f2556ca

25 files changed

+374
-214
lines changed
 

‎README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ Next, install the `dotnet try` global tool:
6565
Finally, launch the `dotnet try` pointing to the tutorial directory inside the cloned repository:
6666

6767
```console
68-
> dotnet try <PATH_TO_COMMAND_LINE_API_REPO>/samples/tutorial
68+
> dotnet try <PATH_TO_COMMAND_LINE_API_REPO>/docs
6969
```
7070

7171
## Code of Conduct

‎docs/DragonFruit-overview.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ Options:
7676

7777
## Arguments
7878

79-
In addition to [options](Syntax-Concepts-and-Parser#Options) as shown in the examples above, DragonFruit also supports [arguments](Syntax-Concepts-and-Parser#Arguments). By convention, if you name a parameter in the `Main` method `args`, `argument`, or `arguments`, it will be exposed as an argument rather than an option.
79+
In addition to [options](Syntax-Concepts-and-Parser#Options) as shown in the examples above, DragonFruit also supports [arguments](Syntax-Concepts-and-Parser#Arguments). By convention, if you name a parameter in the `Main` method `args`, `argument`, or `arguments`, it will be exposed as an argument rather than an option.
8080

8181
```csharp
8282
static void Main(int intOption = 42, string[] args = null)
@@ -106,3 +106,4 @@ Options:
106106
The argument follows the same conventions for arity as described in [arguments](Syntax-Concepts-and-Parser.md#Arguments-and-arity).
107107

108108
You can try out DragonFruit by installing the latest preview [package](https://www.nuget.org/packages/System.CommandLine.DragonFruit).
109+

‎docs/Features-overview.md

+14-13
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
`System.CommandLine` provides a set of default features for both people using it to develop apps and for the users of those apps. This is a quick overview of some of those features.
1+
`System.CommandLine` provides a set of default features for both people using it to develop apps and for the users of those apps. This is a quick overview of some of those features.
22

33
# Suggestions
44

5-
Programs written using `System.CommandLine` have built-in support for tab completion.
5+
Programs written using `System.CommandLine` have built-in support for tab completion.
66

77
![t-rex-suggestions](https://user-images.githubusercontent.com/547415/50387753-ef4c1280-06b8-11e9-90c8-89466d0bb406.gif)
88

9-
To enable it, the end user has to take a few steps once per shell, outlined [here](dotnet-suggest). Once this is done, completions will work for all apps written using `System.CommandLine`.
9+
To enable it, the end user has to take a few steps once per shell, outlined [here](dotnet-suggest.md). Once this is done, completions will work for all apps written using `System.CommandLine`.
1010

1111
# Help
1212

@@ -38,7 +38,7 @@ Users might be accustomed to different prefixes in different ecosystems, especia
3838

3939
Providing a way to check the version of your app is helpful to your users.
4040

41-
`System.CommandLine` provides this by default. In the [help](Features-overview#Help) example you might have noticed an option, `--version`, that was not explicitly configured in the sample code. When you run your program with this option, you'll see something like this:
41+
`System.CommandLine` provides this by default. In the [help](Features-overview.md#Help) example you might have noticed an option, `--version`, that was not explicitly configured in the sample code. When you run your program with this option, you'll see something like this:
4242

4343
```console
4444
> myapp --version
@@ -56,7 +56,7 @@ Both users and developers often find it useful to see how an app will interpret
5656

5757
The `[parse]` directive tells the parser to parse the input and return a diagram of the result. Some things worth noting in the above example:
5858

59-
* Commands (`myapp`), their child options, and the arguments to those options are grouped using square brackets.
59+
* Commands (`myapp`), their child options, and the arguments to those options are grouped using square brackets.
6060
* For the option result `![ --int-option <not-an-int> ]`, the `!` indicates a parsing error. `not-an-int` could not be parsed to the expected type.
6161
* For the option result `*[ --bool-option <False> ]`, the `*` indicates that a value was not specified on the command line, so the parser's configured default was used. `False` is the effective value for this option.
6262

@@ -83,17 +83,17 @@ One or more response files can be specified in this way. Arguments and options a
8383

8484
# Adaptive rendering
8585

86-
ANSI terminals support a variety of features by including ANSI escape sequences in standard input and output. These sequences can control the cursor, set text attributes and colors, and more. Windows [recently joined](https://blogs.msdn.microsoft.com/commandline/2018/06/27/windows-command-line-the-evolution-of-the-windows-command-line/) Linux and Mac in supporting these features. This is a capability of the new Windows Terminal and can be enabled programmatically in the Windows 10 Console.
86+
Many terminals support a variety of features by including [virtual terminal (VT) escape sequences](https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences) in standard input and output. These sequences can control the cursor, set text attributes and colors, and more. Windows [recently joined](https://blogs.msdn.microsoft.com/commandline/2018/06/27/windows-command-line-the-evolution-of-the-windows-command-line/) Linux and Mac in supporting these features. This is a capability of the new Windows Terminal and can also be enabled programmatically in the Windows 10 Console.
8787

8888
`System.Console.Rendering` adds support for detecting terminal settings and enabling the Window 10 Console's ANSI mode on demand. It also provides an API that can write output that looks correct based on those settings as well as when output is redirected, as is commonly the case on a build server or when your command line app is called by another command line app.
8989

9090
The following are examples of output rendered by the same view code in these three different contexts.
9191

92-
In PowerShell on Windows with ANSI mode enabled:
92+
In PowerShell on Windows with VT mode enabled:
9393

9494
![ansi](https://user-images.githubusercontent.com/547415/50388667-575b2280-06d2-11e9-91ae-36e8ffabbf8a.png)
9595

96-
In PowerShell with ANSI mode disabled:
96+
In PowerShell with VT mode disabled:
9797

9898
![non-ansi](https://user-images.githubusercontent.com/547415/50388673-85d8fd80-06d2-11e9-844b-4690e4b4ab5a.png)
9999

@@ -121,13 +121,13 @@ The raw text written to standard out in the first example is this:
121121

122122
```
123123

124-
In ANSI mode, the Windows Console interprets these escape sequences into cursor movements and colors. As you can see in the first example above, ANSI mode enables the display of RGB colors and underlining that are not supported otherwise on Windows. Most Linux and macOS terminals as well as the Windows Terminal support this form of rendering by default.
125-
126-
The examples above build the table structure by positioning the cursor for each cell and then writing the content. In an ANSI-capable terminal, this is done using ANSI escape sequences such as `\u001b[1;1H`. The equivalent `System.Console` call, which is needed in non-ANSI terminals, looks like this: `Console.SetCursorPosition(0, 0)`. Meanwhile, the third example renders the layout using spaces and newlines, since there is no cursor when output is redirected.
124+
In VT mode, the Windows Console interprets these escape sequences into cursor movements and colors. As you can see in the first example above, VT mode enables the display of RGB colors and underlining that are not supported otherwise on Windows. Most Linux and macOS terminals as well as the Windows Terminal support this form of rendering by default.
127125

128-
Providing a common API across these very different modes so that you don't have to write the code three times is a major goal of `System.CommandLine.Rendering`. The API is still very rough but you can explore these capabilities in the `RenderingPlayground` [sample](https://github.com/dotnet/command-line-api/tree/master/samples/RenderingPlayground).
126+
The examples above build the table structure by positioning the cursor for each cell and then writing the content. In a VT-capable terminal, this is done using ANSI escape sequences such as `\u001b[1;1H`. The equivalent `System.Console` call, which is needed in terminals that don't render VT codes, looks like this: `Console.SetCursorPosition(0, 0)`. Meanwhile, the third example renders the layout using spaces and newlines, since there is no cursor when output is redirected.
129127

130-
## Rendering directives
128+
Providing a common API across these very different modes so that you don't have to write the code three times is a major goal of `System.CommandLine.Rendering`. The API is still very rough but you can explore these capabilities in the `RenderingPlayground` [sample](https://github.com/dotnet/command-line-api/tree/master/samples/RenderingPlayground).
129+
130+
## Rendering directives
131131

132132
Output modes can also be specified directly. If you know that you want a specific form of output, you can bypass the mode detection of `System.CommandLine.Rendering` and use a [directive](Syntax-Concepts-and-Parser.md#directives).
133133

@@ -144,3 +144,4 @@ The supported output modes are:
144144
* `Ansi`: Output is rendered using ANSI escape sequences. In-place re-rendering is supported.
145145
* `NonAnsi`: Output is rendered using `System.Console` cursor positioning. In-place re-rendering is supported.
146146
* `PlainText`: Output is rendered with additional whitespace so that, for example, if redirected to a text file, the layout will look correct. In-place re-rendering is not supported.
147+

‎docs/Functional-goals.md

+37-29
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Functional goals
22

3-
The high level goals for `System.CommandLine` support our idea that creating great command line experiences for your users can be easy. We have not yet met all of these goals.
3+
The high level goals for `System.CommandLine` support our idea that creating great command line experiences for your users can be easy. We have not yet met all of these goals.
44

55
## Goals for the end user's experience
66

@@ -11,42 +11,50 @@ The high level goals for `System.CommandLine` support our idea that creating gre
1111
## Goals for the programmer's experience
1212

1313
* Help
14-
* Creating some version of help should be automated, requiring no work.
15-
* Help should be informative if descriptions are supplied.
16-
* Help localization should be straightforward.
14+
15+
* Creating some version of help should be automated, requiring no work.
16+
* Help should be informative if descriptions are supplied.
17+
* Help localization should be straightforward.
1718

1819
* Tab suggestion
19-
* It should just work with no effort on the programmer's part.
20-
* It should provide support for enums.
21-
* It should have a mechanism for dynamic values.
22-
* It should stay out of the way of shell suggestions for files and folders.
23-
* Dynamic suggestions should be extensible for other things I might do.
20+
21+
* It should just work with no effort on the programmer's part.
22+
* It should provide support for enums.
23+
* It should have a mechanism for dynamic values.
24+
* It should stay out of the way of shell suggestions for files and folders.
25+
* Dynamic suggestions should be extensible for other things I might do.
2426

2527
* Validation
26-
* If there are parse errors, it should fail before my application code is called.
27-
* It should check the number and type of arguments.
28-
* It should generally fail if there are unmatched tokens, but I should be able to allow it to pass through.
29-
* It should provide default responses for the user on validation issues.
30-
* I should be able to customize the validation messages.
31-
28+
29+
* If there are parse errors, it should fail before my application code is called.
30+
* It should check the number and type of arguments.
31+
* It should generally fail if there are unmatched tokens, but I should be able to allow it to pass through.
32+
* It should provide default responses for the user on validation issues.
33+
* I should be able to customize the validation messages.
34+
3235
* Debugging and testing
33-
* I should not have to turn a string into an array to interact programmatically.
34-
* I should be able to get a visualization of how a string is parsed.
35-
* It should be easy to test parsing in isolation from the application.
36-
* It should be easy to test the application in isolation from parsing.
37-
* I should be able to specify at the command line that I want to attach a debugger.
36+
37+
* I should not have to turn a string into an array to interact programmatically.
38+
* I should be able to get a visualization of how a string is parsed.
39+
* It should be easy to test parsing in isolation from the application.
40+
* It should be easy to test the application in isolation from parsing.
41+
* I should be able to specify at the command line that I want to attach a debugger.
3842

3943
* Acting on parser results
40-
* Argument results should be strongly typed.
41-
* For advanced scenarios, I can alter and re-parse input.
42-
* It should be simple for me to manage exceptions, output, and exit codes.
44+
45+
* Argument results should be strongly typed.
46+
* For advanced scenarios, I can alter and re-parse input.
47+
* It should be simple for me to manage exceptions, output, and exit codes.
4348

4449
* Rendering
45-
* Provide ways to reason about layout rather than just text.
46-
* Hide Windows/Linux/Mac differences for me.
47-
* Take advantage of new Windows 10 console capabilities.
48-
* Hide non-ANSI/ANSI differences for me.
49-
* Make output look correct when redirected to a file.
50+
51+
* Provide ways to reason about layout rather than just text.
52+
* Hide Windows/Linux/Mac differences for me.
53+
* Take advantage of new Windows 10 console capabilities.
54+
* Hide non-ANSI/ANSI differences for me.
55+
* Make output look correct when redirected to a file.
5056

5157
* Extensibility
52-
* I can compose cross-cutting behaviors using packages.
58+
59+
* I can compose cross-cutting behaviors using packages.
60+

‎docs/History.md

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# History
22

3-
The new `System.CommandLine`'s lineage can be traced through the experiences of various teams at Microsoft building .NET command line applications. Some of its ideas have been expressed in the `dotnet` CLI and `CommandLineUtils` originally created in ASP.NET with a [popular fork](https://github.com/natemcmaster/CommandLineUtils) by @natemcmaster.
3+
The new `System.CommandLine`'s lineage can be traced through the experiences of various teams at Microsoft building .NET command line applications. Some of its ideas have been expressed in the `dotnet` CLI and `CommandLineUtils` originally created in ASP.NET with a [popular fork](https://github.com/natemcmaster/CommandLineUtils) by @natemcmaster.
44

55
This project is called the "new" `System.CommandLine` because Microsoft also had a `System.CommandLine` project in CoreFxLab that has been retired because it did not meet the current needs.
66

@@ -10,16 +10,17 @@ The addition of global tools to the `dotnet` ecosystem meant the creation of mor
1010

1111
Parsing is a deceptively complex problem. With folks on the team that have been involved in writing complex and successful CLIs, we can work in the other direction, focusing first on a solid core and then working outward toward the functionality and API surface. We're building the foundation that the folks who wrote and worked on the `dotnet` CLI wish they had been able to use. We ran this part of the project in private to ensure the core was solid, and as an all-volunteer effort this phase took painfully long.
1212

13-
The next layer, the API over the core functionality, has undergone a rewrite, and we are fairly happy with how you explicitly define your CLI. Explicitly defining a syntax feels like too much work for many scenarios and we've put a lot of thought and discussion into the idea of "app models" that infer the structure of your CLI from something that is natural to write.
13+
The next layer, the API over the core functionality, has undergone a rewrite, and we are fairly happy with how you explicitly define your CLI. Explicitly defining a syntax feels like too much work for many scenarios and we've put a lot of thought and discussion into the idea of "app models" that infer the structure of your CLI from something that is natural to write.
1414

15-
App models have two aspects: defining the CLI's structure and bridging between parse results and your application.
15+
App models have two aspects: defining the CLI's structure and bridging between parse results and your application.
1616

1717
As an example, one approach is to bind to a method, which is executed with parameters matching the options and arguments your user provided. This method binding works well when mapped one-to-one between the command and the invoked method. You can find this as the basis for the experimental "DragonFruit" model. DragonFruit takes this idea one step furher by wrapping your `Program.Main` entry point and just letting your `Main` method have normal parameters that just happen to be able to be of types other than `string`. We have not yet found a way we like to do subcommands with the DragonFruit model.
1818

1919
Other approaches to binding include binding to classes. A fundamental aspect of `System.CommandLine` is top-level support for app models and binders. These may reside outside `System.CommandLine` and we hope it will be a framework that people with other ideas can build on. The goal is that app models will interoperate with one another allowing many choices for programmers.
2020

2121
## Rendering
2222

23-
We've also done preliminary work on rendering. This is another area where `System.Console` is showing its age. In particular, `System.Console` does not supporting ANSI terminals easily. While `ncurses` has long addressed differing terminal capabilities in the non-Windows world, .NET programmers could benefit from something that works consistently on Windows, Linux, and Mac.
23+
We've also done preliminary work on rendering. This is another area where `System.Console` is showing its age. In particular, `System.Console` does not supporting ANSI terminals easily. While `ncurses` has long addressed differing terminal capabilities in the non-Windows world, .NET programmers could benefit from something that works consistently on Windows, Linux, and Mac.
2424

2525
And with the new Windows Terminal and Windows 10 bringing [virtual terminal capabilities](https://blogs.msdn.microsoft.com/commandline/2018/06/27/windows-command-line-the-evolution-of-the-windows-command-line/) to the Windows console, we think there's an opportunity for .NET APIs that these benefits to users.
26+

‎docs/How-To.md

+10-9
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
## Add an alias to an option or command
44

5-
Both commands and options support [aliases](Concepts.md#Aliases). You can add an alias to an option like this:
5+
Both commands and options support [aliases](Syntax-Concepts-And-Parser.md#Aliases). You can add an alias to an option like this:
66

7-
``` csharp
7+
```csharp
88
var option = new Option("--verbose");
99
option.AddAlias("-v");
1010
```
@@ -82,7 +82,7 @@ Of course, if your program is so simple that is has no inputs, you probably didn
8282

8383
## Pass parameters to a method
8484

85-
Usually, your `/* do something */` method has parameters and you would like these to be specified using command line options.
85+
Usually, your `/* do something */` method has parameters and you would like these to be specified using command line options.
8686

8787
```csharp
8888
public static void DoSomething(int anInt, string aString)
@@ -91,13 +91,13 @@ public static void DoSomething(int anInt, string aString)
9191
}
9292
```
9393

94-
This is known as binding. You can learn more about it in the interactive tutorial described in the readme: https://github.com/dotnet/command-line-api#interactive-tutorials
94+
This is known as binding. You can learn more about it in the interactive tutorial described in the readme: [https://github.com/dotnet/command-line-api#interactive-tutorials](https://github.com/dotnet/command-line-api#interactive-tutorials)
9595

9696
There are currently two models for configuring the `System.CommandLine` parser to bind these parameters.
9797

9898
### Syntax-first
9999

100-
One approach that you can use is to configure the parser directly by adding `Option`s to your `RootCommand`. **Note that the option names should match the names of the parameters of the `DoSomething` method.**
100+
One approach that you can use is to configure the parser directly by adding `Option`s to your `RootCommand`. **Note that the option names should match the names of the parameters of the `DoSomething` method.**
101101

102102
Parameters are matched using a naming convention that converts camel-cased parameters to kebab-cased options. In this example, the option `--an-int` matches parameter `anInt` on the `DoSomething` method.
103103

@@ -124,7 +124,6 @@ public static void DoSomething(int anInt, string aString)
124124

125125
Another approach is to let `System.CommandLine` configure the parser for you based on your method signature using the `Command.ConfigureFromMethod` extension method found in the `System.CommandLine.DragonFruit` library. (The [DragonFruit](Your-first-app-with-System.CommandLine.DragonFruit.md) app model uses this approach for its strongly-typed `Main` method but it can be used with any method.)
126126

127-
128127
```csharp
129128
static void Main()
130129
{
@@ -142,7 +141,7 @@ static void Main()
142141

143142
## Argument validation and binding
144143

145-
Arguments can have default values, expected types, and configurable arity. `System.CommandLine` will reject arguments that don't match these expectations.
144+
Arguments can have default values, expected types, and configurable arity. `System.CommandLine` will reject arguments that don't match these expectations.
146145

147146
In this example, a parse error is displayed because the input "not-an-int" could not be converted to an `int`:
148147

@@ -179,11 +178,11 @@ The value of boolOption is: False
179178
The value of fileOption is: null
180179
```
181180

182-
`System.CommandLine` also knows how to bind other argument types. For example, enums and file system objects such as `FileInfo` and `DirectoryInfo` can be bound. `FileInfo` and `DirectoryInfo` examples of a more general convention whereby any type that has a constructor taking a single `string` parameter can be bound without having to write any custom code. But you can also write your own binding logic for your custom types.
181+
`System.CommandLine` also knows how to bind other argument types. For example, enums and file system objects such as `FileInfo` and `DirectoryInfo` can be bound. `FileInfo` and `DirectoryInfo` examples of a more general convention whereby any type that has a constructor taking a single `string` parameter can be bound without having to write any custom code. But you can also write your own binding logic for your custom types.
183182

184183
## Middleware Pipeline
185184

186-
While each command has a handler which `System.CommandLine` will route to based on input, there is also a mechanism for short circuiting or altering the input before invoking you application logic. In between parsing and invocation, there is a chain of responsibility, which you can customize. A number of features of `System.CommandLine` make use of this. This is how the `--help` and `--version` options short circuit calls to your handler.
185+
While each command has a handler which `System.CommandLine` will route to based on input, there is also a mechanism for short circuiting or altering the input before invoking you application logic. In between parsing and invocation, there is a chain of responsibility, which you can customize. A number of features of `System.CommandLine` make use of this. This is how the `--help` and `--version` options short circuit calls to your handler.
187186

188187
Each call in the pipeline can take action based on the `ParseResult` and return early, or choose to call the next item in the pipeline. The `ParseResult` can even be replaced during this phase. The last call in the chain is the handler for the specified command.
189188

@@ -201,9 +200,11 @@ commandLineBuilder.UseMiddleware(async (context, next) => {
201200
}
202201
});
203202
```
203+
204204
```console
205205
> myapp [just-say-hi] --int-option 1234
206206
Hi!
207207
```
208208

209209
In the code above, the middleware writes out "Hi!" if the directive "just-say-hi" is found in the parse result. When this happens, because the provided `next` delegate is not called, then the command's normal handler is not invoked.
210+

‎docs/Layering.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@
22

33
[WIP]
44

5-
![layers](https://user-images.githubusercontent.com/547415/50188724-5fcceb00-02d7-11e9-9c33-4b91d70f963e.png)
5+
![layers](https://user-images.githubusercontent.com/547415/50188724-5fcceb00-02d7-11e9-9c33-4b91d70f963e.png)
6+

‎docs/Process-termination-handling.md

+1
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,4 @@ myCommand.Handler = CommandHandler.Create(async (IConsole console, CancellationT
2828
}
2929
});
3030
```
31+

‎docs/Syntax-Concepts-and-Parser.md

+3-5
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ Some command line apps support subcommands, generally indicating that they can d
2222

2323
When an app has subcommands, then the commands above them in the hierarchy typically do nothing by themselves. `dotnet add` is not a complete command because it has the subcommands `dotnet add package` and `dotnet add reference`.
2424

25-
In `System.CommandLine`, subcommands also use the `Command` class, which can be added to a parent command, whether the parent is a `RootCommand` or `Command`.
25+
In `System.CommandLine`, subcommands also use the `Command` class, which can be added to a parent command, whether the parent is a `RootCommand` or `Command`.
2626

2727
## Options
2828

@@ -76,7 +76,7 @@ An argument is a value passed to an option or command.
7676
command argument
7777
```
7878

79-
Arguments can have default values, expected types, and rules about how many values should be provided ("arity"). The arity of an option or command's argument refers to the number of values that can be passed if that option or command is specified.
79+
Arguments can have default values, expected types, and rules about how many values should be provided ("arity"). The arity of an option or command's argument refers to the number of values that can be passed if that option or command is specified.
8080

8181
Arity is expressed with a minimum value and a maximum value. These are the most common variants:
8282

@@ -131,12 +131,10 @@ Another example of a use for directives is setting the [output rendering mode](F
131131

132132
The general goal of directives is to provide cross-cutting functionality that can be made consistent across command line apps. Because directives are syntatically distinct from the app's own parameters, an input such as `[parse]` can be made consistent across apps. An unrecognized directive will be ignored rather than causing a parsing error.
133133

134-
A directive must conform to the following syntax rules:
134+
A directive must conform to the following syntax rules:
135135

136136
* It is a token on the command line coming after your app's name but before any subcommands or options, and
137137
* It is enclosed in square brackets.
138138
* It does not contain spaces.
139139
* It can include an argument, separated from the directive name by a colon.
140140

141-
142-

‎docs/Technical-motivations.md

+29-28
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,41 @@
11
# Technical motivations
22

33
* Provide a parser that's independent of binding and invocation.
4-
5-
* You can create your own conventions and your own API surface.
6-
* Parsing can easily be tested independently from other application logic.
7-
* The syntax abstraction opens up use cases such as an extensible completions model.
8-
* Features such as syntax validation can be customized independent of your API.
9-
* Grammars can be serialized for interpretation by other tools.
10-
* Different APIs using this base layer can interoperate easily.
11-
* Don't always assume a console app entry point: provide `Main(string[])`-equivalent string splitting.
4+
5+
* You can create your own conventions and your own API surface.
6+
* Parsing can easily be tested independently from other application logic.
7+
* The syntax abstraction opens up use cases such as an extensible completions model.
8+
* Features such as syntax validation can be customized independent of your API.
9+
* Grammars can be serialized for interpretation by other tools.
10+
* Different APIs using this base layer can interoperate easily.
11+
* Don't always assume a console app entry point: provide `Main(string[])`-equivalent string splitting.
1212

1313
* Make the end user command line experience consistent and inclusive.
14-
15-
* Support both POSIX and Windows syntax conventions.
16-
* Make help easy to find by defaulting into all common conventions (`-h`, `--help`, `/h` `/?`, `-?`).
17-
* Make completions work by default, so that they become the norm.
18-
* Make it possible to write completion providers for non-.NET command line applications.
19-
* Localization support for all messages that the library emits.
20-
* Parse diagramming, to help people understand a program's syntax without invoking it, is available by default.
14+
15+
* Support both POSIX and Windows syntax conventions.
16+
* Make help easy to find by defaulting into all common conventions (`-h`, `--help`, `/h` `/?`, `-?`).
17+
* Make completions work by default, so that they become the norm.
18+
* Make it possible to write completion providers for non-.NET command line applications.
19+
* Localization support for all messages that the library emits.
20+
* Parse diagramming, to help people understand a program's syntax without invoking it, is available by default.
2121

2222
* A composable chain of responsibility for subcommand routing, middleware, directives, etc.
23-
24-
* An invocation model that allows for short-circuiting and interception, with access to the parser, meaning cross-cutting behaviors can be composed into your app via NuGet packages.
25-
* Simplify debugging by providing an interception hook in the middleware pipeline.
26-
* Support for handling process cancellation.
27-
* Directive syntax provides a consistent extensibility point that does not interfere with your app's syntax.
28-
* Supports command line API versioning via directives.
23+
24+
* An invocation model that allows for short-circuiting and interception, with access to the parser, meaning cross-cutting behaviors can be composed into your app via NuGet packages.
25+
* Simplify debugging by providing an interception hook in the middleware pipeline.
26+
* Support for handling process cancellation.
27+
* Directive syntax provides a consistent extensibility point that does not interfere with your app's syntax.
28+
* Supports command line API versioning via directives.
2929

3030
* Rich, adapative output rendering
31-
* Write output code once and render it correctly based on the presence or absence of a terminal as well as terminal capabilities.
32-
* Support for higher-level layouts, tables, event-based re-rendering, and animation.
33-
* Support for standard render mode hints via directives.
31+
32+
* Write output code once and render it correctly based on the presence or absence of a terminal as well as terminal capabilities.
33+
* Support for higher-level layouts, tables, event-based re-rendering, and animation.
34+
* Support for standard render mode hints via directives.
3435

3536
* Other things:
36-
* Support arbitrarily deep nesting of subcommands.
37-
* Support response files.
38-
* Restore console state after application exit.
39-
37+
38+
* Support arbitrarily deep nesting of subcommands.
39+
* Support response files.
40+
* Restore console state after application exit.
4041

‎docs/Your-first-app-with-System-CommandLine-DragonFruit.md

+4-2
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,13 @@ Open a new console and run the following commands:
1313

1414
## Install the System.CommandLine.DragonFruit package
1515

16-
[![Nuget](https://img.shields.io/nuget/v/System.CommandLine.DragonFruit.svg)](https://nuget.org/packages/System.CommandLine.DragonFruit)
16+
[![Nuget](https://img.shields.io/nuget/v/System.CommandLine.DragonFruit.svg)](https://nuget.org/packages/System.CommandLine.DragonFruit)
17+
1718
## Add some code
1819

1920
Open `Program.cs`. You'll see that your `Main` method looks like this:
2021

21-
```csharp
22+
```csharp
2223
static void Main(string[] args)
2324
{
2425
Console.WriteLine("Hello World!");
@@ -61,3 +62,4 @@ The value for --file-option is: null
6162
This program is equivalent to the one demonstrated in [Your first app with System.CommandLine](Your-first-app-with-System.CommandLine.md).
6263

6364
To explore its features, take a look at [Features: overview](Features-overview.md)
65+

‎docs/Your-first-app-with-System-CommandLine.md

+3-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ Open a new console and run the following commands:
1313

1414
## Install the System.CommandLine package
1515

16-
[![Nuget](https://img.shields.io/nuget/v/System.CommandLine.svg)](https://nuget.org/packages/System.CommandLine)
16+
[![Nuget](https://img.shields.io/nuget/v/System.CommandLine.svg)](https://nuget.org/packages/System.CommandLine)
1717

1818
## Add some code
1919

@@ -32,7 +32,7 @@ static void Main(string[] args)
3232
}
3333
```
3434

35-
Now, let's add a parser.
35+
Now, let's add a parser.
3636

3737
You'll need a few more `using` directives:
3838

@@ -90,3 +90,4 @@ The value for --file-option is: null
9090
This program is equivalent to the one demonstrated in [Your first app with System.CommandLine.DragonFruit](Your-first-app-with-System.CommandLine.DragonFruit.md).
9191

9292
To explore its features, take a look at [Features: overview](Features-overview.md)
93+

‎docs/dotnet-suggest.md

+10-9
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,24 @@
11
# dotnet-suggest
22

3-
Command line apps built using `System.CommandLine` have built-in support for tab completion.
3+
Command line apps built using `System.CommandLine` have built-in support for tab completion.
44

55
![t-rex-suggestions](https://user-images.githubusercontent.com/547415/50387753-ef4c1280-06b8-11e9-90c8-89466d0bb406.gif)
66

77
On the machine where you'd like to enable completion, you'll need to do two things.
88

9-
1. Install the `dotnet-suggest` global tool:
10-
11-
[![Nuget](https://img.shields.io/nuget/v/dotnet-suggest.svg)](https://nuget.org/packages/dotnet-suggest)
9+
1. Install the `dotnet-suggest` global tool:
10+
11+
[![Nuget](https://img.shields.io/nuget/v/dotnet-suggest.svg)](https://nuget.org/packages/dotnet-suggest)
1212

1313
2. Add the appropriate shim script to your shell profile. You may have to create a shell profile file. The shim script will forward completion requests from your shell to the `dotnet-suggest` tool, which delegates to the appropriate `System.CommandLine`-based app.
14-
15-
* For bash, add the contents of [dotnet-suggest-shim.bash](https://github.com/dotnet/command-line-api/blob/master/src/System.CommandLine.Suggest/dotnet-suggest-shim.bash) to `~/.bash_profile`.
16-
17-
* For PowerShell, add the contents of [dotnet-suggest-shim.ps1](https://github.com/dotnet/command-line-api/blob/master/src/System.CommandLine.Suggest/dotnet-suggest-shim.ps1) to your PowerShell profile. You can find the expected path to your PowerShell profile by running the following in your console:
14+
15+
* For bash, add the contents of [dotnet-suggest-shim.bash](https://github.com/dotnet/command-line-api/blob/master/src/System.CommandLine.Suggest/dotnet-suggest-shim.bash) to `~/.bash_profile`.
16+
17+
* For PowerShell, add the contents of [dotnet-suggest-shim.ps1](https://github.com/dotnet/command-line-api/blob/master/src/System.CommandLine.Suggest/dotnet-suggest-shim.ps1) to your PowerShell profile. You can find the expected path to your PowerShell profile by running the following in your console:
1818

1919
```console
2020
> echo $profile
21-
```
21+
```
2222

2323
(For other shells, please [look for](https://github.com/dotnet/command-line-api/issues?q=is%3Aissue+is%3Aopen+label%3A%22shell+suggestion%22) or open an [issue](https://github.com/dotnet/command-line-api/issues).)
24+

‎docs/model-binding.md

+236
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
# Model Binding
2+
3+
Parsing command line arguments is a means to an end. You probably don't really want to think about parsing the command line. You just want some arguments passed to a method, based on some command line arguments.
4+
5+
In C#, the application entry point method has always looked something like this:
6+
7+
```cs
8+
static void Main(string[] args)
9+
{
10+
}
11+
```
12+
13+
The goal of every command line parsing library is to turn the string array passed to `Main` into something more useful. You might ultimately want to call a method that looks like this:
14+
15+
```cs
16+
void Handle(int anInt)
17+
{
18+
}
19+
```
20+
21+
So for example, you might want an input `123` from the command line to be converted into an `int` with the value `123`. This conversion of command line input into variables or arguments that you can use in your code is called "binding." The term "model binding" refers to binding simple types as well as more complex types in order to pass the values to a method.
22+
23+
# Binding parameters to a command handler
24+
25+
The simplest way to bind command line input is to set the `Handler` property on a `Command`. The `System.CommandLine` model binder will look at the options and arguments for the command and attempt to match them to the parameters of the specified handler method. The default convention is that parameters are matched by name, so in the following example, option `--an-int` matches the parameter named `anInt`. Matching ignores hyphens (and other option prefixes, such as `'/'`) and is case insensitive.
26+
27+
``` cs --source-file ./src/Binding/HandlerBindingSample.cs --project ./src/Binding/Binding.csproj --region MultipleArgs --session MultipleArgs
28+
var command = new RootCommand
29+
{
30+
new Option<string>("--a-string"),
31+
new Option<int>("--an-int")
32+
};
33+
34+
command.Handler = CommandHandler.Create(
35+
(string aString, int anInt) =>
36+
{
37+
Console.WriteLine(aString);
38+
Console.WriteLine(anInt);
39+
});
40+
41+
await command.InvokeAsync("--an-int 123 --a-string \"Hello world!\" ");
42+
```
43+
44+
``` console --session MultipleArgs
45+
Hello world!
46+
123
47+
48+
```
49+
50+
## Booleans (flags)
51+
52+
If `true` or `false` is passed for an option having a `bool` argument, it is parsed and bound as expected. But an option whose argument type is `bool` doesn't require an argument to be specified. The presence of the option token on the command line, with no argument following it, results in a value of `true`. You can see various examples here:
53+
54+
``` cs --source-file ./src/Binding/HandlerBindingSample.cs --project ./src/Binding/Binding.csproj --region Bool --session Bool
55+
var command = new RootCommand
56+
{
57+
new Option<bool>("--a-bool")
58+
};
59+
60+
command.Handler = CommandHandler.Create(
61+
(bool aBool) => Console.WriteLine(aBool));
62+
63+
await command.InvokeAsync("");
64+
await command.InvokeAsync("--a-bool");
65+
await command.InvokeAsync("--a-bool false");
66+
await command.InvokeAsync("--a-bool true");
67+
```
68+
69+
``` console --session Bool
70+
False
71+
True
72+
False
73+
True
74+
75+
```
76+
77+
## Enums
78+
79+
You can bind `enum` types as well. The values are bound by name, and the binding is case insensitive:
80+
81+
``` cs --source-file ./src/Binding/HandlerBindingSample.cs --project ./src/Binding/Binding.csproj --region Enum --session Enum
82+
var command = new RootCommand
83+
{
84+
new Option<System.IO.FileAccess>("--an-enum")
85+
};
86+
87+
command.Handler = CommandHandler.Create(
88+
(FileAccess anEnum) => Console.WriteLine(anEnum));
89+
90+
await command.InvokeAsync("--an-enum Read");
91+
await command.InvokeAsync("--an-enum READ");
92+
```
93+
94+
``` console --session Enum
95+
Read
96+
Read
97+
98+
```
99+
100+
## Arrays, lists, and other enumerable types
101+
102+
Arguments having various enumerable types can be bound. A number of common types implementing `IEnumerable` are supported. In the next example, try changing the type of the `--items` `Option`'s `Argument` property to `Argument<IEnumerable<string>>` or `Argument<List<string>>`.
103+
104+
``` cs --source-file ./src/Binding/HandlerBindingSample.cs --project ./src/Binding/Binding.csproj --region Enumerables --session Enumerables
105+
var command = new RootCommand
106+
{
107+
new Option<string[]>("--items")
108+
};
109+
110+
command.Handler = CommandHandler.Create(
111+
(IEnumerable<string> items) =>
112+
{
113+
Console.WriteLine(items.GetType());
114+
115+
foreach (var item in items)
116+
{
117+
Console.WriteLine(item);
118+
}
119+
});
120+
121+
await command.InvokeAsync("--items one two three");
122+
```
123+
124+
``` console --session Enumerables
125+
System.String[]
126+
one
127+
two
128+
three
129+
130+
```
131+
132+
## File system types
133+
134+
Since command line applications very often have to work with the file system, `FileInfo` and `DirectoryInfo` are clearly important for binding to support. Run the following code, then try changing the generic type argument to `DirectoryInfo` and running it again.
135+
136+
``` cs --source-file ./src/Binding/HandlerBindingSample.cs --project ./src/Binding/Binding.csproj --region FileSystemTypes --session FileSystemTypes
137+
var command = new RootCommand
138+
{
139+
new Option<FileInfo>("-f").ExistingOnly()
140+
};
141+
142+
command.Handler = CommandHandler.Create(
143+
(FileSystemInfo f) =>
144+
{
145+
Console.WriteLine($"{f.GetType()}: {f}");
146+
});
147+
148+
await command.InvokeAsync("-f /path/to/something");
149+
```
150+
151+
``` console --session FileSystemTypes
152+
Usage:
153+
Binding [options]
154+
155+
Options:
156+
-f <f>
157+
--version Show version information
158+
-?, -h, --help Show help and usage information
159+
160+
161+
```
162+
163+
## Anything with a string constructor
164+
165+
But `FileInfo` and `DirectoryInfo` are not special cases. Any type having a constructor that takes a single string parameter can be bound in this way. Go back to the previous example and try using a `Uri` instead.
166+
167+
## More complex types
168+
169+
Binding also supports creating instances of more complex types. If you have a large number of options, this can be cleaner than adding more parameters to your handler. `System.CommandLine` has the default convention of binding `Option` arguments to either properties or constructor parameters by name. The name matching uses the same strategies that are used when matching parameters on a handler method.
170+
171+
In the next sample, the handler accepts an instance of `ComplexType`. Try removing its setters and uncommenting the constructor. Try adding properties, or changing the types or names of its properties.
172+
173+
``` cs --source-file ./src/Binding/HandlerBindingSample.cs --project ./src/Binding/Binding.csproj --region ComplexTypes --session ComplexTypes
174+
public static async Task<int> ComplexTypes()
175+
{
176+
var command = new Command("the-command")
177+
{
178+
new Option<int>("--an-int"),
179+
new Option<string>("--a-string")
180+
};
181+
182+
command.Handler = CommandHandler.Create(
183+
(ComplexType complexType) =>
184+
{
185+
Console.WriteLine(Format(complexType));
186+
});
187+
188+
await command.InvokeAsync("--an-int 123 --a-string 456");
189+
190+
return 0;
191+
}
192+
193+
public class ComplexType
194+
{
195+
// public ComplexType(int anInt, string aString)
196+
// {
197+
// AnInt = anInt;
198+
// AString = aString;
199+
// }
200+
public int AnInt { get; set; }
201+
public string AString { get; set; }
202+
}
203+
```
204+
205+
``` console --session ComplexTypes
206+
AnInt: 123 (System.Int32)
207+
AString: 456 (System.String)
208+
209+
210+
```
211+
212+
## System.CommandLine types
213+
214+
Not everything you might want passed to your handler will necessarily come from parsed command line input. There are a number of types provided by `System.CommandLine` that you can bind to. The following example demonstratres injection of `ParseResult` and `IConsole`. Other types can be passed this way as well.
215+
216+
``` cs --source-file ./src/Binding/HandlerBindingSample.cs --project ./src/Binding/Binding.csproj --region DependencyInjection --session DependencyInjection
217+
var command = new RootCommand
218+
{
219+
new Option<string>("--a-string"),
220+
new Option<int>("--an-int"),
221+
new Option<System.IO.FileAttributes>("--an-enum"),
222+
};
223+
224+
command.Handler = CommandHandler.Create(
225+
(ParseResult parseResult, IConsole console) =>
226+
{
227+
console.Out.WriteLine($"{parseResult}");
228+
});
229+
230+
await command.InvokeAsync("--an-int 123 --a-string \"Hello world!\" --an-enum compressed");
231+
```
232+
233+
``` console --session DependencyInjection
234+
ParseResult: [ Binding [ --an-int <123> ] [ --a-string <Hello world!> ] [ --an-enum <Compressed> ] ]
235+
236+
```

‎docs/readme.md

+1
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,4 @@ The simplest way to create your parser is with the experimental [DragonFruit app
2626
For more complex scenarios, you can use the core APIs directly.
2727

2828
[Your first app with System.CommandLine](Your-first-app-with-System-CommandLine.md)
29+

‎samples/tutorial/src/Binding/Binding.csproj renamed to ‎docs/src/Binding/Binding.csproj

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
</PropertyGroup>
88

99
<ItemGroup>
10-
<PackageReference Include="System.CommandLine.DragonFruit" Version="0.3.0-alpha.20070.2" />
10+
<PackageReference Include="System.CommandLine.DragonFruit" Version="0.3.0-alpha.20362.5" />
1111
</ItemGroup>
1212

1313
</Project>

‎samples/tutorial/src/Binding/GetValueSample.cs renamed to ‎docs/src/Binding/GetValueSample.cs

+3-6
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,9 @@ public static int GetValueFromOptionArgument()
1414
{
1515
#region GetValueFromOptionArgument
1616

17-
var option = new Option("--an-int")
18-
{
19-
Argument = new Argument<int>()
20-
};
21-
var parseResult = option.Parse("--an-int 123");
22-
var value = parseResult.FindResultFor(option).GetValueOrDefault();
17+
var option = new Option<int>("--an-int");
18+
ParseResult parseResult = option.Parse("--an-int 123");
19+
int value = parseResult.ValueForOption(option);
2320
Console.WriteLine(Format(value));
2421

2522
#endregion

‎samples/tutorial/src/Binding/HandlerBindingSample.cs renamed to ‎docs/src/Binding/HandlerBindingSample.cs

+11-11
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ internal static async Task<int> MultipleArgs()
2121

2222
var command = new RootCommand
2323
{
24-
new Option("--a-string") { Argument = new Argument<string>() },
25-
new Option("--an-int") { Argument = new Argument<int>() }
24+
new Option<string>("--a-string"),
25+
new Option<int>("--an-int")
2626
};
2727

2828
command.Handler = CommandHandler.Create(
@@ -45,7 +45,7 @@ internal static async Task<int> Bool()
4545

4646
var command = new RootCommand
4747
{
48-
new Option("--a-bool") { Argument = new Argument<bool>() }
48+
new Option<bool>("--a-bool")
4949
};
5050

5151
command.Handler = CommandHandler.Create(
@@ -67,9 +67,9 @@ internal static async Task<int> DependencyInjection()
6767

6868
var command = new RootCommand
6969
{
70-
new Option("--a-string") { Argument = new Argument<string>() },
71-
new Option("--an-int") { Argument = new Argument<int>() },
72-
new Option("--an-enum") { Argument = new Argument<System.IO.FileAttributes>() },
70+
new Option<string>("--a-string"),
71+
new Option<int>("--an-int"),
72+
new Option<System.IO.FileAttributes>("--an-enum"),
7373
};
7474

7575
command.Handler = CommandHandler.Create(
@@ -91,7 +91,7 @@ internal static async Task<int> Enum()
9191

9292
var command = new RootCommand
9393
{
94-
new Option("--an-enum") { Argument = new Argument<System.IO.FileAccess>() }
94+
new Option<System.IO.FileAccess>("--an-enum")
9595
};
9696

9797
command.Handler = CommandHandler.Create(
@@ -111,7 +111,7 @@ internal static async Task<int> Enumerables()
111111

112112
var command = new RootCommand
113113
{
114-
new Option("--items") { Argument = new Argument<string[]>() }
114+
new Option<string[]>("--items")
115115
};
116116

117117
command.Handler = CommandHandler.Create(
@@ -138,7 +138,7 @@ internal static async Task<int> FileSystemTypes()
138138

139139
var command = new RootCommand
140140
{
141-
new Option("-f") { Argument = new Argument<FileInfo>().ExistingOnly() }
141+
new Option<FileInfo>("-f").ExistingOnly()
142142
};
143143

144144
command.Handler = CommandHandler.Create(
@@ -160,8 +160,8 @@ public static async Task<int> ComplexTypes()
160160
{
161161
var command = new Command("the-command")
162162
{
163-
new Option("--an-int") { Argument = new Argument<int>() },
164-
new Option("--a-string") { Argument = new Argument<string>() }
163+
new Option<int>("--an-int"),
164+
new Option<string>("--a-string")
165165
};
166166

167167
command.Handler = CommandHandler.Create(
File renamed without changes.
File renamed without changes.

‎samples/tutorial/Binding.md

-25
This file was deleted.

‎samples/tutorial/BindingToCommandHandlers.md

-62
This file was deleted.

‎samples/tutorial/readme.md

-4
This file was deleted.

‎src/System.CommandLine.Suggest/dotnet-suggest.csproj

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
<PackAsTool>true</PackAsTool>
77
<PackageId>dotnet-suggest</PackageId>
88
<ToolCommandName>dotnet-suggest</ToolCommandName>
9-
<PackAsToolShimRuntimeIdentifiers>win-x64;win-x86;osx-x64</PackAsToolShimRuntimeIdentifiers>
9+
<PackAsToolShimRuntimeIdentifiers>win-x64;win-x86;osx-x64;linux-x64</PackAsToolShimRuntimeIdentifiers>
1010
<PackagedShimOutputRootDirectory>$(OutputPath)</PackagedShimOutputRootDirectory>
1111

1212
<DotnetSuggestBuildNumber>.1</DotnetSuggestBuildNumber>

0 commit comments

Comments
 (0)
Please sign in to comment.