use std::{io::Write, sync::atomic::Ordering}; use rustyline::{Config, EditMode, ColorMode, Editor, CompletionType, error::ReadlineError}; use matrix_lang::prelude::*; use crate::{State, helper::MatrixHelper}; pub struct Repl<'s, 'a> { state: &'s mut State<'a> } impl<'s, 'a> Repl<'s, 'a> { pub fn new(state: &'s mut State<'a>) -> Self { Self { state } } fn execute(&mut self, line: String) -> Result { let fun = self.state.compile(line)?; let val = self.state.execute(fun)?; Ok(val) } pub fn run(&mut self) -> Result<()> { let interupt = self.state.vm.borrow().interupt(); ctrlc::set_handler(move || { interupt.store(Interupt::KeyboardInterupt as usize, Ordering::SeqCst); }).exception()?; let config = Config::builder() .indent_size(4) .edit_mode(EditMode::Emacs) .check_cursor_position(true) .completion_type(CompletionType::List) .color_mode(if self.state.color { ColorMode::Enabled } else { ColorMode::Disabled }) .build(); let helper = MatrixHelper::new(self.state.vm.clone()); let histfile = std::env::var("MATRIX_HISTORY").ok(); let mut rl = Editor::with_config(config).exception()?; rl.set_helper(Some(helper)); if let Some(hf) = &histfile { rl.load_history(hf).exception()?; } loop { let line = match rl.readline(">> ") { Ok(line) => line, Err(ReadlineError::Eof) => break, Err(_) => continue, }; rl.add_history_entry(&line).exception()?; match self.execute(line) { Ok(val) => { if val != Value::Nil { if self.state.color { println!("{val:#}"); } else { println!("{val}"); } } } Err(err) => crate::error(err, &self.state), }; std::io::stdout().flush().exception()?; } if let Some(hf) = &histfile { rl.save_history(hf).exception()?; } Ok(()) } }