Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/command-line-api/Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.0.1" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="4.0.1" />
<!-- Runtime dependencies -->
<PackageVersion Include="Microsoft.Extensions.Configuration.CommandLine" Version="6.0.0" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="6.0.0" />
<PackageVersion Include="Microsoft.Extensions.Hosting" Version="6.0.0" />
<PackageVersion Include="Microsoft.Extensions.Configuration.CommandLine" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.2" />
<PackageVersion Include="Microsoft.Extensions.Hosting" Version="8.0.1" />
<!-- external dependencies -->
<PackageVersion Include="ApprovalTests" Version="7.0.0-beta.3" />
<PackageVersion Include="BenchmarkDotNet" Version="0.13.1" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@
public System.Collections.Generic.List<System.Action<System.CommandLine.Parsing.OptionResult>> Validators { get; }
public System.Type ValueType { get; }
public System.Collections.Generic.IEnumerable<System.CommandLine.Completions.CompletionItem> GetCompletions(System.CommandLine.Completions.CompletionContext context)
public System.Object GetDefaultValue()
public class Option<T> : Option
.ctor(System.String name, System.String[] aliases)
public Func<System.CommandLine.Parsing.ArgumentResult,T> CustomParser { get; set; }
Expand All @@ -123,11 +124,15 @@
public System.Collections.Generic.IReadOnlyList<System.String> UnmatchedTokens { get; }
public System.CommandLine.Completions.CompletionContext GetCompletionContext()
public System.Collections.Generic.IEnumerable<System.CommandLine.Completions.CompletionItem> GetCompletions(System.Nullable<System.Int32> position = null)
public T GetRequiredValue<T>(Argument<T> argument)
public T GetRequiredValue<T>(Option<T> option)
public T GetRequiredValue<T>(System.String name)
public System.CommandLine.Parsing.ArgumentResult GetResult(Argument argument)
public System.CommandLine.Parsing.CommandResult GetResult(Command command)
public System.CommandLine.Parsing.OptionResult GetResult(Option option)
public System.CommandLine.Parsing.DirectiveResult GetResult(Directive directive)
public System.CommandLine.Parsing.SymbolResult GetResult(Symbol symbol)
public System.CommandLine.Parsing.SymbolResult GetResult(System.String name)
public T GetValue<T>(Argument<T> argument)
public T GetValue<T>(Option<T> option)
public T GetValue<T>(System.String name)
Expand Down Expand Up @@ -178,48 +183,11 @@ System.CommandLine.Completions
System.CommandLine.Help
public class HelpAction : System.CommandLine.Invocation.SynchronousCommandLineAction
.ctor()
public HelpBuilder Builder { get; set; }
public System.Int32 Invoke(System.CommandLine.ParseResult parseResult)
public class HelpBuilder
.ctor(System.Int32 maxWidth = 2147483647)
public System.Int32 MaxWidth { get; }
public System.Void CustomizeLayout(System.Func<HelpContext,System.Collections.Generic.IEnumerable<System.Func<HelpContext,System.Boolean>>> getLayout)
public System.Void CustomizeSymbol(System.CommandLine.Symbol symbol, System.Func<HelpContext,System.String> firstColumnText = null, System.Func<HelpContext,System.String> secondColumnText = null, System.Func<HelpContext,System.String> defaultValue = null)
public System.Void CustomizeSymbol(System.CommandLine.Symbol symbol, System.String firstColumnText = null, System.String secondColumnText = null, System.String defaultValue = null)
public TwoColumnHelpRow GetTwoColumnRow(System.CommandLine.Symbol symbol, HelpContext context)
public System.Void Write(HelpContext context)
public System.Void Write(System.CommandLine.Command command, System.IO.TextWriter writer)
public System.Void WriteColumns(System.Collections.Generic.IReadOnlyList<TwoColumnHelpRow> items, HelpContext context)
static class Default
public static System.Func<HelpContext,System.Boolean> AdditionalArgumentsSection()
public static System.Func<HelpContext,System.Boolean> CommandArgumentsSection()
public static System.Func<HelpContext,System.Boolean> CommandUsageSection()
public static System.String GetArgumentDefaultValue(System.CommandLine.Argument argument)
public static System.String GetArgumentDescription(System.CommandLine.Argument argument)
public static System.String GetArgumentUsageLabel(System.CommandLine.Argument argument)
public static System.String GetCommandUsageLabel(System.CommandLine.Command symbol)
public static System.Collections.Generic.IEnumerable<System.Func<HelpContext,System.Boolean>> GetLayout()
public static System.String GetOptionUsageLabel(System.CommandLine.Option symbol)
public static System.Func<HelpContext,System.Boolean> OptionsSection()
public static System.Func<HelpContext,System.Boolean> SubcommandsSection()
public static System.Func<HelpContext,System.Boolean> SynopsisSection()
public class HelpContext
.ctor(HelpBuilder helpBuilder, System.CommandLine.Command command, System.IO.TextWriter output, System.CommandLine.ParseResult parseResult = null)
public System.CommandLine.Command Command { get; }
public HelpBuilder HelpBuilder { get; }
public System.IO.TextWriter Output { get; }
public System.CommandLine.ParseResult ParseResult { get; }
public class HelpOption : System.CommandLine.Option<System.Boolean>
.ctor()
.ctor(System.String name, System.String[] aliases)
public System.CommandLine.Invocation.CommandLineAction Action { get; set; }
public class TwoColumnHelpRow, System.IEquatable<TwoColumnHelpRow>
.ctor(System.String firstColumnText, System.String secondColumnText)
public System.String FirstColumnText { get; }
public System.String SecondColumnText { get; }
public System.Boolean Equals(System.Object obj)
public System.Boolean Equals(TwoColumnHelpRow other)
public System.Int32 GetHashCode()
System.CommandLine.Invocation
public abstract class AsynchronousCommandLineAction : CommandLineAction
public System.Threading.Tasks.Task<System.Int32> InvokeAsync(System.CommandLine.ParseResult parseResult, System.Threading.CancellationToken cancellationToken = null)
Expand Down Expand Up @@ -269,6 +237,9 @@ System.CommandLine.Parsing
public SymbolResult Parent { get; }
public System.Collections.Generic.IReadOnlyList<Token> Tokens { get; }
public System.Void AddError(System.String errorMessage)
public T GetRequiredValue<T>(Argument<T> argument)
public T GetRequiredValue<T>(Option<T> option)
public T GetRequiredValue<T>(System.String name)
public ArgumentResult GetResult(System.CommandLine.Argument argument)
public CommandResult GetResult(System.CommandLine.Command command)
public OptionResult GetResult(System.CommandLine.Option option)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,48 @@ public void When_an_option_and_argument_use_same_name_on_the_same_level_of_the_t
.Where(ex => ex.Message == $"Command {command.Name} has more than one child named \"{sameName}\".");
}

[Fact]
public void When_options_use_same_name_on_different_levels_of_the_tree_no_exception_is_thrown()
{
const string sameName = "same";

RootCommand command = new()
{
new Command("left")
{
new Option<int>(sameName)
},
new Command("right")
{
new Option<int>(sameName)
},
};

command.Parse($"left {sameName} 1").GetValue<int>(sameName).Should().Be(1);
command.Parse($"right {sameName} 2").GetValue<int>(sameName).Should().Be(2);
}

[Fact]
public void When_the_same_option_used_in_different_levels_of_the_tree_no_exception_is_thrown()
{
Option<int> multipleParents = new("--int");

RootCommand command = new()
{
new Command("left")
{
multipleParents
},
new Command("right")
{
multipleParents
},
};

command.Parse($"left {multipleParents.Name} 1").GetValue<int>(multipleParents.Name).Should().Be(1);
command.Parse($"right {multipleParents.Name} 2").GetValue<int>(multipleParents.Name).Should().Be(2);
}

[Fact]
public void When_an_option_and_argument_use_same_name_on_different_levels_of_the_tree_the_value_which_belongs_to_parsed_command_is_returned()
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using System.CommandLine.Invocation;

namespace System.CommandLine.Help
{
/// <summary>
/// Provides command line help.
/// </summary>
public sealed class CustomHelpAction : SynchronousCommandLineAction
{
private HelpBuilder? _builder;

/// <summary>
/// Specifies an <see cref="Builder"/> to be used to format help output when help is requested.
/// </summary>
internal HelpBuilder Builder
{
get => _builder ??= new HelpBuilder(Console.IsOutputRedirected ? int.MaxValue : Console.WindowWidth);
set => _builder = value ?? throw new ArgumentNullException(nameof(value));
}

/// <inheritdoc />
public override int Invoke(ParseResult parseResult)
{
var output = parseResult.Configuration.Output;

var helpContext = new HelpContext(Builder,
parseResult.CommandResult.Command,
output);

Builder.Write(helpContext);

return 0;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace System.CommandLine.Tests.Help
{
public static class HelpBuilderExtensions
{
public static void Write(
internal static void Write(
this HelpBuilder builder,
Command command,
TextWriter writer) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ public void Option_can_customize_first_column_text_based_on_parse_result()
: optionBFirstColumnText);
command.Options.Add(new HelpOption()
{
Action = new HelpAction()
Action = new CustomHelpAction()
{
Builder = helpBuilder
}
Expand Down Expand Up @@ -140,7 +140,7 @@ public void Option_can_customize_second_column_text_based_on_parse_result()
: optionBDescription);
command.Options.Add(new HelpOption
{
Action = new HelpAction
Action = new CustomHelpAction
{
Builder = helpBuilder
}
Expand Down Expand Up @@ -269,7 +269,7 @@ public void Option_can_fallback_to_default_when_customizing(bool conditionA, boo

command.Options.Add(new HelpOption
{
Action = new HelpAction
Action = new CustomHelpAction
{
Builder = helpBuilder
}
Expand Down Expand Up @@ -317,7 +317,7 @@ public void Argument_can_fallback_to_default_when_customizing(

command.Options.Add(new HelpOption
{
Action = new HelpAction
Action = new CustomHelpAction
{
Builder = helpBuilder
}
Expand All @@ -336,11 +336,20 @@ public void Individual_symbols_can_be_customized()
var option = new Option<int>("-x") { Description = "The default option description" };
var argument = new Argument<int>("int-value") { Description = "The default argument description" };

var rootCommand = new RootCommand
CustomHelpAction helpAction = new();
helpAction.Builder.CustomizeSymbol(subcommand, secondColumnText: "The custom command description");
helpAction.Builder.CustomizeSymbol(option, secondColumnText: "The custom option description");
helpAction.Builder.CustomizeSymbol(argument, secondColumnText: "The custom argument description");

var rootCommand = new Command("name")
{
subcommand,
option,
argument,
new HelpOption()
{
Action = helpAction
}
};

CommandLineConfiguration config = new(rootCommand)
Expand All @@ -350,13 +359,6 @@ public void Individual_symbols_can_be_customized()

ParseResult parseResult = rootCommand.Parse("-h", config);

if (parseResult.Action is HelpAction helpAction)
{
helpAction.Builder.CustomizeSymbol(subcommand, secondColumnText: "The custom command description");
helpAction.Builder.CustomizeSymbol(option, secondColumnText: "The custom option description");
helpAction.Builder.CustomizeSymbol(argument, secondColumnText: "The custom argument description");
}

parseResult.Invoke();

config.Output
Expand All @@ -370,18 +372,16 @@ public void Individual_symbols_can_be_customized()
[Fact]
public void Help_sections_can_be_replaced()
{
CommandLineConfiguration config = new(new RootCommand())
CustomHelpAction helpAction = new();
helpAction.Builder.CustomizeLayout(CustomLayout);

CommandLineConfiguration config = new(new Command("name") { new HelpOption() { Action = helpAction} })
{
Output = new StringWriter()
};

ParseResult parseResult = config.Parse("-h");

if (parseResult.Action is HelpAction helpAction)
{
helpAction.Builder.CustomizeLayout(CustomLayout);
}

parseResult.Invoke();

config.Output.ToString().Should().Be($"one{NewLine}{NewLine}two{NewLine}{NewLine}three{NewLine}{NewLine}");
Expand All @@ -397,20 +397,18 @@ IEnumerable<Func<HelpContext, bool>> CustomLayout(HelpContext _)
[Fact]
public void Help_sections_can_be_supplemented()
{
CommandLineConfiguration config = new(new RootCommand("hello"))
CustomHelpAction helpAction = new();
helpAction.Builder.CustomizeLayout(CustomLayout);

CommandLineConfiguration config = new(new Command("hello") { new HelpOption() { Action = helpAction } })
{
Output = new StringWriter(),
};

var defaultHelp = GetDefaultHelp(config.RootCommand);
var defaultHelp = GetDefaultHelp(new Command("hello"));

ParseResult parseResult = config.Parse("-h");

if (parseResult.Action is HelpAction helpAction)
{
helpAction.Builder.CustomizeLayout(CustomLayout);
}

parseResult.Invoke();

var output = config.Output.ToString();
Expand Down Expand Up @@ -444,7 +442,7 @@ public void Layout_can_be_composed_dynamically_based_on_context()
commandWithCustomHelp
};

command.Options.OfType<HelpOption>().Single().Action = new HelpAction
command.Options.OfType<HelpOption>().Single().Action = new CustomHelpAction
{
Builder = helpBuilder
};
Expand Down Expand Up @@ -480,7 +478,7 @@ public void Help_default_sections_can_be_wrapped()
},
new HelpOption
{
Action = new HelpAction
Action = new CustomHelpAction
{
Builder = new HelpBuilder(30)
}
Expand Down Expand Up @@ -509,19 +507,17 @@ public void Help_default_sections_can_be_wrapped()
[Fact]
public void Help_customized_sections_can_be_wrapped()
{
CommandLineConfiguration config = new(new RootCommand())
CustomHelpAction helpAction = new();
helpAction.Builder = new HelpBuilder(10);
helpAction.Builder.CustomizeLayout(CustomLayout);

CommandLineConfiguration config = new(new Command("name") { new HelpOption() { Action = helpAction } })
{
Output = new StringWriter()
};

ParseResult parseResult = config.Parse("-h");

if (parseResult.Action is HelpAction helpAction)
{
helpAction.Builder = new HelpBuilder(10);
helpAction.Builder.CustomizeLayout(CustomLayout);
}

parseResult.Invoke();

string result = config.Output.ToString();
Expand Down
Loading