1use crate::calc::context::Context;
2use crate::calc::meaning::AreaKind::*;
3use crate::calc::meaning::DeltaKind::*;
4use crate::calc::meaning::LengthKind::*;
5use crate::calc::meaning::SpeedKind::*;
6use crate::calc::meaning::VolumeKind::*;
7use crate::calc::meaning::*;
8use crate::calc::undo::Undo;
9use crate::calc::value::{Value, ValueRef};
10use crate::core::action::Action;
11use crate::core::count::Count;
12use crate::core::helper::{CommandEditor, CommandHelper};
13use crate::core::stack::ValueStack;
14use crate::engine::Engine;
15use crate::error::MyResult;
16use itertools::Itertools;
17use rustyline::config::Configurer;
18use rustyline::CompletionType;
19use std::cell::RefCell;
20use std::collections::{BTreeMap, BTreeSet, HashMap};
21use std::io::Write;
22use std::rc::Rc;
23use std::time::SystemTime;
24
25pub enum Operation<W: Write> {
26 ValueNone(fn() -> MyResult<ValueRef>),
27 ValueOne(fn(ValueRef) -> MyResult<ValueRef>),
28 ValueTwo(fn(ValueRef, ValueRef) -> MyResult<ValueRef>),
29 ValueAll(fn(Vec<ValueRef>) -> MyResult<ValueRef>),
30 SeriesTwo(fn(ValueRef, ValueRef) -> MyResult<Vec<ValueRef>>),
31 SeriesThree(fn(ValueRef, ValueRef, ValueRef) -> MyResult<Vec<ValueRef>>),
32 SeriesAll(fn(Vec<ValueRef>) -> MyResult<Vec<ValueRef>>),
33 TimeNow(fn(&Option<SystemTime>) -> MyResult<ValueRef>),
34 TimeCast(Meaning),
35 ContextNone(fn(&mut Context)),
36 ContextOne(fn(&mut Context, ValueRef)),
37 EngineNone(fn(&mut Engine<W>, &mut W, &mut ValueStack) -> MyResult<Option<bool>>),
38 EngineUndo(fn(&mut Engine<W>, &mut ValueStack, &mut Undo, &mut Undo, Option<&str>) -> MyResult<Option<bool>>, Count, Count),
39}
40
41impl<W: Write> Operation<W> {
42 pub fn count_parameters(&self) -> (Count, Count) {
43 match self {
44 Self::ValueNone(_) => (Count::N(0), Count::N(1)),
45 Self::ValueOne(_) => (Count::N(1), Count::N(1)),
46 Self::ValueTwo(_) => (Count::N(2), Count::N(1)),
47 Self::ValueAll(_) => (Count::All, Count::N(1)),
48 Self::SeriesTwo(_) => (Count::N(2), Count::All),
49 Self::SeriesThree(_) => (Count::N(3), Count::All),
50 Self::SeriesAll(_) => (Count::All, Count::All),
51 Self::TimeNow(_) => (Count::N(0), Count::N(1)),
52 Self::TimeCast(_) => (Count::N(1), Count::N(1)),
53 Self::ContextNone(_) => (Count::N(0), Count::N(0)),
54 Self::ContextOne(_) => (Count::N(1), Count::N(0)),
55 Self::EngineNone(_) => (Count::N(0), Count::N(0)),
56 Self::EngineUndo(_, input, output) => (*input, *output),
57 }
58 }
59}
60
61#[derive(Clone, Copy, Debug, PartialEq)]
62pub enum Completion {
63 Keyword,
64 Filename,
65}
66
67pub enum Directive<W: Write> {
68 EngineOne(fn(&mut Engine<W>, &mut W, &mut ValueStack, Option<String>) -> MyResult<bool>, Completion),
69 EngineAll(fn(&mut Engine<W>, &mut W, &mut ValueStack, Vec<String>) -> MyResult<bool>, Completion),
70 EngineApply(fn(&mut Engine<W>, &mut W, Option<&str>, &mut ValueStack, &mut Undo, &mut Undo, Vec<String>) -> MyResult<bool>, Completion),
71}
72
73pub enum Description {
74 Separator(String),
75 Operation((String, Count, Count, String)),
76 Directive((String, String)),
77}
78
79pub type Operations<W> = HashMap<String, Rc<Operation<W>>>;
80pub type Meanings = HashMap<String, Meaning>;
81pub type Directives<W> = HashMap<String, Rc<Directive<W>>>;
82pub type Definitions<W> = BTreeMap<String, (Vec<Action<W>>, Count, Count, String)>;
83pub type Descriptions = Vec<Description>;
84
85pub struct Interface<W: Write> {
86 operations: Operations<W>,
87 meanings: Meanings,
88 directives: Directives<W>,
89 definitions: Definitions<W>,
90 variables: HashMap<String, ValueRef>,
91 descriptions: Descriptions,
92}
93
94impl<W: Write> Interface<W> {
95 pub fn new() -> Self {
96 let operations = Operations::new();
97 let meanings = Meanings::new();
98 let directives = Directives::new();
99 let definitions = Definitions::new();
100 let variables = HashMap::new();
101 let descriptions = Descriptions::new();
102 Self { operations, meanings, directives, definitions, variables, descriptions }
103 }
104
105 pub fn build() -> Self {
106 let interface = Self::new();
107 let interface = interface
108 .with_separator("Arithmetic operations")
109 .with_operation(vec!["add", "+"], Operation::ValueTwo(Value::calc_add), "Add two values")
110 .with_operation(vec!["sub", "-"], Operation::ValueTwo(Value::calc_sub), "Subtract two values")
111 .with_operation(vec!["mul", "*"], Operation::ValueTwo(Value::calc_mul), "Multiply two values")
112 .with_operation(vec!["div", "/"], Operation::ValueTwo(Value::calc_div), "Divide two values")
113 .with_operation(vec!["mod", "%"], Operation::ValueTwo(Value::calc_mod), "Modulo two values")
114 .with_operation(vec!["neg"], Operation::ValueOne(Value::calc_neg), "Find the negative")
115 .with_operation(vec!["inv"], Operation::ValueOne(Value::calc_inv), "Find the inverse")
116 .with_operation(vec!["pow"], Operation::ValueTwo(Value::calc_pow), "Raise to the power")
117 .with_operation(vec!["sqrt"], Operation::ValueOne(Value::calc_sqrt), "Find the square root")
118 .with_operation(vec!["sum"], Operation::ValueAll(Value::calc_sum), "Sum all values")
119 .with_operation(vec!["prod"], Operation::ValueAll(Value::calc_prod), "Multiply all values");
120 let interface = interface
121 .with_separator("Sequence operations")
122 .with_operation(vec!["seq"], Operation::SeriesTwo(Value::calc_seq), "Generate integer sequence (start to stop)")
123 .with_operation(vec!["step"], Operation::SeriesThree(Value::calc_step), "Generate integer sequence (start with step to stop)")
124 .with_operation(vec!["sort"], Operation::SeriesAll(Value::sort_seq), "Sort stack or sequence")
125 .with_operation(vec!["rev"], Operation::SeriesAll(Value::rev_seq), "Reverse stack or sequence")
126 .with_operation(vec!["flat"], Operation::EngineUndo(Engine::flat_values, Count::All, Count::All), "Flatten entire stack");
127 let interface = interface
128 .with_separator("Bitwise operations")
129 .with_operation(vec!["and"], Operation::ValueTwo(Value::calc_and), "Bitwise AND two values")
130 .with_operation(vec!["or"], Operation::ValueTwo(Value::calc_or), "Bitwise OR two values")
131 .with_operation(vec!["xor"], Operation::ValueTwo(Value::calc_xor), "Bitwise XOR two values")
132 .with_operation(vec!["shl"], Operation::ValueTwo(Value::calc_shl), "Shift left (multiply by power of 2)")
133 .with_operation(vec!["shr"], Operation::ValueTwo(Value::calc_shr), "Shift right (divide by power of 2)");
134 let interface = interface
135 .with_separator("Time operations")
136 .with_operation(vec!["now"], Operation::TimeNow(Value::calc_now), "Get the current time (in UTC)")
137 .with_operation(vec!["plain"], Operation::TimeCast(Meaning::Plain), "Format as a plain value")
138 .with_operation(vec!["delta"], Operation::TimeCast(Meaning::Delta(HMS)), "Format as a delta value (duration)")
139 .with_operation(vec!["time"], Operation::TimeCast(Meaning::Time), "Format as a time value (in UTC)");
140 let interface = interface
141 .with_separator("Formatting commands")
142 .with_operation(vec!["dec"], Operation::ContextNone(Context::set_dec), "Format as decimal values")
143 .with_operation(vec!["hex"], Operation::ContextNone(Context::set_hex), "Format as hexadecimal values")
144 .with_operation(vec!["sep"], Operation::ContextNone(Context::set_sep), "Include comma separators")
145 .with_operation(vec!["nosep"], Operation::ContextNone(Context::no_sep), "Include no separators")
146 .with_operation(vec!["dp"], Operation::ContextOne(Context::set_dp), "Use fixed decimal places")
147 .with_operation(vec!["nodp"], Operation::ContextNone(Context::no_dp), "Use free decimal places");
148 let interface = interface
149 .with_separator("Stack commands")
150 .with_operation(vec!["show"], Operation::EngineNone(Engine::show_stack), "Show all values on the stack")
151 .with_operation(vec!["clear"], Operation::EngineUndo(Engine::clear_values, Count::All, Count::N(0)), "Remove all values from the stack")
152 .with_operation(vec!["pop"], Operation::EngineUndo(Engine::pop_value, Count::N(1), Count::N(0)), "Remove a value from the stack")
153 .with_operation(vec!["dup"], Operation::EngineUndo(Engine::dup_value, Count::N(1), Count::N(2)), "Duplicate a value on the stack")
154 .with_operation(vec!["swap"], Operation::EngineUndo(Engine::swap_values, Count::N(2), Count::N(2)), "Swap two values on the stack")
155 .with_operation(vec!["cut"], Operation::EngineUndo(Engine::cut_value, Count::N(1), Count::N(0)), "Cut a value to the internal clipboard")
156 .with_operation(vec!["copy"], Operation::EngineUndo(Engine::copy_value, Count::N(1), Count::N(1)), "Copy a value to the internal clipboard")
157 .with_operation(vec!["paste"], Operation::EngineUndo(Engine::paste_value, Count::N(0), Count::N(1)), "Paste a value from the internal clipboard");
158 let interface = interface
159 .with_separator("History commands")
160 .with_operation(vec!["undo", "u"], Operation::EngineUndo(Engine::undo_stack, Count::N(0), Count::N(0)), "Undo the last operation")
161 .with_operation(vec!["redo", "r"], Operation::EngineUndo(Engine::redo_stack, Count::N(0), Count::N(0)), "Redo the next operation")
162 .with_operation(vec!["hist"], Operation::EngineNone(Engine::show_history), "Show all undo/redo history");
163 let interface = interface
164 .with_separator("General directives")
165 .with_directive(vec!["import"], Directive::EngineAll(Engine::import_file, Completion::Filename), "Import file e.g. \"import file.txt\"")
166 .with_directive(vec!["export"], Directive::EngineAll(Engine::export_file, Completion::Filename), "Export file e.g. \"export file.txt\"")
167 .with_directive(vec!["set", "="], Directive::EngineOne(Engine::set_variable, Completion::Keyword), "Set variable, e.g. \"set x\"")
168 .with_directive(vec!["define"], Directive::EngineAll(Engine::define_function, Completion::Keyword), "Define function e.g. \"define cube 3 pow\"")
169 .with_directive(vec!["apply"], Directive::EngineApply(Engine::apply_all, Completion::Keyword), "Apply to stack or sequence, e.g. \"apply 3 pow\"");
170 let interface = interface
171 .with_separator("General commands")
172 .with_operation(vec!["units"], Operation::EngineNone(Engine::show_units), "Show unit names and symbols")
173 .with_operation(vec!["help"], Operation::EngineNone(Engine::show_help), "Show this help text");
174 let meanings = Meaning::get_meanings().unwrap_or_default();
175 interface.with_meanings(meanings)
176 }
177
178 fn with_separator(mut self, description: &str) -> Self {
179 self.descriptions.push(Description::Separator(String::from(description)));
180 self
181 }
182
183 fn with_operation(
184 mut self,
185 keywords: Vec<&str>,
186 operation: Operation<W>,
187 description: &str,
188 ) -> Self {
189 let operation = Rc::new(operation);
190 for keyword in keywords.iter() {
191 self.operations.insert(keyword.to_string(), Rc::clone(&operation));
192 }
193 let keywords = Self::describe_keywords(keywords);
194 let (input, output) = operation.count_parameters();
195 self.descriptions.push(Description::Operation((
196 keywords,
197 input,
198 output,
199 String::from(description),
200 )));
201 self
202 }
203
204 fn with_meanings(
205 mut self,
206 meanings: Meanings,
207 ) -> Self {
208 self.meanings = meanings;
209 self
210 }
211
212 fn with_directive(
213 mut self,
214 keywords: Vec<&str>,
215 directive: Directive<W>,
216 description: &str,
217 ) -> Self {
218 let directive = Rc::new(directive);
219 for keyword in keywords.iter() {
220 self.directives.insert(keyword.to_string(), Rc::clone(&directive));
221 }
222 let keyword = Self::describe_keywords(keywords);
223 self.descriptions.push(Description::Directive((
224 format!("{keyword}..."),
225 String::from(description),
226 )));
227 self
228 }
229
230 #[cfg(test)]
231 fn with_definition(
232 mut self,
233 keyword: &str,
234 actions: Vec<Action<W>>,
235 input: Count,
236 output: Count,
237 description: String,
238 ) -> Self {
239 self.insert_definition(keyword, actions, input, output, description);
240 self
241 }
242
243 pub fn insert_definition(
244 &mut self,
245 keyword: &str,
246 actions: Vec<Action<W>>,
247 input: Count,
248 output: Count,
249 description: String,
250 ) {
251 self.definitions.insert(keyword.to_string(), (actions, input, output, description));
252 }
253
254 pub fn remove_definition(&mut self, keyword: &str) {
255 self.definitions.remove(keyword);
256 }
257
258 pub fn insert_variable(&mut self, keyword: String, value: ValueRef) -> bool {
259 self.variables.insert(keyword, value).is_some()
260 }
261
262 pub fn remove_variable(&mut self, keyword: &str) {
263 self.variables.remove(keyword);
264 }
265
266 pub fn get_variable(&self, keyword: &str) -> Option<ValueRef> {
267 if let Some(value) = self.variables.get(keyword) {
268 let value = value.as_ref().borrow().clone();
269 return Some(Rc::new(RefCell::new(value)));
270 }
271 None
272 }
273
274 pub fn get_variables(&self) -> &HashMap<String, ValueRef> {
275 &self.variables
276 }
277
278 fn describe_keywords(keywords: Vec<&str>) -> String {
279 if keywords.len() == 2 {
280 let primary = keywords[0];
281 let secondary = keywords[1];
282 if primary.starts_with(secondary) {
283 let chop = secondary.len();
284 return format!("{}({})", secondary, &primary[chop..]);
285 }
286 }
287 keywords.iter().map(|x| x.to_string()).join(",")
288 }
289
290 pub fn create_editor(&self) -> MyResult<CommandEditor> {
291 let mut editor = CommandEditor::new()?;
292 editor.set_helper(Some(CommandHelper::new()));
293 editor.set_completion_type(CompletionType::List);
294 self.adjust_editor(&mut editor);
295 Ok(editor)
296 }
297
298 pub fn adjust_editor(&self, editor: &mut CommandEditor) {
299 if let Some(helper) = editor.helper_mut() {
300 helper.set_commands(self.get_commands());
301 helper.set_completions(self.get_completions());
302 }
303 }
304
305 fn get_commands(&self) -> Vec<String> {
306 let commands = self.operations.keys()
307 .chain(self.meanings.keys())
308 .chain(self.directives.keys())
309 .chain(self.definitions.keys())
310 .chain(self.variables.keys())
311 .map(String::clone)
312 .collect::<BTreeSet<String>>();
313 commands.into_iter().collect::<Vec<String>>()
314 }
315
316 fn get_completions(&self) -> HashMap<String, Completion> {
317 let mut completions = HashMap::new();
318 for (keyword, directive) in self.directives.iter() {
319 match directive.as_ref() {
320 Directive::EngineOne(_, completion) => {
321 completions.insert(String::from(keyword), *completion);
322 }
323 Directive::EngineAll(_, completion) => {
324 completions.insert(String::from(keyword), *completion);
325 }
326 Directive::EngineApply(_, completion) => {
327 completions.insert(String::from(keyword), *completion);
328 }
329 }
330 }
331 completions
332 }
333
334 pub fn get_operation(&self, keyword: &str) -> Option<Rc<Operation<W>>> {
335 self.operations.get(keyword).map(Rc::clone)
336 }
337
338 pub fn get_meaning(&self, keyword: &str) -> Option<Meaning> {
339 self.meanings.get(keyword).map(Meaning::clone)
340 }
341
342 pub fn get_directive(&self, keyword: &str) -> Option<Rc<Directive<W>>> {
343 self.directives.get(keyword).map(Rc::clone)
344 }
345
346 pub fn get_definition(&self, keyword: &str) -> Option<Vec<Action<W>>> {
347 self.definitions.get(keyword).map(|(x, _, _, _)| x).map(Vec::clone)
348 }
349
350 pub fn show_units(&self, writer: &mut W, interact: bool) -> MyResult<()> {
351 let indent = if interact { " " } else { "" };
352 Self::format_prefixes(writer, indent, "Prefix")?;
353 Self::format_units::<DeltaKind, _>(writer, indent, "Time", Self::translate_generic)?;
354 Self::format_units::<LengthKind, _>(writer, indent, "Length", Self::translate_generic)?;
355 Self::format_units::<AreaKind, _>(writer, indent, "Area", Self::translate_area)?;
356 Self::format_units::<VolumeKind, _>(writer, indent, "Volume", Self::translate_volume)?;
357 Self::format_units::<SpeedKind, _>(writer, indent, "Speed", Self::translate_speed)?;
358 Self::format_units::<MassKind, _>(writer, indent, "Mass", Self::translate_generic)?;
359 Self::format_units::<TempKind, _>(writer, indent, "Temperature", Self::translate_generic)?;
360 Self::format_units::<DataKind, _>(writer, indent, "Data", Self::translate_generic)?;
361 Ok(())
362 }
363
364 fn format_prefixes(writer: &mut W, indent: &str, label: &str) -> MyResult<()> {
365 writeln!(writer, "{}{} units:", indent, label)?;
366 PrefixKind::walk_values(true, true, |prefix| {
367 let symbol = prefix.get_symbol();
368 let name = prefix.get_name();
369 let power = prefix.get_power();
370 match power {
371 0 => writeln!(writer, "{} - - 1", indent)?,
372 1 => writeln!(writer, "{} {:4} {:12} 10", indent, symbol, name)?,
373 _ => writeln!(writer, "{} {:4} {:12} 10^{}", indent, symbol, name, power)?,
374 }
375 Ok(())
376 })
377 }
378
379 fn format_units<U: UnitInfo, F: Fn(U) -> Option<(Option<String>, Option<String>)>>(
380 writer: &mut W,
381 indent: &str,
382 label: &str,
383 function: F,
384 ) -> MyResult<()> {
385 writeln!(writer, "{}{} units:", indent, label)?;
386 U::walk_values(false, false, |unit| {
387 if let Some((symbol, name)) = function(unit) {
388 if let Some(symbol) = symbol {
389 write!(writer, "{} {:4} ", indent, symbol)?;
390 } else {
391 write!(writer, "{} ", indent)?;
392 }
393 if let Some(name) = name {
394 writeln!(writer, "{}", name)?;
395 } else {
396 writeln!(writer, "-")?;
397 }
398 }
399 Ok(())
400 })
401 }
402
403 fn translate_area(unit: AreaKind) -> Option<(Option<String>, Option<String>)> {
404 match unit {
405 Square(Metre(_)) => Self::translate_append(unit, "square-length"),
406 Square(Inch) => None,
407 Square(Foot) => None,
408 Square(Yard) => None,
409 Square(Mile) => None,
410 _ => Self::translate_generic(unit),
411 }
412 }
413
414 fn translate_volume(unit: VolumeKind) -> Option<(Option<String>, Option<String>)> {
415 match unit {
416 Cubic(Metre(_)) => Self::translate_append(unit, "cubic-length"),
417 Cubic(Inch) => None,
418 Cubic(Foot) => None,
419 Cubic(Yard) => None,
420 Cubic(Mile) => None,
421 _ => Self::translate_generic(unit),
422 }
423 }
424
425 fn translate_speed(unit: SpeedKind) -> Option<(Option<String>, Option<String>)> {
426 match unit {
427 Ratio(Metre(_), Second(_)) => Self::translate_append(unit, "length/time"),
428 Ratio(_, _) => None,
429 _ => Self::translate_generic(unit),
430 }
431 }
432
433 fn translate_append<U: UnitInfo>(unit: U, append: &str) -> Option<(Option<String>, Option<String>)> {
434 if let Some((symbol, unit)) = Self::translate_generic(unit) {
435 let unit = unit.map(|x| format!("{} (and other {} units)", x, append));
436 Some((symbol, unit))
437 } else {
438 None
439 }
440 }
441
442 fn translate_generic<U: UnitInfo>(unit: U) -> Option<(Option<String>, Option<String>)> {
443 let symbol = unit.get_symbol();
444 let name = unit.get_name();
445 if symbol.is_some() || name.is_some() {
446 Some((symbol, name))
447 } else {
448 None
449 }
450 }
451
452 pub fn show_help(&self, writer: &mut W, interact: bool) -> MyResult<()> {
461 let indent = if interact { " " } else { "" };
462 for description in self.descriptions.iter() {
463 match description {
464 Description::Separator(description) => {
465 writeln!(writer, "{}{}:", indent, description)?;
466 }
467 Description::Operation((keyword, input, output, description)) => {
468 writeln!(writer, "{} {:>3} {:7} {:3} {}", indent, input, keyword, output, description)?;
469 }
470 Description::Directive((keyword, description)) => {
471 writeln!(writer, "{} {:>3} {:12} {}", indent, "", keyword, description)?;
472 }
473 }
474 }
475 self.show_definitions(writer, interact)?;
476 Ok(())
477 }
478
479 pub fn show_definitions(&self, writer: &mut W, interact: bool) -> MyResult<()> {
480 let indent = if interact { " " } else { "" };
481 if !self.definitions.is_empty() {
482 writeln!(writer, "{}Defined functions:", indent)?;
483 for (keyword, (_, input, output, description)) in self.definitions.iter() {
484 if let Count::N(0) = output {
485 writeln!(writer, "{} {:>3} {:12} Function \"{}\"", indent, input, keyword, description)?;
486 } else {
487 writeln!(writer, "{} {:>3} {:7} {:3} Function \"{}\"", indent, input, keyword, output, description)?;
488 }
489 }
490 }
491 Ok(())
492 }
493}
494
495#[cfg(test)]
496pub mod tests {
497 use crate::calc::value::{Value, ValueRef};
498 use crate::core::count::Count;
499 use crate::core::interface::{Completion, Directive, Interface, Operation};
500 use crate::core::stack::ValueStack;
501 use crate::engine::Engine;
502 use crate::error::MyResult;
503 use crate::util::text::tests::BufferWriter;
504 use pretty_assertions::assert_eq;
505 use std::cell::RefCell;
506 use std::collections::HashMap;
507 use std::rc::Rc;
508
509 #[test]
510 fn test_completes_commands() {
511 let expected_commands = vec![
512 "eight",
513 "five",
514 "four",
515 "nine",
516 "one",
517 "seven",
518 "six",
519 "ten",
520 "three",
521 "two",
522 ];
523 let expected_completions = HashMap::from([
524 (String::from("five"), Completion::Filename),
525 (String::from("six"), Completion::Filename),
526 (String::from("seven"), Completion::Filename),
527 (String::from("eight"), Completion::Keyword),
528 ]);
529 let interface = Interface::<BufferWriter>::new()
530 .with_operation(vec!["one", "two"], Operation::ValueNone(dummy_nullary), "")
531 .with_operation(vec!["three"], Operation::ValueNone(dummy_nullary), "")
532 .with_operation(vec!["four"], Operation::ValueNone(dummy_nullary), "")
533 .with_directive(vec!["five", "six"], Directive::EngineAll(dummy_directive, Completion::Filename), "")
534 .with_directive(vec!["seven"], Directive::EngineAll(dummy_directive, Completion::Filename), "")
535 .with_directive(vec!["eight"], Directive::EngineAll(dummy_directive, Completion::Keyword), "")
536 .with_definition("nine", vec![], Count::N(0), Count::N(0), String::from(""))
537 .with_definition("ten", vec![], Count::N(0), Count::N(0), String::from(""));
538 assert_eq!(interface.get_commands(), expected_commands);
539 assert_eq!(interface.get_completions(), expected_completions);
540 }
541
542 pub fn dummy_nullary() -> MyResult<ValueRef> {
543 Ok(Rc::new(RefCell::new(Value::new(None))))
544 }
545
546 pub fn dummy_unary(_: ValueRef) -> MyResult<ValueRef> {
547 Ok(Rc::new(RefCell::new(Value::new(None))))
548 }
549
550 pub fn dummy_binary(_: ValueRef, _: ValueRef) -> MyResult<ValueRef> {
551 Ok(Rc::new(RefCell::new(Value::new(None))))
552 }
553
554 pub fn dummy_series(_: Vec<ValueRef>) -> MyResult<ValueRef> {
555 Ok(Rc::new(RefCell::new(Value::new(None))))
556 }
557
558 pub fn dummy_binary_series(_: ValueRef, _: ValueRef) -> MyResult<Vec<ValueRef>> {
559 Ok(Vec::new())
560 }
561
562 pub fn dummy_series_series(_: Vec<ValueRef>) -> MyResult<Vec<ValueRef>> {
563 Ok(Vec::new())
564 }
565
566 pub fn dummy_directive(
567 _engine: &mut Engine<BufferWriter>,
568 _writer: &mut BufferWriter,
569 _stack: &mut ValueStack,
570 _tokens: Vec<String>,
571 ) -> MyResult<bool> {
572 Ok(false)
573 }
574
575 #[test]
576 fn test_shows_measurement_units() {
577 let expected = "\
578Prefix units:
579 Q quetta 10^30
580 R ronna 10^27
581 Y yotta 10^24
582 Z zetta 10^21
583 E exa 10^18
584 P peta 10^15
585 T tera 10^12
586 G giga 10^9
587 M mega 10^6
588 k kilo 10^3
589 h hecto 10^2
590 da deca 10
591 - - 1
592 d deci 10^-1
593 c centi 10^-2
594 m milli 10^-3
595 u micro 10^-6
596 n nano 10^-9
597 p pico 10^-12
598 f femto 10^-15
599 a atto 10^-18
600 z zepto 10^-21
601 y yocto 10^-24
602 r ronto 10^-27
603 q quecto 10^-30
604Time units:
605 s second
606 minute
607 hour
608 day
609 week
610 month
611 year
612Length units:
613 m metre
614 inch
615 foot
616 yard
617 mile
618Area units:
619 m^2 square-metre (and other square-length units)
620 hectare
621 acre
622Volume units:
623 m^3 cubic-metre (and other cubic-length units)
624 l litre
625 tsp
626 tbsp
627 floz
628 pint
629 quart
630 gallon
631 barrel
632 ustsp
633 ustbsp
634 usfloz
635 uscup
636 uspint
637 usquart
638 usgallon
639 usbarrel
640Speed units:
641 m/s metre/second (and other length/time units)
642 mach
643 light
644Mass units:
645 g gram
646 ounce
647 pound
648 stone
649 ton
650Temperature units:
651 K kelvin
652 C celsius
653 F fahrenheit
654 R rankine
655Data units:
656 B byte
657 bit
658";
659 let interface = Interface::build();
660 let mut writer = BufferWriter::new();
661 assert!(interface.show_units(&mut writer, false).is_ok());
662 assert_eq!(writer.buffer, expected);
663 }
664
665 #[test]
666 fn test_shows_help_text() {
667 let expected = "\
668Arithmetic operations:
669 N N add,+ N Add two values
670 N N sub,- N Subtract two values
671 N N mul,* N Multiply two values
672 N N div,/ N Divide two values
673 N N mod,% N Modulo two values
674 N neg N Find the negative
675 N inv N Find the inverse
676 N N pow N Raise to the power
677 N sqrt N Find the square root
678 * sum N Sum all values
679 * prod N Multiply all values
680Sequence operations:
681 N N seq * Generate integer sequence (start to stop)
682 3 step * Generate integer sequence (start with step to stop)
683 * sort * Sort stack or sequence
684 * rev * Reverse stack or sequence
685 * flat * Flatten entire stack
686Bitwise operations:
687 N N and N Bitwise AND two values
688 N N or N Bitwise OR two values
689 N N xor N Bitwise XOR two values
690 N N shl N Shift left (multiply by power of 2)
691 N N shr N Shift right (divide by power of 2)
692Time operations:
693 now N Get the current time (in UTC)
694 N plain N Format as a plain value
695 N delta N Format as a delta value (duration)
696 N time N Format as a time value (in UTC)
697Formatting commands:
698 dec Format as decimal values
699 hex Format as hexadecimal values
700 sep Include comma separators
701 nosep Include no separators
702 N dp Use fixed decimal places
703 nodp Use free decimal places
704Stack commands:
705 show Show all values on the stack
706 * clear Remove all values from the stack
707 N pop Remove a value from the stack
708 N dup N N Duplicate a value on the stack
709 N N swap N N Swap two values on the stack
710 N cut Cut a value to the internal clipboard
711 N copy N Copy a value to the internal clipboard
712 paste N Paste a value from the internal clipboard
713History commands:
714 u(ndo) Undo the last operation
715 r(edo) Redo the next operation
716 hist Show all undo/redo history
717General directives:
718 import... Import file e.g. \"import file.txt\"
719 export... Export file e.g. \"export file.txt\"
720 set,=... Set variable, e.g. \"set x\"
721 define... Define function e.g. \"define cube 3 pow\"
722 apply... Apply to stack or sequence, e.g. \"apply 3 pow\"
723General commands:
724 units Show unit names and symbols
725 help Show this help text
726";
727 let interface = Interface::build();
728 let mut writer = BufferWriter::new();
729 assert!(interface.show_help(&mut writer, false).is_ok());
730 assert_eq!(writer.buffer, expected);
731 }
732
733 #[test]
734 fn test_shows_definitions_with_null() {
735 let expected = "\
736Defined functions:
737 answer N Function \"6 7 mul\"
738 N cube N Function \"3 pow\"
739 N N very-long-a Function \"\"
740 N N very-long-bb Function \"\"
741 N N very-long-ccc Function \"\"
742 N N very-long-dddd Function \"\"
743 N N very-long-eeeee Function \"\"
744";
745 let mut interface = Interface::build();
746 let mut writer = BufferWriter::new();
747 interface.insert_definition("answer", vec![], Count::N(0), Count::N(1), String::from("6 7 mul"));
748 interface.insert_definition("cube", vec![], Count::N(1), Count::N(1), String::from("3 pow"));
749 interface.insert_definition("very-long-a", vec![], Count::N(2), Count::N(0), String::from(""));
750 interface.insert_definition("very-long-bb", vec![], Count::N(2), Count::N(0), String::from(""));
751 interface.insert_definition("very-long-ccc", vec![], Count::N(2), Count::N(0), String::from(""));
752 interface.insert_definition("very-long-dddd", vec![], Count::N(2), Count::N(0), String::from(""));
753 interface.insert_definition("very-long-eeeee", vec![], Count::N(2), Count::N(0), String::from(""));
754 assert!(interface.show_definitions(&mut writer, false).is_ok());
755 assert_eq!(writer.buffer, expected);
756 }
757
758 #[test]
759 fn test_shows_definitions_with_value() {
760 let expected = "\
761Defined functions:
762 answer N Function \"6 7 mul\"
763 N cube N Function \"3 pow\"
764 N N long-a N N Function \"\"
765 N N long-bb N N Function \"\"
766 N N long-ccc N N Function \"\"
767 N N long-dddd N N Function \"\"
768 N N long-eeeee N N Function \"\"
769";
770 let mut interface = Interface::build();
771 let mut writer = BufferWriter::new();
772 interface.insert_definition("answer", vec![], Count::N(0), Count::N(1), String::from("6 7 mul"));
773 interface.insert_definition("cube", vec![], Count::N(1), Count::N(1), String::from("3 pow"));
774 interface.insert_definition("long-a", vec![], Count::N(2), Count::N(2), String::from(""));
775 interface.insert_definition("long-bb", vec![], Count::N(2), Count::N(2), String::from(""));
776 interface.insert_definition("long-ccc", vec![], Count::N(2), Count::N(2), String::from(""));
777 interface.insert_definition("long-dddd", vec![], Count::N(2), Count::N(2), String::from(""));
778 interface.insert_definition("long-eeeee", vec![], Count::N(2), Count::N(2), String::from(""));
779 assert!(interface.show_definitions(&mut writer, false).is_ok());
780 assert_eq!(writer.buffer, expected);
781 }
782}