From ea95516537b9ef2c9badd01abcf72f20066f9c55 Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Mon, 2 Nov 2020 01:28:05 +0800 Subject: Add help command Close #41 --- src/error/mod.rs | 42 ++++++++++++++++++++++++++++++++++++++++++ src/lex/mod.rs | 6 +++--- src/main.rs | 4 +++- src/readline/mod.rs | 2 ++ 4 files changed, 50 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/error/mod.rs b/src/error/mod.rs index ec2b555..307ca31 100644 --- a/src/error/mod.rs +++ b/src/error/mod.rs @@ -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 + 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 } diff --git a/src/lex/mod.rs b/src/lex/mod.rs index 3222c12..b3faff8 100644 --- a/src/lex/mod.rs +++ b/src/lex/mod.rs @@ -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 = { + pub static ref OPERATORS: HashMap = { 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)); diff --git a/src/main.rs b/src/main.rs index bc22ce2..7086d15 100644 --- a/src/main.rs +++ b/src/main.rs @@ -193,7 +193,9 @@ fn parse_arguments() -> Configuration { pub fn eval_math_expression(input: &str, prev_ans: Option) -> Result { let input = input.trim(); - let input = input.replace(" ", ""); + if input == "help" { + return Err(CalcError::Help); + } if input.is_empty() { return Ok(0.); } diff --git a/src/readline/mod.rs b/src/readline/mod.rs index ea195ee..d689f95 100644 --- a/src/readline/mod.rs +++ b/src/readline/mod.rs @@ -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)), } } -- cgit v1.2.3