#![allow(clippy::arc_with_non_send_sync)] mod app; mod commands; mod config; mod helper; mod input; mod opcodes_dictionary; use config::CONFIG_DIR; use rustyline::{error::ReadlineError, Config, Editor}; use std::{ path::PathBuf, sync::{atomic::Ordering, LazyLock}, }; fn rustyline_config() -> Config { Config::builder() .completion_type(rustyline::CompletionType::List) .auto_add_history(true) .build() } pub static HOME_DIR: LazyLock = LazyLock::new(|| dirs::home_dir().expect("Could not determine home directory")); pub static HISTORY_FILE: LazyLock = LazyLock::new(|| HOME_DIR.join(".limbo_history")); fn main() -> anyhow::Result<()> { let mut app = app::Limbo::new()?; let _guard = app.init_tracing()?; if std::io::IsTerminal::is_terminal(&std::io::stdin()) { let mut rl = Editor::with_config(rustyline_config())?; if HISTORY_FILE.exists() { rl.load_history(HISTORY_FILE.as_path())?; } let config_file = CONFIG_DIR.join("limbo.toml"); let config = config::Config::from_config_file(config_file); tracing::info!("Configuration: {:?}", config); app = app.with_config(config); app = app.with_readline(rl); } else { tracing::debug!("not in tty"); } loop { let readline = app.readline(); match readline { Ok(line) => match app.handle_input_line(line.trim()) { Ok(_) => {} Err(e) => { eprintln!("{}", e); } }, Err(ReadlineError::Interrupted) => { // At prompt, increment interrupt count if app.interrupt_count.fetch_add(1, Ordering::SeqCst) >= 1 { eprintln!("Interrupted. Exiting..."); let _ = app.close_conn(); break; } println!("Use .quit to exit or press Ctrl-C again to force quit."); app.reset_input(); continue; } Err(ReadlineError::Eof) => { app.handle_remaining_input(); let _ = app.close_conn(); break; } Err(err) => { let _ = app.close_conn(); anyhow::bail!(err) } } } Ok(()) }