11use crate :: get_dimensions;
2- use anyhow:: Result ;
2+ use anyhow:: { Context as _ , Result } ;
33use base64:: { engine, Engine } ;
44use image:: { imageops:: FilterType , DynamicImage } ;
5- use libc:: {
6- c_void, poll, pollfd, read, tcgetattr, tcsetattr, termios, ECHO , ICANON , POLLIN , STDIN_FILENO ,
7- TCSANOW ,
8- } ;
5+
6+ use nix:: poll:: { poll, PollFd , PollFlags , PollTimeout } ;
7+ use nix:: sys:: termios:: { tcgetattr, tcsetattr, LocalFlags , SetArg } ;
8+ use nix:: unistd:: read;
9+
910use std:: io:: { stdout, Write } ;
11+ use std:: os:: fd:: AsFd as _;
1012use std:: time:: Instant ;
1113
1214pub struct KittyBackend ;
1315
1416impl KittyBackend {
15- pub fn supported ( ) -> bool {
17+ pub fn supported ( ) -> Result < bool > {
18+ let stdin = std:: io:: stdin ( ) ;
1619 // save terminal attributes and disable canonical input processing mode
17- let old_attributes = unsafe {
18- let mut old_attributes: termios = std:: mem:: zeroed ( ) ;
19- tcgetattr ( STDIN_FILENO , & mut old_attributes) ;
20+ let old_attributes = {
21+ let old = tcgetattr ( & stdin) . context ( "Failed to recieve terminal attibutes" ) ?;
2022
21- let mut new_attributes = old_attributes;
22- new_attributes. c_lflag &= !ICANON ;
23- new_attributes. c_lflag &= !ECHO ;
24- tcsetattr ( STDIN_FILENO , TCSANOW , & new_attributes) ;
25- old_attributes
23+ let mut new = old. clone ( ) ;
24+ new. local_flags &= !LocalFlags :: ICANON ;
25+ new. local_flags &= !LocalFlags :: ECHO ;
26+ tcsetattr ( & stdin, SetArg :: TCSANOW , & new)
27+ . context ( "Failed to update terminal attributes" ) ?;
28+ old
2629 } ;
2730
2831 // generate red rgba test image
@@ -34,38 +37,30 @@ impl KittyBackend {
3437 "\x1B _Gi=1,f=32,s=32,v=32,a=q;{}\x1B \\ " ,
3538 engine:: general_purpose:: STANDARD . encode( & test_image)
3639 ) ;
37- stdout ( ) . flush ( ) . unwrap ( ) ;
40+ stdout ( ) . flush ( ) ? ;
3841
3942 let start_time = Instant :: now ( ) ;
40- let mut stdin_pollfd = pollfd {
41- fd : STDIN_FILENO ,
42- events : POLLIN ,
43- revents : 0 ,
44- } ;
43+ let mut stdin_pollfd = [ PollFd :: new ( stdin. as_fd ( ) , PollFlags :: POLLIN ) ] ;
4544 let allowed_bytes = [ 0x1B , b'_' , b'G' , b'\\' ] ;
4645 let mut buf = Vec :: < u8 > :: new ( ) ;
4746 loop {
4847 // check for timeout while polling to avoid blocking the main thread
49- while unsafe { poll ( & mut stdin_pollfd, 1 , 0 ) < 1 } {
48+ while poll ( & mut stdin_pollfd, PollTimeout :: ZERO ) ? < 1 {
5049 if start_time. elapsed ( ) . as_millis ( ) > 50 {
51- unsafe {
52- tcsetattr ( STDIN_FILENO , TCSANOW , & old_attributes) ;
53- }
54- return false ;
50+ tcsetattr ( & stdin, SetArg :: TCSANOW , & old_attributes)
51+ . context ( "Failed to update terminal attributes" ) ?;
52+ return Ok ( false ) ;
5553 }
5654 }
57- let mut byte = 0 ;
58- unsafe {
59- read ( STDIN_FILENO , & mut byte as * mut _ as * mut c_void , 1 ) ;
60- }
61- if allowed_bytes. contains ( & byte) {
62- buf. push ( byte) ;
55+ let mut byte = [ 0 ] ;
56+ read ( & stdin, & mut byte) ?;
57+ if allowed_bytes. contains ( & byte[ 0 ] ) {
58+ buf. push ( byte[ 0 ] ) ;
6359 }
6460 if buf. starts_with ( & [ 0x1B , b'_' , b'G' ] ) && buf. ends_with ( & [ 0x1B , b'\\' ] ) {
65- unsafe {
66- tcsetattr ( STDIN_FILENO , TCSANOW , & old_attributes) ;
67- }
68- return true ;
61+ tcsetattr ( & stdin, SetArg :: TCSANOW , & old_attributes)
62+ . context ( "Failed to update terminal attributes" ) ?;
63+ return Ok ( true ) ;
6964 }
7065 }
7166 }
0 commit comments