Add help command

Close #41
This commit is contained in:
Ivan Tham 2020-11-02 01:28:05 +08:00
parent d31097959f
commit ea95516537
4 changed files with 50 additions and 4 deletions

View File

@ -2,11 +2,16 @@
* Refer to LICENCE for more information.
* */
use std::iter::ExactSizeIterator;
use crate::lex;
#[derive(Debug)]
pub enum CalcError {
Math(Math),
Syntax(String),
Parser(String),
Help,
}
#[derive(Debug)]
@ -25,5 +30,42 @@ pub fn handler(e: CalcError) -> String {
},
CalcError::Syntax(details) => format!("Syntax Error: {}", details),
CalcError::Parser(details) => format!("Parser Error: {}", details),
CalcError::Help => format!(
"Constants\n{}\nFunctions\n{}\nOperators\n{}\n",
blocks(lex::CONSTANTS.keys().cloned()),
blocks(lex::FUNCTIONS.keys().cloned()),
{
let l: Vec<_> = lex::OPERATORS.keys().map(|c| c.to_string()).collect();
l.join(" ")
}
),
}
}
/// Convert iterator into strings of chunks of 8 right padded with space.
fn blocks(mut iter: impl Iterator<Item = &'static str> + ExactSizeIterator) -> String {
// calculate max width but ideally this should be calculated once
let mut max_width = 79; // capped at 79
if let Ok(s) = std::env::var("COLUMNS") {
if let Ok(n) = s.parse() {
if n < max_width {
max_width = n;
}
}
}
// multiply by eight since we are formatting it into chunks of 8
let items_per_line = max_width / 8;
let full_bytes = (iter.len() - iter.len() % items_per_line) * 8;
let part_bytes = iter.len() % items_per_line * 8; // leftovers
let n_newlines = iter.len() / items_per_line + if part_bytes > 0 { 1 } else { 0 };
let mut s = String::with_capacity(full_bytes + part_bytes + n_newlines);
for _ in 0..n_newlines {
for item in iter.by_ref().take(items_per_line) {
s.extend(format!("{:>8}", item).chars());
}
s.push('\n');
}
debug_assert_eq!(s.capacity(), s.len()); // check capacity calculation
s
}

View File

@ -70,14 +70,14 @@ pub enum Token {
}
lazy_static! {
static ref CONSTANTS: HashMap<&'static str, Token> = {
pub static ref CONSTANTS: HashMap<&'static str, Token> = {
let mut m = HashMap::new();
m.insert("e", Token::Num(std::f64::consts::E));
m.insert("pi", Token::Num(std::f64::consts::PI));
m
};
static ref FUNCTIONS: HashMap<&'static str, Token> = {
pub static ref FUNCTIONS: HashMap<&'static str, Token> = {
let mut m = HashMap::new();
m.insert("sin", Function::token_from_fn("sin".into(), |x| is_radian_mode(x, CONFIGURATION.radian_mode).sin()));
m.insert("cos", Function::token_from_fn("cos".into(), |x| is_radian_mode(x, CONFIGURATION.radian_mode).cos()));
@ -106,7 +106,7 @@ lazy_static! {
m
};
static ref OPERATORS: HashMap<char, Token> = {
pub static ref OPERATORS: HashMap<char, Token> = {
let mut m = HashMap::new();
m.insert('+', Operator::token_from_op('+', |x, y| x + y, 2, true));
m.insert('-', Operator::token_from_op('-', |x, y| x - y, 2, true));

View File

@ -193,7 +193,9 @@ fn parse_arguments() -> Configuration {
pub fn eval_math_expression(input: &str, prev_ans: Option<f64>) -> Result<f64, CalcError> {
let input = input.trim();
let input = input.replace(" ", "");
if input == "help" {
return Err(CalcError::Help);
}
if input.is_empty() {
return Ok(0.);
}

View File

@ -12,6 +12,7 @@ use directories::ProjectDirs;
use regex::Regex;
use crate::error::CalcError;
use crate::eval_math_expression;
pub struct RLHelper {
@ -67,6 +68,7 @@ impl Highlighter for LineHighlighter {
}
Owned(coloured)
}
Err(CalcError::Help) => Owned(line.replace("help", "\x1b[36mhelp\x1b[0m")),
Err(_) => Owned(format!("\x1b[31m{}\x1b[0m", line)),
}
}