1- use crate :: get_dimensions;
2- use anyhow:: Result ;
1+ use anyhow:: { Context as _, Result } ;
32use base64:: { engine, Engine } ;
43use image:: { imageops:: FilterType , DynamicImage } ;
5- use libc:: {
6- c_void, poll, pollfd, read, tcgetattr, tcsetattr, termios, ECHO , ICANON , POLLIN , STDIN_FILENO ,
7- TCSANOW ,
8- } ;
4+
5+ use rustix:: event:: { poll, PollFd , PollFlags , Timespec } ;
6+ use rustix:: io:: read;
7+ use rustix:: termios:: { tcgetattr, tcgetwinsize, tcsetattr, LocalModes , OptionalActions } ;
8+
99use std:: io:: { stdout, Write } ;
10+ use std:: os:: fd:: AsFd as _;
1011use std:: time:: Instant ;
1112
12- pub struct KittyBackend { }
13+ pub struct KittyBackend ;
1314
1415impl KittyBackend {
15- pub fn new ( ) -> Self {
16- Self { }
17- }
18-
19- pub fn supported ( ) -> bool {
16+ pub fn supported ( ) -> Result < bool > {
17+ let stdin = std:: io:: stdin ( ) ;
2018 // save terminal attributes and disable canonical input processing mode
21- let old_attributes = unsafe {
22- let mut old_attributes: termios = std:: mem:: zeroed ( ) ;
23- tcgetattr ( STDIN_FILENO , & mut old_attributes) ;
19+ let old_attributes = {
20+ let old = tcgetattr ( & stdin) . context ( "Failed to recieve terminal attibutes" ) ?;
2421
25- let mut new_attributes = old_attributes;
26- new_attributes. c_lflag &= !ICANON ;
27- new_attributes. c_lflag &= !ECHO ;
28- tcsetattr ( STDIN_FILENO , TCSANOW , & new_attributes) ;
29- old_attributes
22+ let mut new = old. clone ( ) ;
23+ new. local_modes &= !LocalModes :: ICANON ;
24+ new. local_modes &= !LocalModes :: ECHO ;
25+ tcsetattr ( & stdin, OptionalActions :: Now , & new)
26+ . context ( "Failed to update terminal attributes" ) ?;
27+ old
3028 } ;
3129
3230 // generate red rgba test image
@@ -38,57 +36,44 @@ impl KittyBackend {
3836 "\x1B _Gi=1,f=32,s=32,v=32,a=q;{}\x1B \\ " ,
3937 engine:: general_purpose:: STANDARD . encode( & test_image)
4038 ) ;
41- stdout ( ) . flush ( ) . unwrap ( ) ;
39+ stdout ( ) . flush ( ) ? ;
4240
4341 let start_time = Instant :: now ( ) ;
44- let mut stdin_pollfd = pollfd {
45- fd : STDIN_FILENO ,
46- events : POLLIN ,
47- revents : 0 ,
48- } ;
42+ let stdin_fd = stdin. as_fd ( ) ;
43+ let mut stdin_pollfd = [ PollFd :: new ( & stdin_fd, PollFlags :: IN ) ] ;
4944 let allowed_bytes = [ 0x1B , b'_' , b'G' , b'\\' ] ;
5045 let mut buf = Vec :: < u8 > :: new ( ) ;
5146 loop {
5247 // check for timeout while polling to avoid blocking the main thread
53- while unsafe { poll ( & mut stdin_pollfd, 1 , 0 ) < 1 } {
48+ while poll ( & mut stdin_pollfd, Some ( & Timespec :: default ( ) ) ) ? < 1 {
5449 if start_time. elapsed ( ) . as_millis ( ) > 50 {
55- unsafe {
56- tcsetattr ( STDIN_FILENO , TCSANOW , & old_attributes) ;
57- }
58- return false ;
50+ tcsetattr ( & stdin, OptionalActions :: Now , & old_attributes)
51+ . context ( "Failed to update terminal attributes" ) ?;
52+ return Ok ( false ) ;
5953 }
6054 }
61- let mut byte = 0 ;
62- unsafe {
63- read ( STDIN_FILENO , & mut byte as * mut _ as * mut c_void , 1 ) ;
64- }
65- if allowed_bytes. contains ( & byte) {
66- 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 ] ) ;
6759 }
6860 if buf. starts_with ( & [ 0x1B , b'_' , b'G' ] ) && buf. ends_with ( & [ 0x1B , b'\\' ] ) {
69- unsafe {
70- tcsetattr ( STDIN_FILENO , TCSANOW , & old_attributes) ;
71- }
72- return true ;
61+ tcsetattr ( & stdin, OptionalActions :: Now , & old_attributes)
62+ . context ( "Failed to update terminal attributes" ) ?;
63+ return Ok ( true ) ;
7364 }
7465 }
7566 }
7667}
7768
78- impl Default for KittyBackend {
79- fn default ( ) -> Self {
80- Self :: new ( )
81- }
82- }
83-
8469impl super :: ImageBackend for KittyBackend {
8570 fn add_image (
8671 & self ,
8772 lines : Vec < String > ,
8873 image : & DynamicImage ,
8974 _colors : usize ,
9075 ) -> Result < String > {
91- let tty_size = unsafe { get_dimensions ( ) } ;
76+ let tty_size = tcgetwinsize ( std :: io :: stdin ( ) ) ? ;
9277 let width_ratio = f64:: from ( tty_size. ws_col ) / f64:: from ( tty_size. ws_xpixel ) ;
9378 let height_ratio = f64:: from ( tty_size. ws_row ) / f64:: from ( tty_size. ws_ypixel ) ;
9479
0 commit comments