Skip to main content

mathypad/
cli.rs

1//! Command-line interface functions
2
3use crate::evaluate_expression_with_context;
4use crate::expression::parse_line_reference;
5use crate::units::parse_unit;
6use std::error::Error;
7
8/// Run one-shot evaluation mode (non-interactive)
9pub fn run_one_shot_mode(expression: &str) -> Result<(), Box<dyn Error>> {
10    // Print the expression with syntax highlighting
11    print_formatted_expression(expression);
12
13    // Evaluate the expression (no context for one-shot mode)
14    if let Some(result) = evaluate_expression_with_context(expression, &[], 0) {
15        println!(" = {}", result);
16    } else {
17        println!(" = (invalid expression)");
18    }
19
20    Ok(())
21}
22
23/// Print a mathematical expression with ANSI color formatting
24pub fn print_formatted_expression(text: &str) {
25    // Use ANSI escape codes to print numbers in light blue and units in green
26    let mut current_pos = 0;
27    let chars: Vec<char> = text.chars().collect();
28
29    while current_pos < chars.len() {
30        if chars[current_pos].is_ascii_alphabetic() {
31            // Handle potential units, keywords, and line references first
32            let start_pos = current_pos;
33
34            while current_pos < chars.len()
35                && (chars[current_pos].is_ascii_alphabetic()
36                    || chars[current_pos].is_ascii_digit()
37                    || chars[current_pos] == '/')
38            {
39                current_pos += 1;
40            }
41
42            let word_text: String = chars[start_pos..current_pos].iter().collect();
43
44            // Check if it's a valid unit, keyword, or line reference
45            if parse_line_reference(&word_text).is_some() {
46                // Print line reference in magenta (ANSI color code 95)
47                print!("\x1b[95m{}\x1b[0m", word_text);
48            } else if word_text.to_lowercase() == "to" || word_text.to_lowercase() == "in" {
49                // Print keywords in yellow (ANSI color code 93)
50                print!("\x1b[93m{}\x1b[0m", word_text);
51            } else if parse_unit(&word_text).is_some() {
52                // Print units in green (ANSI color code 92)
53                print!("\x1b[92m{}\x1b[0m", word_text);
54            } else {
55                print!("{}", word_text);
56            }
57        } else if chars[current_pos].is_ascii_digit() || chars[current_pos] == '.' {
58            // Handle numbers
59            let start_pos = current_pos;
60            let mut has_digit = false;
61            let mut has_dot = false;
62
63            while current_pos < chars.len() {
64                let ch = chars[current_pos];
65                if ch.is_ascii_digit() {
66                    has_digit = true;
67                    current_pos += 1;
68                } else if ch == '.' && !has_dot {
69                    has_dot = true;
70                    current_pos += 1;
71                } else if ch == ',' {
72                    current_pos += 1;
73                } else {
74                    break;
75                }
76            }
77
78            if has_digit {
79                let number_text: String = chars[start_pos..current_pos].iter().collect();
80                // Print number in light blue (ANSI color code 94)
81                print!("\x1b[94m{}\x1b[0m", number_text);
82            } else {
83                print!("{}", chars[start_pos]);
84                current_pos = start_pos + 1;
85            }
86        } else if "+-*/()".contains(chars[current_pos]) {
87            // Print operators in cyan (ANSI color code 96)
88            print!("\x1b[96m{}\x1b[0m", chars[current_pos]);
89            current_pos += 1;
90        } else {
91            print!("{}", chars[current_pos]);
92            current_pos += 1;
93        }
94    }
95}