From e65251bb64a076dd64ef46e6e6ea394e0e051276 Mon Sep 17 00:00:00 2001 From: Stuart Lang Date: Sun, 17 Sep 2023 00:41:36 +0100 Subject: [PATCH] Address feedback --- .../Prompts/List/IListPromptStrategy.cs | 8 +--- .../Prompts/List/ListPrompt.cs | 4 +- .../Prompts/MultiSelectionPrompt.cs | 7 +-- .../Prompts/SelectionPrompt.cs | 16 ++++--- .../Prompts/SelectionPromptExtensions.cs | 44 +++++++++++++++++-- 5 files changed, 56 insertions(+), 23 deletions(-) diff --git a/src/Spectre.Console/Prompts/List/IListPromptStrategy.cs b/src/Spectre.Console/Prompts/List/IListPromptStrategy.cs index 3fdbbdc34..a49358c61 100644 --- a/src/Spectre.Console/Prompts/List/IListPromptStrategy.cs +++ b/src/Spectre.Console/Prompts/List/IListPromptStrategy.cs @@ -7,11 +7,6 @@ namespace Spectre.Console; internal interface IListPromptStrategy where T : notnull { - /// - /// Gets a value indicating whether or not the prompt should skip unselectable items. - /// - public bool ShouldSkipUnselectableItems { get; } - /// /// Handles any input received from the user. /// @@ -36,8 +31,9 @@ internal interface IListPromptStrategy /// Whether or not the list is scrollable. /// The cursor index. /// The visible items. + /// A value indicating whether or not the prompt should skip unselectable items. /// The search text. /// A representing the items. public IRenderable Render(IAnsiConsole console, bool scrollable, int cursorIndex, - IEnumerable<(int Index, ListPromptItem Node)> items, string searchText); + IEnumerable<(int Index, ListPromptItem Node)> items, bool skipUnselectableItems, string searchText); } \ 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 eb43d5266..3596af3a3 100644 --- a/src/Spectre.Console/Prompts/List/ListPrompt.cs +++ b/src/Spectre.Console/Prompts/List/ListPrompt.cs @@ -15,6 +15,7 @@ public ListPrompt(IAnsiConsole console, IListPromptStrategy strategy) public async Task> Show( ListPromptTree tree, SelectionMode selectionMode, + bool skipUnselectableItems, bool searchEnabled, int requestedPageSize, bool wrapAround, @@ -40,7 +41,7 @@ public async Task> Show( } var nodes = tree.Traverse().ToList(); - var state = new ListPromptState(nodes, _strategy.CalculatePageSize(_console, nodes.Count, requestedPageSize), wrapAround, selectionMode, _strategy.ShouldSkipUnselectableItems, searchEnabled); + var state = new ListPromptState(nodes, _strategy.CalculatePageSize(_console, nodes.Count, requestedPageSize), wrapAround, selectionMode, skipUnselectableItems, searchEnabled); var hook = new ListPromptRenderHook(_console, () => BuildRenderable(state)); using (new RenderHookScope(_console, hook)) @@ -112,6 +113,7 @@ private IRenderable BuildRenderable(ListPromptState state) scrollable, cursorIndex, state.Items.Skip(skip).Take(take) .Select((node, index) => (index, node)), + state.SkipUnselectableItems, state.SearchText); } } \ No newline at end of file diff --git a/src/Spectre.Console/Prompts/MultiSelectionPrompt.cs b/src/Spectre.Console/Prompts/MultiSelectionPrompt.cs index 1af03b3a9..0a023773c 100644 --- a/src/Spectre.Console/Prompts/MultiSelectionPrompt.cs +++ b/src/Spectre.Console/Prompts/MultiSelectionPrompt.cs @@ -94,7 +94,7 @@ public async Task> ShowAsync(IAnsiConsole console, CancellationToken can { // Create the list prompt var prompt = new ListPrompt(console, this); - var result = await prompt.Show(Tree, Mode, false, PageSize, WrapAround, cancellationToken).ConfigureAwait(false); + var result = await prompt.Show(Tree, Mode, false, false, PageSize, WrapAround, cancellationToken).ConfigureAwait(false); if (Mode == SelectionMode.Leaf) { @@ -145,9 +145,6 @@ public IEnumerable GetParents(T item) return GetParents(item).LastOrDefault(); } - /// - bool IListPromptStrategy.ShouldSkipUnselectableItems => false; - /// ListPromptInputResult IListPromptStrategy.HandleInput(ConsoleKeyInfo key, ListPromptState state) { @@ -226,7 +223,7 @@ int IListPromptStrategy.CalculatePageSize(IAnsiConsole console, int totalItem /// IRenderable IListPromptStrategy.Render(IAnsiConsole console, bool scrollable, int cursorIndex, - IEnumerable<(int Index, ListPromptItem Node)> items, string searchText) + IEnumerable<(int Index, ListPromptItem Node)> items, bool skipUnselectableItems, string searchText) { var list = new List(); var highlightStyle = HighlightStyle ?? Color.Blue; diff --git a/src/Spectre.Console/Prompts/SelectionPrompt.cs b/src/Spectre.Console/Prompts/SelectionPrompt.cs index 08f4333c9..15a7afdd8 100644 --- a/src/Spectre.Console/Prompts/SelectionPrompt.cs +++ b/src/Spectre.Console/Prompts/SelectionPrompt.cs @@ -41,6 +41,11 @@ public sealed class SelectionPrompt : IPrompt, IListPromptStrategy /// public Style? SearchHighlightStyle { get; set; } + /// + /// Gets or sets the text that will be displayed when no search text has been entered. + /// + public string? SearchPlaceholderText { get; set; } + /// /// Gets or sets the converter to get the display string for a choice. By default /// the corresponding is used. @@ -83,9 +88,6 @@ public ISelectionItem AddChoice(T item) return node; } - /// - bool IListPromptStrategy.ShouldSkipUnselectableItems => true; - /// public T Show(IAnsiConsole console) { @@ -97,7 +99,7 @@ public async Task ShowAsync(IAnsiConsole console, CancellationToken cancellat { // Create the list prompt var prompt = new ListPrompt(console, this); - var result = await prompt.Show(_tree, Mode, SearchEnabled, PageSize, WrapAround, cancellationToken).ConfigureAwait(false); + var result = await prompt.Show(_tree, Mode, true, SearchEnabled, PageSize, WrapAround, cancellationToken).ConfigureAwait(false); // Return the selected item return result.Items[result.Index].Data; @@ -106,7 +108,7 @@ public async Task ShowAsync(IAnsiConsole console, CancellationToken cancellat /// ListPromptInputResult IListPromptStrategy.HandleInput(ConsoleKeyInfo key, ListPromptState state) { - if (key.Key == ConsoleKey.Enter || key.Key == ConsoleKey.Packet) + if (key.Key == ConsoleKey.Enter || key.Key == ConsoleKey.Spacebar || key.Key == ConsoleKey.Packet) { // Selecting a non leaf in "leaf mode" is not allowed if (state.Current.IsGroup && Mode == SelectionMode.Leaf) @@ -157,7 +159,7 @@ int IListPromptStrategy.CalculatePageSize(IAnsiConsole console, int totalItem /// IRenderable IListPromptStrategy.Render(IAnsiConsole console, bool scrollable, int cursorIndex, - IEnumerable<(int Index, ListPromptItem Node)> items, string searchText) + IEnumerable<(int Index, ListPromptItem Node)> items, bool skipUnselectableItems, string searchText) { var list = new List(); var disabledStyle = DisabledStyle ?? Color.Grey; @@ -224,7 +226,7 @@ IRenderable IListPromptStrategy.Render(IAnsiConsole console, bool scrollable, if (SearchEnabled) { list.Add(new Markup( - searchText.Length > 0 ? searchText.EscapeMarkup() : ListPromptConstants.SearchPlaceholderMarkup)); + searchText.Length > 0 ? searchText.EscapeMarkup() : SearchPlaceholderText ?? ListPromptConstants.SearchPlaceholderMarkup)); } if (scrollable) diff --git a/src/Spectre.Console/Prompts/SelectionPromptExtensions.cs b/src/Spectre.Console/Prompts/SelectionPromptExtensions.cs index 15cd4d72c..a5d7be133 100644 --- a/src/Spectre.Console/Prompts/SelectionPromptExtensions.cs +++ b/src/Spectre.Console/Prompts/SelectionPromptExtensions.cs @@ -183,13 +183,12 @@ public static SelectionPrompt WrapAround(this SelectionPrompt obj, bool } /// - /// Sets whether the search filter should be enabled. + /// Enables search for the prompt. /// /// The prompt result type. /// The prompt. - /// Whether the search filter should be enabled. /// The same instance so that multiple calls can be chained. - public static SelectionPrompt Search(this SelectionPrompt obj, bool enabled = true) + public static SelectionPrompt EnableSearch(this SelectionPrompt obj) where T : notnull { if (obj is null) @@ -197,7 +196,44 @@ public static SelectionPrompt Search(this SelectionPrompt obj, bool ena throw new ArgumentNullException(nameof(obj)); } - obj.SearchEnabled = enabled; + obj.SearchEnabled = true; + return obj; + } + + /// + /// Disables search for the prompt. + /// + /// The prompt result type. + /// The prompt. + /// The same instance so that multiple calls can be chained. + public static SelectionPrompt DisableSearch(this SelectionPrompt obj) + where T : notnull + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + obj.SearchEnabled = false; + return obj; + } + + /// + /// Sets the text that will be displayed when no search text has been entered. + /// + /// The prompt result type. + /// The prompt. + /// The text to display. + /// The same instance so that multiple calls can be chained. + public static SelectionPrompt SearchPlaceholderText(this SelectionPrompt obj, string? text) + where T : notnull + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + obj.SearchPlaceholderText = text; return obj; }