mirror of
https://github.com/lune-org/lune.git
synced 2024-12-12 13:00:37 +00:00
Make clippy happy for new REPL, minor changes
- Move some code blocks to be able to remove string cloning - Use const strings for user-facing REPL messages - Fix running input code twice when interrupted - Add notes for future extensions and considerations
This commit is contained in:
parent
d8f6703c70
commit
2b855156bf
2 changed files with 46 additions and 51 deletions
|
@ -1,7 +1,7 @@
|
|||
use std::{fmt::Write as _, process::ExitCode};
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
use clap::{CommandFactory, Parser};
|
||||
use clap::Parser;
|
||||
|
||||
use lune::Lune;
|
||||
use tokio::{
|
||||
|
@ -147,14 +147,9 @@ 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 exit_code_status = repl::show_interface(Cli::command()).await;
|
||||
|
||||
return exit_code_status;
|
||||
// If we did not generate any typedefs we know that the user did not
|
||||
// provide any other options, and in that case we should enter the REPL
|
||||
return repl::show_interface().await;
|
||||
}
|
||||
// Figure out if we should read from stdin or from a file,
|
||||
// reading from stdin is marked by passing a single "-"
|
||||
|
|
|
@ -1,42 +1,40 @@
|
|||
use std::{path::PathBuf, process::ExitCode};
|
||||
|
||||
use anyhow::{Error, Result};
|
||||
use clap::Command;
|
||||
use anyhow::{Context, Result};
|
||||
use directories::UserDirs;
|
||||
use lune::Lune;
|
||||
use rustyline::{error::ReadlineError, DefaultEditor};
|
||||
|
||||
use lune::Lune;
|
||||
|
||||
const MESSAGE_WELCOME: &str = concat!("Lune v", env!("CARGO_PKG_VERSION"));
|
||||
const MESSAGE_INTERRUPT: &str = "Interrupt: ^C again to exit";
|
||||
|
||||
#[derive(PartialEq)]
|
||||
enum PromptState {
|
||||
Regular,
|
||||
Continuation,
|
||||
}
|
||||
|
||||
// Isn't dependency injection plain awesome?!
|
||||
pub async fn show_interface(cmd: Command) -> Result<ExitCode> {
|
||||
let lune_version = cmd.get_version();
|
||||
pub async fn show_interface() -> Result<ExitCode> {
|
||||
println!("{MESSAGE_WELCOME}");
|
||||
|
||||
// The version is mandatory and will always exist
|
||||
println!("Lune v{}", lune_version.unwrap());
|
||||
|
||||
let lune_instance = Lune::new();
|
||||
|
||||
let mut repl = DefaultEditor::new()?;
|
||||
let history_file_path: &PathBuf = &UserDirs::new()
|
||||
.ok_or(Error::msg("cannot find user home directory"))?
|
||||
.context("Failed to find user home directory")?
|
||||
.home_dir()
|
||||
.join(".lune_history");
|
||||
|
||||
if !history_file_path.exists() {
|
||||
std::fs::write(&history_file_path, String::new())?;
|
||||
tokio::fs::write(history_file_path, &[]).await?;
|
||||
}
|
||||
|
||||
let mut repl = DefaultEditor::new()?;
|
||||
repl.load_history(history_file_path)?;
|
||||
|
||||
let mut interrupt_counter = 0u32;
|
||||
let mut prompt_state: PromptState = PromptState::Regular;
|
||||
let mut interrupt_counter = 0;
|
||||
let mut prompt_state = PromptState::Regular;
|
||||
let mut source_code = String::new();
|
||||
|
||||
let lune_instance = Lune::new();
|
||||
|
||||
loop {
|
||||
let prompt = match prompt_state {
|
||||
PromptState::Regular => "> ",
|
||||
|
@ -45,43 +43,43 @@ pub async fn show_interface(cmd: Command) -> Result<ExitCode> {
|
|||
|
||||
match repl.readline(prompt) {
|
||||
Ok(code) => {
|
||||
if prompt_state == PromptState::Continuation {
|
||||
source_code.push_str(&code);
|
||||
} else if prompt_state == PromptState::Regular {
|
||||
source_code = code.clone();
|
||||
}
|
||||
|
||||
repl.add_history_entry(code.as_str())?;
|
||||
|
||||
// If source code eval was requested, we reset the counter
|
||||
interrupt_counter = 0;
|
||||
|
||||
// TODO: Should we add history entries for each separate line?
|
||||
// Or should we add and save history only when we have complete
|
||||
// lua input that may or may not be multiple lines long?
|
||||
repl.add_history_entry(&code)?;
|
||||
repl.save_history(history_file_path)?;
|
||||
|
||||
match prompt_state {
|
||||
PromptState::Regular => source_code = code,
|
||||
PromptState::Continuation => source_code.push_str(&code),
|
||||
}
|
||||
}
|
||||
|
||||
Err(ReadlineError::Eof) => break,
|
||||
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 {
|
||||
repl.save_history(history_file_path)?;
|
||||
break;
|
||||
}
|
||||
}
|
||||
Err(ReadlineError::Eof) => {
|
||||
repl.save_history(history_file_path)?;
|
||||
|
||||
// NOTE: We actually want the user to do ^C twice to exit,
|
||||
// and if we get an interrupt we should continue to the next
|
||||
// readline loop iteration so we don't run input code twice
|
||||
if interrupt_counter == 1 {
|
||||
println!("{MESSAGE_INTERRUPT}");
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
Err(err) => {
|
||||
eprintln!("REPL ERROR: {err}");
|
||||
return Ok(ExitCode::FAILURE);
|
||||
}
|
||||
};
|
||||
|
||||
let eval_result = lune_instance.run("REPL", source_code.clone()).await;
|
||||
// TODO: Preserve context here somehow?
|
||||
let eval_result = lune_instance.run("REPL", &source_code).await;
|
||||
|
||||
match eval_result {
|
||||
Ok(_) => prompt_state = PromptState::Regular,
|
||||
|
@ -89,7 +87,7 @@ pub async fn show_interface(cmd: Command) -> Result<ExitCode> {
|
|||
Err(err) => {
|
||||
if err.is_incomplete_input() {
|
||||
prompt_state = PromptState::Continuation;
|
||||
source_code.push('\n')
|
||||
source_code.push('\n');
|
||||
} else {
|
||||
eprintln!("{err}");
|
||||
}
|
||||
|
@ -97,5 +95,7 @@ pub async fn show_interface(cmd: Command) -> Result<ExitCode> {
|
|||
};
|
||||
}
|
||||
|
||||
repl.save_history(history_file_path)?;
|
||||
|
||||
Ok(ExitCode::SUCCESS)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue