diff --git a/Cargo.toml b/Cargo.toml index bfd0e77..092677d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -53,6 +53,18 @@ opt-level = "z" strip = true lto = true +[profile.dev] +lto = "off" +strip = "none" +codegen-units = 256 +panic = "unwind" +opt-level = 0 +incremental = true +overflow-checks = true +debug-assertions = true +debug = true +rpath = false + # All of the dependencies for Lune. # # Dependencies are categorized as following: diff --git a/src/cli/mod.rs b/src/cli/mod.rs index fb709a8..d1fe6b2 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -18,6 +18,7 @@ use tokio::{ }; pub(crate) mod gen; +pub(crate) mod repl; pub(crate) mod setup; pub(crate) mod utils; @@ -154,100 +155,14 @@ impl Cli { if generate_file_requested { return Ok(ExitCode::SUCCESS); } + // HACK: We know that we didn't get any arguments here but since // script_path is optional clap will not error on its own, to fix // we will duplicate the CLI command and fetch the version of // lune to display - let cmd = Cli::command(); - let lune_version = cmd.get_version(); + let exit_code_status = repl::show_interface(Cli::command()).await; - // The version is mandatory and will always exist - println!("Lune v{}", lune_version.unwrap()); - - let lune_instance = Lune::new(); - - let mut repl = DefaultEditor::new()?; - - match repl.load_history(&(|| -> PathBuf { - let dir_opt = home::home_dir(); - - if let Some(dir) = dir_opt { - dir.join(".lune_history") - } else { - eprintln!("Failed to find user home directory, abort!"); - // Doesn't feel right to exit directly with a exit code of 1 - // Lmk if there is a better way of doing this - exit(1); - } - })()) { - Ok(_) => (), - Err(err) => { - match err { - err => { - if let ReadlineError::Io(io_err) = err { - if io_err.kind() == ErrorKind::NotFound { - std::fs::write( - // We know for sure that the home dir already exists - home::home_dir().unwrap().join(".lune_history"), - String::new(), - )?; - } - } - } - } - - eprintln!("WARN: Failed to load REPL history") - } - }; - - // repl.bind_sequence( - // KeyEvent(KeyCode::Enter, Modifiers::SHIFT), - // EventHandler::Simple(Cmd::AcceptOrInsertLine { accept_in_the_middle: true }), - // ); - - let mut interrupt_counter = 0u32; - - loop { - let mut source_code = String::new(); - - match repl.readline("> ") { - Ok(code) => { - source_code = code.clone(); - repl.add_history_entry(code.as_str())?; - - // If source code eval was requested, we reset the counter - interrupt_counter = 0; - } - - Err(ReadlineError::Interrupted) => { - // HACK: We actually want the user to do ^C twice to exit, - // but the user would need to ^C one more time even after - // the check passes, so we check for 1 instead of 2 - if interrupt_counter != 1 { - println!("Interrupt: ^C again to exit"); - - // Increment the counter - interrupt_counter += 1; - } else { - break; - } - } - Err(ReadlineError::Eof) => break, - Err(err) => { - eprintln!("REPL ERROR: {}", err.to_string()); - break; - } - }; - - let eval_result = lune_instance.run("REPL", source_code).await; - - match eval_result { - Ok(_) => (), - Err(err) => eprintln!("{}", err), - } - } - - return Ok(ExitCode::SUCCESS); + return exit_code_status; } // Figure out if we should read from stdin or from a file, // reading from stdin is marked by passing a single "-" diff --git a/src/cli/repl.rs b/src/cli/repl.rs new file mode 100644 index 0000000..4c340ce --- /dev/null +++ b/src/cli/repl.rs @@ -0,0 +1,101 @@ +use std::{ + io::{Error, ErrorKind}, + path::PathBuf, + process::{exit, ExitCode}, +}; + +use clap::Command; +use lune::{Lune, LuneError}; +use rustyline::{error::ReadlineError, DefaultEditor}; + +use super::Cli; + +// Isn't dependency injection plain awesome?! +pub async fn show_interface(cmd: Command) -> Result { + let lune_version = cmd.get_version(); + + // The version is mandatory and will always exist + println!("Lune v{}", lune_version.unwrap()); + + let lune_instance = Lune::new(); + + let mut repl = DefaultEditor::new()?; + + match repl.load_history(&(|| -> PathBuf { + let dir_opt = home::home_dir(); + + if let Some(dir) = dir_opt { + dir.join(".lune_history") + } else { + eprintln!("Failed to find user home directory, abort!"); + // Doesn't feel right to exit directly with a exit code of 1 + // Lmk if there is a better way of doing this + exit(1); + } + })()) { + Ok(_) => (), + Err(err) => { + match err { + err => { + if let ReadlineError::Io(io_err) = err { + if io_err.kind() == ErrorKind::NotFound { + std::fs::write( + // We know for sure that the home dir already exists + home::home_dir().unwrap().join(".lune_history"), + String::new(), + )?; + } + } + } + } + + eprintln!("WARN: Failed to load REPL history") + } + }; + + let mut interrupt_counter = 0u32; + + loop { + let mut source_code = String::new(); + + match repl.readline("> ") { + Ok(code) => { + source_code = code.clone(); + repl.add_history_entry(code.as_str())?; + + // If source code eval was requested, we reset the counter + interrupt_counter = 0; + } + + Err(ReadlineError::Interrupted) => { + // HACK: We actually want the user to do ^C twice to exit, + // but the user would need to ^C one more time even after + // the check passes, so we check for 1 instead of 2 + if interrupt_counter != 1 { + println!("Interrupt: ^C again to exit"); + + // Increment the counter + interrupt_counter += 1; + } else { + break; + } + } + Err(ReadlineError::Eof) => break, + Err(err) => { + eprintln!("REPL ERROR: {}", err.to_string()); + + // This isn't a good way to exit imo, once again + exit(1); + } + }; + + let eval_result = lune_instance.run("REPL", source_code).await; + + match eval_result { + Ok(_) => (), + Err(err) => eprintln!("{}", err), + }; + } + + Ok(ExitCode::SUCCESS) +}