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 4b55062cc..cf2d663d0 100644 --- a/src/Spectre.Console.Tests/Expectations/Public_API.Output.verified.txt +++ b/src/Spectre.Console.Tests/Expectations/Public_API.Output.verified.txt @@ -2324,6 +2324,8 @@ where T : notnull { } public static Spectre.Console.MultiSelectionPrompt AddChoices(this Spectre.Console.MultiSelectionPrompt obj, T choice, System.Action> configurator) where T : notnull { } + public static Spectre.Console.MultiSelectionPrompt DefaultValue(this Spectre.Console.MultiSelectionPrompt obj, T? defaultValue) + where T : notnull { } public static Spectre.Console.MultiSelectionPrompt HighlightStyle(this Spectre.Console.MultiSelectionPrompt obj, Spectre.Console.Style highlightStyle) where T : notnull { } public static Spectre.Console.MultiSelectionPrompt InstructionsText(this Spectre.Console.MultiSelectionPrompt obj, string? text) @@ -2355,6 +2357,7 @@ public MultiSelectionPrompt(System.Collections.Generic.IEqualityComparer? comparer = null) { } public System.Func>? CancelResult { get; set; } public System.Func? Converter { get; set; } + public T DefaultValue { get; set; } public Spectre.Console.Style? HighlightStyle { get; set; } public string? InstructionsText { get; set; } public Spectre.Console.SelectionMode Mode { get; set; } @@ -2698,6 +2701,8 @@ where T : notnull { } public static Spectre.Console.SelectionPrompt AddChoices(this Spectre.Console.SelectionPrompt obj, params T[] choices) where T : notnull { } + public static Spectre.Console.SelectionPrompt DefaultValue(this Spectre.Console.SelectionPrompt obj, T? defaultValue) + where T : notnull { } public static Spectre.Console.SelectionPrompt DisableSearch(this Spectre.Console.SelectionPrompt obj) where T : notnull { } public static Spectre.Console.SelectionPrompt EnableSearch(this Spectre.Console.SelectionPrompt obj) @@ -2722,9 +2727,10 @@ public sealed class SelectionPrompt : Spectre.Console.IPrompt where T : notnull { - public SelectionPrompt() { } + public SelectionPrompt(System.Collections.Generic.IEqualityComparer? comparer = null) { } public System.Func? CancelResult { get; set; } public System.Func? Converter { get; set; } + public T DefaultValue { get; set; } public Spectre.Console.Style? DisabledStyle { get; set; } public Spectre.Console.Style? HighlightStyle { get; set; } public Spectre.Console.SelectionMode Mode { get; set; } diff --git a/src/Spectre.Console.Tests/Unit/Prompts/ListPromptStateTests.cs b/src/Spectre.Console.Tests/Unit/Prompts/ListPromptStateTests.cs index 90bc0f824..eb5f48f8a 100644 --- a/src/Spectre.Console.Tests/Unit/Prompts/ListPromptStateTests.cs +++ b/src/Spectre.Console.Tests/Unit/Prompts/ListPromptStateTests.cs @@ -2,23 +2,25 @@ namespace Spectre.Console.Tests.Unit; public sealed class ListPromptStateTests { - private ListPromptState CreateListPromptState(int count, int pageSize, bool shouldWrap, bool searchEnabled) + private ListPromptState CreateListPromptState(int count, int pageSize, bool shouldWrap, bool searchEnabled, int initialIndex = 0) => new( Enumerable.Range(0, count).Select(i => new ListPromptItem(i.ToString())).ToList(), text => text, - pageSize, shouldWrap, SelectionMode.Independent, true, searchEnabled); + pageSize, shouldWrap, SelectionMode.Independent, true, searchEnabled, initialIndex); - [Fact] - public void Should_Have_Start_Index_Zero() + [Theory] + [InlineData(0)] + [InlineData(1)] + public void Should_Have_Specified_Start_Index(int index) { // Given - var state = CreateListPromptState(100, 10, false, false); + var state = CreateListPromptState(100, 10, false, false, initialIndex: index); // When /* noop */ // Then - state.Index.ShouldBe(0); + state.Index.ShouldBe(index); } [Theory] diff --git a/src/Spectre.Console.Tests/Unit/Prompts/MultiSelectionPromptTests.cs b/src/Spectre.Console.Tests/Unit/Prompts/MultiSelectionPromptTests.cs index edffe03ad..2ab4f53bb 100644 --- a/src/Spectre.Console.Tests/Unit/Prompts/MultiSelectionPromptTests.cs +++ b/src/Spectre.Console.Tests/Unit/Prompts/MultiSelectionPromptTests.cs @@ -250,6 +250,260 @@ public void Should_Return_CancelResult_On_Cancel_EmptyVersion() // Then selection.ShouldBe([]); } + + [Fact] + public void Should_Initially_Select_The_First_Item_When_No_Default_Is_Specified() + { + // Given + var console = new TestConsole(); + console.Profile.Capabilities.Interactive = true; + console.Input.PushKey(ConsoleKey.Spacebar); + console.Input.PushKey(ConsoleKey.Enter); + + // When + var prompt = new MultiSelectionPrompt() + .AddChoices("First", "Second", "Third"); + + prompt.Show(console); + + // Then + console.Lines.ShouldBe([ + "> [ ] First ", + " [ ] Second ", + " [ ] Third ", + " ", + "(Press to select, to accept)> [X] First ", + " [ ] Second ", + " [ ] Third ", + " ", + "(Press to select, to accept)", + ]); + } + + [Fact] + public void Should_Initially_Select_The_Default_Item_When_It_Exists_In_The_Choices() + { + // Given + var console = new TestConsole(); + console.Profile.Capabilities.Interactive = true; + console.Input.PushKey(ConsoleKey.Spacebar); + console.Input.PushKey(ConsoleKey.Enter); + + // When + var prompt = new MultiSelectionPrompt() + .Title("Select one") + .AddChoices("First", "Second", "Third") + .DefaultValue("Second"); + + prompt.Show(console); + + // Then + console.Lines.ShouldBe([ + "Select one ", + " ", + " [ ] First ", + "> [ ] Second ", + " [ ] Third ", + " ", + "(Press to select, to accept)Select one ", + " ", + " [ ] First ", + "> [X] Second ", + " [ ] Third ", + " ", + "(Press to select, to accept)",]); + } + + [Fact] + public void Should_Initially_Select_The_First_Item_When_Default_Does_Not_Exist_In_The_Choices() + { + // Given + var console = new TestConsole(); + console.Profile.Capabilities.Interactive = true; + console.Input.PushKey(ConsoleKey.Spacebar); + console.Input.PushKey(ConsoleKey.Enter); + + // When + var prompt = new MultiSelectionPrompt() + .Title("Select one") + .AddChoices("First", "Second", "Third") + .DefaultValue("Fourth"); + + prompt.Show(console); + + // Then + console.Lines.ShouldBe([ + "Select one ", + " ", + "> [ ] First ", + " [ ] Second ", + " [ ] Third ", + " ", + "(Press to select, to accept)Select one ", + " ", + "> [X] First ", + " [ ] Second ", + " [ ] Third ", + " ", + "(Press to select, to accept)", + ]); + } + + [Fact] + public void Should_Initially_Select_The_Default_Item_When_Scrolling_Is_Required_And_Item_Is_Not_Last() + { + // Given + var console = new TestConsole(); + console.Profile.Capabilities.Interactive = true; + console.Input.PushKey(ConsoleKey.Spacebar); + console.Input.PushKey(ConsoleKey.Enter); + + // When + var prompt = new MultiSelectionPrompt() + .Title("Select one") + .AddChoices("First", "Second", "Third", "Fourth", "Fifth", "Sixth") + .DefaultValue("Third") + .PageSize(3); + + prompt.Show(console); + + // Then + console.Lines.ShouldBe([ + "Select one ", + " ", + " [ ] Second ", + "> [ ] Third ", + " [ ] Fourth ", + " ", + "(Move up and down to reveal more choices) ", + "(Press to select, to accept)Select one ", " ", " [ ] Second ", "> [X] Third ", " [ ] Fourth ", " ", "(Move up and down to reveal more choices) ", + "(Press to select, to accept)", + ]); + } + + [Fact] + public void Should_Initially_Select_The_Default_Item_When_Scrolling_Is_Required_And_Item_Is_Last() + { + // Given + var console = new TestConsole(); + console.Profile.Capabilities.Interactive = true; + console.Input.PushKey(ConsoleKey.Spacebar); + console.Input.PushKey(ConsoleKey.Enter); + + // When + var prompt = new MultiSelectionPrompt() + .Title("Select one") + .AddChoices("First", "Second", "Third", "Fourth", "Fifth", "Sixth") + .DefaultValue("Sixth") + .PageSize(3); + + prompt.Show(console); + + // Then + console.Lines.ShouldBe([ + "Select one ", + " ", + " [ ] Fourth ", + " [ ] Fifth ", + "> [ ] Sixth ", + " ", + "(Move up and down to reveal more choices) ", + "(Press to select, to accept)Select one ", + " ", + " [ ] Fourth ", + " [ ] Fifth ", + "> [X] Sixth ", + " ", + "(Move up and down to reveal more choices) ", + "(Press to select, to accept)", + ]); + } + + [Fact] + public void Should_Initially_Select_The_Default_Value_When_Skipping_Unselectable_Items_And_Default_Value_Is_Leaf() + { + // Given + var console = new TestConsole(); + console.Profile.Capabilities.Interactive = true; + console.Input.PushKey(ConsoleKey.Spacebar); + console.Input.PushKey(ConsoleKey.Enter); + + // When + var prompt = new MultiSelectionPrompt() + .Title("Select one") + .AddChoiceGroup("Group one", "First", "Second") + .AddChoiceGroup("Group two", "Third", "Fourth") + .Mode(SelectionMode.Leaf) + .DefaultValue("Third"); + + prompt.Show(console); + + // Then + console.Lines.ShouldBe([ + "Select one ", + " ", + " [ ] Group one ", + " [ ] First ", + " [ ] Second ", + " [ ] Group two ", + " > [ ] Third ", + " [ ] Fourth ", + " ", + "(Press to select, to accept)Select one ", + " ", + " [ ] Group one ", + " [ ] First ", + " [ ] Second ", + " [ ] Group two ", + " > [X] Third ", + " [ ] Fourth ", + " ", + "(Press to select, to accept)", + ]); + } + + [Fact] + public void Should_Initially_Select_The_First_Leaf_When_Skipping_Unselectable_Items_And_Default_Value_Is_Not_Leaf() + { + // Given + var console = new TestConsole(); + console.Profile.Capabilities.Interactive = true; + console.Input.PushKey(ConsoleKey.Spacebar); + console.Input.PushKey(ConsoleKey.Enter); + + // When + var prompt = new MultiSelectionPrompt() + .Title("Select one") + .AddChoiceGroup("Group one", "First", "Second") + .AddChoiceGroup("Group two", "Third", "Fourth") + .Mode(SelectionMode.Leaf) + .DefaultValue("Group two"); + + prompt.Show(console); + + // Then + console.Lines.ShouldBe([ + "Select one ", + " ", + " [ ] Group one ", + " [ ] First ", + " [ ] Second ", + "> [ ] Group two ", + " [ ] Third ", + " [ ] Fourth ", + " ", + "(Press to select, to accept)Select one ", + " ", + " [ ] Group one ", + " [ ] First ", + " [ ] Second ", + "> [X] Group two ", + " [X] Third ", + " [X] Fourth ", + " ", + "(Press to select, to accept)", + ]); + } } file sealed class CustomItem diff --git a/src/Spectre.Console.Tests/Unit/Prompts/SelectionPromptTests.cs b/src/Spectre.Console.Tests/Unit/Prompts/SelectionPromptTests.cs index 37763c150..a5e670efb 100644 --- a/src/Spectre.Console.Tests/Unit/Prompts/SelectionPromptTests.cs +++ b/src/Spectre.Console.Tests/Unit/Prompts/SelectionPromptTests.cs @@ -265,6 +265,196 @@ public void Should_Search_And_Select_Item_With_Brackets() // Then result.ShouldBe("[Dev] Development"); } + + [Fact] + public void Should_Initially_Select_The_First_Item_When_No_Default_Is_Specified() { + // Given + var console = new TestConsole(); + console.Profile.Capabilities.Interactive = true; + console.Input.PushKey(ConsoleKey.Enter); + + // When + var prompt = new SelectionPrompt() + .Title("Select one") + .AddChoices("First", "Second", "Third"); + + prompt.Show(console); + + // Then + console.Lines.ShouldBe([ + "Select one", + " ", + "> First ", + " Second ", + " Third ", + ]); + } + + [Fact] + public void Should_Initially_Select_The_Default_Item_When_It_Exists_In_The_Choices() { + // Given + var console = new TestConsole(); + console.Profile.Capabilities.Interactive = true; + console.Input.PushKey(ConsoleKey.Enter); + + // When + var prompt = new SelectionPrompt() + .Title("Select one") + .AddChoices("First", "Second", "Third") + .DefaultValue("Second"); + + prompt.Show(console); + + // Then + console.Lines.ShouldBe([ + "Select one", + " ", + " First ", + "> Second ", + " Third ", + ]); + } + + [Fact] + public void Should_Initially_Select_The_First_Item_When_Default_Does_Not_Exist_In_The_Choices() { + // Given + var console = new TestConsole(); + console.Profile.Capabilities.Interactive = true; + console.Input.PushKey(ConsoleKey.Enter); + + // When + var prompt = new SelectionPrompt() + .Title("Select one") + .AddChoices("First", "Second", "Third") + .DefaultValue("Fourth"); + + prompt.Show(console); + + // Then + console.Lines.ShouldBe([ + "Select one", + " ", + "> First ", + " Second ", + " Third ", + ]); + } + + [Fact] + public void Should_Initially_Select_The_Default_Item_When_Scrolling_Is_Required_And_Item_Is_Not_Last() { + // Given + var console = new TestConsole(); + console.Profile.Capabilities.Interactive = true; + console.Input.PushKey(ConsoleKey.Enter); + + // When + var prompt = new SelectionPrompt() + .Title("Select one") + .AddChoices("First", "Second", "Third", "Fourth", "Fifth", "Sixth") + .DefaultValue("Third") + .PageSize(3); + + prompt.Show(console); + + // Then + console.Lines.ShouldBe([ + "Select one ", + " ", + " Second ", + "> Third ", + " Fourth ", + " ", + "(Move up and down to reveal more choices)", + ]); + } + + [Fact] + public void Should_Initially_Select_The_Default_Item_When_Scrolling_Is_Required_And_Item_Is_Last() { + // Given + var console = new TestConsole(); + console.Profile.Capabilities.Interactive = true; + console.Input.PushKey(ConsoleKey.Enter); + + // When + var prompt = new SelectionPrompt() + .Title("Select one") + .AddChoices("First", "Second", "Third", "Fourth", "Fifth", "Sixth") + .DefaultValue("Sixth") + .PageSize(3); + + prompt.Show(console); + + // Then + console.Lines.ShouldBe([ + "Select one ", + " ", + " Fourth ", + " Fifth ", + "> Sixth ", + " ", + "(Move up and down to reveal more choices)", + ]); + } + + [Fact] + public void Should_Initially_Select_The_Default_Value_When_Skipping_Unselectable_Items_And_Default_Value_Is_Leaf() { + // Given + var console = new TestConsole(); + console.Profile.Capabilities.Interactive = true; + console.Input.PushKey(ConsoleKey.Enter); + + // When + var prompt = new SelectionPrompt() + .Title("Select one") + .AddChoiceGroup("Group one", "First", "Second") + .AddChoiceGroup("Group two", "Third", "Fourth") + .Mode(SelectionMode.Leaf) + .DefaultValue("Third"); + + prompt.Show(console); + + // Then + console.Lines.ShouldBe([ + "Select one ", + " ", + " Group one ", + " First ", + " Second ", + " Group two ", + " > Third ", + " Fourth ", + ]); + } + + [Fact] + public void Should_Initially_Select_The_First_Leaf_When_Skipping_Unselectable_Items_And_Default_Value_Is_Not_Leaf() { + // Given + var console = new TestConsole(); + console.Profile.Capabilities.Interactive = true; + console.Input.PushKey(ConsoleKey.Enter); + + // When + var prompt = new SelectionPrompt() + .Title("Select one") + .AddChoiceGroup("Group one", "First", "Second") + .AddChoiceGroup("Group two", "Third", "Fourth") + .Mode(SelectionMode.Leaf) + .DefaultValue("Group two"); + + prompt.Show(console); + + // Then + console.Lines.ShouldBe([ + "Select one ", + " ", + " Group one ", + " > First ", + " Second ", + " Group two ", + " Third ", + " Fourth ", + ]); + } } file sealed class CustomSelectionItem diff --git a/src/Spectre.Console/Prompts/List/IListPromptStrategy.cs b/src/Spectre.Console/Prompts/List/IListPromptStrategy.cs index a49358c61..1d2260a10 100644 --- a/src/Spectre.Console/Prompts/List/IListPromptStrategy.cs +++ b/src/Spectre.Console/Prompts/List/IListPromptStrategy.cs @@ -36,4 +36,11 @@ internal interface IListPromptStrategy /// A representing the items. public IRenderable Render(IAnsiConsole console, bool scrollable, int cursorIndex, IEnumerable<(int Index, ListPromptItem Node)> items, bool skipUnselectableItems, string searchText); + + /// + /// Calculates the state's initial index. + /// + /// The nodes that will be shown in the list. + /// The initial index that should be used. + public int CalculateInitialIndex(IReadOnlyList> nodes); } \ No newline at end of file diff --git a/src/Spectre.Console/Prompts/List/ListPrompt.cs b/src/Spectre.Console/Prompts/List/ListPrompt.cs index 424d597ba..c951e26e2 100644 --- a/src/Spectre.Console/Prompts/List/ListPrompt.cs +++ b/src/Spectre.Console/Prompts/List/ListPrompt.cs @@ -44,7 +44,15 @@ public async Task> Show( throw new InvalidOperationException("Cannot show an empty selection prompt. Please call the AddChoice() method to configure the prompt."); } - var state = new ListPromptState(nodes, converter, _strategy.CalculatePageSize(_console, nodes.Count, requestedPageSize), wrapAround, selectionMode, skipUnselectableItems, searchEnabled); + var state = new ListPromptState( + nodes, + converter, + _strategy.CalculatePageSize(_console, nodes.Count, requestedPageSize), + wrapAround, + selectionMode, + skipUnselectableItems, + searchEnabled, + _strategy.CalculateInitialIndex(nodes)); var hook = new ListPromptRenderHook(_console, () => BuildRenderable(state)); using (new RenderHookScope(_console, hook)) diff --git a/src/Spectre.Console/Prompts/List/ListPromptState.cs b/src/Spectre.Console/Prompts/List/ListPromptState.cs index f89f2b235..60c5e5596 100644 --- a/src/Spectre.Console/Prompts/List/ListPromptState.cs +++ b/src/Spectre.Console/Prompts/List/ListPromptState.cs @@ -25,7 +25,8 @@ public ListPromptState( int pageSize, bool wrapAround, SelectionMode mode, bool skipUnselectableItems, - bool searchEnabled) + bool searchEnabled, + int initialIndex) { _converter = converter ?? throw new ArgumentNullException(nameof(converter)); Items = items; @@ -46,11 +47,11 @@ public ListPromptState( .ToList() .AsReadOnly(); - Index = _leafIndexes.FirstOrDefault(); + Index = _leafIndexes.Contains(initialIndex) ? initialIndex : _leafIndexes.FirstOrDefault(); } else { - Index = 0; + Index = initialIndex; } } diff --git a/src/Spectre.Console/Prompts/List/ListPromptTree.cs b/src/Spectre.Console/Prompts/List/ListPromptTree.cs index 669cdec46..c9d993963 100644 --- a/src/Spectre.Console/Prompts/List/ListPromptTree.cs +++ b/src/Spectre.Console/Prompts/List/ListPromptTree.cs @@ -29,6 +29,22 @@ public ListPromptTree(IEqualityComparer comparer) return null; } + public int? IndexOf(T item) + { + var index = 0; + foreach (var node in Traverse()) + { + if (_comparer.Equals(item, node.Data)) + { + return index; + } + + index++; + } + + return null; + } + public void Add(ListPromptItem node) { _roots.Add(node); diff --git a/src/Spectre.Console/Prompts/MultiSelectionPrompt.cs b/src/Spectre.Console/Prompts/MultiSelectionPrompt.cs index 92a94e808..f4186a101 100644 --- a/src/Spectre.Console/Prompts/MultiSelectionPrompt.cs +++ b/src/Spectre.Console/Prompts/MultiSelectionPrompt.cs @@ -59,6 +59,12 @@ public sealed class MultiSelectionPrompt : IPrompt>, IListPromptStrat internal ListPromptTree Tree { get; } + /// + /// Gets or sets the choice to show as selected when the prompt is first displayed. + /// By default the first choice is selected. + /// + public T? DefaultValue { get; set; } + /// /// Gets or sets a Func that will be triggered if Cancel is triggered by the 'ESC' key. /// @@ -293,4 +299,15 @@ IRenderable IListPromptStrategy.Render(IAnsiConsole console, bool scrollable, // Combine all items return new Rows(list); } + + /// + int IListPromptStrategy.CalculateInitialIndex(IReadOnlyList> nodes) + { + if (DefaultValue is not null) + { + return Tree.IndexOf(DefaultValue) ?? 0; + } + + return 0; + } } \ No newline at end of file diff --git a/src/Spectre.Console/Prompts/MultiSelectionPromptExtensions.cs b/src/Spectre.Console/Prompts/MultiSelectionPromptExtensions.cs index 839b4cd29..87a960ccc 100644 --- a/src/Spectre.Console/Prompts/MultiSelectionPromptExtensions.cs +++ b/src/Spectre.Console/Prompts/MultiSelectionPromptExtensions.cs @@ -363,4 +363,20 @@ public static MultiSelectionPrompt AddCancelResult(this MultiSelectionProm return obj.AddCancelResult([]); } + + /// + /// Sets the choice that will be selected when the prompt is first displayed. + /// + /// The prompt result type. + /// The prompt. + /// The choice to show as selected when the prompt is first displayed. + /// The same instance so that multiple calls can be chained. + public static MultiSelectionPrompt DefaultValue(this MultiSelectionPrompt obj, T? defaultValue) + where T : notnull + { + ArgumentNullException.ThrowIfNull(obj); + + obj.DefaultValue = defaultValue; + return obj; + } } \ No newline at end of file diff --git a/src/Spectre.Console/Prompts/SelectionPrompt.cs b/src/Spectre.Console/Prompts/SelectionPrompt.cs index 57289c38d..9761a8775 100644 --- a/src/Spectre.Console/Prompts/SelectionPrompt.cs +++ b/src/Spectre.Console/Prompts/SelectionPrompt.cs @@ -68,6 +68,12 @@ public sealed class SelectionPrompt : IPrompt, IListPromptStrategy /// public bool SearchEnabled { get; set; } + /// + /// Gets or sets the choice to show as selected when the prompt is first displayed. + /// By default the first choice is selected. + /// + public T? DefaultValue { get; set; } + /// /// Gets or sets a Func that will be triggered if Cancel is triggered by the 'ESC' key. /// @@ -76,9 +82,13 @@ public sealed class SelectionPrompt : IPrompt, IListPromptStrategy /// /// Initializes a new instance of the class. /// - public SelectionPrompt() + /// + /// The implementation to use when comparing items, + /// or null to use the default for the type of the item. + /// + public SelectionPrompt(IEqualityComparer? comparer = null) { - _tree = new ListPromptTree(EqualityComparer.Default); + _tree = new ListPromptTree(comparer ?? EqualityComparer.Default); } /// @@ -243,4 +253,15 @@ IRenderable IListPromptStrategy.Render(IAnsiConsole console, bool scrollable, return new Rows(list); } + + /// + int IListPromptStrategy.CalculateInitialIndex(IReadOnlyList> nodes) + { + if (DefaultValue is not null) + { + return _tree.IndexOf(DefaultValue) ?? 0; + } + + return 0; + } } \ No newline at end of file diff --git a/src/Spectre.Console/Prompts/SelectionPromptExtensions.cs b/src/Spectre.Console/Prompts/SelectionPromptExtensions.cs index 031e548bf..63c2117a3 100644 --- a/src/Spectre.Console/Prompts/SelectionPromptExtensions.cs +++ b/src/Spectre.Console/Prompts/SelectionPromptExtensions.cs @@ -282,4 +282,20 @@ public static SelectionPrompt UseConverter(this SelectionPrompt obj, Fu obj.Converter = displaySelector; return obj; } + + /// + /// Sets the choice that will be selected when the prompt is first displayed. + /// + /// The prompt result type. + /// The prompt. + /// The choice to show as selected when the prompt is first displayed. + /// The same instance so that multiple calls can be chained. + public static SelectionPrompt DefaultValue(this SelectionPrompt obj, T? defaultValue) + where T : notnull + { + ArgumentNullException.ThrowIfNull(obj); + + obj.DefaultValue = defaultValue; + return obj; + } } \ No newline at end of file