diff --git a/Terminal.Gui/Drawing/ColorStrings.cs b/Terminal.Gui/Drawing/ColorStrings.cs index a6b90d800..79ca9f357 100644 --- a/Terminal.Gui/Drawing/ColorStrings.cs +++ b/Terminal.Gui/Drawing/ColorStrings.cs @@ -1,6 +1,7 @@ #nullable enable using System.Collections; using System.Globalization; +using System.Resources; using Terminal.Gui.Resources; namespace Terminal.Gui; @@ -10,6 +11,8 @@ namespace Terminal.Gui; /// public static class ColorStrings { + // PERFORMANCE: See https://stackoverflow.com/a/15521524/297526 for why GlobalResources.GetString is fast. + /// /// Gets the W3C standard string for . /// @@ -17,7 +20,6 @@ public static class ColorStrings /// if there is no standard color name for the specified color. public static string? GetW3CColorName (Color color) { - // Fetch the color name from the resource file return GlobalResources.GetString ($"#{color.R:X2}{color.G:X2}{color.B:X2}", CultureInfo.CurrentUICulture); } @@ -27,18 +29,18 @@ public static class ColorStrings /// public static IEnumerable GetW3CColorNames () { - foreach (DictionaryEntry entry in GlobalResources.GetResourceSet ( - CultureInfo.CurrentUICulture, - true, - true, - e => - { - string keyName = e.Key.ToString () ?? string.Empty; - - return e.Value is string && keyName.StartsWith ('#'); - })!) + ResourceSet? resourceSet = GlobalResources.GetResourceSet (CultureInfo.CurrentUICulture, true, true); + if (resourceSet == null) { - yield return (entry.Value as string)!; + yield break; + } + + foreach (DictionaryEntry entry in resourceSet) + { + if (entry is { Value: string colorName, Key: string key } && key.StartsWith ('#')) + { + yield return colorName; + } } } @@ -50,30 +52,31 @@ public static class ColorStrings /// if was parsed successfully. public static bool TryParseW3CColorName (string name, out Color color) { - // Iterate through all resource entries to find the matching color name foreach (DictionaryEntry entry in GlobalResources.GetResourceSet (CultureInfo.CurrentUICulture, true, true)!) { if (entry.Value is string colorName && colorName.Equals (name, StringComparison.OrdinalIgnoreCase)) { - // Parse the key to extract the color components - string key = entry.Key.ToString () ?? string.Empty; - - if (key.StartsWith ("#") && key.Length == 7) - { - if (int.TryParse (key.Substring (1, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out int r) - && int.TryParse (key.Substring (3, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out int g) - && int.TryParse (key.Substring (5, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out int b)) - { - color = new (r, g, b); - - return true; - } - } + return TryParseColorKey (entry.Key.ToString (), out color); } } - color = default (Color); + return TryParseColorKey (name, out color); - return false; + bool TryParseColorKey (string? key, out Color color) + { + if (key != null && key.StartsWith ('#') && key.Length == 7) + { + if (int.TryParse (key.AsSpan (1, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out int r) && + int.TryParse (key.AsSpan (3, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out int g) && + int.TryParse (key.AsSpan (5, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out int b)) + { + color = new Color (r, g, b); + return true; + } + } + + color = default (Color); + return false; + } } } diff --git a/UnitTests/Resources/ResourceManagerTests.cs b/UnitTests/Resources/ResourceManagerTests.cs index 4d4daa2af..1c49b3447 100644 --- a/UnitTests/Resources/ResourceManagerTests.cs +++ b/UnitTests/Resources/ResourceManagerTests.cs @@ -9,8 +9,10 @@ namespace Terminal.Gui.ResourcesTests; public class ResourceManagerTests { - private const string DODGER_BLUE_COLOR_KEY = "#1E90FF"; + private const string DODGER_BLUE_COLOR_KEY = "DodgerBlue"; private const string DODGER_BLUE_COLOR_NAME = "DodgerBlue"; + private const string NO_NAMED_COLOR_KEY = "#1E80FF"; + private const string NO_NAMED_COLOR_NAME = "#1E80FF"; private const string EXISTENT_CULTURE = "pt-PT"; private const string NO_EXISTENT_CULTURE = "de-DE"; private const string NO_EXISTENT_KEY = "blabla"; @@ -62,7 +64,7 @@ public class ResourceManagerTests RestoreCurrentCultures (); } - [Fact (Skip = "Tig broke this test and doesn't understand why.")] + [Fact] public void GetResourceSet_FallBack_To_Default_For_Not_Translated_Existent_Culture_File () { CultureInfo.CurrentCulture = new (EXISTENT_CULTURE); @@ -82,6 +84,14 @@ public class ResourceManagerTests Assert.True (ColorStrings.TryParseW3CColorName (DODGER_BLUE_COLOR_NAME, out Color color)); Assert.Equal (DODGER_BLUE_COLOR_KEY, color.ToString ()); + // W3CColors.GetColorNames also calls ColorStrings.GetW3CColorNames for no-named colors + colorNames = new W3CColors ().GetColorNames ().ToArray (); + Assert.DoesNotContain (NO_NAMED_COLOR_NAME, colorNames); + + // ColorStrings.TryParseW3CColorName method uses GetResourceSet method to retrieve a color value for no-named colors + Assert.True (ColorStrings.TryParseW3CColorName (NO_NAMED_COLOR_NAME, out color)); + Assert.Equal (NO_NAMED_COLOR_KEY, color.ToString ()); + RestoreCurrentCultures (); }