use std::env; 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 /// * `away` - A mutex, indicating whether or not user is at the prompt /// * `env` - The global shell state /// /// # Examples /// ``` /// fn main() { /// let mut env = compose::env(); /// let mut away = Arc::new(Mutex::new(false)); /// ... /// repl(&mut away, &mut env); /// } /// ``` fn repl(away: &mut Arc>, env: &mut Environment) { // Initial path refresh on startup env.bins = path::refresh(); // Main shell loop loop { // Get the prompt let prompt = match env::var("PS1") { Ok(val) => val, Err(_) => String::from("|> "), }; // Output the prompt print!("{}", prompt); io::stdout().flush().unwrap(); // At the prompt *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"); // 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 *away.lock().unwrap() = true; // Parse the poem let poem = Poem::read(poetry, env); let poem = match poem { Ok(poem) => poem, Err(e) => { eprintln!("dwvsh: {}", e.to_string().to_lowercase()); continue; } }; // Recite the poem match poem.recite(env) { Ok(_) => {} Err(e) => eprintln!("dwvsh: {}", e.to_string().to_lowercase()), } } } /// Shell entry /// /// Shell setup and entry fn main() { // Compose the environment for dwvsh let mut env = compose::env(); // Handle signals let mut away = Arc::new(Mutex::new(true)); unsafe { let away = Arc::clone(&away); signal_hook::low_level::register(signal_hook::consts::SIGINT, move || { if *away.lock().unwrap() { println!(); } else { let prompt = match env::var("PS1") { Ok(val) => val, Err(_) => String::from("|> "), }; print!("\n{}", prompt); io::stdout().flush().unwrap(); } }) .unwrap(); }; // Begin evaluating commands repl(&mut away, &mut env); }