use async_trait::async_trait;
use endbasic_core::console::{ClearType, Console, Key, Position};
use futures_lite::future::block_on;
use std::cell::RefCell;
use std::collections::VecDeque;
use std::env;
use std::fs;
use std::io::{self, Write};
use std::process;
use std::rc::Rc;
#[derive(Default)]
struct IncompleteConsole {
buffer: VecDeque<Key>,
}
fn line_to_keys(s: String) -> VecDeque<Key> {
let mut keys = VecDeque::default();
for ch in s.chars() {
if ch == '\n' {
keys.push_back(Key::NewLine);
} else if ch == '\r' {
keys.push_back(Key::CarriageReturn);
} else {
keys.push_back(Key::Char(ch));
}
}
keys
}
#[async_trait(?Send)]
impl Console for IncompleteConsole {
fn clear(&mut self, _how: ClearType) -> io::Result<()> {
eprintln!("Clearing the screen not implemented");
Ok(())
}
fn color(&mut self, _fg: Option<u8>, _bg: Option<u8>) -> io::Result<()> {
eprintln!("Changing colors not implemented");
Ok(())
}
fn enter_alt(&mut self) -> io::Result<()> {
eprintln!("Alternate console switching not implemented");
Ok(())
}
fn hide_cursor(&mut self) -> io::Result<()> {
eprintln!("Cursor visibility changes not implemented");
Ok(())
}
fn is_interactive(&self) -> bool {
false
}
fn leave_alt(&mut self) -> io::Result<()> {
eprintln!("Alternate console switching not implemented");
Ok(())
}
fn locate(&mut self, _pos: Position) -> io::Result<()> {
eprintln!("Moving the cursor not implemented");
Ok(())
}
fn move_within_line(&mut self, _off: i16) -> io::Result<()> {
eprintln!("Moving the cursor not implemented");
Ok(())
}
fn print(&mut self, text: &str) -> io::Result<()> {
println!("{}", text);
Ok(())
}
async fn read_key(&mut self) -> io::Result<Key> {
if self.buffer.is_empty() {
let mut line = String::new();
if io::stdin().read_line(&mut line)? == 0 {
return Ok(Key::Eof);
}
self.buffer = line_to_keys(line);
}
match self.buffer.pop_front() {
Some(key) => Ok(key),
None => Ok(Key::Eof),
}
}
fn show_cursor(&mut self) -> io::Result<()> {
eprintln!("Cursor visibility changes not implemented");
Ok(())
}
fn size(&self) -> io::Result<Position> {
Ok(Position { row: 24, column: 80 })
}
fn write(&mut self, bytes: &[u8]) -> io::Result<()> {
let stdout = io::stdout();
let mut stdout = stdout.lock();
stdout.write_all(bytes)?;
stdout.flush()
}
}
fn main() {
let args: Vec<String> = env::args().collect();
let path = match args.as_slice() {
[_, path] => path,
_ => {
eprintln!("Usage error: expected a file name");
process::exit(1);
}
};
let console = Rc::from(RefCell::from(IncompleteConsole::default()));
let mut machine = endbasic_core::exec::MachineBuilder::default()
.add_builtins(endbasic_core::console::all_commands(console))
.build();
let mut input = match fs::File::open(path) {
Ok(file) => file,
Err(e) => {
eprintln!("ERROR: {}", e);
process::exit(1);
}
};
match block_on(machine.exec(&mut input)) {
Ok(()) => (),
Err(e) => {
eprintln!("ERROR: {}", e);
process::exit(1);
}
}
}