namespace Spectre.Console; /// /// Represents a single list prompt. /// /// The prompt result type. public sealed class SelectionPrompt : IPrompt, IListPromptStrategy where T : notnull { private readonly ListPromptTree _tree; /// /// Gets or sets the title. /// public string? Title { get; set; } /// /// Gets or sets the page size. /// Defaults to 10. /// public int PageSize { get; set; } = 10; /// /// Gets or sets a value indicating whether the selection should wrap around when reaching the edge. /// Defaults to false. /// public bool WrapAround { get; set; } = false; /// /// Gets or sets the highlight style of the selected choice. /// public Style? HighlightStyle { get; set; } /// /// Gets or sets the style of a disabled choice. /// public Style? DisabledStyle { get; set; } /// /// Gets or sets the converter to get the display string for a choice. By default /// the corresponding is used. /// public Func? Converter { get; set; } /// /// Gets or sets the text that will be displayed if there are more choices to show. /// public string? MoreChoicesText { get; set; } /// /// Gets or sets the selection mode. /// Defaults to . /// public SelectionMode Mode { get; set; } = SelectionMode.Leaf; /// /// Initializes a new instance of the class. /// public SelectionPrompt() { _tree = new ListPromptTree(EqualityComparer.Default); } /// /// Adds a choice. /// /// The item to add. /// A so that multiple calls can be chained. public ISelectionItem AddChoice(T item) { var node = new ListPromptItem(item); _tree.Add(node); return node; } /// public T Show(IAnsiConsole console) { return ShowAsync(console, CancellationToken.None).GetAwaiter().GetResult(); } /// public async Task ShowAsync(IAnsiConsole console, CancellationToken cancellationToken) { // Create the list prompt var prompt = new ListPrompt(console, this); var result = await prompt.Show(_tree, cancellationToken, PageSize, WrapAround).ConfigureAwait(false); // Return the selected item return result.Items[result.Index].Data; } /// ListPromptInputResult IListPromptStrategy.HandleInput(ConsoleKeyInfo key, ListPromptState state) { if (key.Key == ConsoleKey.Enter || key.Key == ConsoleKey.Spacebar) { // Selecting a non leaf in "leaf mode" is not allowed if (state.Current.IsGroup && Mode == SelectionMode.Leaf) { return ListPromptInputResult.None; } return ListPromptInputResult.Submit; } return ListPromptInputResult.None; } /// int IListPromptStrategy.CalculatePageSize(IAnsiConsole console, int totalItemCount, int requestedPageSize) { var extra = 0; if (Title != null) { // Title takes up two rows including a blank line extra += 2; } // Scrolling? if (totalItemCount > requestedPageSize) { // The scrolling instructions takes up two rows extra += 2; } if (requestedPageSize > console.Profile.Height - extra) { return console.Profile.Height - extra; } return requestedPageSize; } /// IRenderable IListPromptStrategy.Render(IAnsiConsole console, bool scrollable, int cursorIndex, IEnumerable<(int Index, ListPromptItem Node)> items) { var list = new List(); var disabledStyle = DisabledStyle ?? new Style(foreground: Color.Grey); var highlightStyle = HighlightStyle ?? new Style(foreground: Color.Blue); if (Title != null) { list.Add(new Markup(Title)); } var grid = new Grid(); grid.AddColumn(new GridColumn().Padding(0, 0, 1, 0).NoWrap()); if (Title != null) { grid.AddEmptyRow(); } foreach (var item in items) { var current = item.Index == cursorIndex; var prompt = item.Index == cursorIndex ? ListPromptConstants.Arrow : new string(' ', ListPromptConstants.Arrow.Length); var style = item.Node.IsGroup && Mode == SelectionMode.Leaf ? disabledStyle : current ? highlightStyle : Style.Plain; var indent = new string(' ', item.Node.Depth * 2); var text = (Converter ?? TypeConverterHelper.ConvertToString)?.Invoke(item.Node.Data) ?? item.Node.Data.ToString() ?? "?"; if (current) { text = text.RemoveMarkup().EscapeMarkup(); } grid.AddRow(new Markup(indent + prompt + " " + text, style)); } list.Add(grid); if (scrollable) { // (Move up and down to reveal more choices) list.Add(Text.Empty); list.Add(new Markup(MoreChoicesText ?? ListPromptConstants.MoreChoicesMarkup)); } return new Rows(list); } }