@@ -2122,26 +2122,49 @@ fn colour_reflect_inline(s: &str) -> String {
21222122 }
21232123 result. push_str ( remaining) ;
21242124
2125- // Fourth pass: "turn N" or "Turn N" → dim cyan (char-safe)
2125+ // Fourth pass: turn references → dim (char-safe)
2126+ // Matches: "Turn N", "Turns N", "turn N", "turns N"
2127+ // followed by digits and optional range/list suffixes like "-24", ", 25-30"
21262128 let mut final_out = String :: with_capacity ( result. len ( ) + 32 ) ;
21272129 let mut rest = result. as_str ( ) ;
21282130 while !rest. is_empty ( ) {
2129- if rest. starts_with ( "turn " ) || rest. starts_with ( "Turn " ) {
2130- let prefix = & rest[ ..5 ] ;
2131- let digits: String = rest[ 5 ..] . chars ( ) . take_while ( |c| c. is_ascii_digit ( ) ) . collect ( ) ;
2132- if !digits. is_empty ( ) {
2133- final_out. push_str ( "\x1b [2;36m" ) ;
2134- final_out. push_str ( prefix) ;
2135- final_out. push_str ( & digits) ;
2136- final_out. push_str ( "\x1b [0m" ) ;
2137- rest = & rest[ 5 + digits. len ( ) ..] ;
2138- continue ;
2139- }
2131+ // Case-insensitive prefix match for "turn " or "turns "
2132+ let lower6 = rest. chars ( ) . take ( 6 ) . collect :: < String > ( ) . to_lowercase ( ) ;
2133+ let ( matched_prefix_len, prefix_str) = if lower6. starts_with ( "turns " ) {
2134+ ( 6 , & rest[ ..6 ] )
2135+ } else if lower6. starts_with ( "turn " ) {
2136+ ( 5 , & rest[ ..5 ] )
2137+ } else {
2138+ let ch = rest. chars ( ) . next ( ) . unwrap ( ) ;
2139+ final_out. push ( ch) ;
2140+ rest = & rest[ ch. len_utf8 ( ) ..] ;
2141+ continue ;
2142+ } ;
2143+
2144+ // What follows must start with a digit to be a real turn reference
2145+ let after = & rest[ matched_prefix_len..] ;
2146+ if !after. starts_with ( |c : char | c. is_ascii_digit ( ) ) {
2147+ // Not a turn reference — emit the prefix literally and move on
2148+ let ch = rest. chars ( ) . next ( ) . unwrap ( ) ;
2149+ final_out. push ( ch) ;
2150+ rest = & rest[ ch. len_utf8 ( ) ..] ;
2151+ continue ;
21402152 }
2141- // Advance one Unicode scalar
2142- let ch = rest. chars ( ) . next ( ) . unwrap ( ) ;
2143- final_out. push ( ch) ;
2144- rest = & rest[ ch. len_utf8 ( ) ..] ;
2153+
2154+ // Consume the full turn reference including ranges (e.g. "1-2", "8-24")
2155+ // and comma-separated lists (e.g. "1, 3-5, 7")
2156+ let ref_body: String = after
2157+ . chars ( )
2158+ . take_while ( |& c| c. is_ascii_digit ( ) || c == '-' || c == ',' || c == ' ' )
2159+ . collect ( ) ;
2160+ // Trim trailing spaces/commas that aren't part of the reference
2161+ let ref_body = ref_body. trim_end_matches ( |c : char | c == ',' || c == ' ' ) ;
2162+
2163+ final_out. push_str ( "\x1b [2m" ) ; // dim only — no colour, just muted
2164+ final_out. push_str ( prefix_str) ;
2165+ final_out. push_str ( ref_body) ;
2166+ final_out. push_str ( "\x1b [0m" ) ;
2167+ rest = & rest[ matched_prefix_len + ref_body. len ( ) ..] ;
21452168 }
21462169
21472170 final_out
0 commit comments