File: InteractiveConsole.cs
Web Access
Project: src\src\sdk\src\Cli\dotnet\dotnet.csproj (dotnet)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.DotNet.Cli.Commands;
using Microsoft.DotNet.Cli.Utils;

namespace Microsoft.DotNet.Cli;

public static class InteractiveConsole
{
    /// <param name="acceptEscapeForFalse">
    /// If you need to confirm an action, Escape means "cancel" and that is fine.
    /// If you need an answer where the "no" might mean something dangerous, Escape should not be used as implicit "no".
    /// </param>
    /// <returns>
    /// <see langword="true"/> if the user confirmed the action,
    /// <see langword="false"/> if the user declined it,
    /// <see langword="null"/> if the user could not answer because <c>--no-interactive</c> was specified.
    /// </returns>
    public static bool? Confirm(string message, bool yesOption, bool interactiveOption, bool acceptEscapeForFalse)
    {
        if (yesOption)
        {
            return true;
        }

        if (!interactiveOption)
        {
            return null;
        }

        using var _ = Activities.Source.StartActivity("confirm-run-from-source");

        Console.Write(AddPromptOptions(message));

        while (true)
        {
            var key = Console.ReadKey();
            Console.WriteLine();

            if (key.Key == ConsoleKey.Enter || KeyMatches(key, CliCommandStrings.ConfirmationPromptYesValue))
            {
                return true;
            }

            if ((acceptEscapeForFalse && key.Key == ConsoleKey.Escape) || KeyMatches(key, CliCommandStrings.ConfirmationPromptNoValue))
            {
                return false;
            }

            Console.Write(AddPromptOptions(string.Format(CliCommandStrings.ConfirmationPromptInvalidChoiceMessage, CliCommandStrings.ConfirmationPromptYesValue, CliCommandStrings.ConfirmationPromptNoValue)));
        }

        static string AddPromptOptions(string message)
        {
            return $"{message} [{CliCommandStrings.ConfirmationPromptYesValue}/{CliCommandStrings.ConfirmationPromptNoValue}] ({CliCommandStrings.ConfirmationPromptYesValue}): ";
        }

        static bool KeyMatches(ConsoleKeyInfo pressedKey, string valueKey)
        {
            //  Apparently you can't do invariant case insensitive comparison on a char directly, so we have to convert it to a string.
            //  The resource string should be a single character, but we take the first character just to be sure.
            return pressedKey.KeyChar.ToString().ToLowerInvariant().Equals(
                valueKey.ToLowerInvariant().Substring(0, 1));
        }
    }
}