From 46a7678472989dd2baaaf270d1f40eb125d53e86 Mon Sep 17 00:00:00 2001 From: MapelSiroup Date: Sat, 2 May 2026 19:47:49 -0400 Subject: [PATCH 1/4] Added arrow-key history support to TextPrompt and ConfirmationPrompt --- .../Unit/Prompts/TextPromptTests.cs | 85 ++++++++++++++++++ .../Extensions/AnsiConsoleExtensions.Input.cs | 89 +++++++++++++++++-- .../Prompts/ConfirmationPrompt.cs | 17 ++-- src/Spectre.Console/Prompts/PromptHistory.cs | 68 ++++++++++++++ src/Spectre.Console/Prompts/TextPrompt.cs | 38 ++++++-- .../Prompts/TextPromptExtensions.cs | 29 ++++++ .../Prompts/TextPromptInputHandler.cs | 4 +- 7 files changed, 311 insertions(+), 19 deletions(-) create mode 100644 src/Spectre.Console/Prompts/PromptHistory.cs diff --git a/src/Spectre.Console.Tests/Unit/Prompts/TextPromptTests.cs b/src/Spectre.Console.Tests/Unit/Prompts/TextPromptTests.cs index 09d0eb983..a882437ae 100644 --- a/src/Spectre.Console.Tests/Unit/Prompts/TextPromptTests.cs +++ b/src/Spectre.Console.Tests/Unit/Prompts/TextPromptTests.cs @@ -17,6 +17,91 @@ public void Should_Return_Entered_Text() result.ShouldBe("Hello World"); } + [Fact] + public void Should_Add_Valid_Text_To_History() + { + // Given + var history = new PromptHistory(); + var console = new TestConsole(); + console.Input.PushTextWithEnter("Hello World"); + + // When + var result = console.Prompt(new TextPrompt("Enter text:") { History = history }); + + // Then + result.ShouldBe("Hello World"); + history.Entries.ShouldBe(new[] { "Hello World" }); + } + + [Fact] + public void Should_Not_Add_Invalid_Text_To_History() + { + // Given + var history = new PromptHistory(); + var console = new TestConsole(); + console.Input.PushTextWithEnter("bad"); + console.Input.PushTextWithEnter("99"); + + // When + console.Prompt(new TextPrompt("Age?") { History = history }); + + // Then + history.Entries.ShouldBe(new[] { "99" }); + } + + [Fact] + public void Should_Not_Add_Secret_Text_To_History_By_Default() + { + // Given + var history = new PromptHistory(); + var console = new TestConsole(); + console.Input.PushTextWithEnter("secret"); + + // When + var result = console.Prompt(new TextPrompt("Password?") { History = history }.Secret()); + + // Then + result.ShouldBe("secret"); + history.Entries.ShouldBeEmpty(); + } + + [Fact] + public void Should_Cycle_Through_History_With_Arrow_Keys() + { + // Given + var history = new PromptHistory(); + history.Add("first"); + history.Add("second"); + + var console = new TestConsole(); + console.Input.PushKey(ConsoleKey.UpArrow); + console.Input.PushKey(ConsoleKey.UpArrow); + console.Input.PushKey(ConsoleKey.DownArrow); + console.Input.PushKey(ConsoleKey.Enter); + + // When + var result = console.Prompt(new TextPrompt("Enter text:") { History = history }); + + // Then + result.ShouldBe("second"); + } + + [Fact] + public void Should_Store_Confirmation_Input_In_History() + { + // Given + var history = new PromptHistory(); + var console = new TestConsole(); + console.Input.PushTextWithEnter("y"); + + // When + var result = console.Prompt(new ConfirmationPrompt("Continue?") { History = history }); + + // Then + result.ShouldBe(true); + history.Entries.ShouldBe(new[] { "y" }); + } + [Fact] [Expectation("ConversionError")] public Task Should_Return_Validation_Error_If_Value_Cannot_Be_Converted() diff --git a/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Input.cs b/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Input.cs index 758804cfe..0def17afa 100644 --- a/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Input.cs +++ b/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Input.cs @@ -5,8 +5,7 @@ namespace Spectre.Console; /// public static partial class AnsiConsoleExtensions { - internal static async Task ReadLine(this IAnsiConsole console, Style? style, bool secret, char? mask, - IEnumerable? items = null, string? initialInput = null, CancellationToken cancellationToken = default) + internal static async Task ReadLine(this IAnsiConsole console, Style? style, bool secret, char? mask, IEnumerable? items = null, CancellationToken cancellationToken = default, string? initialInput = null, PromptHistory? history = null) { ArgumentNullException.ThrowIfNull(console); @@ -14,6 +13,9 @@ internal static async Task ReadLine(this IAnsiConsole console, Style? st var text = string.Empty; var autocomplete = new List(items ?? []); + var historyEntries = history?.Enabled == true ? history.Entries : Array.Empty(); + var historyIndex = -1; + string? pendingText = null; Queue? injectedQueue = null; if (!string.IsNullOrEmpty(initialInput)) @@ -51,6 +53,48 @@ internal static async Task ReadLine(this IAnsiConsole console, Style? st return text; } + if (key.Key == ConsoleKey.UpArrow && historyEntries.Count > 0) + { + if (historyIndex == -1) + { + pendingText = text; + historyIndex = historyEntries.Count - 1; + } + else if (historyIndex > 0) + { + historyIndex--; + } + + var replace = historyEntries[historyIndex]; + ReplaceLine(console, style, text, replace, secret, mask); + text = replace; + continue; + } + + if (key.Key == ConsoleKey.DownArrow && historyEntries.Count > 0) + { + if (historyIndex == -1) + { + continue; + } + + if (historyIndex < historyEntries.Count - 1) + { + historyIndex++; + var replace = historyEntries[historyIndex]; + ReplaceLine(console, style, text, replace, secret, mask); + text = replace; + continue; + } + + var restore = pendingText ?? string.Empty; + ReplaceLine(console, style, text, restore, secret, mask); + text = restore; + pendingText = null; + historyIndex = -1; + continue; + } + if (key.Key == ConsoleKey.Tab && autocomplete.Count > 0) { var autoCompleteDirection = key.Modifiers.HasFlag(ConsoleModifiers.Shift) @@ -69,6 +113,9 @@ internal static async Task ReadLine(this IAnsiConsole console, Style? st if (key.Key == ConsoleKey.Backspace) { + historyIndex = -1; + pendingText = null; + if (text.Length > 0) { var lastChar = text.Last(); @@ -92,6 +139,8 @@ internal static async Task ReadLine(this IAnsiConsole console, Style? st if (!char.IsControl(key.KeyChar)) { + historyIndex = -1; + pendingText = null; text += key.KeyChar.ToString(); var output = key.KeyChar.ToString(); console.Write(secret ? output.Mask(mask) : output, style); @@ -99,8 +148,7 @@ internal static async Task ReadLine(this IAnsiConsole console, Style? st } } - private static string AutoComplete(List autocomplete, string text, - AutoCompleteDirection autoCompleteDirection) + private static string AutoComplete(List autocomplete, string text, AutoCompleteDirection autoCompleteDirection) { var found = autocomplete.Find(i => i == text); var replace = string.Empty; @@ -128,8 +176,37 @@ private static string AutoComplete(List autocomplete, string text, return replace; } - private static string GetAutocompleteValue(AutoCompleteDirection autoCompleteDirection, IList autocomplete, - string found) + private static void ReplaceLine(IAnsiConsole console, Style? style, string currentText, string replace, bool secret, char? mask) + { + if (!string.IsNullOrEmpty(currentText) && !(secret && mask is null)) + { + if (mask is null) + { + console.Write("\b \b".Repeat(currentText.Length), style); + } + else + { + foreach (var c in currentText) + { + if (UnicodeCalculator.GetWidth(c) == 1) + { + console.Write("\b \b", style); + } + else if (UnicodeCalculator.GetWidth(c) == 2) + { + console.Write("\b \b\b \b", style); + } + } + } + } + + if (!string.IsNullOrEmpty(replace) && !(secret && mask is null)) + { + console.Write(secret ? replace.Mask(mask) : replace, style); + } + } + + private static string GetAutocompleteValue(AutoCompleteDirection autoCompleteDirection, IList autocomplete, string found) { var foundAutocompleteIndex = autocomplete.IndexOf(found); var index = autoCompleteDirection switch diff --git a/src/Spectre.Console/Prompts/ConfirmationPrompt.cs b/src/Spectre.Console/Prompts/ConfirmationPrompt.cs index 78ce47562..65462b33c 100644 --- a/src/Spectre.Console/Prompts/ConfirmationPrompt.cs +++ b/src/Spectre.Console/Prompts/ConfirmationPrompt.cs @@ -40,14 +40,12 @@ public sealed class ConfirmationPrompt : IPrompt public bool ShowDefaultValue { get; set; } = true; /// - /// Gets or sets the style in which the default value is displayed. - /// Defaults to green when . + /// Gets or sets the style in which the default value is displayed. Defaults to green when . /// public Style? DefaultValueStyle { get; set; } /// - /// Gets or sets the style in which the list of choices is displayed. - /// Defaults to blue when . + /// Gets or sets the style in which the list of choices is displayed. Defaults to blue when . /// public Style? ChoicesStyle { get; set; } @@ -57,6 +55,11 @@ public sealed class ConfirmationPrompt : IPrompt /// public bool RequireEnter { get; set; } = true; + /// + /// Gets or sets the prompt history. + /// + public PromptHistory? History { get; set; } = PromptHistory.Default; + /// /// Gets or sets the string comparer to use when comparing user input /// against Yes/No choices. @@ -95,6 +98,7 @@ public async Task ShowAsync(IAnsiConsole console, CancellationToken cancel .DefaultValue(DefaultValue ? Yes : No) .DefaultValueStyle(DefaultValueStyle) .UseInputHandler(RequireEnter ? null : SingleKeyInputHandler) + .History(History) .AddChoice(Yes) .AddChoice(No); @@ -106,8 +110,9 @@ public async Task ShowAsync(IAnsiConsole console, CancellationToken cancel private static async Task SingleKeyInputHandler( IAnsiConsole console, Style? style, bool secret, char? mask, IEnumerable? items = null, - string? initialInput = null, - CancellationToken cancellationToken = default) + CancellationToken cancellationToken = default, + string? initialInput = null, PromptHistory? history = null + ) { var key = await console.Input.ReadKeyAsync(true, cancellationToken); if (key != null) diff --git a/src/Spectre.Console/Prompts/PromptHistory.cs b/src/Spectre.Console/Prompts/PromptHistory.cs new file mode 100644 index 000000000..2bccc555c --- /dev/null +++ b/src/Spectre.Console/Prompts/PromptHistory.cs @@ -0,0 +1,68 @@ +namespace Spectre.Console; + +/// +/// Stores the history of valid prompt input entries. +/// +public sealed class PromptHistory +{ + private readonly List _entries; + + /// + /// Gets the default shared prompt history instance. + /// + public static PromptHistory Default { get; } = new PromptHistory(); + + /// + /// Gets or sets a value indicating whether history is enabled. + /// + public bool Enabled { get; set; } = true; + + /// + /// Gets or sets a value indicating whether secret input should be ignored. + /// + public bool IgnoreSecret { get; set; } = true; + + /// + /// Occurs when a new entry is added to history. + /// + public event EventHandler? EntryAdded; + + /// + /// Gets the history entries. + /// + public IReadOnlyList Entries => _entries.AsReadOnly(); + + /// + /// Initializes a new instance of the class. + /// + /// The initial capacity of the history list. + public PromptHistory(int capacity = 32) + { + _entries = new List(capacity); + } + + /// + /// Adds a new entry to the prompt history. + /// + /// The user input entry. + public void Add(string entry) + { + ArgumentNullException.ThrowIfNull(entry); + + if (string.IsNullOrWhiteSpace(entry)) + { + return; + } + + _entries.Add(entry); + EntryAdded?.Invoke(this, entry); + } + + /// + /// Clears the prompt history. + /// + public void Clear() + { + _entries.Clear(); + } +} diff --git a/src/Spectre.Console/Prompts/TextPrompt.cs b/src/Spectre.Console/Prompts/TextPrompt.cs index a085f066c..ed9f4baf4 100644 --- a/src/Spectre.Console/Prompts/TextPrompt.cs +++ b/src/Spectre.Console/Prompts/TextPrompt.cs @@ -29,6 +29,11 @@ public sealed class TextPrompt : IPrompt, IHasCulture /// public string InvalidChoiceMessage { get; set; } = "[red]Please select one of the available options[/]"; + /// + /// Gets or sets the prompt history. + /// + public PromptHistory? History { get; set; } = PromptHistory.Default; + /// /// Gets or sets a value indicating whether input should /// be hidden in the console. @@ -96,6 +101,9 @@ public sealed class TextPrompt : IPrompt, IHasCulture /// public Style? ChoicesStyle { get; set; } + /// + /// Gets or sets the default value. + /// internal DefaultPromptValue? DefaultValue { get; set; } internal TextPromptInputHandler? InputHandler { get; set; } @@ -136,22 +144,39 @@ public async Task ShowAsync(IAnsiConsole console, CancellationToken cancellat WritePrompt(console); + void AddToHistory(string entry) + { + if (string.IsNullOrEmpty(entry)) + { + return; + } + + if (History?.Enabled != true || (IsSecret && History.IgnoreSecret)) + { + return; + } + + History.Add(entry); + } + while (true) { string input; if (EditableDefaultValue && DefaultValue != null) { - input = await inputhandler(console, promptStyle, IsSecret, Mask, choices, - converter(DefaultValue.Value), cancellationToken) + input = await inputhandler(console, promptStyle, IsSecret, Mask, choices,cancellationToken, + converter(DefaultValue.Value), History) .ConfigureAwait(false); } else { - input = await inputhandler(console, promptStyle, IsSecret, Mask, choices, - null, cancellationToken) + input = await inputhandler(console, promptStyle, IsSecret, Mask, choices, cancellationToken, + null, History) .ConfigureAwait(false); } + + // Nothing entered? if (string.IsNullOrWhiteSpace(input)) { @@ -161,6 +186,7 @@ public async Task ShowAsync(IAnsiConsole console, CancellationToken cancellat console.Write(IsSecret ? defaultValue.Mask(Mask) : defaultValue, promptStyle); console.WriteLine(); + AddToHistory(defaultValue); ClearPromptLine(console); return DefaultValue.Value; } @@ -178,6 +204,7 @@ public async Task ShowAsync(IAnsiConsole console, CancellationToken cancellat { if (choiceMap.TryGetValue(input, out result) && result != null) { + AddToHistory(input); ClearPromptLine(console); return result; } @@ -204,6 +231,7 @@ public async Task ShowAsync(IAnsiConsole console, CancellationToken cancellat continue; } + AddToHistory(input); ClearPromptLine(console); return result; } @@ -312,4 +340,4 @@ private bool ValidateResult(T value, [NotNullWhen(false)] out string? message) message = null; return true; } -} \ No newline at end of file +} diff --git a/src/Spectre.Console/Prompts/TextPromptExtensions.cs b/src/Spectre.Console/Prompts/TextPromptExtensions.cs index 79d7ce6dc..eb337496e 100644 --- a/src/Spectre.Console/Prompts/TextPromptExtensions.cs +++ b/src/Spectre.Console/Prompts/TextPromptExtensions.cs @@ -152,6 +152,35 @@ public static TextPrompt InvalidChoiceMessage(this TextPrompt obj, stri return obj; } + /// + /// Uses the provided prompt history for this prompt. + /// + /// The prompt result type. + /// The prompt. + /// The prompt history instance. + /// The same instance so that multiple calls can be chained. + public static TextPrompt History(this TextPrompt obj, PromptHistory? history) + { + ArgumentNullException.ThrowIfNull(obj); + + obj.History = history; + return obj; + } + + /// + /// Disables prompt history for this prompt. + /// + /// The prompt result type. + /// The prompt. + /// The same instance so that multiple calls can be chained. + public static TextPrompt DisableHistory(this TextPrompt obj) + { + ArgumentNullException.ThrowIfNull(obj); + + obj.History = null; + return obj; + } + /// /// Sets the default value of the prompt. /// diff --git a/src/Spectre.Console/Prompts/TextPromptInputHandler.cs b/src/Spectre.Console/Prompts/TextPromptInputHandler.cs index df3b93af4..949eeb894 100644 --- a/src/Spectre.Console/Prompts/TextPromptInputHandler.cs +++ b/src/Spectre.Console/Prompts/TextPromptInputHandler.cs @@ -3,5 +3,5 @@ namespace Spectre.Console; internal delegate Task TextPromptInputHandler( IAnsiConsole console, Style? style, bool secret, char? mask, IEnumerable? items = null, - string? initialInput = null, - CancellationToken cancellationToken = default); \ No newline at end of file + CancellationToken cancellationToken = default, + string? initialInput = null, PromptHistory? history = null); \ No newline at end of file From 9d4d7629bcf2c6cd8a777f5952488c5dc903f65c Mon Sep 17 00:00:00 2001 From: MapelSiroup Date: Sat, 2 May 2026 20:06:51 -0400 Subject: [PATCH 2/4] Added textprompt history tests --- src/Spectre.Console.Tests/Unit/Prompts/TextPromptTests.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Spectre.Console.Tests/Unit/Prompts/TextPromptTests.cs b/src/Spectre.Console.Tests/Unit/Prompts/TextPromptTests.cs index a882437ae..d65bc4af8 100644 --- a/src/Spectre.Console.Tests/Unit/Prompts/TextPromptTests.cs +++ b/src/Spectre.Console.Tests/Unit/Prompts/TextPromptTests.cs @@ -24,7 +24,6 @@ public void Should_Add_Valid_Text_To_History() var history = new PromptHistory(); var console = new TestConsole(); console.Input.PushTextWithEnter("Hello World"); - // When var result = console.Prompt(new TextPrompt("Enter text:") { History = history }); From c3b991139185f84057d4eba3acf06069bfcf8af1 Mon Sep 17 00:00:00 2001 From: MapelSiroup Date: Sat, 2 May 2026 20:23:28 -0400 Subject: [PATCH 3/4] Added ConfirmationPrompt History Tests --- .../Public_API.Output.verified.txt | 15 ++++ .../Unit/Prompts/ConfirmationPromptTests.cs | 82 +++++++++++++++++++ .../Prompts/ConfirmationPrompt.cs | 14 ++++ 3 files changed, 111 insertions(+) diff --git a/src/Spectre.Console.Tests/Expectations/Public_API.Output.verified.txt b/src/Spectre.Console.Tests/Expectations/Public_API.Output.verified.txt index 30a28a284..07a74eea3 100644 --- a/src/Spectre.Console.Tests/Expectations/Public_API.Output.verified.txt +++ b/src/Spectre.Console.Tests/Expectations/Public_API.Output.verified.txt @@ -377,6 +377,7 @@ public System.StringComparer Comparer { get; set; } public bool DefaultValue { get; set; } public Spectre.Console.Style? DefaultValueStyle { get; set; } + public Spectre.Console.PromptHistory? History { get; set; } public string InvalidChoiceMessage { get; set; } public char No { get; set; } public bool RequireEnter { get; set; } @@ -2639,6 +2640,17 @@ public T Update(string key, System.Func func) where T : struct { } } + public sealed class PromptHistory + { + public PromptHistory(int capacity = 32) { } + public bool Enabled { get; set; } + public System.Collections.Generic.IReadOnlyList Entries { get; } + public bool IgnoreSecret { get; set; } + public static Spectre.Console.PromptHistory Default { get; } + public event System.EventHandler? EntryAdded; + public void Add(string entry) { } + public void Clear() { } + } public class Recorder : Spectre.Console.IAnsiConsole, System.IDisposable { public Recorder(Spectre.Console.IAnsiConsole console) { } @@ -3120,9 +3132,11 @@ public static Spectre.Console.TextPrompt ClearOnFinish(this Spectre.Console.TextPrompt obj, bool clear = true) { } public static Spectre.Console.TextPrompt DefaultValue(this Spectre.Console.TextPrompt obj, T value) { } public static Spectre.Console.TextPrompt DefaultValueStyle(this Spectre.Console.TextPrompt obj, Spectre.Console.Style? style) { } + public static Spectre.Console.TextPrompt DisableHistory(this Spectre.Console.TextPrompt obj) { } public static Spectre.Console.TextPrompt EditableDefaultValue(this Spectre.Console.TextPrompt obj, bool state) { } public static Spectre.Console.TextPrompt HideChoices(this Spectre.Console.TextPrompt obj) { } public static Spectre.Console.TextPrompt HideDefaultValue(this Spectre.Console.TextPrompt obj) { } + public static Spectre.Console.TextPrompt History(this Spectre.Console.TextPrompt obj, Spectre.Console.PromptHistory? history) { } public static Spectre.Console.TextPrompt InvalidChoiceMessage(this Spectre.Console.TextPrompt obj, string message) { } public static Spectre.Console.TextPrompt PromptStyle(this Spectre.Console.TextPrompt obj, Spectre.Console.Style style) { } public static Spectre.Console.TextPrompt Secret(this Spectre.Console.TextPrompt obj) { } @@ -3147,6 +3161,7 @@ public System.Globalization.CultureInfo? Culture { get; set; } public Spectre.Console.Style? DefaultValueStyle { get; set; } public bool EditableDefaultValue { get; set; } + public Spectre.Console.PromptHistory? History { get; set; } public string InvalidChoiceMessage { get; set; } public bool IsSecret { get; set; } public char? Mask { get; set; } diff --git a/src/Spectre.Console.Tests/Unit/Prompts/ConfirmationPromptTests.cs b/src/Spectre.Console.Tests/Unit/Prompts/ConfirmationPromptTests.cs index eca32eb52..944799398 100644 --- a/src/Spectre.Console.Tests/Unit/Prompts/ConfirmationPromptTests.cs +++ b/src/Spectre.Console.Tests/Unit/Prompts/ConfirmationPromptTests.cs @@ -48,6 +48,7 @@ public void Should_Not_Require_Enter_If_RequireEnter_Is_Set_To_False( public void Should_Ignore_Invalid_Input() { // Given + var history = new PromptHistory(); var console = new TestConsole(); console.Input.PushCharacter('a'); console.Input.PushCharacter('b'); @@ -65,4 +66,85 @@ public void Should_Ignore_Invalid_Input() result.ShouldBe(true); console.Input.IsKeyAvailable().ShouldBeFalse(); } + + [Fact] + public void Should_Return_True_When_User_Answers_Yes() + { + // Given + var console = new TestConsole(); + console.Input.PushTextWithEnter("y"); + + // When + var result = console.Prompt(new ConfirmationPrompt("Continue?")); + + // Then + result.ShouldBe(true); + } + + [Fact] + public void Should_Return_False_When_User_Answers_No() + { + // Given + var console = new TestConsole(); + console.Input.PushTextWithEnter("n"); + + // When + var result = console.Prompt(new ConfirmationPrompt("Continue?")); + + // Then + result.ShouldBe(false); + } + + [Fact] + public void Should_Add_Confirmation_Input_To_History() + { + // Given + var history = new PromptHistory(); + var console = new TestConsole(); + console.Input.PushTextWithEnter("y"); + + // When + var result = console.Prompt(new ConfirmationPrompt("Continue?") { History = history }); + + // Then + result.ShouldBe(true); + history.Entries.ShouldBe(new[] { "y" }); + } + + [Fact] + public void Should_Share_History_Between_TextPrompt_And_ConfirmationPrompt() + { + // Given + var sharedHistory = new PromptHistory(); + var console = new TestConsole(); + + // First, a text prompt + console.Input.PushTextWithEnter("hello"); + console.Prompt(new TextPrompt("Enter text:") { History = sharedHistory }); + + // Then, a confirmation prompt + console.Input.PushTextWithEnter("n"); + var confirmResult = console.Prompt(new ConfirmationPrompt("Continue?") { History = sharedHistory }); + + // Then + confirmResult.ShouldBe(false); + sharedHistory.Entries.ShouldBe(new[] { "hello", "n" }); + } + + [Fact] + public void Should_Not_Add_Invalid_Confirmation_Input_To_History() + { + // Given + var history = new PromptHistory(); + var console = new TestConsole(); + console.Input.PushTextWithEnter("maybe"); + console.Input.PushTextWithEnter("y"); + + // When + var result = console.Prompt(new ConfirmationPrompt("Continue?") { History = history }); + + // Then + result.ShouldBe(true); + history.Entries.ShouldBe(new[] { "y" }); // Only the valid "y" is stored + } } \ No newline at end of file diff --git a/src/Spectre.Console/Prompts/ConfirmationPrompt.cs b/src/Spectre.Console/Prompts/ConfirmationPrompt.cs index 65462b33c..03a57bf0e 100644 --- a/src/Spectre.Console/Prompts/ConfirmationPrompt.cs +++ b/src/Spectre.Console/Prompts/ConfirmationPrompt.cs @@ -284,4 +284,18 @@ public static ConfirmationPrompt RequireEnter(this ConfirmationPrompt obj, bool obj.RequireEnter = require; return obj; } + + /// + /// Uses the provided prompt history for this prompt. + /// + /// The prompt. + /// The prompt history instance. + /// The same instance so that multiple calls can be chained. + public static ConfirmationPrompt History(this ConfirmationPrompt obj, PromptHistory? history) + { + ArgumentNullException.ThrowIfNull(obj); + + obj.History = history; + return obj; + } } \ No newline at end of file From d2e1902397b56210b3c436952870b6c3b9f7cbf6 Mon Sep 17 00:00:00 2001 From: MapelSiroup Date: Sun, 3 May 2026 17:13:22 -0400 Subject: [PATCH 4/4] Fixed missing API signatures in API Test --- .../Expectations/Public_API.Output.verified.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Spectre.Console.Tests/Expectations/Public_API.Output.verified.txt b/src/Spectre.Console.Tests/Expectations/Public_API.Output.verified.txt index 07a74eea3..bbd7e0a0c 100644 --- a/src/Spectre.Console.Tests/Expectations/Public_API.Output.verified.txt +++ b/src/Spectre.Console.Tests/Expectations/Public_API.Output.verified.txt @@ -393,6 +393,7 @@ public static Spectre.Console.ConfirmationPrompt DefaultValueStyle(this Spectre.Console.ConfirmationPrompt obj, Spectre.Console.Style? style) { } public static Spectre.Console.ConfirmationPrompt HideChoices(this Spectre.Console.ConfirmationPrompt obj) { } public static Spectre.Console.ConfirmationPrompt HideDefaultValue(this Spectre.Console.ConfirmationPrompt obj) { } + public static Spectre.Console.ConfirmationPrompt History(this Spectre.Console.ConfirmationPrompt obj, Spectre.Console.PromptHistory? history) { } public static Spectre.Console.ConfirmationPrompt InvalidChoiceMessage(this Spectre.Console.ConfirmationPrompt obj, string message) { } public static Spectre.Console.ConfirmationPrompt No(this Spectre.Console.ConfirmationPrompt obj, char character) { } public static Spectre.Console.ConfirmationPrompt RequireEnter(this Spectre.Console.ConfirmationPrompt obj, bool require = true) { }