use commands::Commands;
use helper::*;
use io::*;
use loc::*;
use rair_env::*;
use rair_io::*;
use serde::{Deserialize, Serialize};
use std::cell::RefCell;
use std::io;
use std::io::Write;
use std::mem;
use std::rc::Rc;
use utils::register_utils;
use writer::Writer;
use yansi::Paint;
#[derive(Serialize, Deserialize)]
pub struct Core {
pub mode: AddrMode,
pub io: RIO,
loc: u64,
#[serde(skip)]
pub stdout: Writer,
#[serde(skip)]
pub stderr: Writer,
#[serde(skip)]
commands: Rc<RefCell<Commands>>,
#[serde(skip)]
pub env: Rc<RefCell<Environment<Core>>>,
}
impl Default for Core {
fn default() -> Self {
Core {
mode: AddrMode::Phy,
stdout: Writer::new_write(Box::new(io::stdout())),
stderr: Writer::new_write(Box::new(io::stderr())),
io: RIO::new(),
loc: 0,
commands: Default::default(),
env: Default::default(),
}
}
}
fn set_global_color(_: &str, value: bool, _: &Environment<Core>, _: &mut Core) -> bool {
if value {
Paint::enable();
} else {
Paint::disable();
}
return true;
}
impl Core {
pub(crate) fn load_commands(&mut self) {
register_io(self);
register_loc(self);
register_utils(self);
}
pub fn commands(&mut self) -> Rc<RefCell<Commands>> {
return self.commands.clone();
}
pub fn set_commands(&mut self, commands: Rc<RefCell<Commands>>) {
self.commands = commands
}
fn init_colors(&mut self, enable: bool) {
let env = self.env.clone();
env.borrow_mut()
.add_bool_with_cb("color.enable", enable, "Enable/Disable color theme globally", self, set_global_color)
.unwrap();
env.borrow_mut().add_color("color.1", (0x58, 0x68, 0x75), "").unwrap();
env.borrow_mut().add_color("color.2", (0xb5, 0x89, 0x00), "").unwrap();
env.borrow_mut().add_color("color.3", (0xcb, 0x4b, 0x16), "").unwrap();
env.borrow_mut().add_color("color.4", (0xdc, 0x32, 0x2f), "").unwrap();
env.borrow_mut().add_color("color.5", (0xd3, 0x36, 0x82), "").unwrap();
env.borrow_mut().add_color("color.6", (0x6c, 0x71, 0xc4), "").unwrap();
env.borrow_mut().add_color("color.7", (0x26, 0x8b, 0xd2), "").unwrap();
env.borrow_mut().add_color("color.8", (0x2a, 0xa1, 0x98), "").unwrap();
env.borrow_mut().add_color("color.9", (0x85, 0x99, 0x00), "").unwrap();
}
fn new_settings(color: bool) -> Self {
let mut core: Core = Default::default();
core.init_colors(color);
core.load_commands();
return core;
}
pub fn new() -> Self {
Core::new_settings(true)
}
pub fn new_no_colors() -> Self {
Core::new_settings(false)
}
pub fn set_loc(&mut self, loc: u64) {
self.loc = loc;
}
pub fn get_loc(&self) -> u64 {
self.loc
}
pub fn add_command(&mut self, long: &'static str, short: &'static str, funcs: MRc<dyn Cmd>) {
if !long.is_empty() && !self.commands.borrow_mut().add_command(long, funcs.clone()) {
let msg = format!("Command {} already existed.", Paint::default(long).bold());
error_msg(self, "Cannot add this command.", &msg);
}
if !short.is_empty() && !self.commands.borrow_mut().add_command(short, funcs) {
let msg = format!("Command {} already existed.", Paint::default(short).bold());
error_msg(self, "Cannot add this command.", &msg);
}
}
fn command_not_found(&mut self, command: &str) {
let msg = format!("Command {} is not found.", Paint::default(command).bold());
error_msg(self, "Execution failed", &msg);
let commands = self.commands.borrow();
let similar = commands.suggest(&command.to_string(), 2);
let mut s = similar.iter();
if let Some(suggestion) = s.next() {
let (r, g, b) = self.env.borrow().get_color("color.6").unwrap();
write!(self.stderr, "Similar command: {}", Paint::rgb(r, g, b, suggestion)).unwrap();
for suggestion in s {
write!(self.stderr, ", {}", Paint::rgb(r, g, b, suggestion)).unwrap();
}
writeln!(self.stderr, ".").unwrap();
}
}
pub fn run(&mut self, command: &str, args: &[String]) {
let cmds = self.commands.clone();
let cmds_ref = cmds.borrow_mut();
let cmd = cmds_ref.find(&command.to_string());
if let Some(cmd) = cmd {
cmd.borrow_mut().run(self, args);
} else {
drop(cmds_ref);
self.command_not_found(command)
}
}
pub fn run_at(&mut self, command: &str, args: &[String], at: u64) {
let old_loc = mem::replace(&mut self.loc, at);
self.run(command, args);
self.loc = old_loc;
}
pub fn help(&mut self, command: &str) {
let cmds = self.commands.clone();
let cmds_ref = cmds.borrow();
let cmd = cmds_ref.find(&command.to_string());
if let Some(cmd) = cmd {
cmd.borrow().help(self);
} else {
drop(cmds_ref);
self.command_not_found(command);
}
}
}
#[cfg(test)]
mod test_core {
use super::*;
use utils::Quit;
#[test]
fn test_loc() {
let mut core = Core::new_no_colors();
core.set_loc(0x500);
assert_eq!(core.get_loc(), 0x500);
}
#[test]
fn test_add_command() {
let mut core = Core::new_no_colors();
core.stderr = Writer::new_buf();
core.stdout = Writer::new_buf();
core.add_command("a_non_existing_command", "a", Rc::new(RefCell::new(Quit::new())));
assert_eq!(core.stderr.utf8_string().unwrap(), "");
assert_eq!(core.stdout.utf8_string().unwrap(), "");
core.stderr = Writer::new_buf();
core.stdout = Writer::new_buf();
core.add_command("test_command", "s", Rc::new(RefCell::new(Quit::new())));
assert_eq!(core.stderr.utf8_string().unwrap(), "Error: Cannot add this command.\nCommand s already existed.\n");
core.stderr = Writer::new_buf();
core.stdout = Writer::new_buf();
core.add_command("seek", "test_stuff", Rc::new(RefCell::new(Quit::new())));
assert_eq!(core.stderr.utf8_string().unwrap(), "Error: Cannot add this command.\nCommand seek already existed.\n");
}
#[test]
fn test_help() {
let mut core = Core::new_no_colors();
core.stderr = Writer::new_buf();
core.stdout = Writer::new_buf();
core.help("seeker");
assert_eq!(core.stdout.utf8_string().unwrap(), "");
assert_eq!(core.stderr.utf8_string().unwrap(), "Error: Execution failed\nCommand seeker is not found.\nSimilar command: seek.\n");
}
#[test]
fn test_run_at() {
let mut core = Core::new_no_colors();
core.stderr = Writer::new_buf();
core.stdout = Writer::new_buf();
core.run_at("mep", &[], 0x500);
assert_eq!(core.stdout.utf8_string().unwrap(), "");
assert_eq!(
core.stderr.utf8_string().unwrap(),
"Error: Execution failed\nCommand mep is not found.\nSimilar command: map, maps, m, e, er, eh.\n"
);
}
}