@@ -2063,7 +2063,7 @@ fn log_macos_network_overview(reason: &str, state: &MacosCleanupState) {
20632063 & owned_dns,
20642064 & dns_fingerprint,
20652065 ) ;
2066- info ! ( reason, interface = inputs. interface, "\n {table}" ) ;
2066+ info ! ( reason, interface = inputs. interface, "\n {table}\n " ) ;
20672067}
20682068
20692069#[ cfg( target_os = "macos" ) ]
@@ -2104,7 +2104,7 @@ fn format_macos_network_overview_table(
21042104 format_list( & inputs. dns_servers) ,
21052105 dns_fingerprint. primary_service. as_deref( ) . unwrap_or( "none" )
21062106 ) ) ;
2107- lines. extend ( format_table (
2107+ lines. extend ( format_table_with_dimmed_rows (
21082108 & [
21092109 "SERVICE" ,
21102110 "ROLE" ,
@@ -2114,6 +2114,7 @@ fn format_macos_network_overview_table(
21142114 "STATUS" ,
21152115 ] ,
21162116 & macos_dns_overview_rows ( inputs, owned_dns, dns_fingerprint) ,
2117+ macos_log_table_ansi_enabled ( ) ,
21172118 ) ) ;
21182119 lines. join ( "\n " )
21192120}
@@ -2150,16 +2151,19 @@ fn macos_dns_overview_rows(
21502151 inputs : & MacosReconcileInputs ,
21512152 owned_dns : & [ MacosDnsServiceState ] ,
21522153 dns_fingerprint : & MacosDnsFingerprint ,
2153- ) -> Vec < Vec < String > > {
2154+ ) -> Vec < ( Vec < String > , bool ) > {
21542155 if dns_fingerprint. services . is_empty ( ) {
2155- return vec ! [ vec![
2156- "none" . to_string( ) ,
2157- "-" . to_string( ) ,
2158- "-" . to_string( ) ,
2159- "no" . to_string( ) ,
2160- "-" . to_string( ) ,
2161- "no services observed" . to_string( ) ,
2162- ] ] ;
2156+ return vec ! [ (
2157+ vec![
2158+ "none" . to_string( ) ,
2159+ "-" . to_string( ) ,
2160+ "-" . to_string( ) ,
2161+ "no" . to_string( ) ,
2162+ "-" . to_string( ) ,
2163+ "no services observed" . to_string( ) ,
2164+ ] ,
2165+ true ,
2166+ ) ] ;
21632167 }
21642168
21652169 let targets = dns_target_services ( DNS_POLICY , dns_fingerprint) ;
@@ -2176,33 +2180,63 @@ fn macos_dns_overview_rows(
21762180 let targeted = targets. iter ( ) . any ( |target| target == service) ;
21772181 let live_matches_tunnel =
21782182 live_dns. map ( Vec :: as_slice) == Some ( inputs. dns_servers . as_slice ( ) ) ;
2179- vec ! [
2180- service. clone( ) ,
2181- if dns_fingerprint. primary_service. as_ref( ) == Some ( service) {
2182- "primary"
2183- } else {
2184- "secondary"
2185- }
2186- . to_string( ) ,
2187- live_dns. map_or_else( || "empty" . to_string( ) , |servers| format_list( servers) ) ,
2188- if owned. is_some( ) { "yes" } else { "no" } . to_string( ) ,
2189- owned
2190- . and_then( |state| state. dns_servers. as_ref( ) )
2191- . map_or_else( || "empty" . to_string( ) , |servers| format_list( servers) ) ,
2192- match ( targeted, owned. is_some( ) , live_matches_tunnel) {
2193- ( true , true , true ) => "tunnel DNS active" ,
2194- ( true , true , false ) => "owned; pending reapply" ,
2195- ( true , false , true ) => "already tunnel DNS" ,
2196- ( true , false , false ) => "target; not owned" ,
2197- ( false , true , _) => "owned; pending restore" ,
2198- ( false , false , _) => "not targeted" ,
2199- }
2200- . to_string( ) ,
2201- ]
2183+ let status = match ( targeted, owned. is_some ( ) , live_matches_tunnel) {
2184+ ( true , true , true ) => "tunnel DNS active" ,
2185+ ( true , true , false ) => "owned; pending reapply" ,
2186+ ( true , false , true ) => "already tunnel DNS" ,
2187+ ( true , false , false ) => "target; not owned" ,
2188+ ( false , true , _) => "owned; pending restore" ,
2189+ ( false , false , _) => "not targeted" ,
2190+ } ;
2191+ (
2192+ vec ! [
2193+ service. clone( ) ,
2194+ if dns_fingerprint. primary_service. as_ref( ) == Some ( service) {
2195+ "primary"
2196+ } else {
2197+ "secondary"
2198+ }
2199+ . to_string( ) ,
2200+ live_dns. map_or_else( || "empty" . to_string( ) , |servers| format_list( servers) ) ,
2201+ if owned. is_some( ) { "yes" } else { "no" } . to_string( ) ,
2202+ owned
2203+ . and_then( |state| state. dns_servers. as_ref( ) )
2204+ . map_or_else( || "empty" . to_string( ) , |servers| format_list( servers) ) ,
2205+ status. to_string( ) ,
2206+ ] ,
2207+ status == "not targeted" ,
2208+ )
22022209 } )
22032210 . collect ( )
22042211}
22052212
2213+ #[ cfg( target_os = "macos" ) ]
2214+ fn macos_log_table_ansi_enabled ( ) -> bool {
2215+ let Some ( value) = std:: env:: var_os ( crate :: logging:: COLOR_ENV ) else {
2216+ return false ;
2217+ } ;
2218+ matches ! (
2219+ value. to_string_lossy( ) . to_ascii_lowercase( ) . as_str( ) ,
2220+ "always" | "1" | "true" | "yes" | "on"
2221+ )
2222+ }
2223+
2224+ #[ cfg( target_os = "macos" ) ]
2225+ fn format_table_with_dimmed_rows (
2226+ headers : & [ & str ] ,
2227+ rows : & [ ( Vec < String > , bool ) ] ,
2228+ ansi : bool ,
2229+ ) -> Vec < String > {
2230+ let plain_rows = rows. iter ( ) . map ( |( row, _) | row. clone ( ) ) . collect :: < Vec < _ > > ( ) ;
2231+ let mut lines = format_table ( headers, & plain_rows) ;
2232+ for ( line, ( _, dimmed) ) in lines. iter_mut ( ) . skip ( 2 ) . zip ( rows. iter ( ) ) {
2233+ if ansi && * dimmed {
2234+ * line = format ! ( "\x1b [2m{line}\x1b [0m" ) ;
2235+ }
2236+ }
2237+ lines
2238+ }
2239+
22062240#[ cfg( target_os = "macos" ) ]
22072241fn format_table ( headers : & [ & str ] , rows : & [ Vec < String > ] ) -> Vec < String > {
22082242 let mut widths: Vec < usize > = headers. iter ( ) . map ( |header| header. len ( ) ) . collect ( ) ;
0 commit comments