use common_macros::hash_map;
use crate::libs::BuiltinInfo;
use crate::libs::helper::{check_exact_args_len, get_integer_ref};
use crate::{
CFM_CONFIG, Environment, Expression, Int, LmError, MAX_RUNTIME_RECURSION, MAX_SYNTAX_RECURSION,
MAX_USEMODE_RECURSION, PRINT_DIRECT, RuntimeError, STRICT_ENABLED, SyntaxError,
set_cfm_enabled, set_print_direct, set_strict_enabled,
};
use std::collections::BTreeMap;
use crate::libs::lazy_module::LazyModule;
use crate::{reg_info, reg_lazy};
pub fn regist_lazy() -> LazyModule {
reg_lazy!({
dirs, env, vars, has, defined,
error_codes,
info,modes,
max_syntax,
max_runtime,
max_usemode,
set_cfm,
set_pdm,
set_strict
})
}
pub fn regist_info() -> BTreeMap<&'static str, BuiltinInfo> {
reg_info!({
dirs => "system directories map", ""
env => "root env map, or var value", "[var]"
vars => "vars defined in current scope", ""
has => "defined in current scope?", "<var>"
defined => "defined in scope chain?", "<var>"
error_codes => "list lume error codes", ""
info => "os info", ""
modes => "current mode flags {cfm,strict,pdm}", ""
max_syntax => "get/set max syntax recursion depth", "[depth]"
max_runtime => "get/set max runtime recursion depth", "[depth]"
max_usemode => "get/set max use-mode recursion depth", "[depth]"
set_cfm => "set Cmd First Mode", "<boolean|none>"
set_pdm => "enable/disable print direct mode", "<boolean>"
set_strict => "enable/disable strict mode", "<boolean>"
})
}
fn dirs(
_args: Vec<Expression>,
_env: &mut Environment,
_ctx: &Expression,
) -> Result<Expression, RuntimeError> {
let mut dir_tree = BTreeMap::<String, String>::new();
if let Some(home_dir) = dirs::home_dir() {
dir_tree.insert("home".into(), home_dir.to_string_lossy().into());
}
if let Some(config_dir) = dirs::config_dir() {
dir_tree.insert("config".into(), config_dir.to_string_lossy().into());
}
if let Some(cache_dir) = dirs::cache_dir() {
dir_tree.insert("cache".into(), cache_dir.to_string_lossy().into());
}
if let Some(data_dir) = dirs::data_dir() {
dir_tree.insert("data".into(), data_dir.to_string_lossy().into());
}
if let Some(picture_dir) = dirs::picture_dir() {
dir_tree.insert("pic".into(), picture_dir.to_string_lossy().into());
}
if let Some(desktop_dir) = dirs::desktop_dir() {
dir_tree.insert("desk".into(), desktop_dir.to_string_lossy().into());
}
if let Some(document_dir) = dirs::document_dir() {
dir_tree.insert("docs".into(), document_dir.to_string_lossy().into());
}
if let Some(download_dir) = dirs::download_dir() {
dir_tree.insert("down".into(), download_dir.to_string_lossy().into());
}
Ok(Expression::from(dir_tree))
}
fn info(
_args: Vec<Expression>,
_env: &mut Environment,
_ctx: &Expression,
) -> Result<Expression, RuntimeError> {
let info = os_info::get();
Ok(Expression::String(info.to_string()))
}
fn modes(
_args: Vec<Expression>,
_env: &mut Environment,
_ctx: &Expression,
) -> Result<Expression, RuntimeError> {
Ok(Expression::from(hash_map! {
String::from("cfm") => CFM_CONFIG.with_borrow(|c|format!("{}",
match c{
Some(true) => "ON",
Some(false)=>"OFF",
_=>"AUTO"
}
)),
String::from("strict") => STRICT_ENABLED.with_borrow(|c|format!("{}",c)),
String::from("pdm") => PRINT_DIRECT.with_borrow(|c|format!("{}",c)),
}))
}
fn env(
args: Vec<Expression>,
env: &mut Environment,
_ctx: &Expression,
) -> Result<Expression, RuntimeError> {
if args.len() == 1 {
let name = args[0].to_string();
return Ok(env.get(&name).unwrap_or(Expression::None));
}
Ok(Expression::from(env.get_root().clone()))
}
fn vars(
_args: Vec<Expression>,
env: &mut Environment,
_ctx: &Expression,
) -> Result<Expression, RuntimeError> {
Ok(Expression::from(env.get_bindings_map()))
}
fn has(
args: Vec<Expression>,
env: &mut Environment,
ctx: &Expression,
) -> Result<Expression, RuntimeError> {
check_exact_args_len("has", &args, 1, ctx)?;
let name = args[0].to_string();
Ok(Expression::Boolean(env.has(&name)))
}
fn defined(
args: Vec<Expression>,
env: &mut Environment,
ctx: &Expression,
) -> Result<Expression, RuntimeError> {
check_exact_args_len("defined", &args, 1, ctx)?;
let name = args[0].to_string();
Ok(Expression::Boolean(env.is_defined(&name)))
}
fn error_codes(
_args: Vec<Expression>,
_env: &mut Environment,
_: &Expression,
) -> Result<Expression, RuntimeError> {
let mut ecodes = SyntaxError::codes();
ecodes.extend(RuntimeError::codes());
ecodes.extend(LmError::codes());
Ok(Expression::from(ecodes))
}
fn max_syntax(
args: Vec<Expression>,
_env: &mut Environment,
ctx: &Expression,
) -> Result<Expression, RuntimeError> {
if args.is_empty() {
return Ok(Expression::Integer(
MAX_SYNTAX_RECURSION.with_borrow(|x| *x as Int),
));
}
let i = get_integer_ref(&args[0], ctx)?;
MAX_SYNTAX_RECURSION.with_borrow_mut(|v| *v = i as usize);
Ok(Expression::None)
}
fn max_runtime(
args: Vec<Expression>,
_env: &mut Environment,
ctx: &Expression,
) -> Result<Expression, RuntimeError> {
if args.is_empty() {
return Ok(Expression::Integer(
MAX_RUNTIME_RECURSION.with_borrow(|x| *x as Int),
));
}
let i = get_integer_ref(&args[0], ctx)?;
MAX_RUNTIME_RECURSION.with_borrow_mut(|v| *v = i as usize);
Ok(Expression::None)
}
fn max_usemode(
args: Vec<Expression>,
_env: &mut Environment,
ctx: &Expression,
) -> Result<Expression, RuntimeError> {
if args.is_empty() {
return Ok(Expression::Integer(
MAX_USEMODE_RECURSION.with_borrow(|x| *x as Int),
));
}
let i = get_integer_ref(&args[0], ctx)?;
MAX_USEMODE_RECURSION.with_borrow_mut(|v| *v = i as usize);
Ok(Expression::None)
}
fn set_strict(
args: Vec<Expression>,
env: &mut Environment,
ctx: &Expression,
) -> Result<Expression, RuntimeError> {
check_exact_args_len("set_strict", &args, 1, ctx)?;
let b = args[0].is_truthy();
env.define("IS_STRICT", Expression::Boolean(b));
set_strict_enabled(b);
if b {
println!("\x1b[38;5;141m[STRICT Mode: ON]\x1b[0m");
} else {
println!("\x1b[38;5;209m[STRICT Mode: OFF]\x1b[0m");
}
Ok(Expression::None)
}
fn set_cfm(
args: Vec<Expression>,
env: &mut Environment,
ctx: &Expression,
) -> Result<Expression, RuntimeError> {
check_exact_args_len("set_cfm", &args, 1, ctx)?;
let b = match &args[0] {
Expression::None => None,
other => Some(other.is_truthy()),
};
set_cfm_enabled(b);
if let Some(bv) = b {
env.define_in_root("IS_CFM", Expression::Boolean(bv))
};
let tag = match b {
Some(true) => "ON",
Some(false) => "OFF",
_ => "AUTO",
};
println!("\x1b[38;5;141m[Cmd First Mode: {}]\x1b[0m", tag);
Ok(Expression::None)
}
fn set_pdm(
args: Vec<Expression>,
_env: &mut Environment,
ctx: &Expression,
) -> Result<Expression, RuntimeError> {
check_exact_args_len("set_pdm", &args, 1, ctx)?;
let b = args[0].is_truthy();
set_print_direct(b);
if b {
println!("\x1b[38;5;141m[Print Direct Mode: ON]\x1b[0m");
} else {
println!("\x1b[38;5;209m[Print Direct Mode: OFF]\x1b[0m");
}
Ok(Expression::None)
}