diff options
Diffstat (limited to 'src/buffer.rs')
-rw-r--r-- | src/buffer.rs | 59 |
1 files changed, 59 insertions, 0 deletions
diff --git a/src/buffer.rs b/src/buffer.rs new file mode 100644 index 0000000..48e2d85 --- /dev/null +++ b/src/buffer.rs @@ -0,0 +1,59 @@ +use std::io::{self, Read, Write}; +use std::sync::{Arc, Mutex}; + +// STDIN is file descriptor (fd) 0 on Linux and other UN*X-likes +pub const STDIN: i32 = 0; + +/// Retrieve a single byte of input +/// +/// Requires some setup beforehand (see beginning of repl()) +fn getchar() -> u8 { + let mut b = [0; 1]; + io::stdout().lock().flush().unwrap(); + io::stdin().read_exact(&mut b).unwrap(); + b[0] +} + +/// Handle user input at the repl prompt +/// +/// This is required instead of io::stdin().read_line(), because certain +/// keys like `<tab>` and `<up>` have special functions (cycle through +/// autocomplete options, and history, respectively). It leverages +/// [getchar] to read each character as the user inputs it. This also +/// means special cases for handling backspace, newlines, etc. Assumes +/// that (ICANON and ECHO) are off. See the beginning of [crate::repl] +/// for more details. +pub fn getline(buffer: &mut Arc<Mutex<Vec<u8>>>) -> usize { + loop { + let c = getchar(); + match c { + // enter/return + b'\n' => break, + + // tab + b'\t' => { + print!(" "); + buffer.lock().unwrap().push(b' '); + } + + // ctrl-d + 4 => return 0, + + // backspace + 127 => { + buffer.lock().unwrap().pop(); + print!("\u{8} \u{8}"); + } + + // everything else + _ => { + print!("{}", c as char); + buffer.lock().unwrap().push(c); + } + } + } + + println!(); + buffer.lock().unwrap().push(b'\n'); + buffer.lock().unwrap().len() +} |