use std::io::{self, Write}; use std::sync::{Arc, Mutex}; mod path; mod poem; use poem::{read::Readable, recite::Reciteable, Poem}; mod compose; use compose::Environment; /// Starts the main shell loop /// /// # Arguments /// * `prompt` - A string slice indicating the shell's prompt /// * `at_prompt` - A mutex, indicating whether or not user is at the prompt /// /// # Examples /// ``` /// fn main() { /// let prompt = "|> "; /// let mut at_prompt = Arc::new(Mutex::new(false)); /// ... /// repl(prompt, &mut at_prompt); /// } /// ``` fn repl(prompt: &str, at_prompt: &mut Arc>, env: &mut Environment) { // Initial path refresh on startup env.bins = path::refresh(); // Main shell loop loop { // Output the prompt print!("{}", prompt); io::stdout().flush().unwrap(); // At the prompt *at_prompt.lock().unwrap() = true; // 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"); // Check if we've reached EOF (i.e. ) if bytes == 0 { println!(); break; } // Trim the input let poetry = String::from(poetry.trim()); // Skip parsing if there is no poetry if poetry.is_empty() { continue; } // Not at the prompt *at_prompt.lock().unwrap() = false; // Parse the poem let poem = Poem::read(poetry); let poem = match poem { Ok(poem) => poem, Err(e) => { eprintln!("dwvsh: {}", e.to_string().to_lowercase()); continue; } }; // Recite the poem match poem.recite(env, None) { Ok(_) => {} Err(e) => eprintln!("dwvsh: {}", e.to_string().to_lowercase()), } } } /// Shell entry /// /// Shell setup and entry fn main() { // Compose the environment for dwvsh // TODO: All instances of `env!("HOME")` need to be changed to use env::var // TODO: Will probably need to set $HOME in dwv{profile,login} via passwd let mut env = compose::env(); // Set the prompt let prompt = "|> "; let mut at_prompt = Arc::new(Mutex::new(false)); // Handle signals unsafe { let at_prompt = Arc::clone(&at_prompt); signal_hook::low_level::register(signal_hook::consts::SIGINT, move || { if *at_prompt.lock().unwrap() { print!("\n{}", prompt); io::stdout().flush().unwrap(); } else { println!(); } }) .unwrap(); }; // Begin evaluating commands repl(prompt, &mut at_prompt, &mut env); }