MultiStandardColorNameResolver.cs 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. using System.Collections.Frozen;
  2. using System.Collections.Immutable;
  3. using System.Diagnostics.CodeAnalysis;
  4. using System.Globalization;
  5. namespace Terminal.Gui.Drawing;
  6. /// <summary>
  7. /// Color name resolver prioritizing Standard (W3C+) colors with fallback to ANSI 4-bit (16) colors.
  8. /// </summary>
  9. public class MultiStandardColorNameResolver : IColorNameResolver
  10. {
  11. private static readonly AnsiColorNameResolver _ansi = new ();
  12. private static readonly StandardColorsNameResolver _standard = new ();
  13. private static readonly ImmutableArray<string> _combinedColorNames;
  14. private static readonly FrozenDictionary<string, Color> _nameToColorMap;
  15. private static readonly FrozenDictionary<uint, string> _colorToNameMap;
  16. static MultiStandardColorNameResolver ()
  17. {
  18. Dictionary<string, Color> nameToColor = new (StringComparer.OrdinalIgnoreCase);
  19. Dictionary<uint, string> colorToName = new ();
  20. foreach (string name in _standard.GetColorNames ())
  21. {
  22. if (_standard.TryParseColor (name, out Color color))
  23. {
  24. if (nameToColor.TryAdd (name, color))
  25. {
  26. _ = colorToName.TryAdd (color.Argb, name);
  27. }
  28. }
  29. }
  30. foreach (string name in _ansi.GetColorNames ())
  31. {
  32. if (_ansi.TryParseColor (name, out Color color))
  33. {
  34. nameToColor.TryAdd (name, color);
  35. colorToName.TryAdd (color.Argb, name);
  36. }
  37. }
  38. _nameToColorMap = nameToColor.ToFrozenDictionary ();
  39. _colorToNameMap = colorToName.ToFrozenDictionary ();
  40. _combinedColorNames = nameToColor.Keys.Order ().ToImmutableArray ();
  41. }
  42. /// <inheritdoc/>
  43. public IEnumerable<string> GetColorNames () => _combinedColorNames;
  44. /// <inheritdoc/>
  45. public bool TryParseColor (ReadOnlySpan<char> name, out Color color)
  46. {
  47. if (name.StartsWith ("#") || name.StartsWith ("0x", StringComparison.OrdinalIgnoreCase))
  48. {
  49. try
  50. {
  51. color = Color.Parse (name.ToString (), CultureInfo.InvariantCulture);
  52. return true;
  53. }
  54. catch
  55. {
  56. color = default;
  57. return false;
  58. }
  59. }
  60. if (_ansi.TryParseColor (name, out color)) return true;
  61. if (_standard.TryParseColor (name, out color)) return true;
  62. color = default;
  63. return false;
  64. }
  65. /// <inheritdoc/>
  66. public bool TryNameColor (Color color, [NotNullWhen (true)] out string? name)
  67. {
  68. return _colorToNameMap.TryGetValue (color.Argb, out name);
  69. }
  70. }