@@ -50,6 +50,9 @@ pub fn default_bg() -> Option<(u8, u8, u8)> {
5050#[ cfg( all( unix, not( test) ) ) ]
5151mod imp {
5252 use super :: DefaultColors ;
53+ use crossterm:: style:: Color as CrosstermColor ;
54+ use crossterm:: style:: query_background_color;
55+ use crossterm:: style:: query_foreground_color;
5356 use std:: sync:: Mutex ;
5457 use std:: sync:: OnceLock ;
5558
@@ -105,128 +108,16 @@ mod imp {
105108 }
106109
107110 fn query_default_colors ( ) -> std:: io:: Result < Option < DefaultColors > > {
108- use std:: fs:: OpenOptions ;
109- use std:: io:: ErrorKind ;
110- use std:: io:: IsTerminal ;
111- use std:: io:: Read ;
112- use std:: io:: Write ;
113- use std:: os:: fd:: AsRawFd ;
114- use std:: time:: Duration ;
115- use std:: time:: Instant ;
116-
117- let mut stdout_handle = std:: io:: stdout ( ) ;
118- if !stdout_handle. is_terminal ( ) {
119- return Ok ( None ) ;
120- }
121-
122- let mut tty = match OpenOptions :: new ( ) . read ( true ) . open ( "/dev/tty" ) {
123- Ok ( file) => file,
124- Err ( _) => return Ok ( None ) ,
125- } ;
126-
127- let fd = tty. as_raw_fd ( ) ;
128- unsafe {
129- let flags = libc:: fcntl ( fd, libc:: F_GETFL ) ;
130- if flags >= 0 {
131- libc:: fcntl ( fd, libc:: F_SETFL , flags | libc:: O_NONBLOCK ) ;
132- }
133- }
134-
135- stdout_handle. write_all ( b"\x1b ]10;?\x07 \x1b ]11;?\x07 " ) ?;
136- stdout_handle. flush ( ) ?;
137-
138- let mut deadline = Instant :: now ( ) + Duration :: from_millis ( 200 ) ;
139- let mut buffer = Vec :: new ( ) ;
140- let mut fg = None ;
141- let mut bg = None ;
142-
143- while Instant :: now ( ) < deadline {
144- let mut chunk = [ 0u8 ; 128 ] ;
145- match tty. read ( & mut chunk) {
146- Ok ( 0 ) => break ,
147- Ok ( n) => {
148- deadline = Instant :: now ( ) + Duration :: from_millis ( 200 ) ;
149- buffer. extend_from_slice ( & chunk[ ..n] ) ;
150- if fg. is_none ( ) {
151- fg = parse_osc_color ( & buffer, 10 ) ;
152- }
153- if bg. is_none ( ) {
154- bg = parse_osc_color ( & buffer, 11 ) ;
155- }
156- if let ( Some ( fg) , Some ( bg) ) = ( fg, bg) {
157- return Ok ( Some ( DefaultColors { fg, bg } ) ) ;
158- }
159- }
160- Err ( err) if err. kind ( ) == ErrorKind :: WouldBlock => {
161- std:: thread:: sleep ( Duration :: from_millis ( 5 ) ) ;
162- }
163- Err ( err) if err. kind ( ) == ErrorKind :: Interrupted => continue ,
164- Err ( _) => break ,
165- }
166- }
167-
168- if fg. is_none ( ) {
169- fg = parse_osc_color ( & buffer, 10 ) ;
170- }
171- if bg. is_none ( ) {
172- bg = parse_osc_color ( & buffer, 11 ) ;
173- }
174-
111+ let fg = query_foreground_color ( ) ?. and_then ( color_to_tuple) ;
112+ let bg = query_background_color ( ) ?. and_then ( color_to_tuple) ;
175113 Ok ( fg. zip ( bg) . map ( |( fg, bg) | DefaultColors { fg, bg } ) )
176114 }
177115
178- fn parse_component ( component : & str ) -> Option < u8 > {
179- let trimmed = component. trim ( ) ;
180- if trimmed. is_empty ( ) {
181- return None ;
182- }
183- let bits = trimmed. len ( ) . checked_mul ( 4 ) ?;
184- if bits == 0 || bits > 64 {
185- return None ;
186- }
187- let max = if bits == 64 {
188- u64:: MAX
189- } else {
190- ( 1u64 << bits) - 1
191- } ;
192- let value = u64:: from_str_radix ( trimmed, 16 ) . ok ( ) ?;
193- Some ( ( ( value * 255 + max / 2 ) / max) as u8 )
194- }
195-
196- fn parse_osc_color ( buffer : & [ u8 ] , code : u8 ) -> Option < ( u8 , u8 , u8 ) > {
197- let text = std:: str:: from_utf8 ( buffer) . ok ( ) ?;
198- let prefix = match code {
199- 10 => "\u{1b} ]10;" ,
200- 11 => "\u{1b} ]11;" ,
201- _ => return None ,
202- } ;
203- let start = text. rfind ( prefix) ?;
204- let after_prefix = & text[ start + prefix. len ( ) ..] ;
205- let end_bel = after_prefix. find ( '\u{7}' ) ;
206- let end_st = after_prefix. find ( "\u{1b} \\ " ) ;
207- let end_idx = match ( end_bel, end_st) {
208- ( Some ( bel) , Some ( st) ) => bel. min ( st) ,
209- ( Some ( bel) , None ) => bel,
210- ( None , Some ( st) ) => st,
211- ( None , None ) => return None ,
212- } ;
213- let payload = after_prefix[ ..end_idx] . trim ( ) ;
214- parse_color_payload ( payload)
215- }
216-
217- fn parse_color_payload ( payload : & str ) -> Option < ( u8 , u8 , u8 ) > {
218- if payload. is_empty ( ) || payload == "?" {
219- return None ;
220- }
221- let ( model, values) = payload. split_once ( ':' ) ?;
222- if model != "rgb" && model != "rgba" {
223- return None ;
116+ fn color_to_tuple ( color : CrosstermColor ) -> Option < ( u8 , u8 , u8 ) > {
117+ match color {
118+ CrosstermColor :: Rgb { r, g, b } => Some ( ( r, g, b) ) ,
119+ _ => None ,
224120 }
225- let mut parts = values. split ( '/' ) ;
226- let r = parse_component ( parts. next ( ) ?) ?;
227- let g = parse_component ( parts. next ( ) ?) ?;
228- let b = parse_component ( parts. next ( ) ?) ?;
229- Some ( ( r, g, b) )
230121 }
231122}
232123
0 commit comments