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