From 9502aaf2b91b1aaacdae0f0c14173cb18c764146 Mon Sep 17 00:00:00 2001 From: Patrik Svensson Date: Sun, 14 Mar 2021 23:09:17 +0100 Subject: [PATCH] Allow markup in selection prompts Closes #221 --- src/Spectre.Console.Tests/Unit/MarkupTests.cs | 16 ++++++++++++ .../Extensions/StringExtensions.cs | 26 +++++++++++++++++++ src/Spectre.Console/Widgets/Markup.cs | 15 +++++++++++ .../Rendering/RenderableMultiSelectionList.cs | 7 ++--- .../Rendering/RenderableSelectionList.cs | 8 +++--- 5 files changed, 66 insertions(+), 6 deletions(-) diff --git a/src/Spectre.Console.Tests/Unit/MarkupTests.cs b/src/Spectre.Console.Tests/Unit/MarkupTests.cs index baba137..f679827 100644 --- a/src/Spectre.Console.Tests/Unit/MarkupTests.cs +++ b/src/Spectre.Console.Tests/Unit/MarkupTests.cs @@ -25,6 +25,22 @@ namespace Spectre.Console.Tests.Unit } } + public sealed class TheRemoveMethod + { + [Theory] + [InlineData("Hello World", "Hello World")] + [InlineData("Hello [blue]World", "Hello World")] + [InlineData("Hello [blue]World[/]", "Hello World")] + public void Should_Remove_Markup_From_Text(string input, string expected) + { + // Given, When + var result = Markup.Remove(input); + + // Then + result.ShouldBe(expected); + } + } + [Theory] [InlineData("Hello [[ World ]")] [InlineData("Hello [[ World ] !")] diff --git a/src/Spectre.Console/Extensions/StringExtensions.cs b/src/Spectre.Console/Extensions/StringExtensions.cs index f5e150a..991b10f 100644 --- a/src/Spectre.Console/Extensions/StringExtensions.cs +++ b/src/Spectre.Console/Extensions/StringExtensions.cs @@ -34,6 +34,32 @@ namespace Spectre.Console .ReplaceExact("]", "]]"); } + /// + /// Removes markup from the specified string. + /// + /// The text to remove markup from. + /// A string that does not have any markup. + public static string RemoveMarkup(this string? text) + { + if (string.IsNullOrWhiteSpace(text)) + { + return string.Empty; + } + + var result = new StringBuilder(); + + var tokenizer = new MarkupTokenizer(text); + while (tokenizer.MoveNext() && tokenizer.Current != null) + { + if (tokenizer.Current.Kind == MarkupTokenKind.Text) + { + result.Append(tokenizer.Current.Value); + } + } + + return result.ToString(); + } + internal static int CellLength(this string text, RenderContext context) { if (context is null) diff --git a/src/Spectre.Console/Widgets/Markup.cs b/src/Spectre.Console/Widgets/Markup.cs index 1d426a7..d52ca32 100644 --- a/src/Spectre.Console/Widgets/Markup.cs +++ b/src/Spectre.Console/Widgets/Markup.cs @@ -63,5 +63,20 @@ namespace Spectre.Console return text.EscapeMarkup(); } + + /// + /// Removes markup from the specified string. + /// + /// The text to remove markup from. + /// A string that does not have any markup. + public static string Remove(string text) + { + if (text is null) + { + throw new ArgumentNullException(nameof(text)); + } + + return text.RemoveMarkup(); + } } } diff --git a/src/Spectre.Console/Widgets/Prompt/Rendering/RenderableMultiSelectionList.cs b/src/Spectre.Console/Widgets/Prompt/Rendering/RenderableMultiSelectionList.cs index e38bc99..36ce727 100644 --- a/src/Spectre.Console/Widgets/Prompt/Rendering/RenderableMultiSelectionList.cs +++ b/src/Spectre.Console/Widgets/Prompt/Rendering/RenderableMultiSelectionList.cs @@ -81,10 +81,11 @@ namespace Spectre.Console var checkbox = selected ? SelectedCheckbox : Checkbox; var style = current ? _highlightStyle : Style.Plain; + var item = current + ? new Text(choice.Item.RemoveMarkup(), style) + : (IRenderable)new Markup(choice.Item, style); - grid.AddRow( - new Markup($"{prompt}{checkbox}", style), - new Markup(choice.Item.EscapeMarkup(), style)); + grid.AddRow(new Markup(prompt + checkbox, style), item); } list.Add(grid); diff --git a/src/Spectre.Console/Widgets/Prompt/Rendering/RenderableSelectionList.cs b/src/Spectre.Console/Widgets/Prompt/Rendering/RenderableSelectionList.cs index 9f4113e..0bc6425 100644 --- a/src/Spectre.Console/Widgets/Prompt/Rendering/RenderableSelectionList.cs +++ b/src/Spectre.Console/Widgets/Prompt/Rendering/RenderableSelectionList.cs @@ -56,9 +56,11 @@ namespace Spectre.Console var prompt = choice.Index == pointerIndex ? Prompt : string.Empty; var style = current ? _highlightStyle : Style.Plain; - grid.AddRow( - new Markup(prompt, style), - new Markup(choice.Item.EscapeMarkup(), style)); + var item = current + ? new Text(choice.Item.RemoveMarkup(), style) + : (IRenderable)new Markup(choice.Item, style); + + grid.AddRow(new Markup(prompt, style), item); } list.Add(grid);