Skip to content

Commit bc885e7

Browse files
committed
Replace per-subsystem annotation providers with pipeline annotation resolver
This simplifies things and means that subsystem authors have one centralized place to get annotation values, instead of having to know which subsytem to use.
1 parent 1f0c95b commit bc885e7

19 files changed

+250
-123
lines changed

src/System.CommandLine.Subsystems.Tests/AlternateSubsystems.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public VersionThatUsesHelpData(CliSymbol symbol)
3030

3131
public override void Execute(PipelineResult pipelineResult)
3232
{
33-
TryGetAnnotation(Symbol, HelpAnnotations.Description, out string? description);
33+
pipelineResult.Pipeline.Annotations.TryGet(Symbol, HelpAnnotations.Description, out string? description);
3434
pipelineResult.ConsoleHack.WriteLine(description);
3535
pipelineResult.AlreadyHandled = true;
3636
pipelineResult.SetSuccess();
@@ -63,12 +63,12 @@ protected internal override void TearDown(PipelineResult pipelineResult)
6363
}
6464
}
6565

66-
internal class StringDirectiveSubsystem(IAnnotationProvider? annotationProvider = null)
67-
: DirectiveSubsystem("other", SubsystemKind.Diagram, annotationProvider)
66+
internal class StringDirectiveSubsystem()
67+
: DirectiveSubsystem("other", SubsystemKind.Diagram)
6868
{ }
6969

70-
internal class BooleanDirectiveSubsystem(IAnnotationProvider? annotationProvider = null)
71-
: DirectiveSubsystem("diagram", SubsystemKind.Diagram, annotationProvider)
70+
internal class BooleanDirectiveSubsystem()
71+
: DirectiveSubsystem("diagram", SubsystemKind.Diagram)
7272
{ }
7373

7474
}

src/System.CommandLine.Subsystems/CompletionSubsystem.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ namespace System.CommandLine;
1717

1818
public class CompletionSubsystem : CliSubsystem
1919
{
20-
public CompletionSubsystem(IAnnotationProvider? annotationProvider = null)
21-
: base(CompletionAnnotations.Prefix, SubsystemKind.Completion, annotationProvider)
20+
public CompletionSubsystem()
21+
: base(CompletionAnnotations.Prefix, SubsystemKind.Completion)
2222
{ }
2323

2424
// TODO: Figure out trigger for completions

src/System.CommandLine.Subsystems/Directives/DiagramSubsystem.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66

77
namespace System.CommandLine.Directives;
88

9-
public class DiagramSubsystem(IAnnotationProvider? annotationProvider = null)
10-
: DirectiveSubsystem("diagram", SubsystemKind.Diagram, annotationProvider)
9+
public class DiagramSubsystem()
10+
: DirectiveSubsystem("diagram", SubsystemKind.Diagram)
1111
{
1212
//protected internal override bool GetIsActivated(ParseResult? parseResult)
1313
// => parseResult is not null && option is not null && parseResult.GetValue(option);

src/System.CommandLine.Subsystems/Directives/DirectiveSubsystem.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ public abstract class DirectiveSubsystem : CliSubsystem
1313
public string Id { get; }
1414
public Location? Location { get; private set; }
1515

16-
public DirectiveSubsystem(string name, SubsystemKind kind, IAnnotationProvider? annotationProvider = null, string? id = null)
17-
: base(name, kind, annotationProvider: annotationProvider)
16+
public DirectiveSubsystem(string name, SubsystemKind kind, string? id = null)
17+
: base(name, kind)
1818
{
1919
Id = id ?? name;
2020
}

src/System.CommandLine.Subsystems/Directives/ResponseSubsystem.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
namespace System.CommandLine.Directives;
88

99
public class ResponseSubsystem()
10-
: CliSubsystem("Response", SubsystemKind.Response, null)
10+
: CliSubsystem("Response", SubsystemKind.Response)
1111
{
1212
public bool Enabled { get; set; }
1313

src/System.CommandLine.Subsystems/ErrorReportingSubsystem.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ namespace System.CommandLine;
1515
/// </remarks>
1616
public class ErrorReportingSubsystem : CliSubsystem
1717
{
18-
public ErrorReportingSubsystem(IAnnotationProvider? annotationProvider = null)
19-
: base(ErrorReportingAnnotations.Prefix, SubsystemKind.ErrorReporting, annotationProvider)
18+
public ErrorReportingSubsystem()
19+
: base(ErrorReportingAnnotations.Prefix, SubsystemKind.ErrorReporting)
2020
{ }
2121

2222
protected internal override bool GetIsActivated(ParseResult? parseResult)

src/System.CommandLine.Subsystems/HelpAnnotationExtensions.cs

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,28 @@ public static void SetDescription<TSymbol>(this TSymbol symbol, string descripti
4040
/// <param name="symbol">The symbol</param>
4141
/// <returns>The symbol description if any, otherwise <see langword="null"/></returns>
4242
/// <remarks>
43-
/// This is intended to be called by CLI authors. Subsystems should instead call <see cref="HelpSubsystem.TryGetDescription(CliSymbol, out string?)"/>,
44-
/// values from the subsystem's <see cref="IAnnotationProvider"/>.
43+
/// This is intended to be called by CLI authors. Subsystem authors should instead call
44+
/// <see cref="GetDescription{TSymbol}(AnnotationResolver, TSymbol)"/> to get values from
45+
/// the pipeline's <see cref="Pipeline.Annotations"/>, which takes dynamic providers into account.
4546
/// </remarks>
4647
public static string? GetDescription<TSymbol>(this TSymbol symbol) where TSymbol : CliSymbol
4748
{
4849
return symbol.GetAnnotationOrDefault<string>(HelpAnnotations.Description);
4950
}
51+
52+
/// <summary>
53+
/// Get the help description for the <paramref name="symbol"/> from the <paramref name="resolver"/>,
54+
/// which takes dynamic providers into account.
55+
/// </summary>
56+
/// <typeparam name="TSymbol">The type of the symbol</typeparam>
57+
/// <param name="symbol">The symbol</param>
58+
/// <returns>The symbol description if any, otherwise <see langword="null"/></returns>
59+
/// <remarks>
60+
/// This is intended to be called by subsystem authors. CLI authors should instead call
61+
/// <see cref="GetDescription{TSymbol}(TSymbol)"/> to get the value associated directly with the symbol.
62+
/// </remarks>
63+
public static string? GetDescription<TSymbol>(this AnnotationResolver resolver, TSymbol symbol) where TSymbol : CliSymbol
64+
{
65+
return resolver.GetAnnotationOrDefault<string>(symbol, HelpAnnotations.Description);
66+
}
5067
}

src/System.CommandLine.Subsystems/HelpSubsystem.cs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ namespace System.CommandLine;
1515
// var command = new CliCommand("greet")
1616
// .With(help.Description, "Greet the user");
1717
//
18-
public class HelpSubsystem(IAnnotationProvider? annotationProvider = null)
19-
: CliSubsystem(HelpAnnotations.Prefix, SubsystemKind.Help, annotationProvider)
18+
public class HelpSubsystem()
19+
: CliSubsystem(HelpAnnotations.Prefix, SubsystemKind.Help)
2020
{
2121
/// <summary>
2222
/// Gets the help option, which allows the user to customize
@@ -44,7 +44,4 @@ public override void Execute(PipelineResult pipelineResult)
4444
pipelineResult.ConsoleHack.WriteLine("Help me!");
4545
pipelineResult.SetSuccess();
4646
}
47-
48-
public bool TryGetDescription(CliSymbol symbol, out string? description)
49-
=> TryGetAnnotation(symbol, HelpAnnotations.Description, out description);
5047
}

src/System.CommandLine.Subsystems/InvocationSubsystem.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,6 @@
66

77
namespace System.CommandLine;
88

9-
public class InvocationSubsystem(IAnnotationProvider? annotationProvider = null)
10-
: CliSubsystem(InvocationAnnotations.Prefix, SubsystemKind.Invocation, annotationProvider)
9+
public class InvocationSubsystem()
10+
: CliSubsystem(InvocationAnnotations.Prefix, SubsystemKind.Invocation)
1111
{}

src/System.CommandLine.Subsystems/Pipeline.cs

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.CommandLine.Directives;
55
using System.CommandLine.Parsing;
66
using System.CommandLine.Subsystems;
7+
using System.CommandLine.Subsystems.Annotations;
78

89
namespace System.CommandLine;
910

@@ -17,6 +18,7 @@ public partial class Pipeline
1718
private readonly PipelinePhase<InvocationSubsystem> invocationPhase = new(SubsystemKind.Invocation);
1819
private readonly PipelinePhase<ErrorReportingSubsystem> errorReportingPhase = new(SubsystemKind.ErrorReporting);
1920
private readonly IEnumerable<PipelinePhase> phases;
21+
private readonly List<IAnnotationProvider> annotationProviders;
2022

2123
/// <summary>
2224
/// Creates an instance of the pipeline using standard features.
@@ -34,14 +36,15 @@ public static Pipeline Create(HelpSubsystem? help = null,
3436
VersionSubsystem? version = null,
3537
CompletionSubsystem? completion = null,
3638
DiagramSubsystem? diagram = null,
37-
ErrorReportingSubsystem? errorReporting = null)
38-
=> new()
39+
ErrorReportingSubsystem? errorReporting = null,
40+
IEnumerable<IAnnotationProvider>? annotationProviders = null)
41+
=> new(annotationProviders)
3942
{
4043
Help = help ?? new HelpSubsystem(),
4144
Version = version ?? new VersionSubsystem(),
4245
Completion = completion ?? new CompletionSubsystem(),
4346
Diagram = diagram ?? new DiagramSubsystem(),
44-
ErrorReporting = errorReporting ?? new ErrorReportingSubsystem(),
47+
ErrorReporting = errorReporting ?? new ErrorReportingSubsystem()
4548
};
4649

4750
/// <summary>
@@ -54,7 +57,7 @@ public static Pipeline Create(HelpSubsystem? help = null,
5457
public static Pipeline CreateEmpty()
5558
=> new();
5659

57-
private Pipeline()
60+
private Pipeline(IEnumerable<IAnnotationProvider>? annotationProviders = null)
5861
{
5962
Response = new ResponseSubsystem();
6063
Invocation = new InvocationSubsystem();
@@ -68,6 +71,11 @@ private Pipeline()
6871
diagramPhase, completionPhase, helpPhase, versionPhase,
6972
validationPhase, invocationPhase, errorReportingPhase
7073
];
74+
75+
this.annotationProviders = annotationProviders is not null
76+
? [..annotationProviders]
77+
: [];
78+
Annotations = new(this.annotationProviders);
7179
}
7280

7381
/// <summary>
@@ -186,6 +194,21 @@ public ErrorReportingSubsystem? ErrorReporting
186194
/// </summary>
187195
public ResponseSubsystem Response { get; }
188196

197+
/// <summary>
198+
/// Gets the annotation resolver
199+
/// </summary>
200+
public AnnotationResolver Annotations { get; }
201+
202+
/// <summary>
203+
/// Gets the list of annotation providers registered with the pipeline
204+
/// </summary>
205+
public IReadOnlyList<IAnnotationProvider> AnnotationProviders => annotationProviders;
206+
207+
/// <summary>
208+
/// Adds an annotation provider to the pipeline
209+
/// </summary>
210+
public void AddAnnotationProvider(IAnnotationProvider annotationProvider) => annotationProviders.Add(annotationProvider);
211+
189212
public ParseResult Parse(CliConfiguration configuration, string rawInput)
190213
=> Parse(configuration, CliParser.SplitCommandLine(rawInput).ToArray());
191214

0 commit comments

Comments
 (0)