diff options
author | Rory Dudley | 2024-09-30 21:55:32 -0600 |
---|---|---|
committer | Rory Dudley | 2024-09-30 23:01:41 -0600 |
commit | 350be1b8869ce9d3a572348104c30f804d44641e (patch) | |
tree | 75c68761ccd21a3395609f0fb1e2e0a440b441c8 /src/main.rs | |
parent | 243a8c53ae03713b3d6b4f5bf82859f9c93be6ed (diff) | |
download | dwarvish-350be1b8869ce9d3a572348104c30f804d44641e.tar.gz |
Replace io::stdin().read_line() with custom function
Added the termios crate to facilitate the changing of certain terminal
options. It is a wrapper around the termios C library, so 'man 3
termios' for more details.
Added the custom getchar() function, with retrieves characters from
STDIN as they are typed by the user (as opposed to waiting for a
newline, like io::stdin().read_line()). This is necessary, since keys
like <tab> and <up> have special functionality, which needs to be acted
on before command submission.
Added the custom getline() function, which uses getchar() to read
characters as they are typed. The getline() function contains the logic
for the various key presses. For most characters, we simply push the
byte to a buffer, and print it out to the screen (since getline()
assumes ECHO is off).
Signed-off-by: Rory Dudley <rory@netc.lu>
Diffstat (limited to 'src/main.rs')
-rw-r--r-- | src/main.rs | 31 |
1 files changed, 23 insertions, 8 deletions
diff --git a/src/main.rs b/src/main.rs index 98b49ed..d5147ff 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,11 +1,14 @@ use std::env; use std::io::{self, Write}; use std::sync::{Arc, Mutex}; +mod buffer; mod path; mod poem; use poem::{read::Readable, recite::Reciteable, Poem}; mod compose; +use buffer::{getline, STDIN}; use compose::Environment; +use termios::{tcsetattr, Termios, ECHO, ICANON, TCSANOW}; /// Starts the main shell loop /// @@ -22,12 +25,22 @@ use compose::Environment; /// repl(&mut away, &mut env); /// } /// ``` -fn repl(away: &mut Arc<Mutex<bool>>, env: &mut Environment) { +fn repl(away: &mut Arc<Mutex<bool>>, buffer: &mut Arc<Mutex<Vec<u8>>>, env: &mut Environment) { + // Setup termios flags + let mut termios = Termios::from_fd(STDIN).unwrap(); + termios.c_lflag &= !(ICANON | ECHO); + // Initial path refresh on startup env.bins = path::refresh(); // Main shell loop loop { + // Reset terminal using proper termios flags + tcsetattr(STDIN, TCSANOW, &mut termios).unwrap(); + + // Clear the buffer + buffer.lock().unwrap().clear(); + // Get the prompt let prompt = match env::var("PS1") { Ok(val) => val, @@ -42,10 +55,7 @@ fn repl(away: &mut Arc<Mutex<bool>>, env: &mut Environment) { *away.lock().unwrap() = false; // Wait for user input - let mut poetry = String::new(); - let bytes = io::stdin() - .read_line(&mut poetry) - .expect("dwvsh: error: unable to evaluate the input string"); + let bytes = getline(buffer); // Check if we've reached EOF (i.e. <C-d>) if bytes == 0 { @@ -53,8 +63,10 @@ fn repl(away: &mut Arc<Mutex<bool>>, env: &mut Environment) { break; } - // Trim the input - let poetry = String::from(poetry.trim()); + // Convert buffer to a string and trim it + let poetry = String::from_utf8_lossy(&buffer.lock().unwrap()) + .trim() + .to_string(); // Skip parsing if there is no poetry if poetry.is_empty() { @@ -132,9 +144,12 @@ fn main() { // Handle signals let mut away = Arc::new(Mutex::new(true)); + let mut buffer: Arc<Mutex<Vec<u8>>> = Arc::new(Mutex::new(vec![])); unsafe { let away = Arc::clone(&away); + let buffer = Arc::clone(&buffer); signal_hook::low_level::register(signal_hook::consts::SIGINT, move || { + buffer.lock().unwrap().clear(); if *away.lock().unwrap() { println!(); } else { @@ -153,5 +168,5 @@ fn main() { options(&mut env); // Begin evaluating commands - repl(&mut away, &mut env); + repl(&mut away, &mut buffer, &mut env); } |