Replace System.CommandLine with a custom argument parser#749
Merged
tannergooding merged 3 commits intoJul 13, 2026
Merged
Conversation
System.CommandLine has repeatedly broken the CLI, most recently in dotnet#554 where the beta4 response-file tokenizer splits each line on whitespace before options are matched, corrupting `name=value` values that contain spaces (such as a `--remap` to a type with a space in it). The stable package also changed too much to adopt cleanly, so roll a small parser we control instead. The new parser is a plain, reflection-free (AOT-friendly) implementation that reads each response-file line as a single token, preserving embedded spaces, while still supporting multiple pairs across separate tokens, the inline `--opt=value` form, and `#` comments. Drop the System.CommandLine package reference and the CustomHelpBuilder, and regenerate the README help blocks to match the new output. Fixes dotnet#554 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The version shown by --version was a hardcoded "21.1.8" that had to be manually kept in sync with VersionPrefix and the targeted clang release. Read it from the assembly version (major.minor.build) so it tracks VersionPrefix automatically and stays aligned with the clang/clangsharp version lines printed alongside it. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Cover the custom `CommandLineParser` directly, including the dotnet#554 regression: a `name=value` token whose value contains spaces (bare, inline `--opt=`, and via a response file) is preserved as a single value rather than split on whitespace. Also cover multi-pair tokens, single/flag arity, `AllowedValues`, unknown options, and response-file handling. Wire the exe up with `InternalsVisibleTo` so the internal parser types are testable. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Replaces the
System.CommandLinedependency inClangSharpPInvokeGeneratorwith a small, hand-rolled, reflection-free (AOT-friendly) argument parser.System.CommandLinebeta4 tokenizes each response-file line by splitting on whitespace before option matching, so aname=valueargument whose value contains spaces (e.g.__arglist=@params string[] args) was split into multiple tokens and rejected withInvalid key/value pair argument. beta3 kept each line intact, which is why the repo has been pinned there as a workaround. Rather than chase the dependency, this rolls our own parser: each non-empty, non-#response-file line is read as exactly one token and never whitespace-split, so spaced values are preserved. A token is treated as an option only when it exactly equals a known alias, or (for the--opt=valueinline form) the text before the first=is a known alias -- so barename=valuevalues and-m64stay intact.Fixes #554
Also folds in two cleanups:
Major.Minor.Build) instead of a hardcoded string, so it tracksVersionPrefixautomatically.(string[])[.. opt.Values]casts collapse into a singleCommandLineOption.GetValues().Adds
tests/ClangSharpPInvokeGenerator.UnitTestsexercising the parser directly, including the #554 regression three ways (bare, inline--opt=, and via a response file), multi-pair tokens, single/flag arity,-m64-as-value,AllowedValues, and unknown-option/missing-response-file errors. The exe exposes its internals to the test project viaInternalsVisibleTo.Verified: full generator suite 3742/3742 and the new parser suite 11/11 pass with 0 warnings;
--help/--version/config-help and the #554 repro all check out.System.CommandLineis removed from the csproj andDirectory.Packages.props, and the README help blocks are regenerated from actual output.