diff --git a/CliFx.Tests/SuggestDirectiveSpecs.cs b/CliFx.Tests/SuggestDirectiveSpecs.cs new file mode 100644 index 00000000..0b410a08 --- /dev/null +++ b/CliFx.Tests/SuggestDirectiveSpecs.cs @@ -0,0 +1,77 @@ +using CliFx.Tests.Utils; +using CliFx.Tests.Utils.Extensions; +using FluentAssertions; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Xunit; +using Xunit.Abstractions; + +namespace CliFx.Tests +{ + public class SuggestDirectivesSpecs : SpecsBase + { + public SuggestDirectivesSpecs(ITestOutputHelper testOutput) + : base(testOutput) + { + } + + private string _cmdCommandCs = @" +[Command(""cmd"")] +public class Command : ICommand +{ + public ValueTask ExecuteAsync(IConsole console) => default; +} +"; + + public CliApplicationBuilder TestApplicationFactory(params string[] commandClasses) + { + var builder = new CliApplicationBuilder(); + + commandClasses.ToList().ForEach(c => + { + var commandType = DynamicCommandBuilder.Compile(c); + builder = builder.AddCommand(commandType); + }); + + return builder.UseConsole(FakeConsole); + } + + [Theory] + [InlineData(true, 0 )] + [InlineData(false, 1)] + public async Task Suggest_directive_can_be_configured(bool enabled, int expectedExitCode) + { + // Arrange + var application = TestApplicationFactory(_cmdCommandCs) + .AllowSuggestMode(enabled) + .Build(); + + // Act + var exitCode = await application.RunAsync( + new[] { "[suggest]", "clifx.exe", "c" } + ); + + // Assert + exitCode.Should().Be(expectedExitCode); + } + + [Fact] + public async Task Suggest_directive_is_enabled_by_default() + { + // Arrange + var application = TestApplicationFactory(_cmdCommandCs) + .Build(); + + // Act + var exitCode = await application.RunAsync( + new[] { "[suggest]", "clifx.exe", "c" } + ); + + // Assert + exitCode.Should().Be(0); + } + } +} \ No newline at end of file diff --git a/CliFx/ApplicationConfiguration.cs b/CliFx/ApplicationConfiguration.cs index f03de68c..5078ac6f 100644 --- a/CliFx/ApplicationConfiguration.cs +++ b/CliFx/ApplicationConfiguration.cs @@ -23,17 +23,24 @@ public class ApplicationConfiguration /// public bool IsPreviewModeAllowed { get; } + /// + /// Whether suggest mode is allowed in this application. + /// + public bool IsSuggestModeAllowed { get; } + /// /// Initializes an instance of . /// public ApplicationConfiguration( IReadOnlyList commandTypes, bool isDebugModeAllowed, - bool isPreviewModeAllowed) + bool isPreviewModeAllowed, + bool isSuggestModeAllowed) { CommandTypes = commandTypes; IsDebugModeAllowed = isDebugModeAllowed; IsPreviewModeAllowed = isPreviewModeAllowed; + IsSuggestModeAllowed = isSuggestModeAllowed; } } } \ No newline at end of file diff --git a/CliFx/CliApplication.cs b/CliFx/CliApplication.cs index d0be0b90..6e77306f 100644 --- a/CliFx/CliApplication.cs +++ b/CliFx/CliApplication.cs @@ -56,6 +56,9 @@ public class CliApplication private bool IsPreviewModeEnabled(CommandInput commandInput) => Configuration.IsPreviewModeAllowed && commandInput.IsPreviewDirectiveSpecified; + private bool IsSuggestModeEnabled(CommandInput commandInput) => + Configuration.IsSuggestModeAllowed && commandInput.IsSuggestDirectiveSpecified; + private bool ShouldShowHelpText(CommandSchema commandSchema, CommandInput commandInput) => commandSchema.IsHelpOptionAvailable && commandInput.IsHelpOptionSpecified || // Show help text also in case the fallback default command is @@ -103,6 +106,13 @@ private async ValueTask RunAsync(ApplicationSchema applicationSchema, Comma return 0; } + // Handle suggest directive + if (IsSuggestModeEnabled(commandInput)) + { + _console.Output.WriteLine("cmd"); + return 0; + } + // Try to get the command schema that matches the input var commandSchema = applicationSchema.TryFindCommand(commandInput.CommandName) ?? diff --git a/CliFx/CliApplicationBuilder.cs b/CliFx/CliApplicationBuilder.cs index e1abb47a..0be83e7e 100644 --- a/CliFx/CliApplicationBuilder.cs +++ b/CliFx/CliApplicationBuilder.cs @@ -19,6 +19,7 @@ public partial class CliApplicationBuilder private bool _isDebugModeAllowed = true; private bool _isPreviewModeAllowed = true; + private bool _isSuggestModeAllowed = true; private string? _title; private string? _executableName; private string? _versionText; @@ -36,6 +37,7 @@ public CliApplicationBuilder AddCommand(Type commandType) return this; } + /// /// Adds a command to the application. /// @@ -110,6 +112,15 @@ public CliApplicationBuilder AllowPreviewMode(bool isAllowed = true) return this; } + /// + /// Specifies whether suggest mode (enabled with the [suggest] directive) is allowed in the application. + /// + public CliApplicationBuilder AllowSuggestMode(bool isAllowed = true) + { + _isSuggestModeAllowed = isAllowed; + return this; + } + /// /// Sets application title, which is shown in the help text. /// @@ -196,7 +207,8 @@ public CliApplication Build() var configuration = new ApplicationConfiguration( _commandTypes.ToArray(), _isDebugModeAllowed, - _isPreviewModeAllowed + _isPreviewModeAllowed, + _isSuggestModeAllowed ); return new CliApplication( diff --git a/CliFx/Input/CommandInput.cs b/CliFx/Input/CommandInput.cs index 45d514de..f89e336d 100644 --- a/CliFx/Input/CommandInput.cs +++ b/CliFx/Input/CommandInput.cs @@ -22,6 +22,8 @@ internal partial class CommandInput public bool IsPreviewDirectiveSpecified => Directives.Any(d => d.IsPreviewDirective); + public bool IsSuggestDirectiveSpecified => Directives.Any(d => d.IsSuggestDirective); + public bool IsHelpOptionSpecified => Options.Any(o => o.IsHelpOption); public bool IsVersionOptionSpecified => Options.Any(o => o.IsVersionOption); diff --git a/CliFx/Input/DirectiveInput.cs b/CliFx/Input/DirectiveInput.cs index 928aa10f..3ac0c1e2 100644 --- a/CliFx/Input/DirectiveInput.cs +++ b/CliFx/Input/DirectiveInput.cs @@ -12,6 +12,9 @@ internal class DirectiveInput public bool IsPreviewDirective => string.Equals(Name, "preview", StringComparison.OrdinalIgnoreCase); + public bool IsSuggestDirective => + string.Equals(Name, "suggest", StringComparison.OrdinalIgnoreCase); + public DirectiveInput(string name) => Name = name; } } \ No newline at end of file