Skip to content

Commit 4ba4a28

Browse files
authored
merge ParseDirectiveAction and ParseResultExtensions into one internal type (#2125)
make ParseDirectiveAction.InvokeAsync actually async: use the new WriteLine(StringBuilder, CancellationToken) overload
1 parent dcbd1c5 commit 4ba4a28

File tree

7 files changed

+94
-37
lines changed

7 files changed

+94
-37
lines changed

src/System.CommandLine.ApiCompatibility.Tests/ApiCompatibilityApprovalTests.System_CommandLine_api_is_not_changed.approved.txt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -258,8 +258,6 @@ System.CommandLine.Parsing
258258
public static System.CommandLine.ParseResult Parse(System.CommandLine.Command command, System.Collections.Generic.IReadOnlyList<System.String> args, System.CommandLine.CommandLineConfiguration configuration = null)
259259
public static System.CommandLine.ParseResult Parse(System.CommandLine.Command command, System.String commandLine, System.CommandLine.CommandLineConfiguration configuration = null)
260260
public static System.Collections.Generic.IEnumerable<System.String> SplitCommandLine(System.String commandLine)
261-
public static class ParseResultExtensions
262-
public static System.String Diagram(this System.CommandLine.ParseResult parseResult)
263261
public abstract class SymbolResult
264262
public SymbolResult Parent { get; }
265263
public System.Collections.Generic.IReadOnlyList<Token> Tokens { get; }

src/System.CommandLine.Benchmarks/CommandLine/Perf_Parser_ParseResult.cs

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@
44
using System.Collections.Generic;
55
using System.CommandLine.Benchmarks.Helpers;
66
using System.CommandLine.Parsing;
7+
using System.IO;
78
using System.Linq;
9+
using System.Text;
10+
using System.Threading.Tasks;
811
using BenchmarkDotNet.Attributes;
912

1013
namespace System.CommandLine.Benchmarks.CommandLine
@@ -16,14 +19,17 @@ namespace System.CommandLine.Benchmarks.CommandLine
1619
public class Perf_Parser_ParseResult
1720
{
1821
private readonly CommandLineConfiguration _configuration;
22+
private readonly StringWriter _output;
1923

2024
public Perf_Parser_ParseResult()
2125
{
26+
_output = new StringWriter();
2227
var option = new Option<bool>("-opt");
2328

2429
_configuration = new CommandLineConfiguration(new RootCommand { option })
2530
{
26-
Directives = { new ParseDirective() }
31+
Directives = { new ParseDirective() },
32+
Output = _output
2733
};
2834
}
2935

@@ -49,6 +55,29 @@ public ParseResult ParseResult_Directives(string input)
4955
[Benchmark]
5056
[ArgumentsSource(nameof(GenerateTestParseResults))]
5157
public string ParseResult_Diagram(BdnParam<ParseResult> parseResult)
52-
=> parseResult.Value.Diagram();
58+
{
59+
StringBuilder stringBuilder = _output.GetStringBuilder();
60+
61+
// clear the contents, so each benchmark has the same starting state
62+
stringBuilder.Clear();
63+
64+
parseResult.Value.Action!.Invoke(parseResult.Value);
65+
66+
return stringBuilder.ToString();
67+
}
68+
69+
[Benchmark]
70+
[ArgumentsSource(nameof(GenerateTestParseResults))]
71+
public async Task<string> ParseResult_DiagramAsync(BdnParam<ParseResult> parseResult)
72+
{
73+
StringBuilder stringBuilder = _output.GetStringBuilder();
74+
75+
// clear the contents, so each benchmark has the same starting state
76+
stringBuilder.Clear();
77+
78+
await parseResult.Value.Action!.InvokeAsync(parseResult.Value);
79+
80+
return stringBuilder.ToString();
81+
}
5382
}
5483
}

src/System.CommandLine.Rendering.Tests/ViewRenderingTests.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
// Copyright (c) .NET Foundation and contributors. All rights reserved.
22
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
33

4-
using System.CommandLine.IO;
5-
using System.CommandLine.Parsing;
64
using System.CommandLine.Rendering.Views;
75
using System.CommandLine.Tests.Utility;
86
using System.Drawing;
@@ -35,7 +33,7 @@ public void Views_can_be_used_for_specific_types()
3533

3634
config.Invoke("");
3735

38-
terminal.Out.ToString().Should().Contain(parseResult.Diagram());
36+
terminal.Out.ToString().Should().Contain(parseResult.ToString());
3937
}
4038

4139
[Theory]
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
using System.IO;
2+
3+
namespace System.CommandLine.Tests
4+
{
5+
internal static class ParseResultExtensions
6+
{
7+
internal static string Diagram(this ParseResult parseResult)
8+
{
9+
TextWriter outputBefore = parseResult.Configuration.Output;
10+
11+
try
12+
{
13+
parseResult.Configuration.Output = new StringWriter();
14+
new ParseDirective().Action.Invoke(parseResult);
15+
return parseResult.Configuration.Output.ToString()
16+
.TrimEnd(); // the directive adds a new line, tests that used to rely on Diagram extension method don't expect it
17+
}
18+
finally
19+
{
20+
// some of the tests check the Output after getting the Diagram
21+
parseResult.Configuration.Output = outputBefore;
22+
}
23+
}
24+
}
25+
}
Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
using System.CommandLine.Parsing;
2-
using System.Threading;
3-
using System.Threading.Tasks;
42

53
namespace System.CommandLine
64
{
75
/// <summary>
8-
/// Enables the use of the <c>[parse]</c> directive, which when specified on the command line will short circuit normal command handling and display a diagram explaining the parse result for the command line input.
6+
/// Enables the use of the <c>[parse]</c> directive, which when specified on the command line will short
7+
/// circuit normal command handling and display a diagram explaining the parse result for the command line input.
98
/// </summary>
109
public sealed class ParseDirective : Directive
1110
{
@@ -27,23 +26,5 @@ public override CliAction? Action
2726
get => _action ??= new ParseDirectiveAction(DefaultErrorExitCode);
2827
set => _action = value ?? throw new ArgumentNullException(nameof(value));
2928
}
30-
31-
private sealed class ParseDirectiveAction : CliAction
32-
{
33-
private readonly int _errorExitCode;
34-
35-
internal ParseDirectiveAction(int errorExitCode) => _errorExitCode = errorExitCode;
36-
37-
public override int Invoke(ParseResult parseResult)
38-
{
39-
parseResult.Configuration.Output.WriteLine(parseResult.Diagram());
40-
return parseResult.Errors.Count == 0 ? 0 : _errorExitCode;
41-
}
42-
43-
public override Task<int> InvokeAsync(ParseResult parseResult, CancellationToken cancellationToken = default)
44-
=> cancellationToken.IsCancellationRequested
45-
? Task.FromCanceled<int>(cancellationToken)
46-
: Task.FromResult(Invoke(parseResult));
47-
}
4829
}
4930
}

src/System.CommandLine/ParseResult.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ void Populate<TSymbol>(Dictionary<string, SymbolResult?> cache, IList<TSymbol> s
194194
}
195195

196196
/// <inheritdoc />
197-
public override string ToString() => $"{nameof(ParseResult)}: {this.Diagram()}";
197+
public override string ToString() => ParseDirectiveAction.Diagram(this).ToString();
198198

199199
/// <summary>
200200
/// Gets the result, if any, for the specified argument.

src/System.CommandLine/Parsing/ParseResultExtensions.cs renamed to src/System.CommandLine/Parsing/ParseDirectiveAction.cs

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,51 @@
55
using System.CommandLine.Binding;
66
using System.Linq;
77
using System.Text;
8+
using System.Threading.Tasks;
9+
using System.Threading;
810

911
namespace System.CommandLine.Parsing
1012
{
1113
/// <summary>
12-
/// Provides extension methods for parse results.
14+
/// Implements the <c>[parse]</c> directive action, which when specified on the command line
15+
/// will short circuit normal command handling and display a diagram explaining the parse result for the command line input.
1316
/// </summary>
14-
public static class ParseResultExtensions
17+
internal sealed class ParseDirectiveAction : CliAction
1518
{
19+
private readonly int _errorExitCode;
20+
21+
internal ParseDirectiveAction(int errorExitCode) => _errorExitCode = errorExitCode;
22+
23+
public override int Invoke(ParseResult parseResult)
24+
{
25+
parseResult.Configuration.Output.WriteLine(Diagram(parseResult));
26+
return parseResult.Errors.Count == 0 ? 0 : _errorExitCode;
27+
}
28+
29+
public override async Task<int> InvokeAsync(ParseResult parseResult, CancellationToken cancellationToken = default)
30+
{
31+
cancellationToken.ThrowIfCancellationRequested();
32+
33+
StringBuilder diagram = Diagram(parseResult);
34+
35+
#if NET7_0_OR_GREATER
36+
await parseResult.Configuration.Output.WriteLineAsync(diagram, cancellationToken);
37+
#else
38+
await parseResult.Configuration.Output.WriteLineAsync(diagram.ToString());
39+
#endif
40+
return parseResult.Errors.Count == 0 ? 0 : _errorExitCode;
41+
}
42+
1643
/// <summary>
1744
/// Formats a string explaining a parse result.
1845
/// </summary>
1946
/// <param name="parseResult">The parse result to be diagrammed.</param>
2047
/// <returns>A string containing a diagram of the parse result.</returns>
21-
public static string Diagram(this ParseResult parseResult)
48+
internal static StringBuilder Diagram(ParseResult parseResult)
2249
{
2350
var builder = new StringBuilder(100);
2451

25-
builder.Diagram(parseResult.RootCommandResult, parseResult);
52+
Diagram(builder, parseResult.RootCommandResult, parseResult);
2653

2754
var unmatchedTokens = parseResult.UnmatchedTokens;
2855
if (unmatchedTokens.Length > 0)
@@ -37,11 +64,11 @@ public static string Diagram(this ParseResult parseResult)
3764
}
3865
}
3966

40-
return builder.ToString();
67+
return builder;
4168
}
4269

4370
private static void Diagram(
44-
this StringBuilder builder,
71+
StringBuilder builder,
4572
SymbolResult symbolResult,
4673
ParseResult parseResult)
4774
{
@@ -134,7 +161,6 @@ private static void Diagram(
134161
{
135162
builder.Append(((CommandResult)symbolResult).IdentifierToken.Value);
136163
}
137-
138164

139165
foreach (SymbolResult child in symbolResult.SymbolResultTree.GetChildren(symbolResult))
140166
{
@@ -147,7 +173,7 @@ private static void Diagram(
147173

148174
builder.Append(" ");
149175

150-
builder.Diagram(child, parseResult);
176+
Diagram(builder, child, parseResult);
151177
}
152178

153179
builder.Append(" ]");

0 commit comments

Comments
 (0)