| File: Commands\RenderCommand.cs | Web Access |
| Project: src\src\Aspire.Cli\Aspire.Cli.csproj (aspire) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. #if DEBUG using System.CommandLine; using System.Reflection; using Aspire.Cli.Configuration; using Aspire.Cli.Interaction; using Aspire.Cli.Telemetry; using Aspire.Cli.Utils; namespace Aspire.Cli.Commands; /// <summary> /// Debug-only command for smoke testing CLI rendering (emoji alignment, status spinners, etc.). /// </summary> internal sealed class RenderCommand : BaseCommand { /// <summary> /// All emojis defined in <see cref="KnownEmojis"/>, discovered via reflection. /// </summary> private static readonly KnownEmoji[] s_allEmojis = typeof(KnownEmojis) .GetFields(BindingFlags.Public | BindingFlags.Static) .Where(f => f.FieldType == typeof(KnownEmoji)) .Select(f => (KnownEmoji)f.GetValue(null)!) .ToArray(); private static readonly Dictionary<string, string> s_choices = new() { ["displaymessage"] = "Display message (all emojis)", ["showstatus"] = "Show status spinner (first 5 emojis)", ["showstatus-markup"] = "Show status with markup rendered", ["showstatus-escaped"] = "Show status with markup escaped", ["mixed"] = "Mixed interaction service methods", ["exit"] = "Exit", }; public RenderCommand( IFeatures features, ICliUpdateNotifier updateNotifier, CliExecutionContext executionContext, IInteractionService interactionService, AspireCliTelemetry telemetry) : base("render", "Smoke test CLI rendering", features, updateNotifier, executionContext, interactionService, telemetry) { Hidden = true; } protected override bool UpdateNotificationsEnabled => false; protected override async Task<int> ExecuteAsync(ParseResult parseResult, CancellationToken cancellationToken) { while (true) { var choice = await InteractionService.PromptForSelectionAsync( "What do you want to test?", s_choices.Keys, key => s_choices[key], cancellationToken); switch (choice) { case "displaymessage": TestDisplayMessage(); break; case "showstatus": await TestShowStatusAsync(cancellationToken); break; case "showstatus-markup": await TestShowStatusWithMarkupAsync(cancellationToken); break; case "showstatus-escaped": await TestShowStatusEscapedAsync(cancellationToken); break; case "mixed": await TestMixedMethodsAsync(cancellationToken); break; case "exit": return ExitCodeConstants.Success; default: return ExitCodeConstants.InvalidCommand; } } } private int TestDisplayMessage() { foreach (var emoji in s_allEmojis) { InteractionService.DisplayMessage(emoji, $"DisplayMessage with {emoji.Name}"); } return ExitCodeConstants.Success; } private async Task<int> TestShowStatusAsync(CancellationToken cancellationToken) { foreach (var emoji in s_allEmojis.Take(5)) { await InteractionService.ShowStatusAsync( $"ShowStatus with {emoji.Name} for 2 seconds...", async () => { await Task.Delay(TimeSpan.FromSeconds(2), cancellationToken); return ExitCodeConstants.Success; }, emoji: emoji); } return ExitCodeConstants.Success; } private async Task<int> TestShowStatusWithMarkupAsync(CancellationToken cancellationToken) { await InteractionService.ShowStatusAsync( "[bold]Installing[/] packages with [green]markup[/]...", async () => { await Task.Delay(TimeSpan.FromSeconds(2), cancellationToken); return ExitCodeConstants.Success; }, emoji: KnownEmojis.Package, allowMarkup: true); return ExitCodeConstants.Success; } private async Task<int> TestShowStatusEscapedAsync(CancellationToken cancellationToken) { await InteractionService.ShowStatusAsync( "[bold]Installing[/] packages with [green]markup[/] escaped...", async () => { await Task.Delay(TimeSpan.FromSeconds(2), cancellationToken); return ExitCodeConstants.Success; }, emoji: KnownEmojis.Package); return ExitCodeConstants.Success; } private async Task TestMixedMethodsAsync(CancellationToken cancellationToken) { InteractionService.DisplayMessage(KnownEmojis.Rocket, "Starting mixed methods test..."); InteractionService.DisplayEmptyLine(); InteractionService.DisplaySuccess("Step 1 complete!"); InteractionService.DisplaySubtleMessage("This is a subtle hint."); InteractionService.DisplayMessage(KnownEmojis.MagnifyingGlassTiltedLeft, "Searching for [packages]..."); InteractionService.DisplayEmptyLine(); InteractionService.DisplayMarkupLine("[bold green]Bold green markup[/] and [dim]dim text[/]"); InteractionService.DisplayPlainText("Plain text with [brackets] that should appear literally."); InteractionService.DisplayEmptyLine(); await InteractionService.ShowStatusAsync( "Running a quick task...", async () => { await Task.Delay(TimeSpan.FromSeconds(2), cancellationToken); return 42; }, emoji: KnownEmojis.Gear); InteractionService.ShowStatus( "Synchronous status spinner...", () => Thread.Sleep(TimeSpan.FromSeconds(1)), emoji: KnownEmojis.Hammer); InteractionService.DisplayEmptyLine(); var name = await InteractionService.PromptForStringAsync( "Enter a test value", defaultValue: "hello", cancellationToken: cancellationToken); InteractionService.DisplayMessage(KnownEmojis.CheckMark, $"You entered: {name}"); var confirmed = await InteractionService.ConfirmAsync( "Do you want to continue?", defaultValue: true, cancellationToken: cancellationToken); if (confirmed) { InteractionService.DisplaySuccess("Confirmed!"); } else { InteractionService.DisplayError("Cancelled."); } InteractionService.DisplayEmptyLine(); InteractionService.DisplayMessage(KnownEmojis.StopSign, "Mixed methods test complete."); } } #endif