use std::io::{self, BufRead, IsTerminal, Write};
use std::process::ExitCode;
use tclrs::Interp;
const PROMPT: &str = "% ";
pub fn run(interp: &mut Interp, interactive: bool) -> ExitCode {
let stdin = io::stdin();
let mut pending = String::new();
loop {
if interactive && pending.is_empty() {
print!("{PROMPT}");
if io::stdout().flush().is_err() {
return ExitCode::FAILURE;
}
}
let mut line = String::new();
match stdin.lock().read_line(&mut line) {
Ok(0) => return ExitCode::SUCCESS,
Ok(_) => {}
Err(e) => {
eprintln!("tclrs: {e}");
return ExitCode::FAILURE;
}
}
pending.push_str(&line);
if incomplete(&pending) {
continue;
}
let script = std::mem::take(&mut pending);
match interp.eval(&script) {
Ok(result) => {
if interactive && !result.is_empty() {
println!("{result}");
}
}
Err(e) => eprintln!("{}", e.msg),
}
}
}
pub fn incomplete(src: &str) -> bool {
matches!(tclrs::parse(src), Err(e) if UNTERMINATED.contains(&e.msg.as_str()))
}
const UNTERMINATED: &[&str] = &[
"missing close-brace",
"missing close-brace for variable name",
"missing close-bracket",
"missing \"",
"missing )",
];
pub fn stdin_is_terminal() -> bool {
io::stdin().is_terminal()
}