daisycalc/command/
mod.rs

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]units[n]  List available units\n",
74					"      [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				// If you subtract with overflow here,
231				// your padding length is too short.
232				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}