Files
daisy/src/command/mod.rs
Mark e0ca8be79f Added terminal color detection
Added configuration
Cleaned up context args
2023-08-17 10:10:38 -07:00

251 lines
6.4 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

use crate::context::Context;
use crate::parser::Constant;
use crate::parser::substitute;
use crate::formattedtext::FormattedText;
pub fn is_command(
s: &String
) -> bool {
let args: Vec<&str> = s.split(" ").collect();
let first = args[0];
match first {
"help" | "clear"
| "ops" | "operators"
| "fns" | "functions"
| "vars"
| "consts" | "constants"
| "del" | "delete"
=> true,
_ => false
}
}
#[inline(always)]
fn greeter() -> FormattedText {
return FormattedText::new(
format!(
concat!(
"[a] ###### [n] @@@@@@\n",
"[a] # ##[n]@@ @\n",
"[a] ## #[n]@ @@\n",
"[a] [n]@@@@@@@@@@@@@[a]\n",
"[n] @@ @[a]# ##\n",
"[n] @ @@[a]## #\n",
"[n] @@@@@@ [a] ###### [n]\n",
" [t]Daisy[n] [i]v{ver}[n]\n",
"\n"
),
ver = env!("CARGO_PKG_VERSION")
)
);
}
#[inline(always)]
pub fn do_command(
context: &mut Context,
s: &String,
) -> FormattedText {
let args: Vec<&str> = s.split(" ").collect();
let first = args[0];
match first {
"help" => {
let mut t = greeter();
t.push(
concat!(
"Daisy is a high-precision, general-purpose\n",
"scientific calculator.\n",
"\n",
" - Use Up/Down arrows to navigate history.\n",
" - Use Ctrl-C or Ctrl-D to quit.\n",
" - Use [c]ans[n] to reference the last result.\n",
" - Use [c]var = 1337[n] to define varibles.\n",
"\n",
"╞═══════════════ [t]Commands[n] ═══════════════╡\n",
" [c]help[n] Show this help\n",
" [c]clear[n] Clear the terminal\n",
" [c]quit[n] Exit daisy\n",
//" [c]units[n] List available units\n",
" [c]consts[n] List built-in constants\n",
" [c]ops[n] List built-in operators\n",
" [c]fns[n] List built-in functions\n",
" [c]vars[n] List user-defined variables\n",
" [c]del[n] Delete a variable\n",
"\n\n",
)
);
return t;
},
"clear" => {
return FormattedText::new("[clear]".to_string());
},
"ops" | "operators" => {
return FormattedText::new(
concat!(
"\n",
"Operators, sorted by priority (high to low).\n",
"High-piority operators are applied first.\n\n",
"╞═════ [t]Operator[n] ═════╪═════ [t]Syntax[n] ═════╡\n",
" function [c]sin, cos, etc[n]\n",
" factorial [c]![n]\n",
" powers [c]^, **[n]\n",
" implicit multiply [c]3π, 3(2+1), etc[n]\n",
" square root [c]sqrt, rt, √[n]\n",
" negate [c]-3, -(1 + 2)[n]\n",
" modulo (short) [c]%[n]\n",
" multiply, divide [c]*, /, ×, ÷[n]\n",
" add, subtract [c]+, -[n]\n",
" unit conversion [c]to[n]\n",
" division (long) [c]per[n]\n",
" modulo (long) [c]mod[n]\n",
"\n\n"
).to_string()
);
},
"fns" | "functions" => {
return FormattedText::new(
concat!(
"\n╞═══════ [t]Function[n] ═══════╪══════ [t]Syntax[n] ══════╡\n",
" absolute value [c]abs[n]\n",
" floor, ceiling, round [c]floor, ceil, round[n]\n",
" log base e [c]ln[n]\n",
" log base 10 [c]log[n]\n",
" sin, arcsin, cosecant [c]sin, asin, csc[n]\n",
" cos, arccos, secant [c]cos, acos, secant[n]\n",
" tan, arctan, cotan [c]tan, atan, cot[n]\n",
" hyperbolic sin, etc [c]sinh, asinh, csch[n]\n",
" hyperbolic cos, etc [c]cosh, acosh, sech[n]\n",
" hyperbolic tan, etc [c]tanh, atanh, coth[n]\n",
"\n",
" Celsius to Kelvin [c]fromC, fromCelsius[n]\n",
" Kelvin to Celsius [c]toC, toCelsius[n]\n",
" Fahrenheit to Kelvin [c]fromF, fromFahrenheit[n]\n",
" Kelvin to Fahrenheit [c]toF, toFahrenheit[n]\n",
"\n",
" convert to base unit [c]tobase[n]\n",
" remove units [c]nounit[n]\n",
"\n\n"
).to_string()
);
},
"vars" => {
let v = context.get_variables();
let f = context.get_functions();
if v.len() + f.len() == 0 {
return FormattedText::new(
"You have not defined any variables\n\n".to_string()
);
}
let mut t = FormattedText::new("".to_string());
let mut longest = 0;
for (key, _) in v {
if key.len() > longest {
longest = key.len();
}
}
for (key, (args, _exp)) in f {
let s = format!("{key}({})", args.join(", "));
if s.len() > longest {
longest = s.len();
}
}
if v.len() != 0 {
t.push("\n╞═══ [t]User-Defined Variables[n] ═══╡\n");
for (key, value) in v {
let padding = " ".repeat(longest - key.len());
t.push(&format!(
" {key}{padding} = [c]{v}[n]\n",
v = value.display(context),
));
}
}
if f.len() != 0 {
t.push("\n╞═══ [t]User-Defined Functions[n] ═══╡\n");
for (key, (args, exp)) in f {
let s = format!("{key}({})", args.join(", "));
let padding = " ".repeat(longest - s.len());
t.push(&format!(
" {s}{padding} = [c]{v}[n]\n",
v = exp.display(context),
));
}
}
t.push("\n\n");
return t;
},
"consts" | "constants" => {
let a = Constant::all_consts();
let mut t = FormattedText::new(
"\n╞═══ [t]Built-in Constants[n] ═══╡\n".to_string()
);
for c in a {
let Some(p) = c.pretty_name() else { continue };
// If you subtract with overflow here,
// your padding length is too short.
let padding = " ".repeat(25 - p.chars().count());
t.push(&format!(
" {p}{padding}: [c]{s}[n]",
s = c.source_strings().join(", "),
));
t.push(&"\n");
}
t.push(&"\n\n");
return t;
},
"del" | "delete" => {
if args.len() != 2 {
return FormattedText::new(
format!(
"[c]{first}[n] [t]takes exactly two arguments.[n]\n\n",
)
);
}
let v = args[1].to_string();
let v = substitute(context, &v);
let r = context.delete(&v);
return match r {
Ok(()) => { FormattedText::new("".to_string()) },
Err(()) => {
FormattedText::new(
format!(
"[c]{v}[n] [t]isn't a variable.[n]\n\n",
)
)
}
};
},
_ => unreachable!("Bad command!")
};
}