1use crate::context::Context;
2use crate::parser::Constant;
3use crate::parser::substitute;
4use crate::formattedtext::FormattedText;
5
6pub fn is_command(
7 s: &String
8) -> bool {
9 let args: Vec<&str> = s.split(" ").collect();
10 let first = args[0];
11
12 match first {
13 "help" | "clear"
14 | "ops" | "operators"
15 | "fns" | "functions"
16 | "vars"
17 | "consts" | "constants"
18 | "del" | "delete"
19 | "flags"
20 => true,
21 _ => false
22 }
23}
24
25#[inline(always)]
26fn greeter() -> FormattedText {
27 return FormattedText::new(
28 format!(
29 concat!(
30 "[a] ###### [n] @@@@@@\n",
31 "[a] # ##[n]@@ @\n",
32 "[a] ## #[n]@ @@\n",
33 "[a] [n]@@@@@@@@@@@@@[a]\n",
34 "[n] @@ @[a]# ##\n",
35 "[n] @ @@[a]## #\n",
36 "[n] @@@@@@ [a] ###### [n]\n",
37 " [t]Daisy[n] [i]v{ver}[n]\n",
38 "\n"
39 ),
40 ver = env!("CARGO_PKG_VERSION")
41 )
42 );
43}
44
45
46#[inline(always)]
47pub fn do_command(
48 context: &mut Context,
49 s: &String,
50) -> FormattedText {
51 let args: Vec<&str> = s.split(" ").collect();
52 let first = args[0];
53
54 match first {
55 "help" => {
56 let mut t = greeter();
57
58 t.push(
59 concat!(
60 "Daisy is a high-precision, general-purpose\n",
61 "scientific calculator.\n",
62 "\n",
63 " - Use Up/Down arrows to navigate history.\n",
64 " - Use Ctrl-C or Ctrl-D to quit.\n",
65 " - Use [c]ans[n] to reference the last result.\n",
66 " - Use [c]var = 1337[n] to define varibles.\n",
67 "\n",
68 "╞═══════════════ [t]Commands[n] ═══════════════╡\n",
69 " [c]help[n] Show this help\n",
70 " [c]flags[n] Show command-line options\n",
71 " [c]clear[n] Clear the terminal\n",
72 " [c]quit[n] Exit daisy\n",
73 " [c]consts[n] List built-in constants\n",
75 " [c]ops[n] List built-in operators\n",
76 " [c]fns[n] List built-in functions\n",
77 " [c]vars[n] List user-defined variables\n",
78 " [c]del[n] Delete a variable\n",
79 "\n\n",
80 )
81 );
82
83 return t;
84 },
85
86 "flags" => {
87 return FormattedText::new(
88 concat!(
89 "\n",
90 "A list of command-line arguments is below\n",
91 "\n",
92 "╞════ [t]Flag[n] ════╪════════════════ [t]Function[n] ════════════════╡\n",
93 " [c]--help[n] Show help\n",
94 " [c]--version[n] Show version\n",
95 " [c]--info[n] Show system information\n",
96 " [c]--256color[n] Use full color support (default)\n",
97 " [c]--8color[n] Use reduced colors (ANSI, no styling)\n",
98 " [c]--nocolor[n] Do not use colors and styling\n",
99 " [c]--nosub[n] Disable inline substitution\n",
100 " [c]--nosuper[n] Disable superscript powers\n",
101 " [c]--nooneover[n] Disable \"one-over\" fractions as -1 power\n",
102 "\n\n"
103 ).to_string()
104 );
105 },
106
107 "clear" => {
108 return FormattedText::new("[clear]".to_string());
109 },
110
111 "ops" | "operators" => {
112 return FormattedText::new(
113 concat!(
114 "\n",
115 "Operators, sorted by priority (high to low).\n",
116 "High-piority operators are applied first.\n\n",
117 "╞═════ [t]Operator[n] ═════╪═════ [t]Syntax[n] ═════╡\n",
118 " function [c]sin, cos, etc[n]\n",
119 " factorial [c]![n]\n",
120 " powers [c]^, **[n]\n",
121 " implicit multiply [c]3π, 3(2+1), etc[n]\n",
122 " square root [c]sqrt, rt, √[n]\n",
123 " negate [c]-3, -(1 + 2)[n]\n",
124 " modulo (short) [c]%[n]\n",
125 " multiply, divide [c]*, /, ×, ÷[n]\n",
126 " add, subtract [c]+, -[n]\n",
127 " unit conversion [c]to[n]\n",
128 " division (long) [c]per[n]\n",
129 " modulo (long) [c]mod[n]\n",
130 "\n\n"
131 ).to_string()
132 );
133 },
134
135 "fns" | "functions" => {
136 return FormattedText::new(
137 concat!(
138 "\n╞═══════ [t]Function[n] ═══════╪══════ [t]Syntax[n] ══════╡\n",
139 " absolute value [c]abs[n]\n",
140 " floor, ceiling, round [c]floor, ceil, round[n]\n",
141 " log base e [c]ln[n]\n",
142 " log base 10 [c]log[n]\n",
143 " sin, arcsin, cosecant [c]sin, asin, csc[n]\n",
144 " cos, arccos, secant [c]cos, acos, secant[n]\n",
145 " tan, arctan, cotan [c]tan, atan, cot[n]\n",
146 " hyperbolic sin, etc [c]sinh, asinh, csch[n]\n",
147 " hyperbolic cos, etc [c]cosh, acosh, sech[n]\n",
148 " hyperbolic tan, etc [c]tanh, atanh, coth[n]\n",
149 "\n",
150 " Celsius to Kelvin [c]fromC, fromCelsius[n]\n",
151 " Kelvin to Celsius [c]toC, toCelsius[n]\n",
152 " Fahrenheit to Kelvin [c]fromF, fromFahrenheit[n]\n",
153 " Kelvin to Fahrenheit [c]toF, toFahrenheit[n]\n",
154 "\n",
155 " convert to base unit [c]tobase[n]\n",
156 " remove units [c]nounit[n]\n",
157 "\n\n"
158 ).to_string()
159 );
160 },
161
162 "vars" => {
163 let v = context.get_variables();
164 let f = context.get_functions();
165
166 if v.len() + f.len() == 0 {
167 return FormattedText::new(
168 "You have not defined any variables\n\n".to_string()
169 );
170 }
171
172 let mut t = FormattedText::new("".to_string());
173
174 let mut longest = 0;
175 for (key, _) in v {
176 if key.len() > longest {
177 longest = key.len();
178 }
179 }
180 for (key, (args, _exp)) in f {
181 let s = format!("{key}({})", args.join(", "));
182 if s.len() > longest {
183 longest = s.len();
184 }
185 }
186
187
188 if v.len() != 0 {
189 t.push("\n╞═══ [t]User-Defined Variables[n] ═══╡\n");
190
191 for (key, value) in v {
192 let padding = " ".repeat(longest - key.len());
193
194 t.push(&format!(
195 " {key}{padding} = [c]{v}[n]\n",
196 v = value.display(context),
197 ));
198 }
199 }
200
201 if f.len() != 0 {
202 t.push("\n╞═══ [t]User-Defined Functions[n] ═══╡\n");
203
204 for (key, (args, exp)) in f {
205 let s = format!("{key}({})", args.join(", "));
206 let padding = " ".repeat(longest - s.len());
207
208 t.push(&format!(
209 " {s}{padding} = [c]{v}[n]\n",
210 v = exp.display(context),
211 ));
212 }
213 }
214
215 t.push("\n\n");
216 return t;
217 },
218
219 "consts" | "constants" => {
220 let a = Constant::all_consts();
221
222 let mut t = FormattedText::new(
223 "\n╞═══ [t]Built-in Constants[n] ═══╡\n".to_string()
224 );
225
226
227 for c in a {
228 let Some(p) = c.pretty_name() else { continue };
229
230 let padding = " ".repeat(25 - p.chars().count());
233
234 t.push(&format!(
235 " {p}{padding}: [c]{s}[n]",
236 s = c.source_strings().join(", "),
237 ));
238
239 t.push(&"\n");
240 }
241
242 t.push(&"\n\n");
243 return t;
244 },
245
246 "del" | "delete" => {
247 if args.len() != 2 {
248 return FormattedText::new(
249 format!(
250 "[c]{first}[n] [e]takes exactly one argument.[n]\n\n",
251 )
252 );
253 }
254
255 let v = args[1].to_string();
256 let v = substitute(context, &v);
257 let r = context.delete(&v);
258
259 return match r {
260 Ok(()) => { FormattedText::new("".to_string()) },
261 Err(()) => {
262 FormattedText::new(
263 format!(
264 "[c]{v}[n] [e]isn't a variable.[n]\n\n",
265 )
266 )
267 }
268 };
269 },
270
271 _ => unreachable!("Bad command!")
272 };
273}