use super::parse::*;
use super::helpers::*;
use super::print::*;
use crate::parser::interpreter::Interpreter;
use crate::Value;
use crate::modules::repl::{
history::{load_history, save_history_line},
autocomplete::reset_known_commands_from_interp,
input::read_line_with_arrows,
render::forcibly_clear_line,
};
use std::io::stdout;
pub fn run_repl_mode(verbose: bool) -> Result<(), String> {
use crossterm::terminal::{disable_raw_mode, enable_raw_mode};
use crossterm::style::Color;
let version = env!("CARGO_PKG_VERSION");
println!("Burn in Lava {}", version);
enable_raw_mode().map_err(|e| format!("enable_raw_mode error: {}", e))?;
let mut history = load_history();
let mut interpreter = Interpreter::new();
interpreter.set_verbose(verbose);
crate::modules::compose::register_compose_and_pipe(&mut interpreter);
crate::modules::sput::register_sput(&mut interpreter);
crate::modules::slog::register_slog(&mut interpreter);
crate::modules::ink::register_ink(&mut interpreter);
crate::modules::include::register_include(&mut interpreter);
reset_known_commands_from_interp(&interpreter);
let mut partial_code = String::new();
loop {
let prompt_str = if partial_code.is_empty() { "> " } else { "... " };
let user_line = match read_line_with_arrows(
verbose,
&mut history,
prompt_str,
&mut interpreter,
&crate::modules::repl::render::redraw_full,
) {
Ok(ln) => ln,
Err(e) => {
disable_raw_mode().ok();
return Err(e);
}
};
if partial_code.is_empty() && (user_line == ":q" || user_line == ":quit") {
disable_raw_mode().ok();
println!();
interpreter.remove_all_pollers();
return Ok(());
}
if user_line == "<<<EXIT>>>"
{
break;
}
save_history_line(&mut history, &user_line);
partial_code.push_str(&user_line);
partial_code.push('\n');
if !is_input_complete(&partial_code) {
continue;
}
let parse_result = match attempt_parse(&partial_code, verbose) {
Ok(r) => r,
Err(lex_msg) => {
let mut out = stdout();
forcibly_clear_line(&mut out)?;
print_colored_message(&mut out, &lex_msg, Color::Red);
partial_code.clear();
continue;
}
};
match parse_result {
ParseResult::Incomplete => continue,
ParseResult::Error(msg) => {
let mut out = stdout();
forcibly_clear_line(&mut out)?;
print_colored_message(&mut out, &msg, Color::Red);
partial_code.clear();
}
ParseResult::Success(stmts) => {
let mut out = stdout();
forcibly_clear_line(&mut out)?;
let mut last_val = None;
let mut suppress_last_val = false;
for (_stmt_index, stmt) in stmts.iter().enumerate() {
let old_names: Vec<String> = interpreter
.get_dynamic_functions_for_clone()
.keys()
.cloned()
.collect();
let result = interpreter.exec_statement(stmt);
match result {
Ok(v) => {
let show_new_funcs = is_extend_or_include_call(stmt);
if show_new_funcs {
let new_names: Vec<String> = interpreter
.get_dynamic_functions_for_clone()
.keys()
.cloned()
.collect();
let mut newly_imported: Vec<String> = new_names
.iter()
.filter(|nm| !old_names.contains(nm))
.cloned()
.collect();
newly_imported.sort();
reset_known_commands_from_interp(&interpreter);
if !newly_imported.is_empty() {
print_colored_message(
&mut out,
&crate::value_to_string(&Value::StrArray(newly_imported)),
Color::DarkRed,
);
}
suppress_last_val = true;
}
if is_printing_function_stmt(stmt) {
suppress_last_val = true;
}
if matches!(stmt, crate::parser::ast::Stmt::Assignment { .. }) {
reset_known_commands_from_interp(&interpreter);
}
last_val = Some(v);
}
Err(exec_err) => {
forcibly_clear_line(&mut out).ok();
print_colored_message(&mut out, &exec_err, Color::Red);
last_val = None;
break;
}
}
}
if let Some(val) = last_val {
if !suppress_last_val {
print_pretty_value(&mut out, &val);
}
}
partial_code.clear();
}
}
}
disable_raw_mode().ok();
interpreter.remove_all_pollers();
Ok(())
}