diff --git a/System.CommandLine.v3.ncrunchsolution b/System.CommandLine.v3.ncrunchsolution
new file mode 100644
index 0000000000..ed49d122c2
--- /dev/null
+++ b/System.CommandLine.v3.ncrunchsolution
@@ -0,0 +1,12 @@
+
+
+ True
+
+ TargetFrameworks = net8.0
+ TargetFramework = net8.0
+
+ False
+ True
+ True
+
+
\ No newline at end of file
diff --git a/src/System.CommandLine.ApiCompatibility.Tests/ApiCompatibilityApprovalTests.System_CommandLine_api_is_not_changed.approved.txt b/src/System.CommandLine.ApiCompatibility.Tests/ApiCompatibilityApprovalTests.System_CommandLine_api_is_not_changed.approved.txt
index 45cc9f778a..1ef7bd503e 100644
--- a/src/System.CommandLine.ApiCompatibility.Tests/ApiCompatibilityApprovalTests.System_CommandLine_api_is_not_changed.approved.txt
+++ b/src/System.CommandLine.ApiCompatibility.Tests/ApiCompatibilityApprovalTests.System_CommandLine_api_is_not_changed.approved.txt
@@ -49,31 +49,13 @@
public System.Void Add(Option option)
public System.Void Add(Command command)
public System.Collections.Generic.IEnumerable GetCompletions(System.CommandLine.Completions.CompletionContext context)
- public ParseResult Parse(System.Collections.Generic.IReadOnlyList args, CommandLineConfiguration configuration = null)
- public ParseResult Parse(System.String commandLine, CommandLineConfiguration configuration = null)
+ public ParseResult Parse(System.Collections.Generic.IReadOnlyList args, ParserConfiguration configuration = null)
+ public ParseResult Parse(System.String commandLine, ParserConfiguration configuration = null)
public System.Void SetAction(System.Action action)
public System.Void SetAction(System.Func action)
public System.Void SetAction(System.Func action)
public System.Void SetAction(System.Func action)
public System.Void SetAction(System.Func> action)
- public class CommandLineConfiguration
- .ctor(Command rootCommand)
- public System.Boolean EnableDefaultExceptionHandler { get; set; }
- public System.Boolean EnablePosixBundling { get; set; }
- public System.IO.TextWriter Error { get; set; }
- public System.IO.TextWriter Output { get; set; }
- public System.Nullable ProcessTerminationTimeout { get; set; }
- public System.CommandLine.Parsing.TryReplaceToken ResponseFileTokenReplacer { get; set; }
- public Command RootCommand { get; }
- public System.Int32 Invoke(System.String commandLine)
- public System.Int32 Invoke(System.String[] args)
- public System.Threading.Tasks.Task InvokeAsync(System.String commandLine, System.Threading.CancellationToken cancellationToken = null)
- public System.Threading.Tasks.Task InvokeAsync(System.String[] args, System.Threading.CancellationToken cancellationToken = null)
- public ParseResult Parse(System.Collections.Generic.IReadOnlyList args)
- public ParseResult Parse(System.String commandLine)
- public System.Void ThrowIfInvalid()
- public class CommandLineConfigurationException : System.Exception, System.Runtime.Serialization.ISerializable
- .ctor(System.String message)
public static class CompletionSourceExtensions
public static System.Void Add(this System.Collections.Generic.List>> completionSources, System.Func> completionsDelegate)
public static System.Void Add(this System.Collections.Generic.List>> completionSources, System.String[] completions)
@@ -88,6 +70,12 @@
public class EnvironmentVariablesDirective : Directive
.ctor()
public System.CommandLine.Invocation.CommandLineAction Action { get; set; }
+ public class InvocationConfiguration
+ .ctor()
+ public System.Boolean EnableDefaultExceptionHandler { get; set; }
+ public System.IO.TextWriter Error { get; set; }
+ public System.IO.TextWriter Output { get; set; }
+ public System.Nullable ProcessTerminationTimeout { get; set; }
public abstract class Option : Symbol
public System.CommandLine.Invocation.CommandLineAction Action { get; set; }
public System.Collections.Generic.ICollection Aliases { get; }
@@ -115,11 +103,16 @@
public static Option AcceptExistingOnly(this Option option)
public static Option AcceptExistingOnly(this Option option)
public static Option AcceptExistingOnly(this Option option)
+ public class ParserConfiguration
+ .ctor()
+ public System.Boolean EnablePosixBundling { get; set; }
+ public System.CommandLine.Parsing.TryReplaceToken ResponseFileTokenReplacer { get; set; }
public class ParseResult
public System.CommandLine.Invocation.CommandLineAction Action { get; }
public System.CommandLine.Parsing.CommandResult CommandResult { get; }
- public CommandLineConfiguration Configuration { get; }
+ public ParserConfiguration Configuration { get; }
public System.Collections.Generic.IReadOnlyList Errors { get; }
+ public InvocationConfiguration InvocationConfiguration { get; }
public System.CommandLine.Parsing.CommandResult RootCommandResult { get; }
public System.Collections.Generic.IReadOnlyList Tokens { get; }
public System.Collections.Generic.IReadOnlyList UnmatchedTokens { get; }
@@ -137,8 +130,8 @@
public T GetValue(Argument argument)
public T GetValue(Option option)
public T GetValue(System.String name)
- public System.Int32 Invoke()
- public System.Threading.Tasks.Task InvokeAsync(System.Threading.CancellationToken cancellationToken = null)
+ public System.Int32 Invoke(InvocationConfiguration configuration = null)
+ public System.Threading.Tasks.Task InvokeAsync(InvocationConfiguration configuration = null, System.Threading.CancellationToken cancellationToken = null)
public System.String ToString()
public class RootCommand : Command, System.Collections.IEnumerable
public static System.String ExecutableName { get; }
@@ -212,8 +205,8 @@ System.CommandLine.Parsing
public System.Void OnlyTake(System.Int32 numberOfTokens)
public System.String ToString()
public static class CommandLineParser
- public static System.CommandLine.ParseResult Parse(System.CommandLine.Command command, System.Collections.Generic.IReadOnlyList args, System.CommandLine.CommandLineConfiguration configuration = null)
- public static System.CommandLine.ParseResult Parse(System.CommandLine.Command command, System.String commandLine, System.CommandLine.CommandLineConfiguration configuration = null)
+ public static System.CommandLine.ParseResult Parse(System.CommandLine.Command command, System.Collections.Generic.IReadOnlyList args, System.CommandLine.ParserConfiguration configuration = null)
+ public static System.CommandLine.ParseResult Parse(System.CommandLine.Command command, System.String commandLine, System.CommandLine.ParserConfiguration configuration = null)
public static System.Collections.Generic.IEnumerable SplitCommandLine(System.String commandLine)
public class CommandResult : SymbolResult
public System.Collections.Generic.IEnumerable Children { get; }
diff --git a/src/System.CommandLine.Suggest.Tests/EndToEndTestApp/Program.cs b/src/System.CommandLine.Suggest.Tests/EndToEndTestApp/Program.cs
index d11e622ce2..eef852577c 100644
--- a/src/System.CommandLine.Suggest.Tests/EndToEndTestApp/Program.cs
+++ b/src/System.CommandLine.Suggest.Tests/EndToEndTestApp/Program.cs
@@ -33,9 +33,7 @@ static async Task Main(string[] args)
return Task.CompletedTask;
});
- CommandLineConfiguration commandLine = new (rootCommand);
-
- await commandLine.InvokeAsync(args);
+ await rootCommand.Parse(args).InvokeAsync();
}
}
}
diff --git a/src/System.CommandLine.Suggest.Tests/SuggestionShellScriptHandlerTest.cs b/src/System.CommandLine.Suggest.Tests/SuggestionShellScriptHandlerTest.cs
index 0ca6f6805e..4cdf78fa9f 100644
--- a/src/System.CommandLine.Suggest.Tests/SuggestionShellScriptHandlerTest.cs
+++ b/src/System.CommandLine.Suggest.Tests/SuggestionShellScriptHandlerTest.cs
@@ -2,6 +2,7 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.IO;
+using System.Threading;
using System.Threading.Tasks;
using FluentAssertions;
using Xunit;
@@ -10,32 +11,34 @@ namespace System.CommandLine.Suggest.Tests
{
public class SuggestionShellScriptHandlerTest
{
- private readonly CommandLineConfiguration _configuration;
+ private readonly RootCommand _rootCommand;
+ private readonly InvocationConfiguration _configuration;
public SuggestionShellScriptHandlerTest()
{
- _configuration = new SuggestionDispatcher(new TestSuggestionRegistration()).Configuration;
+ _rootCommand = new SuggestionDispatcher(new TestSuggestionRegistration()).RootCommand;
+ _configuration = new()
+ {
+ Output = new StringWriter(),
+ Error = new StringWriter()
+ };
}
[Fact]
public async Task When_shell_type_is_not_supported_it_throws()
{
- _configuration.Error = new StringWriter();
-
- await _configuration.InvokeAsync("script 123");
+ await _rootCommand.Parse("script 123").InvokeAsync(_configuration, CancellationToken.None);
_configuration.Error
- .ToString()
- .Should()
- .Contain("Shell '123' is not supported.");
+ .ToString()
+ .Should()
+ .Contain("Shell '123' is not supported.");
}
[Fact]
public async Task It_should_print_bash_shell_script()
{
- _configuration.Output = new StringWriter();
-
- await _configuration.InvokeAsync("script bash");
+ await _rootCommand.Parse("script bash").InvokeAsync(_configuration, CancellationToken.None);
_configuration.Output.ToString().Should().Contain("_dotnet_bash_complete()");
_configuration.Output.ToString().Should().NotContain("\r\n");
@@ -44,9 +47,7 @@ public async Task It_should_print_bash_shell_script()
[Fact]
public async Task It_should_print_powershell_shell_script()
{
- _configuration.Output = new StringWriter();
-
- await _configuration.InvokeAsync("script powershell");
+ await _rootCommand.Parse("script powershell").InvokeAsync(_configuration, CancellationToken.None);
_configuration.Output.ToString().Should().Contain("Register-ArgumentCompleter");
_configuration.Output.ToString().Should().Contain("\r\n");
@@ -55,12 +56,10 @@ public async Task It_should_print_powershell_shell_script()
[Fact]
public async Task It_should_print_zsh_shell_script()
{
- _configuration.Output = new StringWriter();
+ await _rootCommand.Parse("script zsh").InvokeAsync(_configuration, CancellationToken.None);
- await _configuration.InvokeAsync("script zsh");
-
_configuration.Output.ToString().Should().Contain("_dotnet_zsh_complete()");
_configuration.Output.ToString().Should().NotContain("\r\n");
}
}
-}
+}
\ No newline at end of file
diff --git a/src/System.CommandLine.Suggest/SuggestionDispatcher.cs b/src/System.CommandLine.Suggest/SuggestionDispatcher.cs
index 512712a41f..ec16bd3f16 100644
--- a/src/System.CommandLine.Suggest/SuggestionDispatcher.cs
+++ b/src/System.CommandLine.Suggest/SuggestionDispatcher.cs
@@ -6,7 +6,6 @@
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
-using System.CommandLine.Completions;
namespace System.CommandLine.Suggest
{
@@ -29,7 +28,7 @@ public SuggestionDispatcher(ISuggestionRegistration suggestionRegistration, ISug
};
CompleteScriptCommand.SetAction(context =>
{
- SuggestionShellScriptHandler.Handle(context.Configuration.Output, context.GetValue(shellTypeArgument));
+ SuggestionShellScriptHandler.Handle(context.InvocationConfiguration.Output, context.GetValue(shellTypeArgument));
});
ListCommand = new Command("list")
@@ -38,7 +37,7 @@ public SuggestionDispatcher(ISuggestionRegistration suggestionRegistration, ISug
};
ListCommand.SetAction((ctx, cancellationToken) =>
{
- ctx.Configuration.Output.WriteLine(ShellPrefixesToMatch(_suggestionRegistration));
+ ctx.InvocationConfiguration.Output.WriteLine(ShellPrefixesToMatch(_suggestionRegistration));
return Task.CompletedTask;
});
@@ -59,25 +58,27 @@ public SuggestionDispatcher(ISuggestionRegistration suggestionRegistration, ISug
RegisterCommand.SetAction((context, cancellationToken) =>
{
- Register(context.GetValue(commandPathOption), context.Configuration.Output);
+ Register(context.GetValue(commandPathOption), context.InvocationConfiguration.Output);
return Task.CompletedTask;
});
- var root = new RootCommand
+ RootCommand = new RootCommand
{
ListCommand,
GetCommand,
RegisterCommand,
CompleteScriptCommand,
};
- root.TreatUnmatchedTokensAsErrors = false;
- Configuration = new CommandLineConfiguration(root);
+ RootCommand.TreatUnmatchedTokensAsErrors = false;
+ Configuration = new InvocationConfiguration();
}
private Command CompleteScriptCommand { get; }
private Command GetCommand { get; }
+ public RootCommand RootCommand { get; }
+
private Option ExecutableOption { get; } = GetExecutableOption();
private static Option GetExecutableOption()
@@ -98,11 +99,11 @@ private static Option GetExecutableOption()
private Command RegisterCommand { get; }
- public CommandLineConfiguration Configuration { get; }
+ public InvocationConfiguration Configuration { get; }
public TimeSpan Timeout { get; set; } = TimeSpan.FromMilliseconds(5000);
- public Task InvokeAsync(string[] args) => Configuration.InvokeAsync(args);
+ public Task InvokeAsync(string[] args) => RootCommand.Parse(args).InvokeAsync(Configuration);
private void Register(
string commandPath,
@@ -168,7 +169,7 @@ private Task Get(ParseResult parseResult, CancellationToken cancellationTok
Program.LogDebug($"dotnet-suggest returning: \"{completions.Replace("\r", "\\r").Replace("\n", "\\n")}\"");
#endif
- parseResult.Configuration.Output.Write(completions);
+ parseResult.InvocationConfiguration.Output.Write(completions);
return Task.FromResult(0);
}
diff --git a/src/System.CommandLine.Tests/Binding/TestModels.cs b/src/System.CommandLine.Tests/Binding/TestModels.cs
index 49cd584e22..972f5eb8a2 100644
--- a/src/System.CommandLine.Tests/Binding/TestModels.cs
+++ b/src/System.CommandLine.Tests/Binding/TestModels.cs
@@ -71,7 +71,7 @@ public class ClassWithMethodHavingParameter
public ClassWithMethodHavingParameter(ParseResult parseResult)
{
- _output = parseResult.Configuration.Output;
+ _output = parseResult.InvocationConfiguration.Output;
}
public int Handle(T value)
diff --git a/src/System.CommandLine.Tests/CommandLineConfigurationTests.cs b/src/System.CommandLine.Tests/CommandLineConfigurationTests.cs
deleted file mode 100644
index c0587785ea..0000000000
--- a/src/System.CommandLine.Tests/CommandLineConfigurationTests.cs
+++ /dev/null
@@ -1,296 +0,0 @@
-// Copyright (c) .NET Foundation and contributors. All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-
-using FluentAssertions;
-using Xunit;
-
-namespace System.CommandLine.Tests;
-
-public class CommandLineConfigurationTests
-{
- [Fact]
- public void ThrowIfInvalid_throws_if_there_are_duplicate_sibling_option_aliases_on_the_root_command()
- {
- var option1 = new Option("--dupe");
- var option2 = new Option("-y");
- option2.Aliases.Add("--dupe");
-
- var command = new RootCommand
- {
- option1,
- option2
- };
-
- var config = new CommandLineConfiguration(command);
-
- var validate = () => config.ThrowIfInvalid();
-
- validate.Should()
- .Throw()
- .Which
- .Message
- .Should()
- .Be($"Duplicate alias '--dupe' found on command '{command.Name}'.");
- }
-
- [Fact]
- public void ThrowIfInvalid_throws_if_there_are_duplicate_sibling_option_aliases_on_a_subcommand()
- {
- var option1 = new Option("--dupe");
- var option2 = new Option("--ok");
- option2.Aliases.Add("--dupe");
-
- var command = new RootCommand
- {
- new Command("subcommand")
- {
- option1,
- option2
- }
- };
-
- var config = new CommandLineConfiguration(command);
-
- var validate = () => config.ThrowIfInvalid();
-
- validate.Should()
- .Throw()
- .Which
- .Message
- .Should()
- .Be("Duplicate alias '--dupe' found on command 'subcommand'.");
- }
-
- [Fact]
- public void ThrowIfInvalid_throws_if_there_are_duplicate_sibling_subcommand_aliases_on_the_root_command()
- {
- var command1 = new Command("dupe");
- var command2 = new Command("not-a-dupe");
- command2.Aliases.Add("dupe");
-
- var rootCommand = new RootCommand
- {
- command1,
- command2
- };
-
- var config = new CommandLineConfiguration(rootCommand);
-
- var validate = () => config.ThrowIfInvalid();
-
- validate.Should()
- .Throw()
- .Which
- .Message
- .Should()
- .Be($"Duplicate alias 'dupe' found on command '{rootCommand.Name}'.");
- }
-
- [Fact]
- public void ThrowIfInvalid_throws_if_there_are_duplicate_sibling_subcommand_aliases_on_a_subcommand()
- {
- var command = new RootCommand
- {
- new Command("subcommand")
- {
- new Command("dupe"),
- new Command("not-a-dupe") { Aliases = { "dupe" } }
- }
- };
-
- var config = new CommandLineConfiguration(command);
-
- var validate = () => config.ThrowIfInvalid();
-
- validate.Should()
- .Throw()
- .Which
- .Message
- .Should()
- .Be("Duplicate alias 'dupe' found on command 'subcommand'.");
- }
-
- [Fact]
- public void ThrowIfInvalid_throws_if_sibling_command_and_option_aliases_collide_on_the_root_command()
- {
- var option = new Option("dupe");
- var command = new Command("not-a-dupe");
- command.Aliases.Add("dupe");
-
- var rootCommand = new RootCommand
- {
- option,
- command
- };
-
- var config = new CommandLineConfiguration(rootCommand);
-
- var validate = () => config.ThrowIfInvalid();
-
- validate.Should()
- .Throw()
- .Which
- .Message
- .Should()
- .Be($"Duplicate alias 'dupe' found on command '{rootCommand.Name}'.");
- }
-
- [Fact]
- public void ThrowIfInvalid_throws_if_sibling_command_and_option_aliases_collide_on_a_subcommand()
- {
- var option = new Option("dupe");
- var command = new Command("not-a-dupe");
- command.Aliases.Add("dupe");
-
- var rootCommand = new RootCommand
- {
- new Command("subcommand")
- {
- option,
- command
- }
- };
-
- var config = new CommandLineConfiguration(rootCommand);
-
- var validate = () => config.ThrowIfInvalid();
-
- validate.Should()
- .Throw()
- .Which
- .Message
- .Should()
- .Be("Duplicate alias 'dupe' found on command 'subcommand'.");
- }
-
- [Fact]
- public void ThrowIfInvalid_throws_if_there_are_duplicate_sibling_global_option_aliases_on_the_root_command()
- {
- var option1 = new Option("--dupe") { Recursive = true };
- var option2 = new Option("-y") { Recursive = true };
- option2.Aliases.Add("--dupe");
-
- var command = new RootCommand();
- command.Options.Add(option1);
- command.Options.Add(option2);
-
- var config = new CommandLineConfiguration(command);
-
- var validate = () => config.ThrowIfInvalid();
-
- validate.Should()
- .Throw()
- .Which
- .Message
- .Should()
- .Be($"Duplicate alias '--dupe' found on command '{command.Name}'.");
- }
-
- [Fact]
- public void ThrowIfInvalid_does_not_throw_if_global_option_alias_is_the_same_as_local_option_alias()
- {
- var rootCommand = new RootCommand
- {
- new Command("subcommand")
- {
- new Option("--dupe")
- }
- };
- rootCommand.Options.Add(new Option("--dupe") { Recursive = true });
-
- var config = new CommandLineConfiguration(rootCommand);
-
- var validate = () => config.ThrowIfInvalid();
-
- validate.Should().NotThrow();
- }
-
- [Fact]
- public void ThrowIfInvalid_does_not_throw_if_global_option_alias_is_the_same_as_subcommand_alias()
- {
- var rootCommand = new RootCommand
- {
- new Command("subcommand")
- {
- new Command("--dupe")
- }
- };
- rootCommand.Options.Add(new Option("--dupe") { Recursive = true });
-
- var config = new CommandLineConfiguration(rootCommand);
-
- var validate = () => config.ThrowIfInvalid();
-
- validate.Should().NotThrow();
- }
-
- [Fact]
- public void ThrowIfInvalid_throws_if_a_command_is_its_own_parent()
- {
- var command = new RootCommand();
- command.Add(command);
-
- var config = new CommandLineConfiguration(command);
-
- var validate = () => config.ThrowIfInvalid();
-
- validate.Should()
- .Throw()
- .Which
- .Message
- .Should()
- .Be($"Cycle detected in command tree. Command '{command.Name}' is its own ancestor.");
- }
-
- [Fact]
- public void ThrowIfInvalid_throws_if_a_parentage_cycle_is_detected()
- {
- var command = new Command("command");
- var rootCommand = new RootCommand { command };
- command.Add(rootCommand);
-
- var config = new CommandLineConfiguration(rootCommand);
-
- var validate = () => config.ThrowIfInvalid();
-
- validate.Should()
- .Throw()
- .Which
- .Message
- .Should()
- .Be($"Cycle detected in command tree. Command '{rootCommand.Name}' is its own ancestor.");
- }
-
- [Fact]
- public void It_can_be_subclassed_to_provide_additional_context()
- {
- var command = new RootCommand();
- var commandWasInvoked = false;
- command.SetAction(parseResult =>
- {
- var appConfig = (CustomAppConfiguration)parseResult.Configuration;
-
- // access custom config
-
- commandWasInvoked = true;
-
- return 0;
- });
-
- var config = new CustomAppConfiguration(command);
-
- config.Invoke("");
-
- commandWasInvoked.Should().BeTrue();
- }
-}
-
-public class CustomAppConfiguration : CommandLineConfiguration
-{
- public CustomAppConfiguration(RootCommand command) : base(command)
- {
- EnableDefaultExceptionHandler = false;
- }
-
- public IServiceProvider ServiceProvider { get; }
-}
\ No newline at end of file
diff --git a/src/System.CommandLine.Tests/CompletionTests.cs b/src/System.CommandLine.Tests/CompletionTests.cs
index 84d931f863..4d902ff07a 100644
--- a/src/System.CommandLine.Tests/CompletionTests.cs
+++ b/src/System.CommandLine.Tests/CompletionTests.cs
@@ -185,8 +185,8 @@ public void Command_GetCompletions_with_text_to_match_orders_by_match_position_t
new Command("andmyothersubcommand"),
};
- CommandLineConfiguration simpleConfig = new (command);
- var completions = command.Parse("my", simpleConfig).GetCompletions();
+
+ var completions = command.Parse("my").GetCompletions();
completions
.Select(item => item.Label)
@@ -204,8 +204,8 @@ public void When_an_option_has_a_default_value_it_will_still_be_suggested()
new Option("--cherry")
};
- CommandLineConfiguration simpleConfig = new (command);
- var result = command.Parse("", simpleConfig);
+
+ var result = command.Parse("");
_output.WriteLine(result.ToString());
@@ -235,8 +235,7 @@ public void Command_GetCompletions_can_access_ParseResult()
cloneOption
};
- CommandLineConfiguration simpleConfig = new (rootCommand);
- var result = rootCommand.Parse("--origin test --clone ", simpleConfig);
+ var result = rootCommand.Parse("--origin test --clone ");
_output.WriteLine(result.ToString());
@@ -278,8 +277,8 @@ public void When_one_option_has_been_specified_then_it_and_its_siblings_will_sti
};
var commandLine = "--apple grannysmith";
- CommandLineConfiguration simpleConfig = new (command);
- var result = command.Parse(commandLine, simpleConfig);
+
+ var result = command.Parse(commandLine);
result.GetCompletions(commandLine.Length + 1)
.Select(item => item.Label)
@@ -306,9 +305,8 @@ public void When_a_subcommand_has_been_specified_then_its_sibling_commands_will_
new Option("--rainier")
}
};
- CommandLineConfiguration simpleConfig = new (rootCommand);
- var result = rootCommand.Parse("cherry ", simpleConfig);
+ var result = rootCommand.Parse("cherry ");
result.GetCompletions()
.Select(item => item.Label)
@@ -336,9 +334,8 @@ public void When_a_subcommand_has_been_specified_then_its_sibling_commands_alias
apple,
banana
};
- CommandLineConfiguration simpleConfig = new (rootCommand);
- var result = rootCommand.Parse("banana ", simpleConfig);
+ var result = rootCommand.Parse("banana ");
result.GetCompletions()
.Select(item => item.Label)
@@ -356,8 +353,8 @@ public void When_a_subcommand_has_been_specified_then_its_sibling_options_will_n
};
var commandLine = "child";
- CommandLineConfiguration simpleConfig = new (command);
- var parseResult = command.Parse(commandLine, simpleConfig);
+
+ var parseResult = command.Parse(commandLine);
parseResult
.GetCompletions(commandLine.Length + 1)
@@ -377,8 +374,8 @@ public void When_a_subcommand_has_been_specified_then_its_sibling_options_with_a
};
var commandLine = "--parent-option 123 child";
- CommandLineConfiguration simpleConfig = new (command);
- var parseResult = command.Parse(commandLine, simpleConfig);
+
+ var parseResult = command.Parse(commandLine);
parseResult
.GetCompletions(commandLine.Length + 1)
@@ -400,8 +397,8 @@ public void When_a_subcommand_has_been_specified_then_its_child_options_will_be_
};
var commandLine = "child ";
- CommandLineConfiguration simpleConfig = new (command);
- var parseResult = command.Parse(commandLine, simpleConfig);
+
+ var parseResult = command.Parse(commandLine);
parseResult
.GetCompletions(commandLine.Length + 1)
@@ -430,8 +427,8 @@ public void When_a_subcommand_with_subcommands_has_been_specified_then_its_sibli
};
var commandLine = "cherry";
- CommandLineConfiguration simpleConfig = new (rootCommand);
- var result = rootCommand.Parse(commandLine, simpleConfig);
+
+ var result = rootCommand.Parse(commandLine);
result.GetCompletions(commandLine.Length + 1)
.Select(item => item.Label)
@@ -450,8 +447,8 @@ public void When_one_option_has_been_partially_specified_then_nonmatching_siblin
};
var input = "a";
- CommandLineConfiguration simpleConfig = new (command);
- var result = command.Parse(input, simpleConfig);
+
+ var result = command.Parse(input);
result.GetCompletions(input.Length)
.Select(item => item.Label)
@@ -472,8 +469,7 @@ public void An_option_can_be_hidden_from_completions_by_setting_IsHidden_to_true
new Option("-n") { Description = "Not hidden" }
};
- CommandLineConfiguration simpleConfig = new (command);
- var completions = command.Parse("the-command ", simpleConfig).GetCompletions();
+ var completions = command.Parse("the-command ").GetCompletions();
completions.Select(item => item.Label).Should().NotContain("--hide-me");
}
@@ -488,8 +484,8 @@ public void Parser_options_can_supply_context_sensitive_matches()
};
var commandLine = "--bread";
- CommandLineConfiguration simpleConfig = new (command);
- var result = command.Parse(commandLine, simpleConfig);
+
+ var result = command.Parse(commandLine);
result.GetCompletions(commandLine.Length + 1)
.Select(item => item.Label)
@@ -497,7 +493,7 @@ public void Parser_options_can_supply_context_sensitive_matches()
.BeEquivalentTo("rye", "sourdough", "wheat");
commandLine = "--bread wheat --cheese ";
- result = command.Parse(commandLine, simpleConfig);
+ result = command.Parse(commandLine);
result.GetCompletions(commandLine.Length + 1)
.Select(item => item.Label)
@@ -516,8 +512,8 @@ public void Subcommand_names_are_available_as_suggestions()
};
var commandLine = "test";
- CommandLineConfiguration simpleConfig = new (command);
- command.Parse(commandLine, simpleConfig)
+
+ command.Parse(commandLine)
.GetCompletions(commandLine.Length + 1)
.Select(item => item.Label)
.Should()
@@ -535,8 +531,8 @@ public void Both_subcommands_and_options_are_available_as_suggestions()
};
var commandLine = "test";
- CommandLineConfiguration simpleConfig = new (command);
- command.Parse(commandLine, simpleConfig)
+
+ command.Parse(commandLine)
.GetCompletions(commandLine.Length + 1)
.Select(item => item.Label)
.Should()
@@ -555,8 +551,8 @@ public void Option_GetCompletions_are_not_provided_without_matching_prefix(strin
new Option("--three")
};
- CommandLineConfiguration simpleConfig = new (command);
- ParseResult result = command.Parse(input, simpleConfig);
+
+ ParseResult result = command.Parse(input);
result.GetCompletions()
.Select(item => item.Label)
.Should()
@@ -574,8 +570,8 @@ public void Option_GetCompletions_can_be_based_on_the_proximate_option()
};
var commandLine = "outer";
- CommandLineConfiguration simpleConfig = new (outer);
- ParseResult result = outer.Parse(commandLine, simpleConfig);
+
+ ParseResult result = outer.Parse(commandLine);
result.GetCompletions(commandLine.Length + 1)
.Select(item => item.Label)
@@ -593,8 +589,8 @@ public void Argument_completions_can_be_based_on_the_proximate_option()
};
var commandLine = "outer --two";
- CommandLineConfiguration simpleConfig = new (outer);
- ParseResult result = outer.Parse(commandLine, simpleConfig);
+
+ ParseResult result = outer.Parse(commandLine);
result.GetCompletions(commandLine.Length + 1)
.Select(item => item.Label)
@@ -612,8 +608,7 @@ public void Option_GetCompletions_can_be_based_on_the_proximate_option_and_parti
new Command("three", "Command three")
};
- CommandLineConfiguration simpleConfig = new (outer);
- ParseResult result = outer.Parse("outer o", simpleConfig);
+ ParseResult result = outer.Parse("outer o");
result.GetCompletions()
.Select(item => item.Label)
@@ -632,15 +627,15 @@ public void Completions_can_be_provided_in_the_absence_of_validation()
option
};
- CommandLineConfiguration simpleConfig = new (command);
- command.Parse("the-command -t m", simpleConfig)
+
+ command.Parse("the-command -t m")
.GetCompletions()
.Select(item => item.Label)
.Should()
.BeEquivalentTo("animal",
"mineral");
- command.Parse("the-command -t something-else", simpleConfig)
+ command.Parse("the-command -t something-else")
.Errors
.Should()
.BeEmpty();
@@ -697,9 +692,7 @@ public void When_caller_does_the_tokenizing_then_argument_completions_are_based_
CreateOptionWithAcceptOnlyFromAmong(name: "three", "three-a", "three-b", "three-c")
};
- var configuration = new CommandLineConfiguration(command);
-
- var result = command.Parse("outer two b", configuration);
+ var result = command.Parse("outer two b");
result.GetCompletions()
.Select(item => item.Label)
@@ -788,8 +781,8 @@ public void When_parsing_from_text_if_the_proximate_option_is_completed_then_com
CreateOptionWithAcceptOnlyFromAmong(name: "--language", "C#"),
new Option("--langVersion")
};
- var configuration = new CommandLineConfiguration(command);
- var completions = command.Parse("--framework net8.0 --l", configuration).GetCompletions();
+
+ var completions = command.Parse("--framework net8.0 --l").GetCompletions();
completions.Select(item => item.Label)
.Should()
@@ -805,8 +798,8 @@ public void When_parsing_from_array_if_the_proximate_option_is_completed_then_co
CreateOptionWithAcceptOnlyFromAmong(name: "--language", "C#"),
new Option("--langVersion")
};
- var configuration = new CommandLineConfiguration(command);
- var completions = command.Parse(new[]{"--framework","net8.0","--l"}, configuration).GetCompletions();
+
+ var completions = command.Parse(new[]{"--framework","net8.0","--l"}).GetCompletions();
completions.Select(item => item.Label)
.Should()
@@ -840,8 +833,8 @@ public void Options_that_have_been_specified_to_their_maximum_arity_are_not_sugg
};
var commandLine = "--allows-one x";
- CommandLineConfiguration simpleConfig = new (command);
- var completions = command.Parse(commandLine, simpleConfig).GetCompletions(commandLine.Length + 1);
+
+ var completions = command.Parse(commandLine).GetCompletions(commandLine.Length + 1);
completions.Select(item => item.Label)
.Should()
@@ -851,13 +844,13 @@ public void Options_that_have_been_specified_to_their_maximum_arity_are_not_sugg
[Fact]
public void When_current_symbol_is_an_option_that_requires_arguments_then_parent_symbol_completions_are_omitted()
{
- var configuration = new CommandLineConfiguration(new RootCommand
- {
- new Option("--allows-one"),
- new Option("--allows-many")
- });
+ var rootCommand = new RootCommand
+ {
+ new Option("--allows-one"),
+ new Option("--allows-many")
+ };
- var completions = configuration.Parse("--allows-one ").GetCompletions();
+ var completions = rootCommand.Parse("--allows-one ").GetCompletions();
completions.Should().BeEmpty();
}
@@ -918,8 +911,8 @@ public void Default_completions_can_be_cleared_and_replaced()
{
argument
};
- CommandLineConfiguration simpleConfig = new (command);
- var completions = command.Parse("the-command s", simpleConfig)
+
+ var completions = command.Parse("the-command s")
.GetCompletions();
completions.Select(item => item.Label)
@@ -938,8 +931,8 @@ public void Default_completions_can_be_appended_to()
}
};
- CommandLineConfiguration simpleConfig = new (command);
- var completions = command.Parse("the-command s", simpleConfig)
+
+ var completions = command.Parse("the-command s")
.GetCompletions();
completions
@@ -991,9 +984,8 @@ public void When_option_completions_are_available_then_they_are_suggested_when_a
{
Option option = new ("--day");
RootCommand rootCommand = new () { option };
- CommandLineConfiguration simpleConfig = new (rootCommand);
- var result = rootCommand.Parse("--day SleepyDay", simpleConfig);
+ var result = rootCommand.Parse("--day SleepyDay");
result.Errors
.Should()
diff --git a/src/System.CommandLine.Tests/CustomParsingTests.cs b/src/System.CommandLine.Tests/CustomParsingTests.cs
index fe706a04cb..7a1d14936d 100644
--- a/src/System.CommandLine.Tests/CustomParsingTests.cs
+++ b/src/System.CommandLine.Tests/CustomParsingTests.cs
@@ -220,8 +220,7 @@ public void Option_ArgumentResult_Parent_is_set_correctly_when_token_is_implicit
}
};
- CommandLineConfiguration simpleConfig = new (command);
- command.Parse("", simpleConfig);
+ command.Parse("");
argumentResult
.Parent
diff --git a/src/System.CommandLine.Tests/DirectiveTests.cs b/src/System.CommandLine.Tests/DirectiveTests.cs
index 9d2851726d..d4a70847b4 100644
--- a/src/System.CommandLine.Tests/DirectiveTests.cs
+++ b/src/System.CommandLine.Tests/DirectiveTests.cs
@@ -49,11 +49,11 @@ public void Multiple_directives_are_allowed()
RootCommand root = new() { new Option("-y") };
Directive parseDirective = new ("parse");
Directive suggestDirective = new ("suggest");
- CommandLineConfiguration config = new(root);
+
root.Add(parseDirective);
root.Add(suggestDirective);
- var result = root.Parse("[parse] [suggest] -y", config);
+ var result = root.Parse("[parse] [suggest] -y");
result.GetResult(parseDirective).Should().NotBeNull();
result.GetResult(suggestDirective).Should().NotBeNull();
@@ -77,21 +77,21 @@ public async Task Multiple_instances_of_the_same_directive_can_be_invoked(bool i
: new SynchronousTestAction(incrementCallCount, terminating: false)
};
- var config = new CommandLineConfiguration(new RootCommand
+ var rootCommand = new RootCommand
{
Action = invokeAsync
? new AsynchronousTestAction(verifyActionWasCalled, terminating: false)
: new SynchronousTestAction(verifyActionWasCalled, terminating: false),
Directives = { testDirective }
- });
+ };
if (invokeAsync)
{
- await config.InvokeAsync("[test:1] [test:2]");
+ await rootCommand.Parse("[test:1] [test:2]").InvokeAsync();
}
else
{
- config.Invoke("[test:1] [test:2]");
+ rootCommand.Parse("[test:1] [test:2]").Invoke();
}
using var _ = new AssertionScope();
@@ -117,18 +117,19 @@ public async Task Multiple_different_directives_can_be_invoked(bool invokeAsync)
{
Action = new SynchronousTestAction(_ => directiveTwoActionWasCalled = true, terminating: false)
};
- var config = new CommandLineConfiguration(new RootCommand
+
+ var rootCommand = new RootCommand
{
Action = new SynchronousTestAction(_ => commandActionWasCalled = true, terminating: false), Directives = { directiveOne, directiveTwo }
- });
+ };
if (invokeAsync)
{
- await config.InvokeAsync("[one] [two]");
+ await rootCommand.Parse("[one] [two]").InvokeAsync();
}
else
{
- config.Invoke("[one] [two]");
+ rootCommand.Parse("[one] [two]").Invoke();
}
using var _ = new AssertionScope();
@@ -213,10 +214,10 @@ public void When_a_directive_is_specified_more_than_once_then_its_values_are_agg
private static ParseResult Parse(Option option, Directive directive, string commandLine)
{
RootCommand root = new() { option };
- CommandLineConfiguration config = new(root);
+
root.Directives.Add(directive);
- return root.Parse(commandLine, config);
+ return root.Parse(commandLine);
}
}
}
\ No newline at end of file
diff --git a/src/System.CommandLine.Tests/EnvironmentVariableDirectiveTests.cs b/src/System.CommandLine.Tests/EnvironmentVariableDirectiveTests.cs
index 47ee79f8ce..218cd3a8e0 100644
--- a/src/System.CommandLine.Tests/EnvironmentVariableDirectiveTests.cs
+++ b/src/System.CommandLine.Tests/EnvironmentVariableDirectiveTests.cs
@@ -1,4 +1,5 @@
-using System.CommandLine.Help;
+using System.Collections;
+using System.CommandLine.Help;
using System.CommandLine.Invocation;
using FluentAssertions;
using System.Linq;
@@ -28,12 +29,12 @@ public async Task Sets_environment_variable_to_value()
Environment.GetEnvironmentVariable(_testVariableName).Should().Be(value);
});
- var config = new CommandLineConfiguration(rootCommand)
+ var config = new InvocationConfiguration
{
EnableDefaultExceptionHandler = false
};
- await config.InvokeAsync($"[env:{_testVariableName}={value}]");
+ await rootCommand.Parse($"[env:{_testVariableName}={value}]").InvokeAsync(config);
asserted.Should().BeTrue();
}
@@ -53,12 +54,12 @@ public async Task Sets_environment_variable_value_containing_equals_sign()
Environment.GetEnvironmentVariable(_testVariableName).Should().Be(value);
});
- var config = new CommandLineConfiguration(rootCommand)
+ var config = new InvocationConfiguration
{
EnableDefaultExceptionHandler = false
};
- await config.InvokeAsync($"[env:{_testVariableName}={value}]" );
+ await rootCommand.Parse($"[env:{_testVariableName}={value}]" ).InvokeAsync(config);
asserted.Should().BeTrue();
}
@@ -78,12 +79,12 @@ public async Task Ignores_environment_directive_without_equals_sign()
Environment.GetEnvironmentVariable(variable).Should().BeNull();
});
- var config = new CommandLineConfiguration(rootCommand)
+ var config = new InvocationConfiguration
{
EnableDefaultExceptionHandler = false
};
- await config.InvokeAsync( $"[env:{variable}]" );
+ await rootCommand.Parse( $"[env:{variable}]" ).InvokeAsync(config);
asserted.Should().BeTrue();
}
@@ -97,23 +98,20 @@ public static async Task Ignores_environment_directive_with_empty_variable_name(
{
new EnvironmentVariablesDirective()
};
+
+ IDictionary env = null;
rootCommand.SetAction(_ =>
{
asserted = true;
- var env = Environment.GetEnvironmentVariables();
- env.Values.Cast().Should().NotContain(value);
+ env = Environment.GetEnvironmentVariables();
});
- var config = new CommandLineConfiguration(rootCommand)
- {
- EnableDefaultExceptionHandler = false
- };
-
- var result = config.Parse($"[env:={value}]");
+ var result = rootCommand.Parse($"[env:={value}]");
await result.InvokeAsync();
asserted.Should().BeTrue();
+ env.Values.Cast().Should().NotContain(value);
}
[Fact]
@@ -125,10 +123,9 @@ public void It_does_not_prevent_help_from_being_invoked()
var customHelpAction = new CustomHelpAction();
root.Options.OfType().Single().Action = customHelpAction;
- var config = new CommandLineConfiguration(root);
root.Directives.Add(new EnvironmentVariablesDirective());
- root.Parse($"[env:{_testVariableName}=1] -h", config).Invoke();
+ root.Parse($"[env:{_testVariableName}=1] -h").Invoke();
customHelpAction.WasCalled.Should().BeTrue();
Environment.GetEnvironmentVariable(_testVariableName).Should().Be("1");
diff --git a/src/System.CommandLine.Tests/Help/CustomHelpAction.cs b/src/System.CommandLine.Tests/Help/CustomHelpAction.cs
index cac66dc599..e24e22c729 100644
--- a/src/System.CommandLine.Tests/Help/CustomHelpAction.cs
+++ b/src/System.CommandLine.Tests/Help/CustomHelpAction.cs
@@ -1,4 +1,7 @@
-using System.CommandLine.Invocation;
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using System.CommandLine.Invocation;
namespace System.CommandLine.Help
{
@@ -21,7 +24,7 @@ internal HelpBuilder Builder
///
public override int Invoke(ParseResult parseResult)
{
- var output = parseResult.Configuration.Output;
+ var output = parseResult.InvocationConfiguration.Output;
var helpContext = new HelpContext(Builder,
parseResult.CommandResult.Command,
diff --git a/src/System.CommandLine.Tests/Help/HelpBuilderTests.Customization.cs b/src/System.CommandLine.Tests/Help/HelpBuilderTests.Customization.cs
index 22cced02a0..703f33d221 100644
--- a/src/System.CommandLine.Tests/Help/HelpBuilderTests.Customization.cs
+++ b/src/System.CommandLine.Tests/Help/HelpBuilderTests.Customization.cs
@@ -1,11 +1,12 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+using FluentAssertions;
+using Microsoft.VisualStudio.TestPlatform.Utilities;
using System.Collections.Generic;
using System.CommandLine.Help;
using System.IO;
using System.Linq;
-using FluentAssertions;
using Xunit;
using static System.Environment;
@@ -92,26 +93,22 @@ public void Option_can_customize_first_column_text_based_on_parse_result()
ctx.Command.Equals(commandA)
? optionAFirstColumnText
: optionBFirstColumnText);
- command.Options.Add(new HelpOption()
+ command.Options.Add(new HelpOption
{
- Action = new CustomHelpAction()
+ Action = new CustomHelpAction
{
Builder = helpBuilder
}
});
- var console = new StringWriter();
- var config = new CommandLineConfiguration(command)
- {
- Output = console
- };
- command.Parse("root a -h", config).Invoke();
- console.ToString().Should().Contain(optionAFirstColumnText);
+ var output = new StringWriter();
+
+ command.Parse("root a -h").Invoke(new() { Output = output });
+ output.ToString().Should().Contain(optionAFirstColumnText);
- console = new StringWriter();
- config.Output = console;
- command.Parse("root b -h", config).Invoke();
- console.ToString().Should().Contain(optionBFirstColumnText);
+ output = new StringWriter();
+ command.Parse("root b -h").Invoke(new() { Output = output });
+ output.ToString().Should().Contain(optionBFirstColumnText);
}
[Fact]
@@ -146,17 +143,14 @@ public void Option_can_customize_second_column_text_based_on_parse_result()
}
});
- var config = new CommandLineConfiguration(command)
- {
- Output = new StringWriter()
- };
+ var output = new StringWriter();
- config.Invoke("root a -h");
- config.Output.ToString().Should().Contain($"option {optionADescription}");
+ command.Parse("root a -h").Invoke(new(){Output=output});
+ output.ToString().Should().Contain($"option {optionADescription}");
- config.Output = new StringWriter();
- config.Invoke("root b -h");
- config.Output.ToString().Should().Contain($"option {optionBDescription}");
+ output = new StringWriter();
+ command.Parse("root b -h").Invoke(new(){Output=output});
+ output.ToString().Should().Contain($"option {optionBDescription}");
}
[Fact]
@@ -275,11 +269,9 @@ public void Option_can_fallback_to_default_when_customizing(bool conditionA, boo
}
});
- CommandLineConfiguration config = new (command);
- var console = new StringWriter();
- config.Output = console;
- command.Parse("test -h", config).Invoke();
- console.ToString().Should().MatchRegex(expected);
+ var output = new StringWriter();
+ command.Parse("test -h").Invoke(new() { Output = output });
+ output.ToString().Should().MatchRegex(expected);
}
[Theory]
@@ -312,9 +304,6 @@ public void Argument_can_fallback_to_default_when_customizing(
secondColumnText: ctx => conditionB ? "custom 2nd" : HelpBuilder.Default.GetArgumentDescription(argument),
defaultValue: ctx => conditionC ? "custom def" : HelpBuilder.Default.GetArgumentDefaultValue(argument));
-
- CommandLineConfiguration config = new (command);
-
command.Options.Add(new HelpOption
{
Action = new CustomHelpAction
@@ -323,9 +312,9 @@ public void Argument_can_fallback_to_default_when_customizing(
}
});
- config.Output = new StringWriter();
- command.Parse("test -h", config).Invoke();
- config.Output.ToString().Should().MatchRegex(expected);
+ var output = new StringWriter();
+ command.Parse("test -h").Invoke(new() { Output = output });
+ output.ToString().Should().MatchRegex(expected);
}
[Fact]
@@ -351,17 +340,13 @@ public void Individual_symbols_can_be_customized()
}
};
- CommandLineConfiguration config = new(rootCommand)
- {
- Output = new StringWriter()
- };
+ var output = new StringWriter();
- ParseResult parseResult = rootCommand.Parse("-h", config);
+ ParseResult parseResult = rootCommand.Parse("-h");
- parseResult.Invoke();
+ parseResult.Invoke(new() { Output = output });
- config.Output
- .ToString()
+ output.ToString()
.Should()
.ContainAll("The custom command description",
"The custom option description",
@@ -374,16 +359,16 @@ public void Help_sections_can_be_replaced()
CustomHelpAction helpAction = new();
helpAction.Builder.CustomizeLayout(CustomLayout);
- CommandLineConfiguration config = new(new Command("name") { new HelpOption() { Action = helpAction} })
+ var command = new Command("name")
{
- Output = new StringWriter()
+ new HelpOption { Action = helpAction }
};
- ParseResult parseResult = config.Parse("-h");
+ var output = new StringWriter();
- parseResult.Invoke();
+ command.Parse("-h").Invoke(new() { Output = output });
- config.Output.ToString().Should().Be($"one{NewLine}{NewLine}two{NewLine}{NewLine}three{NewLine}{NewLine}");
+ output.ToString().Should().Be($"one{NewLine}{NewLine}two{NewLine}{NewLine}three{NewLine}{NewLine}");
IEnumerable> CustomLayout(HelpContext _)
{
@@ -399,22 +384,18 @@ public void Help_sections_can_be_supplemented()
CustomHelpAction helpAction = new();
helpAction.Builder.CustomizeLayout(CustomLayout);
- CommandLineConfiguration config = new(new Command("hello") { new HelpOption() { Action = helpAction } })
+ var command = new Command("hello")
{
- Output = new StringWriter(),
+ new HelpOption { Action = helpAction }
};
var defaultHelp = GetDefaultHelp(new Command("hello"));
- ParseResult parseResult = config.Parse("-h");
-
- parseResult.Invoke();
-
- var output = config.Output.ToString();
+ var output = new StringWriter();
- var expected = $"first{NewLine}{NewLine}{defaultHelp}{NewLine}last{NewLine}{NewLine}";
+ command.Parse("-h").Invoke(new() { Output = output });
- output.Should().Be(expected);
+ output.ToString().Should().Be($"first{NewLine}{NewLine}{defaultHelp}{NewLine}last{NewLine}{NewLine}");
IEnumerable> CustomLayout(HelpContext _)
{
@@ -446,7 +427,6 @@ public void Layout_can_be_composed_dynamically_based_on_context()
Builder = helpBuilder
};
- var config = new CommandLineConfiguration(command);
helpBuilder.CustomizeLayout(c =>
c.Command == commandWithTypicalHelp
? HelpBuilder.Default.GetLayout()
@@ -454,12 +434,10 @@ public void Layout_can_be_composed_dynamically_based_on_context()
.Concat(HelpBuilder.Default.GetLayout()));
var typicalOutput = new StringWriter();
- config.Output = typicalOutput;
- command.Parse("typical -h", config).Invoke();
+ command.Parse("typical -h").Invoke(new() { Output = typicalOutput });
var customOutput = new StringWriter();
- config.Output = customOutput;
- command.Parse("custom -h", config).Invoke();
+ command.Parse("custom -h").Invoke(new() { Output = customOutput });
typicalOutput.ToString().Should().Be(GetDefaultHelp(commandWithTypicalHelp, false));
customOutput.ToString().Should().Be($"Custom layout!{NewLine}{NewLine}{GetDefaultHelp(commandWithCustomHelp, false)}");
@@ -484,15 +462,10 @@ public void Help_default_sections_can_be_wrapped()
}
};
- CommandLineConfiguration config = new(command)
- {
- Output = new StringWriter()
- };
+ var output = new StringWriter();
+ command.Parse("test -h").Invoke(new() { Output = output });
- config.Invoke("test -h");
-
- string result = config.Output.ToString();
- result.Should().Be(
+ output.ToString().Should().Be(
$"Description:{NewLine}{NewLine}" +
$"Usage:{NewLine} test [options]{NewLine}{NewLine}" +
$"Options:{NewLine}" +
@@ -510,16 +483,16 @@ public void Help_customized_sections_can_be_wrapped()
helpAction.Builder = new HelpBuilder(10);
helpAction.Builder.CustomizeLayout(CustomLayout);
- CommandLineConfiguration config = new(new Command("name") { new HelpOption() { Action = helpAction } })
+ var command = new Command("name")
{
- Output = new StringWriter()
+ new HelpOption { Action = helpAction }
};
- ParseResult parseResult = config.Parse("-h");
+ var output = new StringWriter();
- parseResult.Invoke();
+ command.Parse("-h").Invoke(new() { Output = output });
- string result = config.Output.ToString();
+ string result = output.ToString();
result.Should().Be($" 123 123{NewLine} 456 456{NewLine} 78 789{NewLine} 0{NewLine}{NewLine}");
IEnumerable> CustomLayout(HelpContext _)
@@ -544,12 +517,12 @@ private string GetDefaultHelp(Command command, bool trimOneNewline = true)
command.Options.Add(defaultHelp);
}
- CommandLineConfiguration config = new(command)
+ InvocationConfiguration config = new()
{
Output = new StringWriter()
};
- config.Invoke("-h");
+ command.Parse("-h").Invoke(config);
var output = config.Output.ToString();
diff --git a/src/System.CommandLine.Tests/Help/HelpBuilderTests.cs b/src/System.CommandLine.Tests/Help/HelpBuilderTests.cs
index 4a735a4aad..1b41d2b9cb 100644
--- a/src/System.CommandLine.Tests/Help/HelpBuilderTests.cs
+++ b/src/System.CommandLine.Tests/Help/HelpBuilderTests.cs
@@ -1235,9 +1235,9 @@ public void Required_options_are_indicated_when_argument_is_named()
[Fact]
public void Help_option_is_shown_in_help()
{
- var configuration = new CommandLineConfiguration(new RootCommand());
+ var rootCommand = new RootCommand();
- _helpBuilder.Write(configuration.RootCommand, _console);
+ _helpBuilder.Write(rootCommand, _console);
var help = _console.ToString();
diff --git a/src/System.CommandLine.Tests/HelpOptionTests.cs b/src/System.CommandLine.Tests/HelpOptionTests.cs
index 401656ce0c..5a6261a48d 100644
--- a/src/System.CommandLine.Tests/HelpOptionTests.cs
+++ b/src/System.CommandLine.Tests/HelpOptionTests.cs
@@ -2,10 +2,12 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using FluentAssertions;
+using Microsoft.VisualStudio.TestPlatform.Utilities;
using System.CommandLine.Help;
using System.CommandLine.Invocation;
using System.CommandLine.Tests.Utility;
using System.IO;
+using System.Threading;
using System.Threading.Tasks;
using Xunit;
@@ -24,18 +26,14 @@ public async Task Help_option_writes_help_for_the_specified_command()
}
};
- CommandLineConfiguration config = new(command)
- {
- Output = new StringWriter()
- };
-
- var result = command.Parse("command subcommand --help", config);
+ var result = command.Parse("command subcommand --help");
- await result.InvokeAsync();
+ var output = new StringWriter();
+ await result.InvokeAsync(new() { Output = output }, CancellationToken.None);
- config.Output.ToString().Should().Contain($"{RootCommand.ExecutableName} command subcommand [options]");
+ output.ToString().Should().Contain($"{RootCommand.ExecutableName} command subcommand [options]");
}
-
+
[Fact]
public async Task Help_option_interrupts_execution_of_the_specified_command()
{
@@ -45,12 +43,9 @@ public async Task Help_option_interrupts_execution_of_the_specified_command()
subcommand.SetAction(_ => wasCalled = true);
command.Subcommands.Add(subcommand);
- CommandLineConfiguration config = new(command)
- {
- Output = new StringWriter()
- };
+ var output = new StringWriter();
- await command.Parse("command subcommand --help", config).InvokeAsync();
+ await command.Parse("command subcommand --help").InvokeAsync(new() { Output = output }, CancellationToken.None);
wasCalled.Should().BeFalse();
}
@@ -62,17 +57,16 @@ public async Task Help_option_interrupts_execution_of_the_specified_command()
[InlineData("/?")]
public async Task Help_option_accepts_default_values(string value)
{
- CommandLineConfiguration config = new(new Command("command") { new HelpOption() })
+ var command = new Command("command")
{
- Output = new StringWriter()
+ new HelpOption()
};
- StringWriter console = new();
- config.Output = console;
+ StringWriter output = new();
- await config.InvokeAsync($"command {value}");
+ await command.Parse($"command {value}").InvokeAsync(new() { Output = output }, CancellationToken.None);
- console.ToString().Should().ShowHelp();
+ output.ToString().Should().ShowHelp();
}
[Fact]
@@ -80,15 +74,12 @@ public async Task Help_option_does_not_display_when_option_defined_with_same_ali
{
var command = new Command("command");
command.Options.Add(new Option("-h"));
+
+ var output = new StringWriter();
- CommandLineConfiguration config = new(command)
- {
- Output = new StringWriter()
- };
-
- await command.Parse("command -h", config).InvokeAsync();
+ await command.Parse("command -h").InvokeAsync(new() { Output = output }, CancellationToken.None);
- config.Output.ToString().Should().NotShowHelp();
+ output.ToString().Should().NotShowHelp();
}
[Fact]
@@ -156,14 +147,11 @@ public async Task HelpOption_with_custom_aliases_uses_aliases(string helpAlias)
{
new HelpOption("/lost", "--confused")
};
- CommandLineConfiguration config = new(command)
- {
- Output = new StringWriter()
- };
+ var output = new StringWriter();
- await config.InvokeAsync(helpAlias);
+ await command.Parse(helpAlias).InvokeAsync(new() { Output = output }, CancellationToken.None);
- config.Output.ToString().Should().ShowHelp();
+ output.ToString().Should().ShowHelp();
}
[Theory]
@@ -178,14 +166,11 @@ public async Task Help_option_with_custom_aliases_does_not_recognize_default_ali
command.Options.Clear();
command.Options.Add(new HelpOption("--confused"));
- CommandLineConfiguration config = new(command)
- {
- Output = new StringWriter(),
- };
+ var output = new StringWriter();
- await config.InvokeAsync(helpAlias);
+ await command.Parse(helpAlias).InvokeAsync(new() { Output = output }, CancellationToken.None);
- config.Output.ToString().Should().NotContain(helpAlias);
+ output.ToString().Should().NotContain(helpAlias);
}
[Theory]
@@ -208,13 +193,9 @@ public void The_users_can_provide_usage_examples(bool subcommand)
});
TextWriter output = new StringWriter();
- CommandLineConfiguration config = new(rootCommand)
- {
- Output = output
- };
-
- var result = subcommand ? config.Parse("subcommand -h") : config.Parse("-h");
-
+
+ var result = subcommand ? rootCommand.Parse("subcommand -h") : rootCommand.Parse("-h");
+ result.InvocationConfiguration.Output = output;
result.Invoke();
if (subcommand)
@@ -242,13 +223,9 @@ public void The_users_can_print_help_output_of_a_subcommand()
};
rootCommand.Subcommands.Add(subcommand);
- TextWriter output = new StringWriter();
- CommandLineConfiguration config = new(subcommand)
- {
- Output = output
- };
+ var output = new StringWriter();
- subcommand.Parse("--help", config).Invoke();
+ subcommand.Parse("--help").Invoke(new() { Output = output });
output.ToString().Should().Contain(SubcommandDescription);
output.ToString().Should().NotContain(RootDescription);
@@ -271,7 +248,7 @@ public override int Invoke(ParseResult parseResult)
if (parseResult.CommandResult.Command.Name == "subcommand")
{
- var output = parseResult.Configuration.Output;
+ var output = parseResult.InvocationConfiguration.Output;
output.WriteLine(CustomUsageText);
}
diff --git a/src/System.CommandLine.Tests/Invocation/CancelOnProcessTerminationTests.cs b/src/System.CommandLine.Tests/Invocation/CancelOnProcessTerminationTests.cs
index 656bba1424..3197ad3198 100644
--- a/src/System.CommandLine.Tests/Invocation/CancelOnProcessTerminationTests.cs
+++ b/src/System.CommandLine.Tests/Invocation/CancelOnProcessTerminationTests.cs
@@ -56,10 +56,12 @@ private static Task Program(string[] args)
};
command.Action = new CustomCliAction();
- return new CommandLineConfiguration(command)
+ var config = new InvocationConfiguration
{
ProcessTerminationTimeout = TimeSpan.FromSeconds(2)
- }.InvokeAsync(args);
+ };
+
+ return command.Parse(args).InvokeAsync(config);
}
private sealed class CustomCliAction : AsynchronousCommandLineAction
diff --git a/src/System.CommandLine.Tests/Invocation/InvocationTests.cs b/src/System.CommandLine.Tests/Invocation/InvocationTests.cs
index b9cc930bef..0de312a178 100644
--- a/src/System.CommandLine.Tests/Invocation/InvocationTests.cs
+++ b/src/System.CommandLine.Tests/Invocation/InvocationTests.cs
@@ -2,7 +2,6 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.CommandLine.Help;
-using System.CommandLine.Invocation;
using System.CommandLine.Parsing;
using System.IO;
using System.Threading;
@@ -16,7 +15,7 @@ namespace System.CommandLine.Tests.Invocation
public class InvocationTests
{
[Fact]
- public async Task Command_InvokeAsync_enables_help_by_default()
+ public async Task Command_InvokeAsync_displays_help_when_HelpOption_is_present()
{
var command = new Command("the-command")
{
@@ -26,12 +25,8 @@ public async Task Command_InvokeAsync_enables_help_by_default()
command.Description = theHelpText;
StringWriter output = new();
- CommandLineConfiguration config = new(command)
- {
- Output = output
- };
-
- await command.Parse("-h", config).InvokeAsync();
+
+ await command.Parse("-h").InvokeAsync(new() { Output = output }, CancellationToken.None);
output.ToString()
.Should()
@@ -39,7 +34,7 @@ public async Task Command_InvokeAsync_enables_help_by_default()
}
[Fact]
- public void Command_Invoke_enables_help_by_default()
+ public void Command_Invoke_displays_help_when_HelpOption_is_present()
{
var command = new Command("the-command")
{
@@ -49,12 +44,8 @@ public void Command_Invoke_enables_help_by_default()
command.Description = theHelpText;
StringWriter output = new ();
- CommandLineConfiguration config = new(command)
- {
- Output = output
- };
-
- command.Parse("-h", config).Invoke();
+
+ command.Parse("-h").Invoke(new() { Output = output });
output.ToString()
.Should()
@@ -313,7 +304,7 @@ public void Directive_action_takes_precedence_over_option_action()
directive
};
- ParseResult parseResult = command.Parse("[directive] cmd -x", new CommandLineConfiguration(command));
+ ParseResult parseResult = command.Parse("[directive] cmd -x");
using var _ = new AssertionScope();
diff --git a/src/System.CommandLine.Tests/Invocation/TypoCorrectionTests.cs b/src/System.CommandLine.Tests/Invocation/TypoCorrectionTests.cs
index 9a9322dc35..1bac77d500 100644
--- a/src/System.CommandLine.Tests/Invocation/TypoCorrectionTests.cs
+++ b/src/System.CommandLine.Tests/Invocation/TypoCorrectionTests.cs
@@ -1,9 +1,12 @@
-using System.CommandLine.Help;
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using FluentAssertions;
+using Microsoft.VisualStudio.TestPlatform.Utilities;
using System.CommandLine.Invocation;
using System.IO;
-using System.Linq;
+using System.Threading;
using System.Threading.Tasks;
-using FluentAssertions;
using Xunit;
using static System.Environment;
@@ -14,21 +17,18 @@ public class TypoCorrectionTests
[Fact]
public async Task When_option_is_mistyped_it_is_suggested()
{
- RootCommand rootCommand = new ()
+ RootCommand rootCommand = new()
{
new Option("info")
};
- CommandLineConfiguration config = new(rootCommand)
- {
- Output = new StringWriter()
- };
+ var output = new StringWriter();
- var result = rootCommand.Parse("niof", config);
+ var result = rootCommand.Parse("niof");
- await result.InvokeAsync();
+ await result.InvokeAsync(new() { Output = output }, CancellationToken.None);
- config.Output.ToString().Should().Contain($"'niof' was not matched. Did you mean one of the following?{NewLine}info");
+ output.ToString().Should().Contain($"'niof' was not matched. Did you mean one of the following?{NewLine}info");
}
[Fact]
@@ -39,39 +39,18 @@ public async Task Typo_corrections_can_be_disabled()
new Option("info")
};
- CommandLineConfiguration config = new(rootCommand)
- {
- Output = new StringWriter()
- };
+ var output = new StringWriter();
- var result = rootCommand.Parse("niof", config);
+ var result = rootCommand.Parse("niof");
if (result.Action is ParseErrorAction parseError)
{
parseError.ShowTypoCorrections = false;
}
- await result.InvokeAsync();
+ await result.InvokeAsync(new() { Output = output }, CancellationToken.None);
- config.Output.ToString().Should().NotContain("Did you mean");
- }
-
- [Fact]
- public async Task When_there_are_no_matches_then_nothing_is_suggested()
- {
- var option = new Option("info");
- RootCommand rootCommand = new() { option };
-
- CommandLineConfiguration configuration = new(rootCommand)
- {
- Output = new StringWriter()
- };
-
- var result = rootCommand.Parse("zzzzzzz", configuration);
-
- await result.InvokeAsync();
-
- configuration.Output.ToString().Should().NotContain("was not matched");
+ output.ToString().Should().NotContain("Did you mean");
}
[Fact]
@@ -80,16 +59,13 @@ public async Task When_command_is_mistyped_it_is_suggested()
var command = new Command("restore");
RootCommand rootCommand = new() { command };
- CommandLineConfiguration configuration = new(rootCommand)
- {
- Output = new StringWriter()
- };
+ var output = new StringWriter();
- var result = rootCommand.Parse("sertor", configuration);
+ var result = rootCommand.Parse("sertor");
- await result.InvokeAsync();
+ await result.InvokeAsync(new() { Output = output }, CancellationToken.None);
- configuration.Output.ToString().Should().Contain($"'sertor' was not matched. Did you mean one of the following?{NewLine}restore");
+ output.ToString().Should().Contain($"'sertor' was not matched. Did you mean one of the following?{NewLine}restore");
}
[Fact]
@@ -99,23 +75,35 @@ public async Task When_there_are_multiple_matches_it_picks_the_best_matches()
var seenCommand = new Command("seen");
var aOption = new Option("a");
var beenOption = new Option("been");
- RootCommand rootCommand = new ()
+ RootCommand rootCommand = new()
{
fromCommand,
seenCommand,
aOption,
beenOption
};
- CommandLineConfiguration configuration = new(rootCommand)
- {
- Output = new StringWriter()
- };
- var result = rootCommand.Parse("een", configuration);
+ var output = new StringWriter();
- await result.InvokeAsync();
+ var result = rootCommand.Parse("een");
- configuration.Output.ToString().Should().Contain($"'een' was not matched. Did you mean one of the following?{NewLine}seen{NewLine}been");
+ await result.InvokeAsync(new() { Output = output }, CancellationToken.None);
+
+ output.ToString().Should().Contain($"'een' was not matched. Did you mean one of the following?{NewLine}seen{NewLine}been");
+ }
+
+ [Fact]
+ public async Task When_there_are_no_matches_then_nothing_is_suggested()
+ {
+ var option = new Option("info");
+ RootCommand rootCommand = new() { option };
+
+ var output = new StringWriter();
+ var result = rootCommand.Parse("zzzzzzz");
+
+ await result.InvokeAsync(new() { Output = output }, CancellationToken.None);
+
+ output.ToString().Should().NotContain("was not matched");
}
[Fact]
@@ -131,16 +119,13 @@ public async Task Hidden_commands_are_not_suggested()
beenCommand
};
- CommandLineConfiguration configuration = new(rootCommand)
- {
- Output = new StringWriter()
- };
+ var output = new StringWriter();
- var result = rootCommand.Parse("een", configuration);
+ var result = rootCommand.Parse("een");
- await result.InvokeAsync();
+ await result.InvokeAsync(new() { Output = output }, CancellationToken.None);
- configuration.Output.ToString().Should().Contain($"'een' was not matched. Did you mean one of the following?{NewLine}been");
+ output.ToString().Should().Contain($"'een' was not matched. Did you mean one of the following?{NewLine}been");
}
[Fact]
@@ -154,20 +139,17 @@ public async Task Arguments_are_not_suggested()
command
};
- CommandLineConfiguration configuration = new(rootCommand)
- {
- Output = new StringWriter()
- };
+ var output = new StringWriter();
- var result = rootCommand.Parse("een", configuration);
+ var result = rootCommand.Parse("een");
var parseErrorAction = (ParseErrorAction)result.Action;
parseErrorAction.ShowHelp = false;
parseErrorAction.ShowTypoCorrections = true;
-
- await result.InvokeAsync();
- configuration.Output.ToString().Should().NotContain("the-argument");
+ await result.InvokeAsync(new() { Output = output }, CancellationToken.None);
+
+ output.ToString().Should().NotContain("the-argument");
}
[Fact]
@@ -182,16 +164,13 @@ public async Task Hidden_options_are_not_suggested()
seenOption,
beenOption
};
- CommandLineConfiguration config = new(rootCommand)
- {
- Output = new StringWriter()
- };
+ var output = new StringWriter();
- var result = rootCommand.Parse("een", config);
+ var result = rootCommand.Parse("een");
- await result.InvokeAsync();
+ await result.InvokeAsync(new() { Output = output }, CancellationToken.None);
- config.Output.ToString().Should().Contain($"'een' was not matched. Did you mean one of the following?{NewLine}been");
+ output.ToString().Should().Contain($"'een' was not matched. Did you mean one of the following?{NewLine}been");
}
[Fact]
@@ -202,15 +181,12 @@ public async Task Suggestions_favor_matches_with_prefix()
new Option("/call", "-call", "--call"),
new Option("/email", "-email", "--email")
};
- CommandLineConfiguration config = new(rootCommand)
- {
- Output = new StringWriter()
- };
- var result = rootCommand.Parse("-all", config);
+ var output = new StringWriter();
+ var result = rootCommand.Parse("-all");
- await result.InvokeAsync();
+ await result.InvokeAsync(new() { Output = output }, CancellationToken.None);
- config.Output.ToString().Should().Contain($"'-all' was not matched. Did you mean one of the following?{NewLine}-call");
+ output.ToString().Should().Contain($"'-all' was not matched. Did you mean one of the following?{NewLine}-call");
}
}
}
\ No newline at end of file
diff --git a/src/System.CommandLine.Tests/InvocationConfigurationTests.cs b/src/System.CommandLine.Tests/InvocationConfigurationTests.cs
new file mode 100644
index 0000000000..a92626c709
--- /dev/null
+++ b/src/System.CommandLine.Tests/InvocationConfigurationTests.cs
@@ -0,0 +1,40 @@
+using FluentAssertions;
+using Xunit;
+
+namespace System.CommandLine.Tests;
+
+public class InvocationConfigurationTests
+{
+ [Fact]
+ public void It_can_be_subclassed_to_provide_additional_context()
+ {
+ var command = new RootCommand();
+ var commandWasInvoked = false;
+ command.SetAction(parseResult =>
+ {
+ var appConfig = (CustomAppConfiguration)parseResult.InvocationConfiguration;
+
+ // access custom config
+
+ commandWasInvoked = true;
+
+ return 0;
+ });
+
+ var config = new CustomAppConfiguration();
+
+ command.Parse("").Invoke(config);
+
+ commandWasInvoked.Should().BeTrue();
+ }
+
+ public class CustomAppConfiguration : InvocationConfiguration
+ {
+ public CustomAppConfiguration()
+ {
+ EnableDefaultExceptionHandler = false;
+ }
+
+ public IServiceProvider ServiceProvider { get; }
+ }
+}
\ No newline at end of file
diff --git a/src/System.CommandLine.Tests/ParseDirectiveTests.cs b/src/System.CommandLine.Tests/ParseDirectiveTests.cs
index 8ed409e34d..8490e8d579 100644
--- a/src/System.CommandLine.Tests/ParseDirectiveTests.cs
+++ b/src/System.CommandLine.Tests/ParseDirectiveTests.cs
@@ -3,6 +3,7 @@
using FluentAssertions;
using System.IO;
+using System.Threading;
using System.Threading.Tasks;
using Xunit;
using Xunit.Abstractions;
@@ -30,73 +31,55 @@ public async Task Diagram_directive_writes_parse_diagram(bool treatUnmatchedToke
subcommand.Options.Add(option);
subcommand.TreatUnmatchedTokensAsErrors = treatUnmatchedTokensAsErrors;
- CommandLineConfiguration config = new(rootCommand)
- {
- Output = new StringWriter()
- };
+ var output = new StringWriter();
- var result = rootCommand.Parse("[diagram] subcommand -c 34 --nonexistent wat", config);
+ var result = rootCommand.Parse("[diagram] subcommand -c 34 --nonexistent wat");
- output.WriteLine(result.Diagram());
-
- await result.InvokeAsync();
+ await result.InvokeAsync(new() { Output = output }, CancellationToken.None);
string expected = treatUnmatchedTokensAsErrors
? $"[ {RootCommand.ExecutableName} ![ subcommand [ -c <34> ] ] ] ???--> --nonexistent wat" + Environment.NewLine
: $"[ {RootCommand.ExecutableName} [ subcommand [ -c <34> ] ] ] ???--> --nonexistent wat" + Environment.NewLine;
- config.Output
- .ToString()
+ output.ToString()
.Should()
.Be(expected);
}
[Fact]
- public async Task When_diagram_directive_is_used_the_help_is_not_displayed()
+ public async Task When_diagram_directive_is_used_then_help_is_not_displayed()
{
RootCommand rootCommand = new()
{
new DiagramDirective()
};
- CommandLineConfiguration config = new(rootCommand)
- {
- Output = new StringWriter(),
- };
-
- var result = rootCommand.Parse("[diagram] --help", config);
+ var output = new StringWriter();
- output.WriteLine(result.Diagram());
+ var result = rootCommand.Parse("[diagram] --help");
- await result.InvokeAsync();
+ await result.InvokeAsync(new() { Output = output }, CancellationToken.None);
- config.Output
- .ToString()
- .Should()
- .Be($"[ {RootCommand.ExecutableName} [ --help ] ]" + Environment.NewLine);
+ output.ToString()
+ .Should()
+ .Be($"[ {RootCommand.ExecutableName} [ --help ] ]" + Environment.NewLine);
}
[Fact]
- public async Task When_diagram_directive_is_used_the_version_is_not_displayed()
+ public async Task When_diagram_directive_is_used_then_version_is_not_displayed()
{
RootCommand rootCommand = new()
{
new DiagramDirective()
};
- CommandLineConfiguration config = new(rootCommand)
- {
- Output = new StringWriter()
- };
-
- var result = rootCommand.Parse("[diagram] --version", config);
+ var output = new StringWriter();
- output.WriteLine(result.Diagram());
+ var result = rootCommand.Parse("[diagram] --version");
- await result.InvokeAsync();
+ await result.InvokeAsync(new() { Output = output }, CancellationToken.None);
- config.Output
- .ToString()
+ output.ToString()
.Should()
.Be($"[ {RootCommand.ExecutableName} [ --version ] ]" + Environment.NewLine);
}
@@ -110,12 +93,9 @@ public async Task When_there_are_no_errors_then_diagram_directive_sets_exit_code
new DiagramDirective()
};
- CommandLineConfiguration config = new(command)
- {
- Output = new StringWriter(),
- };
+ var output = new StringWriter();
- var exitCode = await command.Parse("[diagram] -x 123", config).InvokeAsync();
+ var exitCode = await command.Parse("[diagram] -x 123").InvokeAsync(new() { Output = output }, CancellationToken.None);
exitCode.Should().Be(0);
}
@@ -129,12 +109,9 @@ public async Task When_there_are_errors_then_diagram_directive_sets_exit_code_1(
new DiagramDirective()
};
- CommandLineConfiguration config = new(command)
- {
- Output = new StringWriter(),
- };
+ var output = new StringWriter();
- var exitCode = await command.Parse("[diagram] -x not-an-int", config).InvokeAsync();
+ var exitCode = await command.Parse("[diagram] -x not-an-int").InvokeAsync(new() { Output = output }, CancellationToken.None);
exitCode.Should().Be(1);
}
@@ -151,12 +128,10 @@ public async Task When_there_are_errors_then_diagram_directive_sets_exit_code_to
}
};
- CommandLineConfiguration config = new(command)
- {
- Output = new StringWriter()
- };
+ var output = new StringWriter();
- int exitCode = await config.InvokeAsync("[diagram] -x not-an-int");
+ int exitCode = await command.Parse("[diagram] -x not-an-int")
+ .InvokeAsync(new() { Output = output }, CancellationToken.None);
exitCode.Should().Be(42);
}
diff --git a/src/System.CommandLine.Tests/ParseErrorReportingTests.cs b/src/System.CommandLine.Tests/ParseErrorReportingTests.cs
index 48d3d0e2d4..d66f37d816 100644
--- a/src/System.CommandLine.Tests/ParseErrorReportingTests.cs
+++ b/src/System.CommandLine.Tests/ParseErrorReportingTests.cs
@@ -1,14 +1,15 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+using FluentAssertions;
using System.CommandLine.Help;
using System.CommandLine.Invocation;
-using System.IO;
-using FluentAssertions;
-using Xunit;
using System.CommandLine.Tests.Utility;
+using System.IO;
using System.Linq;
+using System.Threading;
using System.Threading.Tasks;
+using Xunit;
namespace System.CommandLine.Tests;
@@ -24,14 +25,11 @@ public void Parse_error_reporting_reports_error_when_help_is_used_and_required_s
};
var output = new StringWriter();
- var parseResult = root.Parse("", new CommandLineConfiguration(root)
- {
- Output = output,
- });
+ var parseResult = root.Parse("");
parseResult.Errors.Should().NotBeEmpty();
- var result = parseResult.Invoke();
+ var result = parseResult.Invoke(new() { Output = output });
result.Should().Be(1);
output.ToString().Should().ShowHelp();
@@ -45,23 +43,18 @@ public void Help_display_can_be_disabled()
new Option("--verbose")
};
- CommandLineConfiguration config = new(rootCommand)
- {
- Output = new StringWriter()
- };
+ var output = new StringWriter();
- var result = rootCommand.Parse("oops", config);
+ var result = rootCommand.Parse("oops");
if (result.Action is ParseErrorAction parseError)
{
parseError.ShowHelp = false;
}
- result.Invoke();
+ result.Invoke(new() { Output = output });
- var output = config.Output.ToString();
-
- output.Should().NotShowHelp();
+ output.ToString().Should().NotShowHelp();
}
[Theory] // https://github.com/dotnet/command-line-api/issues/2226
@@ -104,9 +97,7 @@ public async Task When_there_are_parse_errors_then_customized_help_action_on_anc
rootHelpWasCalled = true;
});
- var config = new CommandLineConfiguration(rootCommand);
-
- await config.Parse("child grandchild oops").InvokeAsync();
+ await rootCommand.Parse("child grandchild oops").InvokeAsync();
rootHelpWasCalled.Should().BeTrue();
}
@@ -117,12 +108,8 @@ public void When_no_help_option_is_present_then_help_is_not_shown_for_parse_erro
RootCommand rootCommand = new();
rootCommand.Options.Clear();
var output = new StringWriter();
- CommandLineConfiguration config = new(rootCommand)
- {
- Output = output
- };
-
- config.Parse("oops").Invoke();
+
+ rootCommand.Parse("oops").Invoke(new() { Output = output } );
output.ToString().Should().NotShowHelp();
}
diff --git a/src/System.CommandLine.Tests/ParserTests.SetupErrors.cs b/src/System.CommandLine.Tests/ParserTests.SetupErrors.cs
index d5e2e52202..915a1d4290 100644
--- a/src/System.CommandLine.Tests/ParserTests.SetupErrors.cs
+++ b/src/System.CommandLine.Tests/ParserTests.SetupErrors.cs
@@ -60,9 +60,8 @@ public void When_command_names_collide_with_directive_names_it_does_not_throw_on
var rootCommand = new RootCommand();
rootCommand.Add(new Command("one"));
rootCommand.Add(new Directive("one"));
- var cliConfiguration = new CommandLineConfiguration(rootCommand);
- rootCommand.Invoking(c => c.Parse("", cliConfiguration)).Should().NotThrow();
+ rootCommand.Invoking(c => c.Parse("")).Should().NotThrow();
}
}
}
\ No newline at end of file
diff --git a/src/System.CommandLine.Tests/ParserTests.cs b/src/System.CommandLine.Tests/ParserTests.cs
index 410c67bc82..09a3d8a397 100644
--- a/src/System.CommandLine.Tests/ParserTests.cs
+++ b/src/System.CommandLine.Tests/ParserTests.cs
@@ -137,7 +137,7 @@ public void Options_short_forms_do_not_get_unbundled_if_unbundling_is_turned_off
}
};
- CommandLineConfiguration configuration = new (rootCommand)
+ ParserConfiguration configuration = new()
{
EnablePosixBundling = false
};
diff --git a/src/System.CommandLine.Tests/ResponseFileTests.cs b/src/System.CommandLine.Tests/ResponseFileTests.cs
index 5404fdee22..1528009e3b 100644
--- a/src/System.CommandLine.Tests/ResponseFileTests.cs
+++ b/src/System.CommandLine.Tests/ResponseFileTests.cs
@@ -287,9 +287,8 @@ public void When_response_file_parse_as_space_separated_returns_expected_values(
optionOne,
optionTwo
};
- CommandLineConfiguration config = new (rootCommand);
- var result = rootCommand.Parse($"@{responseFile}", config);
+ var result = rootCommand.Parse($"@{responseFile}");
result.GetValue(optionOne).Should().Be("first value");
result.GetValue(optionTwo).Should().Be(123);
@@ -302,7 +301,7 @@ public void When_response_file_processing_is_disabled_then_it_returns_response_f
{
new Argument>("arg")
};
- CommandLineConfiguration configuration = new(command)
+ ParserConfiguration configuration = new()
{
ResponseFileTokenReplacer = null
};
diff --git a/src/System.CommandLine.Tests/SuggestDirectiveTests.cs b/src/System.CommandLine.Tests/SuggestDirectiveTests.cs
index ec1bb7209e..ccb482315f 100644
--- a/src/System.CommandLine.Tests/SuggestDirectiveTests.cs
+++ b/src/System.CommandLine.Tests/SuggestDirectiveTests.cs
@@ -1,11 +1,13 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+using FluentAssertions;
+using Microsoft.VisualStudio.TestPlatform.Utilities;
using System.CommandLine.Completions;
using System.CommandLine.Help;
using System.IO;
+using System.Threading;
using System.Threading.Tasks;
-using FluentAssertions;
using Xunit;
using static System.Environment;
@@ -42,16 +44,13 @@ public async Task It_writes_suggestions_for_option_arguments_when_under_subcomma
_eatCommand,
new SuggestDirective()
};
- CommandLineConfiguration config = new(rootCommand)
- {
- Output = new StringWriter()
- };
+ var output= new StringWriter();
- var result = rootCommand.Parse("[suggest:13] \"eat --fruit\"", config);
+ var result = rootCommand.Parse("[suggest:13] \"eat --fruit\"");
- await result.InvokeAsync();
+ await result.InvokeAsync(new() { Output = output }, CancellationToken.None);
- config.Output
+ output
.ToString()
.Should()
.Be($"apple{NewLine}banana{NewLine}cherry{NewLine}");
@@ -60,24 +59,21 @@ public async Task It_writes_suggestions_for_option_arguments_when_under_subcomma
[Fact]
public async Task It_writes_suggestions_for_option_arguments_when_under_root_command()
{
- RootCommand rootCommand = new ()
+ RootCommand rootCommand = new()
{
_fruitOption,
_vegetableOption
};
- CommandLineConfiguration config = new (rootCommand)
- {
- Output = new StringWriter()
- };
+ var output = new StringWriter();
- var result = rootCommand.Parse($"[suggest:8] \"--fruit\"", config);
+ var result = rootCommand.Parse($"[suggest:8] \"--fruit\"");
- await result.InvokeAsync();
+ await result.InvokeAsync(new() { Output = output }, CancellationToken.None);
- config.Output
- .ToString()
- .Should()
- .Be($"apple{NewLine}banana{NewLine}cherry{NewLine}");
+ output
+ .ToString()
+ .Should()
+ .Be($"apple{NewLine}banana{NewLine}cherry{NewLine}");
}
[Theory]
@@ -86,21 +82,18 @@ public async Task It_writes_suggestions_for_option_arguments_when_under_root_com
public async Task It_writes_suggestions_for_option_aliases_under_subcommand(string commandLine, string[] expectedCompletions)
{
RootCommand rootCommand = new() { _eatCommand };
- CommandLineConfiguration config = new(rootCommand)
- {
- Output = new StringWriter()
- };
+
+ var output = new StringWriter();
- var result = rootCommand.Parse(commandLine, config);
+ var result = rootCommand.Parse(commandLine);
- await result.InvokeAsync();
+ await result.InvokeAsync(new() { Output = output }, CancellationToken.None);
string expected = string.Join(NewLine, expectedCompletions) + NewLine;
- config.Output
- .ToString()
- .Should()
- .Be(expected);
+ output.ToString()
+ .Should()
+ .Be(expected);
}
[Theory]
@@ -115,18 +108,14 @@ public async Task It_writes_suggestions_for_option_aliases_under_root_command(st
_vegetableOption,
_fruitOption
};
- CommandLineConfiguration config = new(rootCommand)
- {
- Output = new StringWriter()
- };
+ var output = new StringWriter();
- var result = rootCommand.Parse(input, config);
- await result.InvokeAsync();
+ await rootCommand.Parse(input).InvokeAsync(new() { Output = output }, CancellationToken.None);
- config.Output
- .ToString()
- .Should()
- .Be($"--fruit{NewLine}--help{NewLine}--vegetable{NewLine}--version{NewLine}-?{NewLine}-h{NewLine}/?{NewLine}/h{NewLine}");
+ output
+ .ToString()
+ .Should()
+ .Be($"--fruit{NewLine}--help{NewLine}--vegetable{NewLine}--version{NewLine}-?{NewLine}-h{NewLine}/?{NewLine}/h{NewLine}");
}
[Fact]
@@ -136,18 +125,15 @@ public async Task It_writes_suggestions_for_subcommand_aliases_under_root_comman
{
_eatCommand
};
- CommandLineConfiguration config = new(rootCommand)
- {
- Output = new StringWriter()
- };
+ var output = new StringWriter();
- var result = rootCommand.Parse("[suggest]", config);
- await result.InvokeAsync();
+ var result = rootCommand.Parse("[suggest]");
+ await result.InvokeAsync(new() { Output = output }, CancellationToken.None);
- config.Output
- .ToString()
- .Should()
- .Be($"--help{NewLine}--version{NewLine}-?{NewLine}-h{NewLine}/?{NewLine}/h{NewLine}eat{NewLine}");
+ output
+ .ToString()
+ .Should()
+ .Be($"--help{NewLine}--version{NewLine}-?{NewLine}-h{NewLine}/?{NewLine}/h{NewLine}eat{NewLine}");
}
[Fact]
@@ -158,19 +144,17 @@ public async Task It_writes_suggestions_for_partial_option_aliases_under_root_co
_fruitOption,
_vegetableOption
};
- CommandLineConfiguration config = new (rootCommand)
- {
- Output = new StringWriter(),
- };
+
+ var output = new StringWriter();
- var result = rootCommand.Parse("[suggest:1] \"f\"", config);
+ var result = rootCommand.Parse("[suggest:1] \"f\"");
- await result.InvokeAsync();
+ await result.InvokeAsync(new() { Output = output }, CancellationToken.None);
- config.Output
- .ToString()
- .Should()
- .Be($"--fruit{NewLine}");
+ output
+ .ToString()
+ .Should()
+ .Be($"--fruit{NewLine}");
}
[Fact]
@@ -181,19 +165,16 @@ public async Task It_writes_suggestions_for_partial_subcommand_aliases_under_roo
_eatCommand,
new Command("wash-dishes")
};
- CommandLineConfiguration config = new (rootCommand)
- {
- Output = new StringWriter()
- };
+ var output = new StringWriter();
- var result = rootCommand.Parse("[suggest:1] \"d\"", config);
+ var result = rootCommand.Parse("[suggest:1] \"d\"");
- await result.InvokeAsync();
+ await result.InvokeAsync(new() { Output = output }, CancellationToken.None);
- config.Output
- .ToString()
- .Should()
- .Be($"wash-dishes{NewLine}");
+ output
+ .ToString()
+ .Should()
+ .Be($"wash-dishes{NewLine}");
}
[Fact]
@@ -204,19 +185,16 @@ public async Task It_writes_suggestions_for_partial_option_and_subcommand_aliase
_eatCommand,
new Command("wash-dishes"),
};
- CommandLineConfiguration config = new (rootCommand)
- {
- Output = new StringWriter()
- };
+ var output = new StringWriter();
- var result = rootCommand.Parse("[suggest:5] \"--ver\"", config);
+ var result = rootCommand.Parse("[suggest:5] \"--ver\"");
- await result.InvokeAsync();
+ await result.InvokeAsync(new() { Output = output }, CancellationToken.None);
- config.Output
- .ToString()
- .Should()
- .Be($"--version{NewLine}");
+ output
+ .ToString()
+ .Should()
+ .Be($"--version{NewLine}");
}
[Fact]
@@ -229,17 +207,14 @@ public async Task It_writes_suggestions_for_partial_option_and_subcommand_aliase
new Option("--option2"),
new Argument("arg")
};
- CommandLineConfiguration config = new (command)
- {
- Output = new StringWriter()
- };
- await config.InvokeAsync("[suggest:3] \"opt\"");
+ var output = new StringWriter();
- config.Output
- .ToString()
- .Should()
- .Be($"--option1{NewLine}--option2{NewLine}");
+ await command.Parse("[suggest:3] \"opt\"").InvokeAsync(new() { Output = output }, CancellationToken.None);
+
+ output.ToString()
+ .Should()
+ .Be($"--option1{NewLine}--option2{NewLine}");
}
[Fact]
@@ -249,19 +224,17 @@ public async Task It_does_not_repeat_suggestion_for_already_specified_bool_optio
{
new Option("--bool-option")
};
- CommandLineConfiguration config = new (command)
- {
- Output = new StringWriter()
- };
+
+ var output = new StringWriter();
var commandLine = "--bool-option false";
- await command.Parse($"[suggest:{commandLine.Length + 1}] \"{commandLine}\"", config).InvokeAsync();
+ await command.Parse($"[suggest:{commandLine.Length + 1}] \"{commandLine}\"").InvokeAsync(new() { Output = output }, CancellationToken.None);
- config.Output
- .ToString()
- .Should()
- .NotContain("--bool-option");
+ output
+ .ToString()
+ .Should()
+ .NotContain("--bool-option");
}
}
}
diff --git a/src/System.CommandLine.Tests/TestApps/NativeAOT/Program.cs b/src/System.CommandLine.Tests/TestApps/NativeAOT/Program.cs
index 37c80614cd..c390af65a6 100644
--- a/src/System.CommandLine.Tests/TestApps/NativeAOT/Program.cs
+++ b/src/System.CommandLine.Tests/TestApps/NativeAOT/Program.cs
@@ -17,7 +17,7 @@ private static int Main(string[] args)
command.SetAction(Run);
- return new CommandLineConfiguration(command).Invoke(args);
+ return command.Parse(args).Invoke();
void Run(ParseResult parseResult)
{
diff --git a/src/System.CommandLine.Tests/TokenReplacementTests.cs b/src/System.CommandLine.Tests/TokenReplacementTests.cs
index c96af9b0c2..908ba5cc23 100644
--- a/src/System.CommandLine.Tests/TokenReplacementTests.cs
+++ b/src/System.CommandLine.Tests/TokenReplacementTests.cs
@@ -18,7 +18,7 @@ public void Token_replacer_receives_the_token_from_the_command_line_with_the_lea
string receivedToken = null;
- CommandLineConfiguration config = new (command)
+ ParserConfiguration config = new ()
{
ResponseFileTokenReplacer = (string tokenToReplace, out IReadOnlyList tokens, out string message) =>
{
@@ -41,7 +41,7 @@ public void Token_replacer_can_expand_argument_values()
var command = new RootCommand { argument };
- CommandLineConfiguration config = new(command)
+ ParserConfiguration config = new()
{
ResponseFileTokenReplacer = (string tokenToReplace, out IReadOnlyList tokens, out string message) =>
{
@@ -65,7 +65,7 @@ public void Custom_token_replacer_can_expand_option_argument_values()
var command = new RootCommand { option };
- CommandLineConfiguration config = new(command)
+ ParserConfiguration config = new()
{
ResponseFileTokenReplacer = (string tokenToReplace, out IReadOnlyList tokens, out string message) =>
{
@@ -89,7 +89,7 @@ public void Custom_token_replacer_can_expand_subcommands_and_options_and_argumen
var command = new RootCommand { new Command("subcommand") { option } };
- CommandLineConfiguration config = new(command)
+ ParserConfiguration config = new()
{
ResponseFileTokenReplacer = (string tokenToReplace, out IReadOnlyList tokens, out string message) =>
{
@@ -113,7 +113,7 @@ public void Expanded_tokens_containing_whitespace_are_parsed_as_single_tokens()
var command = new RootCommand { argument };
- CommandLineConfiguration config = new(command)
+ ParserConfiguration config = new()
{
ResponseFileTokenReplacer = (string tokenToReplace, out IReadOnlyList tokens, out string message) =>
{
@@ -135,7 +135,7 @@ public void Token_replacer_can_set_a_custom_error_message()
var command = new RootCommand { argument };
- CommandLineConfiguration config = new(command)
+ ParserConfiguration config = new()
{
ResponseFileTokenReplacer = (string tokenToReplace, out IReadOnlyList tokens, out string message) =>
{
@@ -159,7 +159,7 @@ public void When_token_replacer_returns_false_without_setting_an_error_message_t
var command = new RootCommand { argument };
- CommandLineConfiguration config = new(command)
+ ParserConfiguration config = new()
{
ResponseFileTokenReplacer = (string tokenToReplace, out IReadOnlyList tokens, out string message) =>
{
@@ -183,7 +183,7 @@ public void Token_replacer_will_delete_token_when_delegate_returns_true_and_sets
var command = new RootCommand { argument };
- CommandLineConfiguration config = new(command)
+ ParserConfiguration config = new()
{
ResponseFileTokenReplacer = (string tokenToReplace, out IReadOnlyList tokens, out string message) =>
{
@@ -207,7 +207,7 @@ public void Token_replacer_will_delete_token_when_delegate_returns_true_and_sets
var command = new RootCommand { argument };
- CommandLineConfiguration config = new(command)
+ ParserConfiguration config = new()
{
ResponseFileTokenReplacer = (string tokenToReplace, out IReadOnlyList tokens, out string message) =>
{
diff --git a/src/System.CommandLine.Tests/UseExceptionHandlerTests.cs b/src/System.CommandLine.Tests/UseExceptionHandlerTests.cs
index 5acf4b59b5..201f0ee869 100644
--- a/src/System.CommandLine.Tests/UseExceptionHandlerTests.cs
+++ b/src/System.CommandLine.Tests/UseExceptionHandlerTests.cs
@@ -1,9 +1,10 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+using FluentAssertions;
using System.IO;
+using System.Threading;
using System.Threading.Tasks;
-using FluentAssertions;
using Xunit;
namespace System.CommandLine.Tests
@@ -16,12 +17,7 @@ public async Task UseExceptionHandler_catches_command_handler_exceptions_and_set
var command = new Command("the-command");
command.SetAction((_, __) => Task.FromException(new Exception("oops!")));
- CommandLineConfiguration config = new(command)
- {
- Error = new StringWriter(),
- };
-
- var resultCode = await config.InvokeAsync("the-command");
+ var resultCode = await command.Parse("the-command").InvokeAsync(new() { Error = new StringWriter() },CancellationToken.None);
resultCode.Should().Be(1);
}
@@ -32,14 +28,11 @@ public async Task UseExceptionHandler_catches_command_handler_exceptions_and_wri
var command = new Command("the-command");
command.SetAction((_, __) => Task.FromException(new Exception("oops!")));
- CommandLineConfiguration config = new(command)
- {
- Error = new StringWriter(),
- };
+ var error = new StringWriter();
- await config.InvokeAsync("the-command");
+ await command.Parse("the-command").InvokeAsync(new() { Error = error }, CancellationToken.None);
- config.Error.ToString().Should().Contain("System.Exception: oops!");
+ error.ToString().Should().Contain("System.Exception: oops!");
}
[Fact]
@@ -48,16 +41,12 @@ public async Task When_thrown_exception_is_from_cancelation_no_output_is_generat
Command command = new("the-command");
command.SetAction((_, __) => throw new OperationCanceledException());
- CommandLineConfiguration config = new(command)
- {
- Output = new StringWriter(),
- Error = new StringWriter()
- };
+ var output = new StringWriter();
+ var error = new StringWriter();
- int resultCode = await config
- .InvokeAsync("the-command");
+ int resultCode = await command.Parse("the-command").InvokeAsync(new() { Output = output, Error = error }, CancellationToken.None);
- config.Output.ToString().Should().BeEmpty();
+ output.ToString().Should().BeEmpty();
resultCode.Should().NotBe(0);
}
@@ -70,24 +59,26 @@ public async Task Exception_output_can_be_customized(bool async)
Command command = new("the-command");
command.SetAction((_, __) => throw expectedException);
- CommandLineConfiguration config = new(command)
+ InvocationConfiguration config = new()
{
Error = new StringWriter(),
EnableDefaultExceptionHandler = false
};
- ParseResult parseResult = command.Parse("the-command", config);
+ ParseResult parseResult = command.Parse("the-command");
int resultCode = 0;
try
{
- resultCode = async ? await parseResult.InvokeAsync() : parseResult.Invoke();
+ resultCode = async
+ ? await parseResult.InvokeAsync(config)
+ : parseResult.Invoke(config);
}
catch (Exception ex)
{
ex.Should().Be(expectedException);
- parseResult.Configuration.Error.Write("Well that's awkward.");
+ parseResult.InvocationConfiguration.Error.Write("Well that's awkward.");
resultCode = 22;
}
diff --git a/src/System.CommandLine.Tests/Utility/ParseResultExtensions.cs b/src/System.CommandLine.Tests/Utility/ParseResultExtensions.cs
index 60e46a2599..9cfadd03b2 100644
--- a/src/System.CommandLine.Tests/Utility/ParseResultExtensions.cs
+++ b/src/System.CommandLine.Tests/Utility/ParseResultExtensions.cs
@@ -7,19 +7,19 @@ internal static class ParseResultExtensions
{
internal static string Diagram(this ParseResult parseResult)
{
- TextWriter outputBefore = parseResult.Configuration.Output;
+ TextWriter outputBefore = parseResult.InvocationConfiguration.Output;
try
{
- parseResult.Configuration.Output = new StringWriter();
+ parseResult.InvocationConfiguration.Output = new StringWriter();
((SynchronousCommandLineAction)new DiagramDirective().Action!).Invoke(parseResult);
- return parseResult.Configuration.Output.ToString()
+ return parseResult.InvocationConfiguration.Output.ToString()
.TrimEnd(); // the directive adds a new line, tests that used to rely on Diagram extension method don't expect it
}
finally
{
// some of the tests check the Output after getting the Diagram
- parseResult.Configuration.Output = outputBefore;
+ parseResult.InvocationConfiguration.Output = outputBefore;
}
}
}
diff --git a/src/System.CommandLine.Tests/VersionOptionTests.cs b/src/System.CommandLine.Tests/VersionOptionTests.cs
index b796349136..5e7f528ab2 100644
--- a/src/System.CommandLine.Tests/VersionOptionTests.cs
+++ b/src/System.CommandLine.Tests/VersionOptionTests.cs
@@ -1,12 +1,13 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-using FluentAssertions;
-using FluentAssertions.Execution;
using System.IO;
using System.Linq;
using System.Reflection;
+using System.Threading;
using System.Threading.Tasks;
+using FluentAssertions;
+using FluentAssertions.Execution;
using Xunit;
using static System.Environment;
@@ -14,21 +15,21 @@ namespace System.CommandLine.Tests
{
public class VersionOptionTests
{
- private static readonly string version = (Assembly.GetEntryAssembly() ?? Assembly.GetExecutingAssembly())
- .GetCustomAttribute()
- .InformationalVersion;
+ private static readonly string version = (Assembly.GetEntryAssembly() ??
+ Assembly.GetExecutingAssembly())
+ .GetCustomAttribute()
+ .InformationalVersion;
[Fact]
public async Task When_the_version_option_is_specified_then_the_version_is_written_to_standard_out()
{
- CommandLineConfiguration configuration = new(new RootCommand())
- {
- Output = new StringWriter()
- };
+ var rootCommand = new RootCommand();
- await configuration.InvokeAsync("--version");
+ var output = new StringWriter();
- configuration.Output.ToString().Should().Be($"{version}{NewLine}");
+ await rootCommand.Parse("--version").InvokeAsync(new() { Output = output }, CancellationToken.None);
+
+ output.ToString().Should().Be($"{version}{NewLine}");
}
[Fact]
@@ -38,12 +39,9 @@ public async Task When_the_version_option_is_specified_then_invocation_is_short_
var rootCommand = new RootCommand();
rootCommand.SetAction((_) => wasCalled = true);
- CommandLineConfiguration configuration = new(rootCommand)
- {
- Output = new StringWriter()
- };
+ var output = new StringWriter();
- await configuration.InvokeAsync("--version");
+ await rootCommand.Parse("--version").InvokeAsync(new() { Output = output }, CancellationToken.None);
wasCalled.Should().BeFalse();
}
@@ -51,17 +49,13 @@ public async Task When_the_version_option_is_specified_then_invocation_is_short_
[Fact]
public async Task Version_option_appears_in_help()
{
- CommandLineConfiguration configuration = new(new RootCommand())
- {
- Output = new StringWriter()
- };
-
- await configuration.InvokeAsync("--help");
+ var output = new StringWriter();
+ await new RootCommand().Parse("--help").InvokeAsync(new() { Output = output }, CancellationToken.None);
- configuration.Output
- .ToString()
- .Should()
- .Match("*Options:*--version*Show version information*");
+ output
+ .ToString()
+ .Should()
+ .Match("*Options:*--version*Show version information*");
}
[Fact]
@@ -76,33 +70,27 @@ public async Task When_the_version_option_is_specified_and_there_are_default_opt
};
rootCommand.SetAction((_) => { });
- CommandLineConfiguration configuration = new(rootCommand)
- {
- Output = new StringWriter()
- };
+ var output = new StringWriter();
- await configuration.InvokeAsync("--version");
+ await rootCommand.Parse("--version").InvokeAsync(new() { Output = output }, CancellationToken.None);
- configuration.Output.ToString().Should().Be($"{version}{NewLine}");
+ output.ToString().Should().Be($"{version}{NewLine}");
}
[Fact]
public async Task When_the_version_option_is_specified_and_there_are_default_arguments_then_the_version_is_written_to_standard_out()
{
- RootCommand rootCommand = new ()
+ RootCommand rootCommand = new()
{
- new Argument("x") { DefaultValueFactory =(_) => true },
+ new Argument("x") { DefaultValueFactory = (_) => true },
};
rootCommand.SetAction((_) => { });
- CommandLineConfiguration configuration = new(rootCommand)
- {
- Output = new StringWriter()
- };
+ var output = new StringWriter();
- await configuration.InvokeAsync("--version");
+ await rootCommand.Parse("--version").InvokeAsync(new() { Output = output }, CancellationToken.None);
- configuration.Output.ToString().Should().Be($"{version}{NewLine}");
+ output.ToString().Should().Be($"{version}{NewLine}");
}
[Theory]
@@ -119,40 +107,27 @@ public void Version_is_not_valid_with_other_tokens(string commandLine)
};
rootCommand.SetAction(_ => { });
- CommandLineConfiguration configuration = new(rootCommand)
- {
- Output = new StringWriter()
- };
+ var output = new StringWriter();
- var result = rootCommand.Parse(commandLine, configuration);
+ var result = rootCommand.Parse(commandLine);
result.Errors.Should().Contain(e => e.Message == "--version option cannot be combined with other arguments.");
}
-
+
[Fact]
public void Version_option_is_not_added_to_subcommands()
{
- var childCommand = new Command("subcommand");
- childCommand.SetAction(_ => { });
-
var rootCommand = new RootCommand
{
- childCommand
- };
- rootCommand.SetAction(_ => { });
-
- CommandLineConfiguration configuration = new(rootCommand)
- {
- Output = new StringWriter()
+ new Command("subcommand")
};
- configuration
- .RootCommand
- .Subcommands
- .Single(c => c.Name == "subcommand")
- .Options
- .Should()
- .BeEmpty();
+ rootCommand
+ .Subcommands
+ .Single(c => c.Name == "subcommand")
+ .Options
+ .Should()
+ .BeEmpty();
}
[Fact]
@@ -163,19 +138,16 @@ public async Task Version_can_specify_additional_alias()
rootCommand.Options.Clear();
rootCommand.Add(new VersionOption("-v", "-version"));
- CommandLineConfiguration configuration = new(rootCommand)
- {
- Output = new StringWriter()
- };
+ var output = new StringWriter();
using var _ = new AssertionScope();
- await configuration.InvokeAsync("-v");
- configuration.Output.ToString().Should().Be($"{version}{NewLine}");
+ await rootCommand.Parse("-v").InvokeAsync(new() { Output = output }, CancellationToken.None);
+ output.ToString().Should().Be($"{version}{NewLine}");
- configuration.Output = new StringWriter();
- await configuration.InvokeAsync("-version");
- configuration.Output.ToString().Should().Be($"{version}{NewLine}");
+ output = new StringWriter();
+ await rootCommand.Parse("-version").InvokeAsync(new() { Output = output }, CancellationToken.None);
+ output.ToString().Should().Be($"{version}{NewLine}");
}
[Fact]
@@ -193,14 +165,9 @@ public void Version_is_not_valid_with_other_tokens_when_it_uses_custom_alias()
rootCommand.SetAction(_ => { });
- CommandLineConfiguration configuration = new(rootCommand)
- {
- Output = new StringWriter()
- };
-
- var result = rootCommand.Parse("-v subcommand", configuration);
+ var result = rootCommand.Parse("-v subcommand");
result.Errors.Should().ContainSingle(e => e.Message == "-v option cannot be combined with other arguments.");
}
}
-}
+}
\ No newline at end of file
diff --git a/src/System.CommandLine/Command.cs b/src/System.CommandLine/Command.cs
index 7a1bc15941..44e60aa1e8 100644
--- a/src/System.CommandLine/Command.cs
+++ b/src/System.CommandLine/Command.cs
@@ -222,7 +222,7 @@ public void SetAction(Func> action)
/// The string arguments to parse.
/// The configuration on which the parser's grammar and behaviors are based.
/// A parse result describing the outcome of the parse operation.
- public ParseResult Parse(IReadOnlyList args, CommandLineConfiguration? configuration = null)
+ public ParseResult Parse(IReadOnlyList args, ParserConfiguration? configuration = null)
=> CommandLineParser.Parse(this, args, configuration);
///
@@ -232,7 +232,7 @@ public ParseResult Parse(IReadOnlyList args, CommandLineConfiguration? c
/// A command line string to parse, which can include spaces and quotes equivalent to what can be entered into a terminal.
/// The configuration on which the parser's grammar and behaviors are based.
/// A parse result describing the outcome of the parse operation.
- public ParseResult Parse(string commandLine, CommandLineConfiguration? configuration = null)
+ public ParseResult Parse(string commandLine, ParserConfiguration? configuration = null)
=> CommandLineParser.Parse(this, commandLine, configuration);
///
diff --git a/src/System.CommandLine/CommandLineConfiguration.cs b/src/System.CommandLine/CommandLineConfiguration.cs
deleted file mode 100644
index 80800653e1..0000000000
--- a/src/System.CommandLine/CommandLineConfiguration.cs
+++ /dev/null
@@ -1,225 +0,0 @@
-// Copyright (c) .NET Foundation and contributors. All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-
-using System.Collections.Generic;
-using System.CommandLine.Parsing;
-using System.Linq;
-using System.Threading.Tasks;
-using System.Threading;
-using System.IO;
-using System.CommandLine.Invocation;
-
-namespace System.CommandLine
-{
- ///
- /// Represents the configuration used by the .
- ///
- public class CommandLineConfiguration
- {
- private TextWriter? _output, _error;
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The root command for the parser.
- public CommandLineConfiguration(Command rootCommand)
- {
- RootCommand = rootCommand ?? throw new ArgumentNullException(nameof(rootCommand));
- }
-
- internal bool HasDirectives =>
- RootCommand switch
- {
- RootCommand root => root.Directives.Count > 0,
- _ => false
- };
-
- ///
- /// Enables the parser to recognize and expand POSIX-style bundled options.
- ///
- /// to parse POSIX bundles; otherwise, .
- ///
- /// POSIX conventions recommend that single-character options be allowed to be specified together after a single - prefix. When is set to , the following command lines are equivalent:
- ///
- ///
- /// > myapp -a -b -c
- /// > myapp -abc
- ///
- ///
- /// If an argument is provided after an option bundle, it applies to the last option in the bundle. When is set to , all of the following command lines are equivalent:
- ///
- /// > myapp -a -b -c arg
- /// > myapp -abc arg
- /// > myapp -abcarg
- ///
- ///
- ///
- public bool EnablePosixBundling { get; set; } = true;
-
- ///
- /// Enables a default exception handler to catch any unhandled exceptions thrown during invocation. Enabled by default.
- ///
- public bool EnableDefaultExceptionHandler { get; set; } = true;
-
- ///
- /// Enables signaling and handling of process termination (Ctrl+C, SIGINT, SIGTERM) via a
- /// that can be passed to a during invocation.
- /// If not provided, a default timeout of 2 seconds is enforced.
- ///
- public TimeSpan? ProcessTerminationTimeout { get; set; } = TimeSpan.FromSeconds(2);
-
- ///
- /// Response file token replacer, enabled by default.
- /// To disable response files support, this property needs to be set to null.
- ///
- ///
- /// When enabled, any token prefixed with @
can be replaced with zero or more other tokens. This is mostly commonly used to expand tokens from response files and interpolate them into a command line prior to parsing.
- ///
- public TryReplaceToken? ResponseFileTokenReplacer { get; set; } = StringExtensions.TryReadResponseFile;
-
- ///
- /// Gets the root command.
- ///
- public Command RootCommand { get; }
-
- ///
- /// The standard output. Used by Help and other facilities that write non-error information.
- /// By default it's set to .
- /// For testing purposes, it can be set to a new instance of .
- /// If you want to disable the output, please set it to .
- ///
- public TextWriter Output
- {
- get => _output ??= Console.Out;
- set => _output = value ?? throw new ArgumentNullException(nameof(value), "Use TextWriter.Null to disable the output");
- }
-
- ///
- /// The standard error. Used for printing error information like parse errors.
- /// By default it's set to .
- /// For testing purposes, it can be set to a new instance of .
- ///
- public TextWriter Error
- {
- get => _error ??= Console.Error;
- set => _error = value ?? throw new ArgumentNullException(nameof(value), "Use TextWriter.Null to disable the output");
- }
-
- ///
- /// Parses an array strings using the configured .
- ///
- /// The string arguments to parse.
- /// A parse result describing the outcome of the parse operation.
- public ParseResult Parse(IReadOnlyList args)
- => CommandLineParser.Parse(RootCommand, args, this);
-
- ///
- /// Parses a command line string value using the configured .
- ///
- /// The command line string input will be split into tokens as if it had been passed on the command line.
- /// A command line string to parse, which can include spaces and quotes equivalent to what can be entered into a terminal.
- /// A parse result describing the outcome of the parse operation.
- public ParseResult Parse(string commandLine)
- => CommandLineParser.Parse(RootCommand, commandLine, this);
-
- ///
- /// Parses a command line string value and invokes the handler for the indicated command.
- ///
- /// The exit code for the invocation.
- /// The command line string input will be split into tokens as if it had been passed on the command line.
- public int Invoke(string commandLine)
- => RootCommand.Parse(commandLine, this).Invoke();
-
- ///
- /// Parses a command line string array and invokes the handler for the indicated command.
- ///
- /// The exit code for the invocation.
- public int Invoke(string[] args)
- => RootCommand.Parse(args, this).Invoke();
-
- ///
- /// Parses a command line string value and invokes the handler for the indicated command.
- ///
- /// The exit code for the invocation.
- /// The command line string input will be split into tokens as if it had been passed on the command line.
- public Task InvokeAsync(string commandLine, CancellationToken cancellationToken = default)
- => RootCommand.Parse(commandLine, this).InvokeAsync(cancellationToken);
-
- ///
- /// Parses a command line string array and invokes the handler for the indicated command.
- ///
- /// The exit code for the invocation.
- public Task InvokeAsync(string[] args, CancellationToken cancellationToken = default)
- => RootCommand.Parse(args, this).InvokeAsync(cancellationToken);
-
- ///
- /// Throws an exception if the parser configuration is ambiguous or otherwise not valid.
- ///
- /// Due to the performance cost of this method, it is recommended to be used in unit testing or in scenarios where the parser is configured dynamically at runtime.
- /// Thrown if the configuration is found to be invalid.
- public void ThrowIfInvalid()
- {
- ThrowIfInvalid(RootCommand);
-
- static void ThrowIfInvalid(Command command)
- {
- if (command.Parents.FlattenBreadthFirst(c => c.Parents).Any(ancestor => ancestor == command))
- {
- throw new CommandLineConfigurationException($"Cycle detected in command tree. Command '{command.Name}' is its own ancestor.");
- }
-
- int count = command.Subcommands.Count + command.Options.Count;
- for (var i = 0; i < count; i++)
- {
- Symbol symbol1 = GetChild(i, command, out AliasSet? aliases1);
- for (var j = i + 1; j < count; j++)
- {
- Symbol symbol2 = GetChild(j, command, out AliasSet? aliases2);
-
- if (symbol1.Name.Equals(symbol2.Name, StringComparison.Ordinal)
- || (aliases1 is not null && aliases1.Contains(symbol2.Name)))
- {
- throw new CommandLineConfigurationException($"Duplicate alias '{symbol2.Name}' found on command '{command.Name}'.");
- }
- else if (aliases2 is not null && aliases2.Contains(symbol1.Name))
- {
- throw new CommandLineConfigurationException($"Duplicate alias '{symbol1.Name}' found on command '{command.Name}'.");
- }
-
- if (aliases1 is not null && aliases2 is not null)
- {
- // take advantage of the fact that we are dealing with two hash sets
- if (aliases1.Overlaps(aliases2))
- {
- foreach (string symbol2Alias in aliases2)
- {
- if (aliases1.Contains(symbol2Alias))
- {
- throw new CommandLineConfigurationException($"Duplicate alias '{symbol2Alias}' found on command '{command.Name}'.");
- }
- }
- }
- }
- }
-
- if (symbol1 is Command childCommand)
- {
- ThrowIfInvalid(childCommand);
- }
- }
- }
-
- static Symbol GetChild(int index, Command command, out AliasSet? aliases)
- {
- if (index < command.Subcommands.Count)
- {
- aliases = command.Subcommands[index]._aliases;
- return command.Subcommands[index];
- }
-
- aliases = command.Options[index - command.Subcommands.Count]._aliases;
- return command.Options[index - command.Subcommands.Count];
- }
- }
- }
-}
\ No newline at end of file
diff --git a/src/System.CommandLine/CommandLineConfigurationException.cs b/src/System.CommandLine/CommandLineConfigurationException.cs
deleted file mode 100644
index 35a49e88a6..0000000000
--- a/src/System.CommandLine/CommandLineConfigurationException.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright (c) .NET Foundation and contributors. All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-
-namespace System.CommandLine;
-
-///
-/// Indicates that a command line configuration is invalid.
-///
-public class CommandLineConfigurationException : Exception
-{
- ///
- public CommandLineConfigurationException(string message) : base(message)
- {
- }
-}
\ No newline at end of file
diff --git a/src/System.CommandLine/Completions/CompletionAction.cs b/src/System.CommandLine/Completions/CompletionAction.cs
index 7757568630..e6e8f36518 100644
--- a/src/System.CommandLine/Completions/CompletionAction.cs
+++ b/src/System.CommandLine/Completions/CompletionAction.cs
@@ -30,7 +30,9 @@ public override int Invoke(ParseResult parseResult)
var completions = completionParseResult.GetCompletions(position);
- parseResult.Configuration.Output.WriteLine(
+ var output = parseResult.InvocationConfiguration.Output;
+
+ output.WriteLine(
string.Join(
Environment.NewLine,
completions));
diff --git a/src/System.CommandLine/Help/HelpAction.cs b/src/System.CommandLine/Help/HelpAction.cs
index 7658ddeaad..c04a8db53a 100644
--- a/src/System.CommandLine/Help/HelpAction.cs
+++ b/src/System.CommandLine/Help/HelpAction.cs
@@ -21,7 +21,7 @@ internal HelpBuilder Builder
///
public override int Invoke(ParseResult parseResult)
{
- var output = parseResult.Configuration.Output;
+ var output = parseResult.InvocationConfiguration.Output;
var helpContext = new HelpContext(Builder,
parseResult.CommandResult.Command,
@@ -32,4 +32,4 @@ public override int Invoke(ParseResult parseResult)
return 0;
}
}
-}
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/src/System.CommandLine/Invocation/InvocationPipeline.cs b/src/System.CommandLine/Invocation/InvocationPipeline.cs
index 3cbca453ea..c41d2686d6 100644
--- a/src/System.CommandLine/Invocation/InvocationPipeline.cs
+++ b/src/System.CommandLine/Invocation/InvocationPipeline.cs
@@ -45,9 +45,12 @@ internal static async Task InvokeAsync(ParseResult parseResult, Cancellatio
case AsynchronousCommandLineAction asyncAction:
var startedInvocation = asyncAction.InvokeAsync(parseResult, cts.Token);
- if (parseResult.Configuration.ProcessTerminationTimeout.HasValue)
+
+ var timeout = parseResult.InvocationConfiguration.ProcessTerminationTimeout;
+
+ if (timeout.HasValue)
{
- terminationHandler = new(cts, startedInvocation, parseResult.Configuration.ProcessTerminationTimeout.Value);
+ terminationHandler = new(cts, startedInvocation, timeout.Value);
}
if (terminationHandler is null)
@@ -67,9 +70,9 @@ internal static async Task InvokeAsync(ParseResult parseResult, Cancellatio
throw new ArgumentOutOfRangeException(nameof(parseResult.Action));
}
}
- catch (Exception ex) when (parseResult.Configuration.EnableDefaultExceptionHandler)
+ catch (Exception ex) when (parseResult.InvocationConfiguration.EnableDefaultExceptionHandler)
{
- return DefaultExceptionHandler(ex, parseResult.Configuration);
+ return DefaultExceptionHandler(ex, parseResult);
}
finally
{
@@ -96,7 +99,7 @@ internal static int Invoke(ParseResult parseResult)
if (action is not SynchronousCommandLineAction)
{
- parseResult.Configuration.EnableDefaultExceptionHandler = false;
+ parseResult.InvocationConfiguration.EnableDefaultExceptionHandler = false;
throw new Exception(
$"This should not happen. An instance of {nameof(AsynchronousCommandLineAction)} ({action}) was called within {nameof(InvocationPipeline)}.{nameof(Invoke)}. This is supposed to be detected earlier resulting in a call to {nameof(InvocationPipeline)}{nameof(InvokeAsync)}");
}
@@ -114,9 +117,9 @@ internal static int Invoke(ParseResult parseResult)
return syncAction.Invoke(parseResult);
}
- catch (Exception ex) when (parseResult.Configuration.EnableDefaultExceptionHandler)
+ catch (Exception ex) when (parseResult.InvocationConfiguration.EnableDefaultExceptionHandler)
{
- return DefaultExceptionHandler(ex, parseResult.Configuration);
+ return DefaultExceptionHandler(ex, parseResult);
}
default:
@@ -124,15 +127,17 @@ internal static int Invoke(ParseResult parseResult)
}
}
- private static int DefaultExceptionHandler(Exception exception, CommandLineConfiguration config)
+ private static int DefaultExceptionHandler(Exception exception, ParseResult parseResult)
{
if (exception is not OperationCanceledException)
{
ConsoleHelpers.ResetTerminalForegroundColor();
ConsoleHelpers.SetTerminalForegroundRed();
- config.Error.Write(LocalizationResources.ExceptionHandlerHeader());
- config.Error.WriteLine(exception.ToString());
+ var error = parseResult.InvocationConfiguration.Error;
+
+ error.Write(LocalizationResources.ExceptionHandlerHeader());
+ error.WriteLine(exception.ToString());
ConsoleHelpers.ResetTerminalForegroundColor();
}
diff --git a/src/System.CommandLine/Invocation/ParseErrorAction.cs b/src/System.CommandLine/Invocation/ParseErrorAction.cs
index fdb4e01b45..3f35c2cc1e 100644
--- a/src/System.CommandLine/Invocation/ParseErrorAction.cs
+++ b/src/System.CommandLine/Invocation/ParseErrorAction.cs
@@ -49,12 +49,14 @@ private static void WriteErrorDetails(ParseResult parseResult)
ConsoleHelpers.ResetTerminalForegroundColor();
ConsoleHelpers.SetTerminalForegroundRed();
+ var stdErr = parseResult.InvocationConfiguration.Error;
+
foreach (var error in parseResult.Errors)
{
- parseResult.Configuration.Error.WriteLine(error.Message);
+ stdErr.WriteLine(error.Message);
}
- parseResult.Configuration.Error.WriteLine();
+ stdErr.WriteLine();
ConsoleHelpers.ResetTerminalForegroundColor();
}
@@ -96,17 +98,17 @@ private static void WriteTypoCorrectionSuggestions(ParseResult parseResult)
{
if (first)
{
- parseResult.Configuration.Output.WriteLine(LocalizationResources.SuggestionsTokenNotMatched(token));
+ parseResult.InvocationConfiguration.Output.WriteLine(LocalizationResources.SuggestionsTokenNotMatched(token));
first = false;
}
- parseResult.Configuration.Output.WriteLine(suggestion);
+ parseResult.InvocationConfiguration.Output.WriteLine(suggestion);
}
}
if (unmatchedTokens.Count != 0)
{
- parseResult.Configuration.Output.WriteLine();
+ parseResult.InvocationConfiguration.Output.WriteLine();
}
static IEnumerable GetPossibleTokens(Command targetSymbol, string token)
diff --git a/src/System.CommandLine/InvocationConfiguration.cs b/src/System.CommandLine/InvocationConfiguration.cs
new file mode 100644
index 0000000000..a7eaeedd85
--- /dev/null
+++ b/src/System.CommandLine/InvocationConfiguration.cs
@@ -0,0 +1,45 @@
+using System.CommandLine.Invocation;
+using System.IO;
+using System.Threading;
+
+namespace System.CommandLine;
+
+public class InvocationConfiguration
+{
+ private TextWriter? _output, _error;
+
+ ///
+ /// Enables a default exception handler to catch any unhandled exceptions thrown during invocation. Enabled by default.
+ ///
+ public bool EnableDefaultExceptionHandler { get; set; } = true;
+
+ ///
+ /// Enables signaling and handling of process termination (Ctrl+C, SIGINT, SIGTERM) via a
+ /// that can be passed to a during invocation.
+ /// If not provided, a default timeout of 2 seconds is enforced.
+ ///
+ public TimeSpan? ProcessTerminationTimeout { get; set; }
+
+ ///
+ /// The standard output. Used by Help and other facilities that write non-error information.
+ /// By default it's set to .
+ /// For testing purposes, it can be set to a new instance of .
+ /// If you want to disable the output, please set it to .
+ ///
+ public TextWriter Output
+ {
+ get => _output ??= Console.Out;
+ set => _output = value ?? throw new ArgumentNullException(nameof(value), "Use TextWriter.Null to disable the output");
+ }
+
+ ///
+ /// The standard error. Used for printing error information like parse errors.
+ /// By default it's set to .
+ /// For testing purposes, it can be set to a new instance of .
+ ///
+ public TextWriter Error
+ {
+ get => _error ??= Console.Error;
+ set => _error = value ?? throw new ArgumentNullException(nameof(value), "Use TextWriter.Null to disable the output");
+ }
+}
\ No newline at end of file
diff --git a/src/System.CommandLine/ParseResult.cs b/src/System.CommandLine/ParseResult.cs
index 0bbd1ad093..3153acaacf 100644
--- a/src/System.CommandLine/ParseResult.cs
+++ b/src/System.CommandLine/ParseResult.cs
@@ -21,9 +21,10 @@ public sealed class ParseResult
private CompletionContext? _completionContext;
private readonly CommandLineAction? _action;
private readonly List? _preActions;
+ private InvocationConfiguration? _invocationConfiguration;
internal ParseResult(
- CommandLineConfiguration configuration,
+ ParserConfiguration configuration,
CommandResult rootCommandResult,
CommandResult commandResult,
List tokens,
@@ -68,7 +69,16 @@ internal ParseResult(
///
/// The configuration used to produce the parse result.
///
- public CommandLineConfiguration Configuration { get; }
+ public ParserConfiguration Configuration { get; }
+
+ ///
+ /// The configuration used to specify command line runtime behavior.
+ ///
+ public InvocationConfiguration InvocationConfiguration
+ {
+ get => _invocationConfiguration ??= new();
+ private set => _invocationConfiguration = value;
+ }
///
/// Gets the root command result.
@@ -262,19 +272,35 @@ static string[] OptionsWithArgumentLimitReached(CommandResult commandResult) =>
///
/// Invokes the appropriate command handler for a parsed command line input.
///
+ /// The configuration used to define invocation behaviors.
/// A token that can be used to cancel an invocation.
/// A task whose result can be used as a process exit code.
- public Task InvokeAsync(CancellationToken cancellationToken = default)
- => InvocationPipeline.InvokeAsync(this, cancellationToken);
+ public Task InvokeAsync(
+ InvocationConfiguration? configuration = null,
+ CancellationToken cancellationToken = default)
+ {
+ if (configuration is not null)
+ {
+ InvocationConfiguration = configuration;
+ }
+
+ return InvocationPipeline.InvokeAsync(this, cancellationToken);
+ }
///
/// Invokes the appropriate command handler for a parsed command line input.
///
+ /// The configuration used to define invocation behaviors.
/// A value that can be used as a process exit code.
- public int Invoke()
+ public int Invoke(InvocationConfiguration? configuration = null)
{
var useAsync = false;
+ if (configuration is not null)
+ {
+ InvocationConfiguration = configuration;
+ }
+
if (Action is AsynchronousCommandLineAction)
{
useAsync = true;
diff --git a/src/System.CommandLine/ParserConfiguration.cs b/src/System.CommandLine/ParserConfiguration.cs
new file mode 100644
index 0000000000..f239c3c4b4
--- /dev/null
+++ b/src/System.CommandLine/ParserConfiguration.cs
@@ -0,0 +1,45 @@
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using System.CommandLine.Parsing;
+using System.Linq;
+
+namespace System.CommandLine
+{
+ ///
+ /// Represents the configuration used by the .
+ ///
+ public class ParserConfiguration
+ {
+ ///
+ /// Enables the parser to recognize and expand POSIX-style bundled options.
+ ///
+ /// to parse POSIX bundles; otherwise, .
+ ///
+ /// POSIX conventions recommend that single-character options be allowed to be specified together after a single - prefix. When is set to , the following command lines are equivalent:
+ ///
+ ///
+ /// > myapp -a -b -c
+ /// > myapp -abc
+ ///
+ ///
+ /// If an argument is provided after an option bundle, it applies to the last option in the bundle. When is set to , all of the following command lines are equivalent:
+ ///
+ /// > myapp -a -b -c arg
+ /// > myapp -abc arg
+ /// > myapp -abcarg
+ ///
+ ///
+ ///
+ public bool EnablePosixBundling { get; set; } = true;
+
+ ///
+ /// Response file token replacer, enabled by default.
+ /// To disable response files support, this property needs to be set to null.
+ ///
+ ///
+ /// When enabled, any token prefixed with @
can be replaced with zero or more other tokens. This is mostly commonly used to expand tokens from response files and interpolate them into a command line prior to parsing.
+ ///
+ public TryReplaceToken? ResponseFileTokenReplacer { get; set; } = StringExtensions.TryReadResponseFile;
+ }
+}
\ No newline at end of file
diff --git a/src/System.CommandLine/Parsing/CommandLineParser.cs b/src/System.CommandLine/Parsing/CommandLineParser.cs
index 69d629b31d..ee60feddda 100644
--- a/src/System.CommandLine/Parsing/CommandLineParser.cs
+++ b/src/System.CommandLine/Parsing/CommandLineParser.cs
@@ -18,7 +18,7 @@ public static class CommandLineParser
/// The string array typically passed to a program's Main method.
/// The configuration on which the parser's grammar and behaviors are based.
/// A providing details about the parse operation.
- public static ParseResult Parse(Command command, IReadOnlyList args, CommandLineConfiguration? configuration = null)
+ public static ParseResult Parse(Command command, IReadOnlyList args, ParserConfiguration? configuration = null)
=> Parse(command, args, null, configuration);
///
@@ -29,7 +29,7 @@ public static ParseResult Parse(Command command, IReadOnlyList args, Com
/// The configuration on which the parser's grammar and behaviors are based.
/// The command line string input will be split into tokens as if it had been passed on the command line.
/// A providing details about the parse operation.
- public static ParseResult Parse(Command command, string commandLine, CommandLineConfiguration? configuration = null)
+ public static ParseResult Parse(Command command, string commandLine, ParserConfiguration? configuration = null)
=> Parse(command, SplitCommandLine(commandLine).ToArray(), commandLine, configuration);
///
@@ -139,16 +139,17 @@ private static ParseResult Parse(
Command command,
IReadOnlyList arguments,
string? rawInput,
- CommandLineConfiguration? configuration)
+ ParserConfiguration? configuration)
{
if (arguments is null)
{
throw new ArgumentNullException(nameof(arguments));
}
- configuration ??= new CommandLineConfiguration(command);
+ configuration ??= new ParserConfiguration();
arguments.Tokenize(
+ command,
configuration,
inferRootCommand: rawInput is not null,
out List tokens,
@@ -156,6 +157,7 @@ private static ParseResult Parse(
var operation = new ParseOperation(
tokens,
+ command,
configuration,
tokenizationErrors,
rawInput);
diff --git a/src/System.CommandLine/Parsing/ParseDiagramAction.cs b/src/System.CommandLine/Parsing/ParseDiagramAction.cs
index bbae57609f..f3abe87b27 100644
--- a/src/System.CommandLine/Parsing/ParseDiagramAction.cs
+++ b/src/System.CommandLine/Parsing/ParseDiagramAction.cs
@@ -20,7 +20,7 @@ internal sealed class ParseDiagramAction : SynchronousCommandLineAction
public override int Invoke(ParseResult parseResult)
{
- parseResult.Configuration.Output.WriteLine(Diagram(parseResult));
+ parseResult.InvocationConfiguration.Output.WriteLine(Diagram(parseResult));
return parseResult.Errors.Count == 0 ? 0 : _parseErrorReturnValue;
}
diff --git a/src/System.CommandLine/Parsing/ParseOperation.cs b/src/System.CommandLine/Parsing/ParseOperation.cs
index de7dcf2d9c..8ac410566c 100644
--- a/src/System.CommandLine/Parsing/ParseOperation.cs
+++ b/src/System.CommandLine/Parsing/ParseOperation.cs
@@ -10,7 +10,7 @@ namespace System.CommandLine.Parsing
internal sealed class ParseOperation
{
private readonly List _tokens;
- private readonly CommandLineConfiguration _configuration;
+ private readonly ParserConfiguration _configuration;
private readonly string? _rawInput;
private readonly SymbolResultTree _symbolResultTree;
private readonly CommandResult _rootCommandResult;
@@ -21,22 +21,25 @@ internal sealed class ParseOperation
private bool _isTerminatingDirectiveSpecified;
private CommandLineAction? _primaryAction;
private List? _preActions;
+ private readonly Command _rootCommand;
public ParseOperation(
List tokens,
- CommandLineConfiguration configuration,
+ Command rootCommand,
+ ParserConfiguration configuration,
List? tokenizeErrors,
string? rawInput)
{
_tokens = tokens;
_configuration = configuration;
+ _rootCommand = rootCommand;
_rawInput = rawInput;
- _symbolResultTree = new(_configuration.RootCommand, tokenizeErrors);
+ _symbolResultTree = new(_rootCommand, tokenizeErrors);
_innermostCommandResult = _rootCommandResult = new CommandResult(
- _configuration.RootCommand,
+ _rootCommand,
CurrentToken,
_symbolResultTree);
- _symbolResultTree.Add(_configuration.RootCommand, _rootCommandResult);
+ _symbolResultTree.Add(_rootCommand, _rootCommandResult);
Advance();
}
@@ -296,7 +299,7 @@ private void ParseDirectives()
{
while (More(out TokenType currentTokenType) && currentTokenType == TokenType.Directive)
{
- if (_configuration.HasDirectives)
+ if (_rootCommand is RootCommand { Directives.Count: > 0 })
{
ParseDirective(); // kept in separate method to avoid JIT
}
diff --git a/src/System.CommandLine/Parsing/StringExtensions.cs b/src/System.CommandLine/Parsing/StringExtensions.cs
index b1f7b63ad2..a018f04fcd 100644
--- a/src/System.CommandLine/Parsing/StringExtensions.cs
+++ b/src/System.CommandLine/Parsing/StringExtensions.cs
@@ -27,7 +27,8 @@ internal static int IndexOfCaseInsensitive(
// this method is not returning a Value Tuple or a dedicated type to avoid JITting
internal static void Tokenize(
this IReadOnlyList args,
- CommandLineConfiguration configuration,
+ Command rootCommand,
+ ParserConfiguration configuration,
bool inferRootCommand,
out List tokens,
out List? errors)
@@ -36,22 +37,22 @@ internal static void Tokenize(
List? errorList = null;
- var currentCommand = configuration.RootCommand;
+ var currentCommand = rootCommand;
var foundDoubleDash = false;
var foundEndOfDirectives = false;
var tokenList = new List(args.Count);
- var knownTokens = configuration.RootCommand.ValidTokens();
+ var knownTokens = rootCommand.ValidTokens();
- int i = FirstArgumentIsRootCommand(args, configuration.RootCommand, inferRootCommand)
+ int i = FirstArgumentIsRootCommand(args, rootCommand, inferRootCommand)
? 0
: FirstArgIsNotRootCommand;
for (; i < args.Count; i++)
{
var arg = i == FirstArgIsNotRootCommand
- ? configuration.RootCommand.Name
+ ? rootCommand.Name
: args[i];
if (foundDoubleDash)
@@ -96,7 +97,7 @@ internal static void Tokenize(
continue;
}
- if (!configuration.RootCommand.EqualsNameOrAlias(arg))
+ if (!rootCommand.EqualsNameOrAlias(arg))
{
foundEndOfDirectives = true;
}
@@ -143,7 +144,7 @@ internal static void Tokenize(
Command cmd = (Command)token.Symbol!;
if (cmd != currentCommand)
{
- if (cmd != configuration.RootCommand)
+ if (cmd != rootCommand)
{
knownTokens = cmd.ValidTokens(); // config contains Directives, they are allowed only for RootCommand
}
diff --git a/src/System.CommandLine/VersionOption.cs b/src/System.CommandLine/VersionOption.cs
index 6c31ab1485..0fde75a764 100644
--- a/src/System.CommandLine/VersionOption.cs
+++ b/src/System.CommandLine/VersionOption.cs
@@ -65,7 +65,7 @@ private sealed class VersionOptionAction : SynchronousCommandLineAction
{
public override int Invoke(ParseResult parseResult)
{
- parseResult.Configuration.Output.WriteLine(RootCommand.ExecutableVersion);
+ parseResult.InvocationConfiguration.Output.WriteLine(RootCommand.ExecutableVersion);
return 0;
}
}