use super::{
ReplConfig, EnhancedEditor, HistoryManager, Debugger,
CompletionProvider, SyntaxHighlighter, CodeInspector, SessionManager
};
use crate::{Lambdust, Result};
#[cfg(feature = "repl")]
use colored::*;
pub struct EnhancedRepl {
config: ReplConfig,
lambdust: Lambdust,
editor: EnhancedEditor,
history: HistoryManager,
debugger: Debugger,
completion: CompletionProvider,
highlighter: SyntaxHighlighter,
inspector: CodeInspector,
session: SessionManager,
line_number: usize,
}
impl EnhancedRepl {
pub fn new(lambdust: Lambdust, config: ReplConfig) -> Result<Self> {
let history = HistoryManager::new(config.max_history)?;
let debugger = Debugger::new();
let completion = CompletionProvider::new(&lambdust)?;
let highlighter = SyntaxHighlighter::new()?;
let inspector = CodeInspector::new();
let session = SessionManager::new()?;
let editor = EnhancedEditor::new(config.clone())?;
Ok(Self {
config,
lambdust,
editor,
history,
debugger,
completion,
highlighter,
inspector,
session,
line_number: 1,
})
}
pub fn with_defaults(lambdust: Lambdust) -> Result<Self> {
Self::new(lambdust, ReplConfig::default())
}
pub fn config(&self) -> &ReplConfig {
&self.config
}
pub fn lambdust(&self) -> &Lambdust {
&self.lambdust
}
pub fn lambdust_mut(&mut self) -> &mut Lambdust {
&mut self.lambdust
}
pub fn editor(&self) -> &EnhancedEditor {
&self.editor
}
pub fn editor_mut(&mut self) -> &mut EnhancedEditor {
&mut self.editor
}
pub fn history(&self) -> &HistoryManager {
&self.history
}
pub fn history_mut(&mut self) -> &mut HistoryManager {
&mut self.history
}
pub fn debugger(&self) -> &Debugger {
&self.debugger
}
pub fn debugger_mut(&mut self) -> &mut Debugger {
&mut self.debugger
}
pub fn completion(&self) -> &CompletionProvider {
&self.completion
}
pub fn highlighter(&self) -> &SyntaxHighlighter {
&self.highlighter
}
pub fn inspector(&self) -> &CodeInspector {
&self.inspector
}
pub fn session(&self) -> &SessionManager {
&self.session
}
pub fn session_mut(&mut self) -> &mut SessionManager {
&mut self.session
}
pub fn line_number(&self) -> usize {
self.line_number
}
pub fn increment_line_number(&mut self) {
self.line_number += 1;
}
pub fn set_line_number(&mut self, line_number: usize) {
self.line_number = line_number;
}
pub fn run(&mut self) -> Result<()> {
#[cfg(feature = "repl")]
{
println!("{}", format!("Lambdust {} Enhanced REPL", crate::VERSION).bright_blue().bold());
println!("{}", "Type :help for available commands or (exit) to quit".dimmed());
}
#[cfg(not(feature = "repl"))]
{
println!("Lambdust {} Enhanced REPL", crate::VERSION);
println!("Type :help for available commands or (exit) to quit");
}
println!();
loop {
let prompt = format!("λust:{line}> ", line = self.line_number);
match self.editor.read_line(&prompt, &mut self.completion, &self.highlighter) {
Ok(Some(line)) => {
let line = line.trim();
if line.is_empty() {
continue;
}
if let Some(result) = self.handle_repl_command(line)? {
if result {
continue;
} else {
break;
}
}
self.history.add_entry(line.to_string());
match self.evaluate_expression(line) {
Ok(result) => {
if !matches!(result, crate::eval::Value::Unspecified) {
#[cfg(feature = "repl")]
println!("{}", format!("{result}").bright_green());
#[cfg(not(feature = "repl"))]
println!("{result}");
self.session.add_command(line.to_string(), Some(result.to_string()), None)?;
} else {
self.session.add_command(line.to_string(), None, None)?;
}
}
Err(e) => {
#[cfg(feature = "repl")]
eprintln!("{}", format!("Error: {e}").bright_red());
#[cfg(not(feature = "repl"))]
eprintln!("Error: {e}");
self.session.add_command(line.to_string(), None, Some(e.to_string()))?;
}
}
self.increment_line_number();
}
Ok(None) => {
println!("^D");
break;
}
Err(e) => {
eprintln!("Error: {e:?}");
break;
}
}
}
if self.session.has_unsaved_changes() {
self.session.save_current_session()?;
}
println!("Goodbye!");
Ok(())
}
fn handle_repl_command(&mut self, line: &str) -> Result<Option<bool>> {
match line {
"(exit)" | "(quit)" | ":quit" | ":q" => Ok(Some(false)),
":help" | ":h" => {
self.print_help();
Ok(Some(true))
}
":version" | ":v" => {
println!("Lambdust version: {}", crate::VERSION);
println!("Language version: {}", crate::LANGUAGE_VERSION);
Ok(Some(true))
}
":session" => {
self.session.show_current_session()?;
Ok(Some(true))
}
":sessions" => {
self.session.list_sessions()?;
Ok(Some(true))
}
line if line.starts_with(":load ") => {
let session_id = line.strip_prefix(":load ").unwrap().trim();
self.session.load_session(session_id)?;
println!("Loaded session: {session_id}");
Ok(Some(true))
}
line if line.starts_with(":save ") => {
let session_name = line.strip_prefix(":save ").unwrap().trim();
self.session.save_session(session_name)?;
Ok(Some(true))
}
_ => Ok(None)
}
}
fn evaluate_expression(&mut self, source: &str) -> Result<crate::eval::Value> {
self.lambdust.eval(source, Some("<repl>"))
}
fn print_help(&self) {
#[cfg(feature = "repl")]
{
println!("{}", "Lambdust Enhanced REPL Commands:".bright_blue().bold());
println!(" {} - Show this help", ":help, :h".bright_yellow());
println!(" {} - Show version information", ":version, :v".bright_yellow());
println!(" {} - Show current session info", ":session".bright_yellow());
println!(" {} - List all sessions", ":sessions".bright_yellow());
println!(" {} - Load a session by ID", ":load <session-id>".bright_yellow());
println!(" {} - Save current session with name", ":save <name>".bright_yellow());
println!(" {} - Exit the REPL", "(exit), (quit), :quit, :q".bright_yellow());
println!();
println!("{}", "Example expressions:".bright_blue().bold());
println!(" {} - Basic arithmetic", "(+ 1 2 3)".bright_cyan());
println!(" {} - Function definition", "(define (square x) (* x x))".bright_cyan());
println!(" {} - Type annotation", "(:: (+ 1 2) Number)".bright_cyan());
println!(" {} - Import a library", "(import (scheme base))".bright_cyan());
}
#[cfg(not(feature = "repl"))]
{
println!("Lambdust Enhanced REPL Commands:");
println!(" :help, :h - Show this help");
println!(" :version, :v - Show version information");
println!(" :session - Show current session info");
println!(" :sessions - List all sessions");
println!(" :load <session-id> - Load a session by ID");
println!(" :save <name> - Save current session with name");
println!(" (exit), (quit), :quit, :q - Exit the REPL");
println!();
println!("Example expressions:");
println!(" (+ 1 2 3) - Basic arithmetic");
println!(" (define (square x) (* x x)) - Function definition");
println!(" (:: (+ 1 2) Number) - Type annotation");
println!(" (import (scheme base)) - Import a library");
}
println!();
}
}