#![warn(clippy::pedantic)]
use anyhow::{Error, Result};
use kameo::actor::ActorRef;
use mlua::Value as LuaValue;
use sscan::{
lua_vm::{
messages::{CheckoutTable, CommitTable, EvaluateChunk, ExecuteChunk},
LuaVM,
},
system::{messages::GetActorLuaVM, System},
};
use std::io::stdin;
const RCFILE_DEFAULT: &str = include_str!("sscani/rc.default.lua");
const LIB_SSCANI_HELP: &str = include_str!("sscani/sscani.help.lua");
const LIB_SSCANI_STD: &str = include_str!("sscani/sscani.std.lua");
#[tokio::main]
async fn main() -> Result<()> {
let prompt_request: ExecuteChunk = ExecuteChunk::using("sscani.prompt()");
let continuation_request: ExecuteChunk = ExecuteChunk::using("sscani.prompt_continue()");
let system: ActorRef<System> = kameo::spawn(System::default());
let vm: ActorRef<LuaVM> = if let Some(vm) = system.ask(GetActorLuaVM).await? {
vm
} else {
eprintln!("Could not get a handle to the Lua userscript environment.");
eprintln!("Shutting down now.");
return Ok(());
};
load_sscani_libs(&vm).await?;
load_default_rcfile(&vm).await?;
loop {
vm.ask(prompt_request.clone()).await?;
let mut buffer: String = String::with_capacity(2048);
stdin().read_line(&mut buffer)?;
while !buffer.trim_end().ends_with(';') {
vm.ask(continuation_request.clone()).await?;
stdin().read_line(&mut buffer)?;
}
let snippet: &str = buffer.trim_end_matches(';');
let eval_request: EvaluateChunk = EvaluateChunk::using(snippet);
match vm.ask(eval_request).await {
Ok(retval) => match retval {
LuaValue::Nil => {}
LuaValue::Boolean(b) => println!("{b}"),
LuaValue::Function(f) => {
let func_ptr: usize = f.to_pointer() as usize;
println!("<function @ {func_ptr:#x}>");
}
LuaValue::Integer(i) => println!("{i}"),
LuaValue::Number(f) => println!("{f}"),
LuaValue::String(s) => println!("{}", s.to_string_lossy()),
_ => println!("<{}>", retval.type_name()),
},
Err(err) => {
let err: Error = Error::new(err).context("unable to execute chunk");
eprintln!("Error: {err:?}");
}
}
}
}
async fn load_sscani_libs(vm: &ActorRef<LuaVM>) -> Result<()> {
let chunk: String = format!("{LIB_SSCANI_HELP}\n{LIB_SSCANI_STD}");
let exec_request: ExecuteChunk = ExecuteChunk::using(&chunk);
Ok(vm.ask(exec_request).await?)
}
async fn load_default_rcfile(vm: &ActorRef<LuaVM>) -> Result<()> {
let checkout_request: CheckoutTable = CheckoutTable::with_name("sscani");
let table: mlua::Table = vm.ask(checkout_request).await?;
table.set("rc_default", RCFILE_DEFAULT)?;
let commit_request: CommitTable = CommitTable::using(table, "sscani");
Ok(vm.ask(commit_request).await?)
}