Skip to content

Commit 2464766

Browse files
baronfeljeffhandley
authored andcommitted
Merge pull request #2679 from dotnet/add-package-readme
[release/10.0] Add package readme for the core System.CommandLine package
1 parent 18a0a54 commit 2464766

File tree

2 files changed

+281
-0
lines changed

2 files changed

+281
-0
lines changed

src/System.CommandLine/README.md

Lines changed: 279 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,279 @@
1+
# System.CommandLine
2+
3+
System.CommandLine provides robust support for command-line parsing, invocation, and shell completions in .NET applications. It supports both POSIX and Windows conventions, making it easy to build professional command-line interfaces.
4+
5+
## Getting Started
6+
7+
### Basic Command
8+
9+
Here's a simple "Hello World" command-line application:
10+
11+
```csharp
12+
using System.CommandLine;
13+
14+
RootCommand rootCommand = new("Sample command-line app");
15+
16+
Option<string> nameOption = new("--name", "-n")
17+
{
18+
Description = "Your name"
19+
};
20+
21+
rootCommand.Options.Add(nameOption);
22+
23+
rootCommand.SetAction(parseResult =>
24+
{
25+
string name = parseResult.GetValue(nameOption);
26+
Console.WriteLine($"Hello, {name ?? "World"}!");
27+
});
28+
29+
return rootCommand.Parse(args).Invoke();
30+
```
31+
32+
In this example, we create a `RootCommand`, add an option for the user's name, and define an action that prints a greeting. The `RootCommand` is a special kind of `Command` that comes with a few predefined behaviors:
33+
34+
* It discovers its name automatically from the currently-running application
35+
* It automatically provides `--help` and `--version` options and default behaviors for them
36+
* It provides a default integration with `dotnet-suggest` for dynamic [shell completions](#shell-completions)
37+
38+
You can always override or customize these behaviors as needed on a `RootCommand`, or create your own top-level `Command` instead.
39+
40+
### Commands with Arguments
41+
42+
Arguments are values passed directly to commands without option names:
43+
44+
```csharp
45+
var fileArgument = new Argument<FileInfo>("file")
46+
{
47+
Description = "The file to process"
48+
};
49+
50+
var processCommand = new Command("process", "Process a file");
51+
processCommand.Arguments.Add(fileArgument);
52+
53+
processCommand.SetAction(parseResult =>
54+
{
55+
FileInfo file = parseResult.GetValue(fileArgument);
56+
Console.WriteLine($"Processing {file.FullName}");
57+
});
58+
59+
var rootCommand = new RootCommand();
60+
61+
rootCommand.Subcommands.Add(processCommand);
62+
```
63+
64+
### Options with Default Values
65+
66+
Options can have default values and validation:
67+
68+
```csharp
69+
var rootCommand = new RootCommand();
70+
71+
var delayOption = new Option<int>("--delay", "-d")
72+
{
73+
Description = "Delay in milliseconds",
74+
DefaultValueFactory = _ => 1000
75+
};
76+
77+
delayOption.Validators.Add(result =>
78+
{
79+
if (result.GetValueOrDefault<int>() < 0)
80+
{
81+
result.AddError("Delay must be non-negative");
82+
}
83+
});
84+
85+
rootCommand.Options.Add(delayOption);
86+
```
87+
88+
### Subcommands
89+
90+
Build complex CLI applications with nested commands:
91+
92+
```csharp
93+
var rootCommand = new RootCommand("My application");
94+
95+
var configCommand = new Command("config", "Configure the application");
96+
var configSetCommand = new Command("set", "Set a configuration value");
97+
var configGetCommand = new Command("get", "Get a configuration value");
98+
99+
var keyOption = new Option<string>("--key")
100+
{
101+
Description = "Configuration key"
102+
};
103+
var valueOption = new Option<string>("--value")
104+
{
105+
Description = "Configuration value"
106+
};
107+
108+
configSetCommand.Options.Add(keyOption);
109+
configSetCommand.Options.Add(valueOption);
110+
configGetCommand.Options.Add(keyOption);
111+
112+
configCommand.Subcommands.Add(configSetCommand);
113+
configCommand.Subcommands.Add(configGetCommand);
114+
rootCommand.Subcommands.Add(configCommand);
115+
116+
// Usage: myapp config set --key "apiUrl" --value "https://api.example.com"
117+
// Usage: myapp config get --key "apiUrl"
118+
```
119+
120+
### Using Options in Command Actions
121+
122+
Access option values through the ParseResult:
123+
124+
```csharp
125+
var connectionOption = new Option<string>("--connection")
126+
{
127+
Description = "Database connection string"
128+
};
129+
var timeoutOption = new Option<int>("--timeout")
130+
{
131+
Description = "Timeout in seconds",
132+
DefaultValueFactory = _ => 30
133+
};
134+
var verboseOption = new Option<bool>("--verbose")
135+
{
136+
Description = "Enable verbose output"
137+
};
138+
139+
rootCommand.Options.Add(connectionOption);
140+
rootCommand.Options.Add(timeoutOption);
141+
rootCommand.Options.Add(verboseOption);
142+
143+
rootCommand.SetAction(parseResult =>
144+
{
145+
var connection = parseResult.GetValue(connectionOption);
146+
var timeout = parseResult.GetValue(timeoutOption);
147+
var verbose = parseResult.GetValue(verboseOption);
148+
149+
Console.WriteLine($"Connection: {connection}");
150+
Console.WriteLine($"Timeout: {timeout}");
151+
Console.WriteLine($"Verbose: {verbose}");
152+
});
153+
```
154+
155+
### Shell Completions
156+
157+
Enable tab completion for your CLI:
158+
159+
```csharp
160+
// Completions are automatically available for all commands, options, and arguments
161+
var rootCommand = new RootCommand("My app with completions");
162+
163+
var fileOption = new Option<FileInfo>("--file")
164+
{
165+
Description = "The file to process"
166+
};
167+
168+
// Add custom completions using CompletionSources
169+
fileOption.CompletionSources.Add(ctx =>
170+
// hard-coded list of files
171+
["file1.txt", "file2.txt", "file3.txt" ]
172+
);
173+
174+
// Or add simple string suggestions
175+
fileOption.CompletionSources.Add("option1", "option2", "option3");
176+
177+
rootCommand.Options.Add(fileOption);
178+
```
179+
180+
Users can then easily trigger your completions using `dotnet-suggest`:
181+
182+
```shell
183+
> dotnet tool install -g dotnet-suggest
184+
> dotnet suggest script bash > ~/.bashrc
185+
```
186+
187+
```powershell
188+
> dotnet tool install -g dotnet-suggest
189+
> dotnet suggest script powershell >> $PROFILE
190+
```
191+
192+
Once `dotnet-suggest` is installed, you can register your app with it for completions support:
193+
194+
```shell
195+
> dotnet-suggest register --command-path /path/to/myapp
196+
```
197+
198+
Alternatively, you can create your own commands for completion generation and instruct users on how to set them up.
199+
200+
### Async Command Handlers
201+
202+
Support for asynchronous operations:
203+
204+
```csharp
205+
var urlOption = new Option<string>("--url")
206+
{
207+
Description = "The URL to fetch"
208+
};
209+
rootCommand.Options.Add(urlOption);
210+
211+
rootCommand.SetAction(async (parseResult, cancellationToken) =>
212+
{
213+
var url = parseResult.GetValue(urlOption);
214+
if (url != null)
215+
{
216+
using var client = new HttpClient();
217+
var response = await client.GetStringAsync(url, cancellationToken);
218+
Console.WriteLine(response);
219+
}
220+
});
221+
222+
// Or return an exit code:
223+
rootCommand.SetAction(async (parseResult, cancellationToken) =>
224+
{
225+
// Your async logic here
226+
return await Task.FromResult(0); // Return exit code
227+
});
228+
```
229+
230+
## Notable Changes Since v2.0.0-beta7
231+
232+
### New Features
233+
- **Improved Help System**: Enhanced `HelpAction` to allow users to provide custom `MaxWidth` for help text formatting ([#2635](https://github.com/dotnet/command-line-api/pull/2635)). Note that if you create custom Help or Version actions, you'll want to set `ClearsParseErrors` to `true` to ensure that invoking those features isn't treated like an error by the parser.
234+
- **`Task<int>` Support**: Added `SetAction` overload for `Task<int>` return types ([#2634](https://github.com/dotnet/command-line-api/issues/2634))
235+
- **Detect Implicit Arguments**: Added the `ArgumentResult.Implicit` property for better argument handling ([#2622](https://github.com/dotnet/command-line-api/issues/2622), [#2625](https://github.com/dotnet/command-line-api/pull/2625))
236+
- **Performance Improvements**: Reduced reflection usage throughout the library for better performance ([#2662](https://github.com/dotnet/command-line-api/pull/2662))
237+
238+
### Bug Fixes
239+
- Fixed issue [#2128](https://github.com/dotnet/command-line-api/issues/2128): Resolved command parsing edge cases ([#2656](https://github.com/dotnet/command-line-api/pull/2656))
240+
- Fixed issue [#2257](https://github.com/dotnet/command-line-api/issues/2257): Corrected argument validation behavior
241+
- Fixed issue [#2589](https://github.com/dotnet/command-line-api/issues/2589): Improved error message clarity ([#2654](https://github.com/dotnet/command-line-api/pull/2654))
242+
- Fixed issue [#2591](https://github.com/dotnet/command-line-api/issues/2591): Resolved option parsing inconsistencies ([#2644](https://github.com/dotnet/command-line-api/pull/2644))
243+
- Fixed issue [#2622](https://github.com/dotnet/command-line-api/issues/2622): Enhanced implicit argument support ([#2625](https://github.com/dotnet/command-line-api/pull/2625))
244+
- Fixed issue [#2628](https://github.com/dotnet/command-line-api/issues/2628): Corrected help text formatting issues
245+
- Fixed issue [#2634](https://github.com/dotnet/command-line-api/issues/2634): Added missing Task<int> action support
246+
- Fixed issue [#2640](https://github.com/dotnet/command-line-api/issues/2640): Resolved completion suggestions for nested commands ([#2646](https://github.com/dotnet/command-line-api/pull/2646))
247+
248+
### Breaking Changes
249+
- Default value handling for `ProcessTerminationTimeout` has been re-added ([#2672](https://github.com/dotnet/command-line-api/pull/2672))
250+
- Some internal APIs have been refactored to reduce reflection usage ([#2662](https://github.com/dotnet/command-line-api/pull/2662))
251+
252+
### Other Improvements
253+
- Updated to .NET 10.0 RC1 compatibility
254+
- Improved memory usage and performance optimizations
255+
- Better handling of complex command hierarchies
256+
257+
## Documentation
258+
259+
For comprehensive documentation, tutorials, and API reference, visit:
260+
- **[Microsoft Learn Documentation](https://learn.microsoft.com/en-us/dotnet/standard/commandline/)** - Complete guides and API reference
261+
- **[GitHub Repository](https://github.com/dotnet/command-line-api)** - Source code, samples, and issues
262+
263+
## Framework Support
264+
265+
- **.NET 8.0+** - Full feature support with trimming and AOT compilation
266+
- **.NET Standard 2.0** - Compatible with .NET Framework 4.6.1+, .NET Core 2.0+
267+
268+
## License
269+
270+
This package is licensed under the [MIT License](https://opensource.org/licenses/MIT).
271+
272+
## Contributing
273+
274+
We welcome contributions! Please see our [Contributing Guide](https://github.com/dotnet/command-line-api/blob/main/CONTRIBUTING.md) for details.
275+
276+
## Support
277+
278+
- **Issues**: [GitHub Issues](https://github.com/dotnet/command-line-api/issues)
279+
- **Discussions**: [GitHub Discussions](https://github.com/dotnet/command-line-api/discussions)

src/System.CommandLine/System.CommandLine.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
<Description>Support for parsing command lines, supporting both POSIX and Windows conventions and shell-agnostic command line completions.</Description>
88
<GenerateDocumentationFile>true</GenerateDocumentationFile>
99
<DebugType Condition="'$(Configuration)' == 'Debug'">portable</DebugType>
10+
<PackageReadmeFile>README.md</PackageReadmeFile>
1011
</PropertyGroup>
1112

1213
<PropertyGroup Condition="'$(TargetFramework)' == '$(NetMinimum)'">
@@ -17,6 +18,7 @@
1718

1819
<ItemGroup>
1920
<Compile Include="..\System.Diagnostics.CodeAnalysis.cs" Link="System.Diagnostics.CodeAnalysis\System.Diagnostics.CodeAnalysis.cs" />
21+
<None Include="README.md" Pack="true" PackagePath="/README.md" />
2022
</ItemGroup>
2123

2224
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">

0 commit comments

Comments
 (0)