11use std:: env;
22use std:: fmt:: Display ;
33use std:: fs;
4- use std:: io:: { self , BufRead , BufReader } ;
4+ use std:: io:: { self , BufRead , BufReader , Read } ;
55use std:: mem;
66use std:: os:: fd:: { AsRawFd , RawFd } ;
77use std:: str;
@@ -94,6 +94,15 @@ impl Input<BufReader<fs::File>> {
9494 }
9595}
9696
97+ impl < T : Read > Read for Input < T > {
98+ fn read ( & mut self , buf : & mut [ u8 ] ) -> io:: Result < usize > {
99+ match self {
100+ Self :: Stdin ( s) => s. read ( buf) ,
101+ Self :: File ( f) => f. read ( buf) ,
102+ }
103+ }
104+ }
105+
97106impl < T : BufRead > Input < T > {
98107 fn read_line ( & mut self , buf : & mut String ) -> io:: Result < usize > {
99108 match self {
@@ -143,199 +152,132 @@ pub(crate) fn read_secure() -> io::Result<String> {
143152 } )
144153}
145154
146- fn poll_fd ( fd : RawFd , timeout : i32 ) -> io:: Result < bool > {
147- let mut pollfd = libc:: pollfd {
148- fd,
149- events : libc:: POLLIN ,
150- revents : 0 ,
151- } ;
152- let ret = unsafe { libc:: poll ( & mut pollfd as * mut _ , 1 , timeout) } ;
153- if ret < 0 {
154- Err ( io:: Error :: last_os_error ( ) )
155- } else {
156- Ok ( pollfd. revents & libc:: POLLIN != 0 )
157- }
158- }
159-
160- #[ cfg( target_os = "macos" ) ]
161- fn select_fd ( fd : RawFd , timeout : i32 ) -> io:: Result < bool > {
162- unsafe {
163- let mut read_fd_set: libc:: fd_set = mem:: zeroed ( ) ;
164-
165- let mut timeout_val;
166- let timeout = if timeout < 0 {
167- std:: ptr:: null_mut ( )
168- } else {
169- timeout_val = libc:: timeval {
170- tv_sec : ( timeout / 1000 ) as _ ,
171- tv_usec : ( timeout * 1000 ) as _ ,
172- } ;
173- & mut timeout_val
174- } ;
175-
176- libc:: FD_ZERO ( & mut read_fd_set) ;
177- libc:: FD_SET ( fd, & mut read_fd_set) ;
178- let ret = libc:: select (
179- fd + 1 ,
180- & mut read_fd_set,
181- std:: ptr:: null_mut ( ) ,
182- std:: ptr:: null_mut ( ) ,
183- timeout,
184- ) ;
185- if ret < 0 {
186- Err ( io:: Error :: last_os_error ( ) )
187- } else {
188- Ok ( libc:: FD_ISSET ( fd, & read_fd_set) )
155+ fn read_single_char < T : Read + AsRawFd > ( input : & mut T ) -> io:: Result < Option < char > > {
156+ let original = unsafe { libc:: fcntl ( input. as_raw_fd ( ) , libc:: F_GETFL ) } ;
157+ c_result ( || unsafe {
158+ libc:: fcntl (
159+ input. as_raw_fd ( ) ,
160+ libc:: F_SETFL ,
161+ original | libc:: O_NONBLOCK ,
162+ )
163+ } ) ?;
164+ let mut buf = [ 0u8 ; 1 ] ;
165+ let result = read_bytes ( input, & mut buf) ;
166+ c_result ( || unsafe { libc:: fcntl ( input. as_raw_fd ( ) , libc:: F_SETFL , original) } ) ?;
167+ match result {
168+ Ok ( ( ) ) => {
169+ let [ c] = buf;
170+ Ok ( Some ( c as char ) )
189171 }
190- }
191- }
192-
193- fn select_or_poll_term_fd ( fd : RawFd , timeout : i32 ) -> io:: Result < bool > {
194- // There is a bug on macos that ttys cannot be polled, only select()
195- // works. However given how problematic select is in general, we
196- // normally want to use poll there too.
197- #[ cfg( target_os = "macos" ) ]
198- {
199- if unsafe { libc:: isatty ( fd) == 1 } {
200- return select_fd ( fd, timeout) ;
172+ Err ( err) => {
173+ if err. kind ( ) == io:: ErrorKind :: WouldBlock {
174+ Ok ( None )
175+ } else {
176+ Err ( err)
177+ }
201178 }
202179 }
203- poll_fd ( fd, timeout)
204180}
205181
206- fn read_single_char ( fd : RawFd ) -> io:: Result < Option < char > > {
207- // timeout of zero means that it will not block
208- let is_ready = select_or_poll_term_fd ( fd, 0 ) ?;
209-
210- if is_ready {
211- // if there is something to be read, take 1 byte from it
212- let mut buf: [ u8 ; 1 ] = [ 0 ] ;
213-
214- read_bytes ( fd, & mut buf, 1 ) ?;
215- Ok ( Some ( buf[ 0 ] as char ) )
216- } else {
217- //there is nothing to be read
218- Ok ( None )
219- }
220- }
221-
222- // Similar to libc::read. Read count bytes into slice buf from descriptor fd.
223- // If successful, return the number of bytes read.
224- // Will return an error if nothing was read, i.e when called at end of file.
225- fn read_bytes ( fd : RawFd , buf : & mut [ u8 ] , count : u8 ) -> io:: Result < u8 > {
226- let read = unsafe { libc:: read ( fd, buf. as_mut_ptr ( ) as * mut _ , count as usize ) } ;
227- if read < 0 {
228- Err ( io:: Error :: last_os_error ( ) )
229- } else if read == 0 {
230- Err ( io:: Error :: new (
231- io:: ErrorKind :: UnexpectedEof ,
232- "Reached end of file" ,
233- ) )
234- } else if buf[ 0 ] == b'\x03' {
235- Err ( io:: Error :: new (
182+ fn read_bytes ( input : & mut impl Read , buf : & mut [ u8 ] ) -> io:: Result < ( ) > {
183+ input. read_exact ( buf) ?;
184+ match buf {
185+ [ b'\x03' , ..] => Err ( io:: Error :: new (
236186 io:: ErrorKind :: Interrupted ,
237187 "read interrupted" ,
238- ) )
239- } else {
240- Ok ( read as u8 )
188+ ) ) ,
189+ _ => Ok ( ( ) ) ,
241190 }
242191}
243192
244- fn read_single_key_impl ( fd : RawFd ) -> Result < Key , io:: Error > {
245- loop {
246- match read_single_char ( fd) ? {
247- Some ( '\x1b' ) => {
248- // Escape was read, keep reading in case we find a familiar key
249- break if let Some ( c1) = read_single_char ( fd) ? {
250- if c1 == '[' {
251- if let Some ( c2) = read_single_char ( fd) ? {
252- match c2 {
253- 'A' => Ok ( Key :: ArrowUp ) ,
254- 'B' => Ok ( Key :: ArrowDown ) ,
255- 'C' => Ok ( Key :: ArrowRight ) ,
256- 'D' => Ok ( Key :: ArrowLeft ) ,
257- 'H' => Ok ( Key :: Home ) ,
258- 'F' => Ok ( Key :: End ) ,
259- 'Z' => Ok ( Key :: BackTab ) ,
260- _ => {
261- let c3 = read_single_char ( fd) ?;
262- if let Some ( c3) = c3 {
263- if c3 == '~' {
264- match c2 {
265- '1' => Ok ( Key :: Home ) , // tmux
266- '2' => Ok ( Key :: Insert ) ,
267- '3' => Ok ( Key :: Del ) ,
268- '4' => Ok ( Key :: End ) , // tmux
269- '5' => Ok ( Key :: PageUp ) ,
270- '6' => Ok ( Key :: PageDown ) ,
271- '7' => Ok ( Key :: Home ) , // xrvt
272- '8' => Ok ( Key :: End ) , // xrvt
273- _ => Ok ( Key :: UnknownEscSeq ( vec ! [ c1, c2, c3] ) ) ,
274- }
275- } else {
276- Ok ( Key :: UnknownEscSeq ( vec ! [ c1, c2, c3] ) )
193+ fn read_single_key_impl < T : Read + AsRawFd > ( input : & mut T ) -> Result < Key , io:: Error > {
194+ let mut buf = [ 0u8 ; 1 ] ;
195+ read_bytes ( input, & mut buf) ?;
196+ let [ c] = buf;
197+ match c {
198+ b'\x1b' => {
199+ // Escape was read, keep reading in case we find a familiar key
200+ if let Some ( c1) = read_single_char ( input) ? {
201+ if c1 == '[' {
202+ if let Some ( c2) = read_single_char ( input) ? {
203+ match c2 {
204+ 'A' => Ok ( Key :: ArrowUp ) ,
205+ 'B' => Ok ( Key :: ArrowDown ) ,
206+ 'C' => Ok ( Key :: ArrowRight ) ,
207+ 'D' => Ok ( Key :: ArrowLeft ) ,
208+ 'H' => Ok ( Key :: Home ) ,
209+ 'F' => Ok ( Key :: End ) ,
210+ 'Z' => Ok ( Key :: BackTab ) ,
211+ _ => {
212+ let c3 = read_single_char ( input) ?;
213+ if let Some ( c3) = c3 {
214+ if c3 == '~' {
215+ match c2 {
216+ '1' => Ok ( Key :: Home ) , // tmux
217+ '2' => Ok ( Key :: Insert ) ,
218+ '3' => Ok ( Key :: Del ) ,
219+ '4' => Ok ( Key :: End ) , // tmux
220+ '5' => Ok ( Key :: PageUp ) ,
221+ '6' => Ok ( Key :: PageDown ) ,
222+ '7' => Ok ( Key :: Home ) , // xrvt
223+ '8' => Ok ( Key :: End ) , // xrvt
224+ _ => Ok ( Key :: UnknownEscSeq ( vec ! [ c1, c2, c3] ) ) ,
277225 }
278226 } else {
279- // \x1b[ and 1 more char
280- Ok ( Key :: UnknownEscSeq ( vec ! [ c1, c2] ) )
227+ Ok ( Key :: UnknownEscSeq ( vec ! [ c1, c2, c3] ) )
281228 }
229+ } else {
230+ // \x1b[ and 1 more char
231+ Ok ( Key :: UnknownEscSeq ( vec ! [ c1, c2] ) )
282232 }
283233 }
284- } else {
285- // \x1b[ and no more input
286- Ok ( Key :: UnknownEscSeq ( vec ! [ c1] ) )
287234 }
288235 } else {
289- // char after escape is not [
236+ // \x1b[ and no more input
290237 Ok ( Key :: UnknownEscSeq ( vec ! [ c1] ) )
291238 }
292239 } else {
293- //nothing after escape
294- Ok ( Key :: Escape )
295- } ;
240+ // char after escape is not [
241+ Ok ( Key :: UnknownEscSeq ( vec ! [ c1] ) )
242+ }
243+ } else {
244+ //nothing after escape
245+ Ok ( Key :: Escape )
296246 }
297- Some ( c) => {
298- let byte = c as u8 ;
247+ }
248+ byte => {
249+ if byte & 224u8 == 192u8 {
250+ // a two byte unicode character
251+ let mut buf: [ u8 ; 2 ] = [ byte, 0 ] ;
252+ read_bytes ( input, & mut buf[ 1 ..] ) ?;
253+ Ok ( key_from_utf8 ( & buf) )
254+ } else if byte & 240u8 == 224u8 {
255+ // a three byte unicode character
256+ let mut buf: [ u8 ; 3 ] = [ byte, 0 , 0 ] ;
257+ read_bytes ( input, & mut buf[ 1 ..] ) ?;
258+ Ok ( key_from_utf8 ( & buf) )
259+ } else if byte & 248u8 == 240u8 {
260+ // a four byte unicode character
299261 let mut buf: [ u8 ; 4 ] = [ byte, 0 , 0 , 0 ] ;
300-
301- break if byte & 224u8 == 192u8 {
302- // a two byte unicode character
303- read_bytes ( fd, & mut buf[ 1 ..] , 1 ) ?;
304- Ok ( key_from_utf8 ( & buf[ ..2 ] ) )
305- } else if byte & 240u8 == 224u8 {
306- // a three byte unicode character
307- read_bytes ( fd, & mut buf[ 1 ..] , 2 ) ?;
308- Ok ( key_from_utf8 ( & buf[ ..3 ] ) )
309- } else if byte & 248u8 == 240u8 {
310- // a four byte unicode character
311- read_bytes ( fd, & mut buf[ 1 ..] , 3 ) ?;
312- Ok ( key_from_utf8 ( & buf[ ..4 ] ) )
313- } else {
314- Ok ( match c {
315- '\n' | '\r' => Key :: Enter ,
316- '\x7f' => Key :: Backspace ,
317- '\t' => Key :: Tab ,
318- '\x01' => Key :: Home , // Control-A (home)
319- '\x05' => Key :: End , // Control-E (end)
320- '\x08' => Key :: Backspace , // Control-H (8) (Identical to '\b')
321- _ => Key :: Char ( c) ,
322- } )
323- } ;
324- }
325- None => {
326- // there is no subsequent byte ready to be read, block and wait for input
327- // negative timeout means that it will block indefinitely
328- match select_or_poll_term_fd ( fd, -1 ) {
329- Ok ( _) => continue ,
330- Err ( _) => break Err ( io:: Error :: last_os_error ( ) ) ,
331- }
262+ read_bytes ( input, & mut buf[ 1 ..] ) ?;
263+ Ok ( key_from_utf8 ( & buf) )
264+ } else {
265+ Ok ( match c as char {
266+ '\n' | '\r' => Key :: Enter ,
267+ '\x7f' => Key :: Backspace ,
268+ '\t' => Key :: Tab ,
269+ '\x01' => Key :: Home , // Control-A (home)
270+ '\x05' => Key :: End , // Control-E (end)
271+ '\x08' => Key :: Backspace , // Control-H (8) (Identical to '\b')
272+ c => Key :: Char ( c) ,
273+ } )
332274 }
333275 }
334276 }
335277}
336278
337279pub ( crate ) fn read_single_key ( ctrlc_key : bool ) -> io:: Result < Key > {
338- let input = Input :: < fs:: File > :: new ( ) ?;
280+ let mut input = Input :: < fs:: File > :: new ( ) ?;
339281
340282 let mut termios = core:: mem:: MaybeUninit :: uninit ( ) ;
341283 c_result ( || unsafe { libc:: tcgetattr ( input. as_raw_fd ( ) , termios. as_mut_ptr ( ) ) } ) ?;
@@ -344,7 +286,7 @@ pub(crate) fn read_single_key(ctrlc_key: bool) -> io::Result<Key> {
344286 unsafe { libc:: cfmakeraw ( & mut termios) } ;
345287 termios. c_oflag = original. c_oflag ;
346288 c_result ( || unsafe { libc:: tcsetattr ( input. as_raw_fd ( ) , libc:: TCSADRAIN , & termios) } ) ?;
347- let rv: io:: Result < Key > = read_single_key_impl ( input. as_raw_fd ( ) ) ;
289+ let rv: io:: Result < Key > = read_single_key_impl ( & mut input) ;
348290 c_result ( || unsafe { libc:: tcsetattr ( input. as_raw_fd ( ) , libc:: TCSADRAIN , & original) } ) ?;
349291
350292 // if the user hit ^C we want to signal SIGINT to outselves.
0 commit comments