mirror of
https://github.com/rm-dr/daisy
synced 2025-04-16 09:55:59 -07:00
274 lines
7.3 KiB
Rust
274 lines
7.3 KiB
Rust
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"
|
||
| "flags"
|
||
=> 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]flags[n] Show command-line options\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;
|
||
},
|
||
|
||
"flags" => {
|
||
return FormattedText::new(
|
||
concat!(
|
||
"\n",
|
||
"A list of command-line arguments is below\n",
|
||
"\n",
|
||
"╞════ [t]Flag[n] ════╪════════════════ [t]Function[n] ════════════════╡\n",
|
||
" [c]--help[n] Show help\n",
|
||
" [c]--version[n] Show version\n",
|
||
" [c]--info[n] Show system information\n",
|
||
" [c]--256color[n] Use full color support (default)\n",
|
||
" [c]--8color[n] Use reduced colors (ANSI, no styling)\n",
|
||
" [c]--nocolor[n] Do not use colors and styling\n",
|
||
" [c]--nosub[n] Disable inline substitution\n",
|
||
" [c]--nosuper[n] Disable superscript powers\n",
|
||
" [c]--nooneover[n] Disable \"one-over\" fractions as -1 power\n",
|
||
"\n\n"
|
||
).to_string()
|
||
);
|
||
},
|
||
|
||
"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 one argument.[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!")
|
||
};
|
||
}
|