use std::io::Write;
use mingling_core::{Program, ProgramCollect, hook::ProgramHook, setup::ProgramSetup};
pub struct BasicREPLReadlineSetup;
impl<C> ProgramSetup<C> for BasicREPLReadlineSetup
where
C: ProgramCollect<Enum = C>,
{
fn setup(&mut self, program: &mut Program<C>) {
program.with_hook(ProgramHook::empty().on_repl_readline(|| readline().ok()));
}
}
pub enum BasicREPLPromptSetup {
Prompt(String),
Func(fn() -> String),
}
impl BasicREPLPromptSetup {
pub fn simple(prompt: impl Into<String>) -> Self {
Self::Prompt(prompt.into())
}
pub fn func(func: fn() -> String) -> Self {
Self::Func(func)
}
}
impl<C> ProgramSetup<C> for BasicREPLPromptSetup
where
C: ProgramCollect<Enum = C>,
{
fn setup(&mut self, program: &mut Program<C>) {
match self {
BasicREPLPromptSetup::Prompt(prompt) => {
static PROMPT: std::sync::OnceLock<String> = std::sync::OnceLock::new();
let _ = PROMPT.set(prompt.clone());
fn print_prompt() {
print!("{}", PROMPT.get().unwrap());
let _ = std::io::stdout().flush();
}
program.with_hook(ProgramHook::empty().on_repl_pre_readline(print_prompt));
}
BasicREPLPromptSetup::Func(f) => {
static FUNC: std::sync::OnceLock<fn() -> String> = std::sync::OnceLock::new();
let _ = FUNC.set(*f);
fn print_func_prompt() {
print!("{}", FUNC.get().unwrap()());
let _ = std::io::stdout().flush();
}
program.with_hook(ProgramHook::empty().on_repl_pre_readline(print_func_prompt));
}
}
}
}
pub struct BasicREPLOutputSetup;
impl<C> ProgramSetup<C> for BasicREPLOutputSetup
where
C: ProgramCollect<Enum = C>,
{
fn setup(&mut self, program: &mut Program<C>) {
program.with_hook(ProgramHook::empty().on_repl_receive_result(|r| {
if !r.is_empty() {
println!("{}", r.trim())
}
}));
}
}
fn readline() -> Result<String, std::io::Error> {
let mut input = String::new();
std::io::stdout().flush()?;
std::io::stdin().read_line(&mut input)?;
Ok(input.trim().to_string())
}