use crate::{
CleanPrompt,
repl::{config::ReplConfig, highlighter::KeywordHighlighter},
};
use reedline::{Prompt, Reedline, Signal};
use std::{
io::{Result, Write, stdout},
sync::Arc,
};
pub struct InputHandler {
line_editor: Reedline,
prompt: Arc<dyn Prompt>,
}
impl InputHandler {
pub fn new(config: Arc<ReplConfig>) -> Self {
let default_prompt = CleanPrompt::default();
let prompt = config
.prompt()
.clone()
.unwrap_or_else(|| Arc::new(default_prompt));
let line_editor = match &config.kw_style() {
Some(style) => Reedline::create().with_highlighter(Box::new(KeywordHighlighter::new(
&style.keywords,
style.foreground,
))),
None => Reedline::create(),
};
Self {
line_editor,
prompt,
}
}
pub fn run<F>(&mut self, func: F) -> Result<()>
where
F: Fn(String) -> bool,
{
loop {
match self.line_editor.read_line(self.prompt.as_ref()) {
Ok(Signal::Success(buffer)) => {
if func(buffer) {
break;
}
}
Ok(Signal::CtrlC) | Ok(Signal::CtrlD) => {
println!("\nAborted!");
break;
}
Err(err) => eprintln!("Input error: {err}"),
}
stdout().flush()?;
}
Ok(())
}
}
impl Drop for InputHandler {
fn drop(&mut self) {
if let Err(err) = stdout().flush() {
eprintln!("Failed to flush stdout during cleanup: {err}");
}
}
}