AutoSpectre.SourceGeneration 0.8.1

There is a newer prerelease version of this package available.
See the version list below for details.
dotnet add package AutoSpectre.SourceGeneration --version 0.8.1
NuGet\Install-Package AutoSpectre.SourceGeneration -Version 0.8.1
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="AutoSpectre.SourceGeneration" Version="0.8.1" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add AutoSpectre.SourceGeneration --version 0.8.1
#r "nuget: AutoSpectre.SourceGeneration, 0.8.1"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install AutoSpectre.SourceGeneration as a Cake Addin
#addin nuget:?package=AutoSpectre.SourceGeneration&version=0.8.1

// Install AutoSpectre.SourceGeneration as a Cake Tool
#tool nuget:?package=AutoSpectre.SourceGeneration&version=0.8.1

AutoSpectre Source Generation

This allows you to decorate a class with the AutoSpectreForm attribute and decorate properties on that class with:

  • TextPromptAttribute
  • SelectPromptAttribute

and void or Task methods with

  • TaskStepAttribute

and behind the scenes a Form (SpectreFactory) will be generated to request input using Spectre.Console

Example

Code

[AutoSpectreForm]
public class Example
{
    [TextPrompt(Title = "Add item")] public int[] IntItems { get; set; } = Array.Empty<int>();

    [TextPrompt(Title = "Enter first name", DefaultValueStyle = "bold")]
    public string? FirstName { get; set; } = "John Doe"; // Default value in prompt

    [TextPrompt(PromptStyle = "green bold")] 
    public bool LeftHanded { get; set; }

    [TextPrompt(Title = "Choose your [red]value[/]" )]
    public SomeEnum Other { get; set; }
    
    [TextPrompt(Secret = true, Mask = '*')]
    public string? Password { get; set; }

    [TextPrompt] public OtherAutoSpectreFormClass ChildForm { get; set; } = new();

    [TextPrompt]
    public IReadOnlyList<OtherAutoSpectreFormClass> Investors { get; set; } = new List<OtherAutoSpectreFormClass>();

    [TaskStep(UseStatus = true, StatusText = "This will take a while", SpinnerType = SpinnerKnownTypes.Christmas, SpinnerStyle = "green on yellow")]
    public void DoSomething(IAnsiConsole console)
    {
        console.Write(new FigletText("A figlet text is needed"));
    }

    [SelectPrompt(WrapAround = true, PageSize = 3,
        MoreChoicesText = "Press down to see more choices", HighlightStyle = "purple")]
    //[SelectPrompt(Source = nameof(ItemSource))]
    public string Item { get; set; } = string.Empty;

    public List<string> ItemSource { get; } = new() { "Alpha", "Bravo", "Charlie" };

    [SelectPrompt(InstructionsText = "Check the special items you want to select")]
    //[SelectPrompt(Converter = nameof(SpecialProjectionConverter))]
    public List<int> SpecialProjection { get; set; } = new();

    public string SpecialProjectionConverter(int source) => $"Number {source}";
    public List<int> SpecialProjectionSource { get; set; } = new() { 1, 2, 3, 4 };

    [TextPrompt]
    // [TextPrompt(Validator = nameof(EnterYearValidator))]
    public int EnterYear { get; set; }

    public string? EnterYearValidator(int year)
    {
        return year <= DateTime.Now.Year ? null : "Year cannot be larger than current year";
    }

    [TextPrompt] public HashSet<string> Names { get; set; } = new(StringComparer.OrdinalIgnoreCase);

    public string? NamesValidator(List<string> items, string newItem)
    {
        if (newItem == "Foobar")
            return "Cannot be Foobar";

        if (items.Contains(newItem))
            return $"{newItem} has already been added";

        return null;
    }

    [TextPrompt] public bool AddExistingName { get; set; }

    [TextPrompt(Condition = nameof(AddExistingName))]
    public string? ExistingName { get; set; }

    [TextPrompt(Condition = nameof(AddExistingName), NegateCondition = true)]
    public string? NewName { get; set; }
}

Output

/// <summary>
/// Helps create and fill <see cref = "Example"/> with values
/// </summary>
public interface IExampleSpectreFactory
{
    Example Get(Example destination = null);
}

/// <summary>
/// Helps create and fill <see cref = "Example"/> with values
/// </summary>
public class ExampleSpectreFactory : IExampleSpectreFactory
{
    public Example Get(Example destination = null)
    {
        IOtherAutoSpectreFormClassSpectreFactory OtherAutoSpectreFormClassSpectreFactory = new OtherAutoSpectreFormClassSpectreFactory();
        destination ??= new ConsoleApp1.Example();
        // Prompt for values for destination.IntItems
        {
            List<int> items = new List<int>();
            bool continuePrompting = true;
            do
            {
                var item = AnsiConsole.Prompt(new TextPrompt<int>("Add item"));
                items.Add(item);
                continuePrompting = AnsiConsole.Confirm("Add more items?");
            }
            while (continuePrompting);
            int[] result = items.ToArray();
            destination.IntItems = result;
        }

        destination.FirstName = AnsiConsole.Prompt(new TextPrompt<string?>("Enter first name").AllowEmpty().DefaultValue("John Doe").DefaultValueStyle("bold"));
        destination.LeftHanded = AnsiConsole.Confirm("Enter [green]LeftHanded[/]");
        destination.Other = AnsiConsole.Prompt(new SelectionPrompt<SomeEnum>().Title("Choose your [red]value[/]").PageSize(10).AddChoices(Enum.GetValues<SomeEnum>()));
        destination.Password = AnsiConsole.Prompt(new TextPrompt<string?>("Enter [green]Password[/]").AllowEmpty().Secret('*'));
        {
            AnsiConsole.MarkupLine("Enter [green]ChildForm[/]");
            var item = OtherAutoSpectreFormClassSpectreFactory.Get();
            destination.ChildForm = item;
        }

        // Prompt for values for destination.Investors
        {
            List<OtherAutoSpectreFormClass> items = new List<OtherAutoSpectreFormClass>();
            bool continuePrompting = true;
            do
            {
                {
                    AnsiConsole.MarkupLine("Enter [green]Investors[/]");
                    var newItem = OtherAutoSpectreFormClassSpectreFactory.Get();
                    items.Add(newItem);
                }

                continuePrompting = AnsiConsole.Confirm("Add more items?");
            }
            while (continuePrompting);
            System.Collections.Generic.IReadOnlyList<ConsoleApp1.OtherAutoSpectreFormClass> result = items;
            destination.Investors = result;
        }

        AnsiConsole.MarkupLine("Calling method [green]DoSomething[/]");
        AnsiConsole.Status().SpinnerStyle("green on yellow").Spinner(Spinner.Known.Christmas).Start("This will take a while", ctx =>
        {
            destination.DoSomething(AnsiConsole.Console);
        });
        destination.Item = AnsiConsole.Prompt(new SelectionPrompt<string>().Title("Enter [green]Item[/]").PageSize(3).WrapAround(true).MoreChoicesText("Press down to see more choices").HighlightStyle("purple").AddChoices(destination.ItemSource.ToArray()));
        destination.SpecialProjection = AnsiConsole.Prompt(new MultiSelectionPrompt<int>().Title("Enter [green]SpecialProjection[/]").UseConverter(destination.SpecialProjectionConverter).PageSize(10).InstructionsText("Check the special items you want to select").AddChoices(destination.SpecialProjectionSource.ToArray()));
        destination.EnterYear = AnsiConsole.Prompt(new TextPrompt<int>("Enter [green]EnterYear[/]").Validate(ctx =>
        {
            var result = destination.EnterYearValidator(ctx);
            return result == null ? ValidationResult.Success() : ValidationResult.Error(result);
        }));
        // Prompt for values for destination.Names
        {
            List<string> items = new List<string>();
            bool continuePrompting = true;
            do
            {
                bool valid = false;
                while (!valid)
                {
                    var item = AnsiConsole.Prompt(new TextPrompt<string>("Enter [green]Names[/]"));
                    var validationResult = destination.NamesValidator(items, item);
                    if (validationResult is { } error)
                    {
                        AnsiConsole.MarkupLine($"[red]{error}[/]");
                        valid = false;
                    }
                    else
                    {
                        valid = true;
                        items.Add(item);
                    }
                }

                continuePrompting = AnsiConsole.Confirm("Add more items?");
            }
            while (continuePrompting);
            System.Collections.Generic.HashSet<string> result = new System.Collections.Generic.HashSet<string>(items);
            destination.Names = result;
        }

        destination.AddExistingName = AnsiConsole.Confirm("Enter [green]AddExistingName[/]");
        if (destination.AddExistingName == true)
        {
            destination.ExistingName = AnsiConsole.Prompt(new TextPrompt<string?>("Enter [green]ExistingName[/]").AllowEmpty());
        }

        if (destination.AddExistingName == false)
        {
            destination.NewName = AnsiConsole.Prompt(new TextPrompt<string?>("Enter [green]NewName[/]").AllowEmpty());
        }

        return destination;
    }
}

Credits

Fear icons created by Smashicons - Flaticon

There are no supported framework assets in this package.

Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
0.9.0-preview-0.2 43 4/23/2024
0.8.1 107 2/5/2024
0.8.1-preview-01 78 2/4/2024
0.8.0 185 11/30/2023
0.8.0-preview.0.1 95 11/4/2023
0.7.0 258 10/3/2023
0.7.0-preview.0.8 65 10/2/2023
0.7.0-preview.0.7 60 10/2/2023
0.7.0-preview.0.6 66 10/1/2023
0.7.0-preview.0.5 67 9/26/2023
0.7.0-preview.0.4.2 62 9/20/2023
0.7.0-preview.0.3 49 9/18/2023
0.7.0-preview.0.2 68 9/15/2023
0.7.0-preview.0.1 79 9/14/2023
0.6.0 293 9/12/2023
0.6.0-preview.0.4 68 9/10/2023
0.6.0-preview.0.1 64 9/3/2023
0.5.3 275 8/28/2023
0.5.2 275 8/27/2023
0.5.1 270 8/25/2023
0.5.0 293 8/23/2023
0.4.0 309 8/15/2023
0.3.8 317 8/6/2023
0.3.7.2 184 7/29/2023
0.3.6.1 183 7/25/2023
0.3.5 148 7/24/2023
0.3.4 171 7/23/2023
0.3.3 158 7/23/2023
0.3.2 320 1/22/2023
0.3.1 330 1/16/2023
0.3.0 333 1/6/2023
0.2.0.2 324 12/14/2022
0.2.0.1 301 12/14/2022
0.1.6 361 12/2/2022
0.1.5 336 11/30/2022

Focus on issues preventing build. Added handling of UsedConstructor