@@ -289,8 +289,17 @@ public static string EscapeInvalidMarkupTags(string input)
289289 string tagContent = input . Substring ( start + 1 , j - start - 1 ) ;
290290 if ( IsValidTagContent ( tagContent ) )
291291 {
292- // Append the entire tag as is
293- result . Append ( input , start , j - start + 1 ) ;
292+ // Normalize underscores in color names for Spectre compatibility.
293+ // Spectre.Console's ColorTable uses concatenated names (e.g. "darkcyan")
294+ // but callers may write "dark_cyan". Style keywords (bold, italic, etc.)
295+ // and structural tokens (/, on) don't contain underscores, so stripping
296+ // them only affects color name segments.
297+ string normalized = tagContent . Contains ( '_' )
298+ ? tagContent . Replace ( "_" , "" )
299+ : tagContent ;
300+ result . Append ( '[' ) ;
301+ result . Append ( normalized ) ;
302+ result . Append ( ']' ) ;
294303 i = j + 1 ;
295304 continue ;
296305 }
@@ -866,47 +875,46 @@ private static bool IsKnownColorName(string colorName)
866875 if ( string . IsNullOrWhiteSpace ( colorName ) )
867876 return false ;
868877
869- // Basic set of standard colors supported by Spectre.Console
878+ // Spectre.Console color names — uses concatenated lowercase with NO underscores.
879+ // The lookup is case-insensitive. This set covers the basic 16 colors, their
880+ // common aliases, and frequently-used extended 256-color palette names.
870881 var standardColors = new HashSet < string > ( StringComparer . OrdinalIgnoreCase )
871882 {
872- "default" , "black" , "blue" , "cyan" , "dark_blue" , "dark_cyan" ,
873- "dark_green" , "dark_grey" , "dark_magenta" , "dark_red" , "dark_yellow" ,
874- "grey" , "gray" , "green" , "magenta" , "maroon" , "navy" , "purple" ,
875- "red" , "silver" , "teal" , "white" , "yellow" ,
876- "brightblack" , "bright_black" , "brightblue" , "bright_blue" ,
877- "brightcyan" , "bright_cyan" , "brightgreen" , "bright_green" ,
878- "brightmagenta" , "bright_magenta" , "brightred" , "bright_red" ,
879- "brightwhite" , "bright_white" , "brightyellow" , "bright_yellow" ,
880- "steelblue" , "steel_blue" , "darkorange" , "dark_orange" ,
881- "lime" , "olive" , "aqua" , "fuchsia" , "darkgrey" , "dark_grey" ,
882- "lightgrey" , "light_grey" , "lightblue" , "light_blue" ,
883- "lightgreen" , "light_green" , "lightcyan" , "light_cyan" ,
884- "lightred" , "light_red" , "lightmagenta" , "light_magenta" ,
885- "lightyellow" , "light_yellow" , "cornflowerblue" , "cornflower_blue" ,
886- "hotpink" , "hot_pink" , "pink" , "deeppink" , "deep_pink"
883+ // Basic 16 colors
884+ "default" , "black" , "maroon" , "green" , "olive" , "navy" , "purple" ,
885+ "teal" , "silver" , "grey" , "red" , "lime" , "yellow" , "blue" ,
886+ "fuchsia" , "aqua" , "white" ,
887+ // Aliases for basic colors
888+ "gray" , "magenta" , "cyan" ,
889+ // Common extended palette names (no underscores — matches Spectre's ColorTable)
890+ "darkblue" , "darkgreen" , "darkcyan" , "darkred" , "darkmagenta" ,
891+ "darkviolet" , "darkorange" , "darkturquoise" , "darkolivegreen" ,
892+ "darkgoldenrod" , "darkseagreen" , "darkslategray" , "darkkhaki" ,
893+ "deeppink" , "deepskyblue" ,
894+ "lightblue" , "lightcyan" , "lightgreen" , "lightcoral" ,
895+ "lightgoldenrodyellow" , "lightpink" , "lightsalmon" , "lightseagreen" ,
896+ "lightskyblue" , "lightslategray" , "lightsteelblue" , "lightyellow" ,
897+ "mediumorchid" , "mediumpurple" , "mediumseagreen" , "mediumslateblue" ,
898+ "mediumspringgreen" , "mediumturquoise" , "mediumvioletred" ,
899+ "hotpink" , "cornflowerblue" , "steelblue" , "cadetblue" , "rosybrown" ,
900+ "plum" , "orchid" , "violet" , "thistle" , "indianred" ,
901+ "palegreen" , "paleturquoise" , "palevioletred" ,
902+ "springgreen" , "chartreuse" , "blueviolet" , "greenyellow" ,
903+ "navyblue" , "navajowhite" , "mistyrose" , "honeydew" , "khaki" ,
904+ "wheat" , "salmon" , "sandybrown" , "tan" , "pink" ,
887905 } ;
888906
889- // Check for basic color names first
890- if ( standardColors . Contains ( colorName ) )
891- return true ;
907+ // Normalize: strip underscores and spaces so callers can use
908+ // "dark_cyan", "dark cyan", or "darkcyan" interchangeably.
909+ string normalizedName = colorName . Replace ( "_" , "" ) . Replace ( " " , "" ) . ToLowerInvariant ( ) ;
892910
893- // Check for web colors with underscores or camelCase (e.g., "dark_blue" or "darkblue")
894- string normalizedName = colorName . Replace ( "_" , "" ) . ToLowerInvariant ( ) ;
895911 if ( standardColors . Contains ( normalizedName ) )
896912 return true ;
897913
898- // Check for numbered color variants (e.g., "grey46", "orange3")
899- if ( Regex . IsMatch ( colorName , @"^[a-z]+\d+$" , RegexOptions . IgnoreCase ) )
914+ // Numbered color variants (e.g., "grey46", "orange3", "dodgerblue2 ")
915+ if ( Regex . IsMatch ( normalizedName , @"^[a-z]+\d+$" , RegexOptions . IgnoreCase ) )
900916 return true ;
901917
902- // Check for color names with spaces (e.g., "hot pink", "light blue")
903- if ( colorName . Contains ( " " ) )
904- {
905- string spacelessName = colorName . Replace ( " " , "" ) . ToLowerInvariant ( ) ;
906- if ( standardColors . Contains ( spacelessName ) )
907- return true ;
908- }
909-
910918 return false ;
911919 }
912920
0 commit comments