Skip to content

Commit a1e0e42

Browse files
authored
Merge pull request #61 from dotnet-campus/t/walterlv/one-step
提升解析性能,标准化解析行为
2 parents 67d4af0 + 5c00cf7 commit a1e0e42

File tree

155 files changed

+11490
-14369
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

155 files changed

+11490
-14369
lines changed

.github/workflows/dotnet-build.yml

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,17 @@ jobs:
1313
uses: actions/setup-dotnet@v1
1414
with:
1515
dotnet-version: |
16-
3.1.x
17-
6.0.x
1816
8.0.x
17+
9.0.x
1918
2019
- name: Build
21-
run: dotnet build --configuration Release
20+
run: dotnet build -c release
2221

23-
- name: Test
24-
run: dotnet test --configuration Release
22+
- name: Test Debug
23+
run: dotnet test -c debug
24+
25+
- name: Test Release
26+
run: dotnet test -c release
2527

2628
- name: Pack
27-
run: dotnet pack --configuration Release --no-build
29+
run: dotnet pack ./src/DotNetCampus.CommandLine -c release --no-build

.github/workflows/nuget-tag-publish.yml

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,8 @@ jobs:
1717
uses: actions/setup-dotnet@v1
1818
with:
1919
dotnet-version: |
20-
3.1.x
21-
6.0.x
2220
8.0.x
21+
9.0.x
2322
2423
- name: Install dotnet tool
2524
run: dotnet tool install -g dotnetCampus.TagToVersion
@@ -29,8 +28,8 @@ jobs:
2928

3029
- name: Build with dotnet
3130
run: |
32-
dotnet build --configuration Release
33-
dotnet pack --configuration Release --no-build
31+
dotnet build -c release
32+
dotnet pack ./src/DotNetCampus.CommandLine -c release --no-build
3433
3534
- name: Install Nuget
3635
uses: nuget/setup-nuget@v1

Directory.Packages.props

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
<Project>
22
<ItemGroup>
3-
<PackageVersion Include="BenchmarkDotNet" Version="0.15.2" />
4-
<PackageVersion Include="dotnetCampus.LatestCSharpFeatures" Version="13.0.0" />
3+
<PackageVersion Include="BenchmarkDotNet" Version="0.15.4" />
4+
<PackageVersion Include="ConsoleAppFramework" Version="5.6.1" />
5+
<PackageVersion Include="DotNetCampus.CodeAnalysisUtils" Version="0.0.1-alpha.3" />
6+
<PackageVersion Include="DotNetCampus.CommandLine.Temp40" Version="4.0.1-benchmark.1" />
7+
<PackageVersion Include="DotNetCampus.LatestCSharpFeatures" Version="13.0.1" />
58
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" />
69
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.11.0" />
710
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.11.0" />
811
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
912
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="8.0.0" />
10-
<PackageVersion Include="MSTest.TestAdapter" Version="3.10.3" />
11-
<PackageVersion Include="MSTest.TestFramework" Version="3.10.3" />
13+
<PackageVersion Include="MSTest.TestAdapter" Version="3.10.4" />
14+
<PackageVersion Include="MSTest.TestFramework" Version="3.10.4" />
1215
<PackageVersion Include="MSTestEnhancer" Version="2.2.2" />
1316
<PackageVersion Include="System.Collections.Immutable" Version="8.0.0" />
1417
<PackageVersion Include="System.CommandLine" Version="2.0.0-beta4.22272.1" />

DotNetCampus.CommandLine.sln

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotNetCampus.CommandLine.Te
2828
EndProject
2929
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotNetCampus.CommandLine.Performance", "tests\DotNetCampus.CommandLine.Performance\DotNetCampus.CommandLine.Performance.csproj", "{56B65FC1-CE75-4981-A880-954D891901D6}"
3030
EndProject
31+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotNetCampus.CommandLine.FakeObjects", "tests\DotNetCampus.CommandLine.FakeObjects\DotNetCampus.CommandLine.FakeObjects.csproj", "{413E4F7B-4E26-4D88-B7E9-13A6831A9E42}"
32+
EndProject
3133
Global
3234
GlobalSection(SolutionConfigurationPlatforms) = preSolution
3335
Debug|Any CPU = Debug|Any CPU
@@ -76,6 +78,14 @@ Global
7678
{56B65FC1-CE75-4981-A880-954D891901D6}.Release|Any CPU.Build.0 = Release|Any CPU
7779
{56B65FC1-CE75-4981-A880-954D891901D6}.Release|x86.ActiveCfg = Release|Any CPU
7880
{56B65FC1-CE75-4981-A880-954D891901D6}.Release|x86.Build.0 = Release|Any CPU
81+
{413E4F7B-4E26-4D88-B7E9-13A6831A9E42}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
82+
{413E4F7B-4E26-4D88-B7E9-13A6831A9E42}.Debug|Any CPU.Build.0 = Debug|Any CPU
83+
{413E4F7B-4E26-4D88-B7E9-13A6831A9E42}.Debug|x86.ActiveCfg = Debug|Any CPU
84+
{413E4F7B-4E26-4D88-B7E9-13A6831A9E42}.Debug|x86.Build.0 = Debug|Any CPU
85+
{413E4F7B-4E26-4D88-B7E9-13A6831A9E42}.Release|Any CPU.ActiveCfg = Release|Any CPU
86+
{413E4F7B-4E26-4D88-B7E9-13A6831A9E42}.Release|Any CPU.Build.0 = Release|Any CPU
87+
{413E4F7B-4E26-4D88-B7E9-13A6831A9E42}.Release|x86.ActiveCfg = Release|Any CPU
88+
{413E4F7B-4E26-4D88-B7E9-13A6831A9E42}.Release|x86.Build.0 = Release|Any CPU
7989
EndGlobalSection
8090
GlobalSection(SolutionProperties) = preSolution
8191
HideSolutionNode = FALSE
@@ -84,6 +94,7 @@ Global
8494
{6B8F7500-B161-408D-BFA3-AE77CB8CF4D8} = {F26EAA27-AA79-4B28-890C-D759F1D1A374}
8595
{70991994-BB0C-4D00-9B74-E8736D0AD7C1} = {7DDA8183-3606-4B08-86E3-A4537860448F}
8696
{56B65FC1-CE75-4981-A880-954D891901D6} = {7DDA8183-3606-4B08-86E3-A4537860448F}
97+
{413E4F7B-4E26-4D88-B7E9-13A6831A9E42} = {7DDA8183-3606-4B08-86E3-A4537860448F}
8798
EndGlobalSection
8899
GlobalSection(ExtensibilityGlobals) = postSolution
89100
SolutionGuid = {52E30C59-C5C8-4517-811A-667BFA2BFABB}

Nuget.config

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<configuration>
3+
<packageSources>
4+
<add key="Benchmark-Local" value="./tests/DotNetCampus.CommandLine.Performance/CompareTo" />
5+
</packageSources>
6+
</configuration>

README.md

Lines changed: 62 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@
99
[zh-hans]: /docs/zh-hans/README.md
1010
[zh-hant]: /docs/zh-hant/README.md
1111

12-
DotNetCampus.CommandLine is a simple yet high-performance command line parsing library for .NET. Thanks to the power of source code generators, it provides efficient parsing capabilities with a developer-friendly experience.
12+
DotNetCampus.CommandLine is a simple and high-performance command line parsing library for .NET. Benefiting from source generators (and interceptors), it delivers efficient parsing and a friendly development experience across multiple command line styles. All features live under the `DotNetCampus.Cli` namespace.
1313

14-
Parsing a typical command line takes only about 0.8μs (microseconds), making it one of the fastest command line parsers available in .NET.
14+
Benchmarks show parsing a typical command line takes well under a microsecond in many scenarios, placing it among the fastest .NET command line parsers while still pursuing full‑featured syntax support.
1515

1616
## Get Started
1717

@@ -37,63 +37,81 @@ class Program
3737
Define a class that maps command line arguments:
3838

3939
```csharp
40-
class Options
40+
public class Options
4141
{
42-
[Value(0)]
43-
public required string FilePath { get; init; }
42+
[Option("debug")]
43+
public required bool IsDebugMode { get; init; }
4444

45-
[Option('s', "silence")]
46-
public bool IsSilence { get; init; }
45+
[Option('c', "count")]
46+
public required int TestCount { get; init; }
4747

48-
[Option('m', "mode")]
49-
public string? StartMode { get; init; }
48+
[Option('n', "test-name")]
49+
public string? TestName { get; set; }
5050

51-
[Option("startup-sessions")]
52-
public IReadOnlyList<string> StartupSessions { get; init; } = [];
51+
[Option("test-category")]
52+
public string? TestCategory { get; set; }
53+
54+
[Option('d', "detail-level")]
55+
public DetailLevel DetailLevel { get; set; } = DetailLevel.Medium;
56+
57+
[Value(0, int.MaxValue)]
58+
public IReadOnlyList<string> TestItems { get; init; } = null!;
59+
}
60+
61+
public enum DetailLevel
62+
{
63+
Low,
64+
Medium,
65+
High,
5366
}
5467
```
5568

56-
Then use different command line styles to populate instances of this type:
69+
Then use different command line styles to populate instances of this type (the library supports multiple styles):
5770

58-
### Windows PowerShell Style
71+
| Style | Example |
72+
| --------------- | ------------------------------------------------------------------------------------------ |
73+
| DotNet | `demo.exe 1.txt 2.txt -c:20 --test-name:BenchmarkTest --detail-level=High --debug` |
74+
| Windows Classic | `demo.exe 1.txt 2.txt 3.txt -c 20 -TestName BenchmarkTest -DetailLevel High -Debug` |
75+
| CMD | `demo.exe 1.txt 2.txt 3.txt /c 20 /TestName BenchmarkTest /DetailLevel High /Debug` |
76+
| Gnu | `demo.exe 1.txt 2.txt 3.txt -c 20 --test-name BenchmarkTest --detail-level High --debug` |
77+
| Flexible | `demo.exe 1.txt 2.txt 3.txt --count:20 /TestName BenchmarkTest --detail-level=High -Debug` |
5978

60-
```powershell
61-
> demo.exe "C:\Users\lvyi\Desktop\demo.txt" -s -Mode Edit -StartupSessions A B C
62-
```
79+
## Command Styles and Features
6380

64-
### Windows CMD Style
81+
Multiple command line styles are supported; select one when parsing (Flexible is default). Styles differ in case sensitivity, accepted prefixes, separators, and naming forms. A detailed capability matrix (boolean literals, collection parsing forms, naming conventions, URL form, etc.) is documented in the full English guide under `docs/en/README.md`.
6582

66-
```cmd
67-
> demo.exe "C:\Users\lvyi\Desktop\demo.txt" /s /Mode Edit /StartupSessions A B C
68-
```
83+
Core capabilities:
84+
- Rich option syntax: long & short options; separators `= : space`; multi-value & repeat forms
85+
- Boolean literals: `true/false`, `yes/no`, `on/off`, `1/0`
86+
- Collections & dictionaries: repeat, comma, semicolon forms; key-value dictionaries
87+
- Positional arguments: via `[Value(index)]` (ranges supported with `(index, length)` overload — second parameter is count)
88+
- Property semantics: `required`, `init`, nullable reference/value types unified behavior
89+
- Commands & subcommands: multi-word `[Command]` supported with handler chaining or `ICommandHandler`
90+
- URL protocol parsing: `scheme://command/sub/positional1?...` for integration scenarios
91+
- High performance: source generators + interceptors, minimizing allocations
92+
- AOT compatible: no reflection; even enum name lookups are avoided at runtime
6993

70-
### Linux/GNU Style
94+
For the full feature matrix (including whether a style supports space-separated collections, explicit boolean values, multi-char short option groups, etc.), see the English documentation table.
7195

72-
```bash
73-
$ demo.exe "C:/Users/lvyi/Desktop/demo.txt" -s --mode Edit --startup-sessions A --startup-sessions B --startup-sessions C
74-
```
96+
### Naming
7597

76-
### .NET CLI Style
77-
```
78-
> demo.exe "C:\Users\lvyi\Desktop\demo.txt" -s:true --mode:Edit --startup-sessions:A;B;C
79-
```
98+
Define options using kebab-case in attributes (e.g., `[Option("test-name")]`). The analyzer warns (`DCL101`) if not kebab-case; we still treat what you write as kebab-case so users may invoke with PascalCase/camelCase depending on style.
8099

81-
## Command Styles and Features
100+
### Required Options and Default Values
101+
102+
Modifiers: `required` (must be supplied), `init` (immutable after construction), `?` (nullable). Initial value semantics follow the table in `docs/en/README.md`: required & missing → exception; nullable + init → null; non-nullable collection → empty; non-nullable scalar → default value (value types) or empty string for `string`; otherwise keep initializer.
103+
104+
### Commands and Subcommands
105+
106+
Register handlers with `AddHandler<T>()` or implement `ICommandHandler`. Multi-word `[Command("remote add")]` expresses subcommands. Ambiguity throws `CommandNameAmbiguityException`. Use `RunAsync` if any handler is async.
107+
108+
### URL Protocol
109+
110+
You may express a command invocation as a URL: `dotnet-campus://1.txt/2.txt?count=20&test-name=BenchmarkTest&detail-level=High&debug` enabling shell integration or deep links.
111+
112+
### Performance
82113

83-
The library supports multiple command line styles through `CommandLineStyle` enum:
84-
- Flexible (default): Intelligently recognizes multiple styles
85-
- GNU: GNU standard compliant
86-
- POSIX: POSIX standard compliant
87-
- DotNet: .NET CLI style
88-
- PowerShell: PowerShell style
89-
90-
Advanced features include:
91-
- Support for various data types including collections and dictionaries
92-
- Positional arguments with `ValueAttribute`
93-
- Required properties with C# `required` modifier
94-
- Command handling with command support
95-
- URL protocol parsing
96-
- High performance thanks to source generators
114+
Benchmarks (see docs for detailed tables) show very low latency (hundreds of ns typical) and minimal allocations compared to earlier versions and other libraries, while preserving rich syntax coverage.
97115

98116
## Engage, Contribute and Provide Feedback
99117

@@ -107,7 +125,7 @@ Click here to file a new issue:
107125

108126
### Contributing Guide
109127

110-
Be kindly.
128+
Be kind.
111129

112130
## License
113131

0 commit comments

Comments
 (0)