summaryrefslogtreecommitdiffstats
path: root/src/buffer.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/buffer.rs')
-rw-r--r--src/buffer.rs59
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()
+}