66using System ;
77using System . Collections . Generic ;
88using System . CommandLine ;
9- using System . CommandLine . Invocation ;
9+ using System . IO ;
1010using System . Linq ;
11-
12- using Microsoft . AspNetCore . Authentication ;
1311using Microsoft . DotNet . Watcher . Tools ;
1412using Microsoft . Extensions . Tools . Internal ;
1513
@@ -77,112 +75,131 @@ dotnet watch test
7775 public required IReadOnlyList < string > RemainingArguments { get ; init ; }
7876 public RunCommandLineOptions ? RunOptions { get ; init ; }
7977
80- public static CommandLineOptions ? Parse ( string [ ] args , IReporter reporter , out int errorCode , System . CommandLine . IConsole ? console = null )
78+ public static CommandLineOptions ? Parse ( string [ ] args , IReporter reporter , out int errorCode , TextWriter ? output = null , TextWriter ? error = null )
8179 {
82- var quietOption = new Option < bool > ( new [ ] { "--quiet" , "-q" } , "Suppresses all output except warnings and errors" ) ;
83- var verboseOption = new Option < bool > ( new [ ] { "--verbose" , "-v" } , "Show verbose output" ) ;
80+ var quietOption = new CliOption < bool > ( "--quiet" , "-q" )
81+ {
82+ Description = "Suppresses all output except warnings and errors"
83+ } ;
8484
85- verboseOption . AddValidator ( v =>
85+ var verboseOption = new CliOption < bool > ( "--verbose" , "-v" )
8686 {
87- if ( v . FindResultFor ( quietOption ) is not null && v . FindResultFor ( verboseOption ) is not null )
87+ Description = "Show verbose output"
88+ } ;
89+
90+ verboseOption . Validators . Add ( v =>
91+ {
92+ if ( v . GetResult ( quietOption ) is not null && v . GetResult ( verboseOption ) is not null )
8893 {
89- v . ErrorMessage = Resources . Error_QuietAndVerboseSpecified ;
94+ v . AddError ( Resources . Error_QuietAndVerboseSpecified ) ;
9095 }
9196 } ) ;
9297
93- var listOption = new Option < bool > ( "--list" , "Lists all discovered files without starting the watcher." ) ;
94- var shortProjectOption = new Option < string > ( "-p" , "The project to watch." ) { IsHidden = true } ;
95- var longProjectOption = new Option < string > ( "--project" , "The project to watch" ) ;
98+ var listOption = new CliOption < bool > ( "--list" ) { Description = "Lists all discovered files without starting the watcher." } ;
99+ var shortProjectOption = new CliOption < string > ( "-p" ) { Description = "The project to watch." , Hidden = true } ;
100+ var longProjectOption = new CliOption < string > ( "--project" ) { Description = "The project to watch" } ;
96101
97102 // launch profile used by dotnet-watch
98- var launchProfileWatchOption = new Option < string > ( new [ ] { "-lp" , LaunchProfileOptionName } , "The launch profile to start the project with (case-sensitive)." ) ;
99- var noLaunchProfileWatchOption = new Option < bool > ( new [ ] { NoLaunchProfileOptionName } , "Do not attempt to use launchSettings.json to configure the application." ) ;
103+ var launchProfileWatchOption = new CliOption < string > ( LaunchProfileOptionName , "-lp" )
104+ {
105+ Description = "The launch profile to start the project with (case-sensitive)."
106+ } ;
107+ var noLaunchProfileWatchOption = new CliOption < bool > ( NoLaunchProfileOptionName )
108+ {
109+ Description = "Do not attempt to use launchSettings.json to configure the application."
110+ } ;
100111
101112 // launch profile used by dotnet-run
102- var launchProfileRunOption = new Option < string > ( new [ ] { "-lp" , LaunchProfileOptionName } ) { IsHidden = true } ;
103- var noLaunchProfileRunOption = new Option < bool > ( new [ ] { NoLaunchProfileOptionName } ) { IsHidden = true } ;
113+ var launchProfileRunOption = new CliOption < string > ( LaunchProfileOptionName , "-lp" ) { Hidden = true } ;
114+ var noLaunchProfileRunOption = new CliOption < bool > ( NoLaunchProfileOptionName ) { Hidden = true } ;
104115
105- var targetFrameworkOption = new Option < string > ( new [ ] { "-f" , "--framework" } , "The target framework to run for. The target framework must also be specified in the project file." ) ;
106- var propertyOption = new Option < string [ ] > ( new [ ] { "--property" } , "Properties to be passed to MSBuild." ) ;
116+ var targetFrameworkOption = new CliOption < string > ( "--framework" , "-f" )
117+ {
118+ Description = "The target framework to run for. The target framework must also be specified in the project file."
119+ } ;
120+ var propertyOption = new CliOption < string [ ] > ( "--property" )
121+ {
122+ Description = "Properties to be passed to MSBuild."
123+ } ;
107124
108- propertyOption . AddValidator ( v =>
125+ propertyOption . Validators . Add ( v =>
109126 {
110127 var invalidProperty = v . GetValue ( propertyOption ) ? . FirstOrDefault (
111128 property => ! ( property . IndexOf ( '=' ) is > 0 and var index && index < property . Length - 1 && property [ ..index ] . Trim ( ) . Length > 0 ) ) ;
112129
113130 if ( invalidProperty != null )
114131 {
115- v . ErrorMessage = $ "Invalid property format: '{ invalidProperty } '. Expected 'name=value'.";
132+ v . AddError ( $ "Invalid property format: '{ invalidProperty } '. Expected 'name=value'.") ;
116133 }
117134 } ) ;
118135
119- var noHotReloadOption = new Option < bool > ( "--no-hot-reload" , "Suppress hot reload for supported apps." ) ;
120- var nonInteractiveOption = new Option < bool > (
121- "--non-interactive" ,
122- "Runs dotnet-watch in non-interactive mode. This option is only supported when running with Hot Reload enabled. " +
123- "Use this option to prevent console input from being captured." ) ;
136+ var noHotReloadOption = new CliOption < bool > ( "--no-hot-reload" ) { Description = "Suppress hot reload for supported apps." } ;
137+ var nonInteractiveOption = new CliOption < bool > ( "--non-interactive" )
138+ {
139+ Description = "Runs dotnet-watch in non-interactive mode. This option is only supported when running with Hot Reload enabled. " +
140+ "Use this option to prevent console input from being captured."
141+ } ;
124142
125- var remainingWatchArgs = new Argument < string [ ] > ( "forwardedArgs" , "Arguments to pass to the child dotnet process." ) ;
126- var remainingRunArgs = new Argument < string [ ] > ( name : null ) ;
143+ var remainingWatchArgs = new CliArgument < string [ ] > ( "forwardedArgs" ) { Description = "Arguments to pass to the child dotnet process." } ;
144+ var remainingRunArgs = new CliArgument < string [ ] > ( "remainingRunArgs" ) ;
127145
128- var runCommand = new Command ( "run" ) { IsHidden = true } ;
129- var rootCommand = new RootCommand ( Description ) ;
130- addOptions ( runCommand ) ;
131- addOptions ( rootCommand ) ;
146+ var runCommand = new CliCommand ( "run" ) { Hidden = true } ;
147+ var rootCommand = new CliRootCommand ( Description ) ;
148+ AddSymbols ( runCommand ) ;
149+ AddSymbols ( rootCommand ) ;
132150
133- void addOptions ( Command command )
151+ void AddSymbols ( CliCommand command )
134152 {
135- command . Add ( quietOption ) ;
136- command . Add ( verboseOption ) ;
137- command . Add ( noHotReloadOption ) ;
138- command . Add ( nonInteractiveOption ) ;
139- command . Add ( longProjectOption ) ;
140- command . Add ( shortProjectOption ) ;
153+ command . Options . Add ( quietOption ) ;
154+ command . Options . Add ( verboseOption ) ;
155+ command . Options . Add ( noHotReloadOption ) ;
156+ command . Options . Add ( nonInteractiveOption ) ;
157+ command . Options . Add ( longProjectOption ) ;
158+ command . Options . Add ( shortProjectOption ) ;
141159
142160 if ( command == runCommand )
143161 {
144- command . Add ( launchProfileRunOption ) ;
145- command . Add ( noLaunchProfileRunOption ) ;
162+ command . Options . Add ( launchProfileRunOption ) ;
163+ command . Options . Add ( noLaunchProfileRunOption ) ;
146164 }
147165 else
148166 {
149- command . Add ( launchProfileWatchOption ) ;
150- command . Add ( noLaunchProfileWatchOption ) ;
167+ command . Options . Add ( launchProfileWatchOption ) ;
168+ command . Options . Add ( noLaunchProfileWatchOption ) ;
151169 }
152170
153- command . Add ( targetFrameworkOption ) ;
154- command . Add ( propertyOption ) ;
171+ command . Options . Add ( targetFrameworkOption ) ;
172+ command . Options . Add ( propertyOption ) ;
155173
156- command . Add ( listOption ) ;
174+ command . Options . Add ( listOption ) ;
157175
158176 if ( command == runCommand )
159177 {
160- command . Add ( remainingRunArgs ) ;
178+ command . Arguments . Add ( remainingRunArgs ) ;
161179 }
162180 else
163181 {
164- command . Add ( runCommand ) ;
165- command . Add ( remainingWatchArgs ) ;
182+ command . Subcommands . Add ( runCommand ) ;
183+ command . Arguments . Add ( remainingWatchArgs ) ;
166184 }
167185 } ;
168186
169187 CommandLineOptions ? options = null ;
170188
171- runCommand . SetHandler ( context =>
189+ runCommand . SetAction ( parseResult =>
172190 {
173- RootHandler ( context , new ( )
191+ RootHandler ( parseResult , new ( )
174192 {
175- LaunchProfileName = context . ParseResult . GetValue ( launchProfileRunOption ) ,
176- NoLaunchProfile = context . ParseResult . GetValue ( noLaunchProfileRunOption ) ,
177- RemainingArguments = context . ParseResult . GetValue ( remainingRunArgs ) ,
193+ LaunchProfileName = parseResult . GetValue ( launchProfileRunOption ) ,
194+ NoLaunchProfile = parseResult . GetValue ( noLaunchProfileRunOption ) ,
195+ RemainingArguments = parseResult . GetValue ( remainingRunArgs ) ?? Array . Empty < string > ( ) ,
178196 } ) ;
179197 } ) ;
180198
181- rootCommand . SetHandler ( context => RootHandler ( context , runOptions : null ) ) ;
199+ rootCommand . SetAction ( parseResult => RootHandler ( parseResult , runOptions : null ) ) ;
182200
183- void RootHandler ( InvocationContext context , RunCommandLineOptions ? runOptions )
201+ void RootHandler ( ParseResult parseResults , RunCommandLineOptions ? runOptions )
184202 {
185- var parseResults = context . ParseResult ;
186203 var projectValue = parseResults . GetValue ( longProjectOption ) ;
187204 if ( string . IsNullOrEmpty ( projectValue ) )
188205 {
@@ -207,12 +224,17 @@ void RootHandler(InvocationContext context, RunCommandLineOptions? runOptions)
207224 TargetFramework = parseResults . GetValue ( targetFrameworkOption ) ,
208225 BuildProperties = parseResults . GetValue ( propertyOption ) ?
209226 . Select ( p => ( p [ ..p . IndexOf ( '=' ) ] . Trim ( ) , p [ ( p . IndexOf ( '=' ) + 1 ) ..] ) ) . ToArray ( ) ,
210- RemainingArguments = parseResults . GetValue ( remainingWatchArgs ) ,
227+ RemainingArguments = parseResults . GetValue ( remainingWatchArgs ) ?? Array . Empty < string > ( ) ,
211228 RunOptions = runOptions ,
212229 } ;
213230 }
214231
215- errorCode = rootCommand . Invoke ( args , console ) ;
232+ errorCode = new CliConfiguration ( rootCommand )
233+ {
234+ Output = output ?? Console . Out ,
235+ Error = error ?? Console . Error
236+ } . Invoke ( args ) ;
237+
216238 return options ;
217239 }
218240
0 commit comments