Browse Source

Fixed TryParseW3CColorName

Tig 10 months ago
parent
commit
7fcb5007ec
2 changed files with 42 additions and 29 deletions
  1. 30 27
      Terminal.Gui/Drawing/ColorStrings.cs
  2. 12 2
      UnitTests/Resources/ResourceManagerTests.cs

+ 30 - 27
Terminal.Gui/Drawing/ColorStrings.cs

@@ -1,6 +1,7 @@
 #nullable enable
 #nullable enable
 using System.Collections;
 using System.Collections;
 using System.Globalization;
 using System.Globalization;
+using System.Resources;
 using Terminal.Gui.Resources;
 using Terminal.Gui.Resources;
 
 
 namespace Terminal.Gui;
 namespace Terminal.Gui;
@@ -10,6 +11,8 @@ namespace Terminal.Gui;
 /// </summary>
 /// </summary>
 public static class ColorStrings
 public static class ColorStrings
 {
 {
+    // PERFORMANCE: See https://stackoverflow.com/a/15521524/297526 for why GlobalResources.GetString is fast.
+
     /// <summary>
     /// <summary>
     ///     Gets the W3C standard string for <paramref name="color"/>.
     ///     Gets the W3C standard string for <paramref name="color"/>.
     /// </summary>
     /// </summary>
@@ -17,7 +20,6 @@ public static class ColorStrings
     /// <returns><see langword="null"/> if there is no standard color name for the specified color.</returns>
     /// <returns><see langword="null"/> if there is no standard color name for the specified color.</returns>
     public static string? GetW3CColorName (Color 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);
         return GlobalResources.GetString ($"#{color.R:X2}{color.G:X2}{color.B:X2}", CultureInfo.CurrentUICulture);
     }
     }
 
 
@@ -27,18 +29,18 @@ public static class ColorStrings
     /// <returns></returns>
     /// <returns></returns>
     public static IEnumerable<string> GetW3CColorNames ()
     public static IEnumerable<string> GetW3CColorNames ()
     {
     {
-        foreach (DictionaryEntry entry in GlobalResources.GetResourceSet (
-                                                                          CultureInfo.CurrentUICulture,
-                                                                          true,
-                                                                          true,
-                                                                          e =>
-                                                                          {
-                                                                              string keyName = e.Key.ToString () ?? string.Empty;
+        ResourceSet? resourceSet = GlobalResources.GetResourceSet (CultureInfo.CurrentUICulture, true, true);
+        if (resourceSet == null)
+        {
+            yield break;
+        }
 
 
-                                                                              return e.Value is string && keyName.StartsWith ('#');
-                                                                          })!)
+        foreach (DictionaryEntry entry in resourceSet)
         {
         {
-            yield return (entry.Value as string)!;
+            if (entry is { Value: string colorName, Key: string key } && key.StartsWith ('#'))
+            {
+                yield return colorName;
+            }
         }
         }
     }
     }
 
 
@@ -50,30 +52,31 @@ public static class ColorStrings
     /// <returns><see langword="true"/> if <paramref name="name"/> was parsed successfully.</returns>
     /// <returns><see langword="true"/> if <paramref name="name"/> was parsed successfully.</returns>
     public static bool TryParseW3CColorName (string name, out Color color)
     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)!)
         foreach (DictionaryEntry entry in GlobalResources.GetResourceSet (CultureInfo.CurrentUICulture, true, true)!)
         {
         {
             if (entry.Value is string colorName && colorName.Equals (name, StringComparison.OrdinalIgnoreCase))
             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;
+                return TryParseColorKey (entry.Key.ToString (), out color);
+            }
+        }
 
 
-                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 TryParseColorKey (name, out color);
 
 
-                        return true;
-                    }
+        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;
+            color = default (Color);
+            return false;
+        }
     }
     }
 }
 }

+ 12 - 2
UnitTests/Resources/ResourceManagerTests.cs

@@ -9,8 +9,10 @@ namespace Terminal.Gui.ResourcesTests;
 
 
 public class ResourceManagerTests
 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 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 EXISTENT_CULTURE = "pt-PT";
     private const string NO_EXISTENT_CULTURE = "de-DE";
     private const string NO_EXISTENT_CULTURE = "de-DE";
     private const string NO_EXISTENT_KEY = "blabla";
     private const string NO_EXISTENT_KEY = "blabla";
@@ -62,7 +64,7 @@ public class ResourceManagerTests
         RestoreCurrentCultures ();
         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 ()
     public void GetResourceSet_FallBack_To_Default_For_Not_Translated_Existent_Culture_File ()
     {
     {
         CultureInfo.CurrentCulture = new (EXISTENT_CULTURE);
         CultureInfo.CurrentCulture = new (EXISTENT_CULTURE);
@@ -82,6 +84,14 @@ public class ResourceManagerTests
         Assert.True (ColorStrings.TryParseW3CColorName (DODGER_BLUE_COLOR_NAME, out Color color));
         Assert.True (ColorStrings.TryParseW3CColorName (DODGER_BLUE_COLOR_NAME, out Color color));
         Assert.Equal (DODGER_BLUE_COLOR_KEY, color.ToString ());
         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 ();
         RestoreCurrentCultures ();
     }
     }