diff --git a/src/calc.rs b/src/calc.rs index 3646283..d6d24d6 100644 --- a/src/calc.rs +++ b/src/calc.rs @@ -143,7 +143,7 @@ impl<'a> Calculator<'a> { Ok(()) } 'R' => { - self.state = CalculatorState::WaitingForRegister(RegisterState::Load); + self.state = CalculatorState::WaitingForRegister(RegisterState::Save); Ok(()) } _ => { @@ -215,7 +215,24 @@ impl<'a> Calculator<'a> { self.state = CalculatorState::Normal; self.active_macros.clear(); } + pub fn backspace(&mut self) -> CalculatorResult<()> { + self.l.pop(); + Ok(()) + } + pub fn edit(&mut self) -> CalculatorResult<()> { + if self.l.len() > 0 { + return Ok(()); + } + self.l = self + .pop() + .or(Err(CalculatorError::NotEnoughStackEntries))? + .to_string(); + Ok(()) + } + pub fn get_l(&mut self) -> &str { + self.l.as_ref() + } fn entry(&mut self, c: char) -> CalculatorResult<()> { match c { '0'..='9' => { @@ -245,6 +262,9 @@ impl<'a> Calculator<'a> { } } + pub fn get_state(&self) -> &CalculatorState { + &self.state + } pub fn get_constants_iter(&'a self) -> CalculatorConstantsIter<'a> { self.constants.iter() } diff --git a/src/calc/constants.rs b/src/calc/constants.rs index 01201a3..932f584 100644 --- a/src/calc/constants.rs +++ b/src/calc/constants.rs @@ -8,7 +8,6 @@ pub enum RegisterState { pub enum CalculatorState { Normal, - //Macro, WaitingForConstant, WaitingForMacro, WaitingForRegister(RegisterState), diff --git a/src/main.rs b/src/main.rs index eaeb72c..ea1a717 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,12 +4,11 @@ mod calc; mod util; -use calc::errors::{CalculatorError, CalculatorResult}; +use calc::constants::{CalculatorState, RegisterState}; +use calc::errors::CalculatorResult; use calc::Calculator; use std::cmp; use std::convert::TryFrom; -use util::event::{Event, Events}; -//use util::event::T; use std::{error::Error, io}; use termion::{event::Key, raw::IntoRawMode, screen::AlternateScreen}; use tui::{ @@ -21,27 +20,19 @@ use tui::{ widgets::{Block, Borders, Clear, List, ListItem, Paragraph}, Terminal, }; +use util::event::{Event, Events}; struct Dimensions { width: u16, height: u16, } -enum RegisterState { - Save, - Load, -} - enum AppState { Calculator, Help, - Constants, - Macros, - Registers(RegisterState), } struct App<'a> { - input: String, calculator: Calculator<'a>, error_msg: Option, state: AppState, @@ -51,7 +42,6 @@ struct App<'a> { impl<'a> Default for App<'a> { fn default() -> App<'a> { App { - input: String::new(), calculator: Calculator::default(), error_msg: None, state: AppState::Calculator, @@ -121,11 +111,6 @@ fn main() -> Result<(), Box> { }) .collect(); - // stack.insert( - // 0, - // ListItem::new(Span::raw(format!("dbg: {}", chunks[2].height))), - // ); - for _ in 0..(chunks[1] .height .saturating_sub(stack.len() as u16) @@ -138,15 +123,18 @@ fn main() -> Result<(), Box> { List::new(stack).block(Block::default().borders(Borders::ALL).title("Stack")); f.render_widget(stack, chunks[1]); - let input = Paragraph::new(app.input.as_ref()) + let input = Paragraph::new(app.calculator.get_l().as_ref()) .style(Style::default()) .block(Block::default().borders(Borders::ALL).title("Input")); f.render_widget(input, chunks[2]); - f.set_cursor(chunks[2].x + app.input.len() as u16 + 1, chunks[2].y + 1); + f.set_cursor( + chunks[2].x + app.calculator.get_l().len() as u16 + 1, + chunks[2].y + 1, + ); - match &app.state { - AppState::Help => { + match (&app.state, app.calculator.get_state()) { + (AppState::Help, _) => { draw_clippy_rect( ClippyRectangle { title: "Help", @@ -171,7 +159,7 @@ fn main() -> Result<(), Box> { f, ); } - AppState::Constants => { + (AppState::Calculator, CalculatorState::WaitingForConstant) => { draw_clippy_rect( ClippyRectangle { title: "Constants", @@ -187,8 +175,8 @@ fn main() -> Result<(), Box> { f, ); } - AppState::Registers(state) => { - let title = match state { + (AppState::Calculator, CalculatorState::WaitingForRegister(register_state)) => { + let title = match register_state { RegisterState::Save => "Registers (press char to save)", RegisterState::Load => "Registers", }; @@ -205,7 +193,7 @@ fn main() -> Result<(), Box> { f, ); } - AppState::Macros => { + (AppState::Calculator, CalculatorState::WaitingForMacro) => { draw_clippy_rect( ClippyRectangle { title: "Macros", @@ -252,167 +240,54 @@ fn main() -> Result<(), Box> { } fn handle_key(app: &mut App, events: &Events, key: Key) -> CalculatorResult { - match &app.state { - AppState::Calculator => match key { + match (&app.state, app.calculator.get_state()) { + (AppState::Calculator, CalculatorState::Normal) => match key { Key::Char('q') => { return Ok(true); } - // Key::Ctrl('c') => { - // app.state = AppState::Constants; - // } - // Key::Char('r') => { - // app.state = AppState::Registers(RegisterState::Load); - // } - // Key::Char('R') => { - // app.state = AppState::Registers(RegisterState::Save); - // } - // Key::Char('m') => { - // app.state = AppState::Macros; - // } Key::Char('h') => { app.state = AppState::Help; } - Key::Char(c @ '0'..='9') => { - app.input.push(c); - } - Key::Char('e') => { - if app.input.is_empty() { - let f = app - .calculator - .pop() - .or(Err(CalculatorError::NotEnoughStackEntries))?; - app.input = f.to_string(); - } - - if !app.input.contains('e') { - app.input.push('e'); - } - } - Key::Char('.') => { - if !app.input.contains('.') { - app.input.push('.'); - } - } Key::Char('\n') | Key::Char(' ') => { - if app.input.is_empty() { - calc_operation(app, ' ')?; - } else { - let mut tmp_input = app.input.clone(); - if tmp_input.ends_with('e') { - let tmp_input = tmp_input.push('0'); - } - - if let Ok(f) = tmp_input.parse::() { - if app.calculator.push(f).is_ok() { - app.input.clear(); - } - } - } + app.calculator.take_input(' ')?; } Key::Right => { - calc_operation(app, '>')?; + app.calculator.take_input('>')?; } Key::Down => { - // TODO: Internal calculator function - if let Ok(x) = app.calculator.pop() { - app.input = x.to_string(); - } + app.calculator.edit()?; } Key::Backspace => { - app.input.pop(); - } - Key::Delete => { - app.input.clear(); + app.calculator.backspace()?; } Key::Char(c) => { - calc_operation(app, c)?; + app.calculator.take_input(c)?; } _ => {} }, - AppState::Help => match key { + (AppState::Help, _) => match key { Key::Esc | Key::Char('q') => { app.state = AppState::Calculator; app.calculator.cancel(); } _ => {} }, - AppState::Constants => match key { + (AppState::Calculator, CalculatorState::WaitingForConstant) + | (AppState::Calculator, CalculatorState::WaitingForRegister(_)) + | (AppState::Calculator, CalculatorState::WaitingForMacro) => match key { Key::Esc => { app.state = AppState::Calculator; app.calculator.cancel(); } Key::Char(c) => { - app.calculator.push_constant(c)?; - app.input.clear(); - app.state = AppState::Calculator; - app.calculator.cancel(); + app.calculator.take_input(c)?; } _ => {} }, - AppState::Registers(task) => match key { - Key::Esc => { - app.state = AppState::Calculator; - app.calculator.cancel(); - } - // Key::Char(c) => { - // match task { - // RegisterState::Save => { - // app.calculator.save_register(c)?; - // } - // RegisterState::Load => { - // app.calculator.push_register(c)?; - // } - // } - // app.input.clear(); - // app.state = AppState::Calculator; - // } - _ => {} - }, - AppState::Macros => match key { - Key::Esc => { - app.state = AppState::Calculator; - app.calculator.cancel(); - } - // Key::Char(c) => { - // if !app.input.is_empty() { - // //TODO: A better way to do this - // //Can use calc_operation in the future. Already performs this check - // let f = app - // .input - // .parse::() - // .or(Err(CalculatorError::ParseError))?; - // app.calculator.push(f).and_then(|()| { - // app.input.clear(); - // Ok(()) - // })?; - // } - - // // TODO: Handle macros internally to the calculator - // let mac = app.calculator.get_macro(c)?; - // events.fill_event_buf(mac.value); - // app.state = AppState::Calculator; - // } - _ => {} - }, } return Ok(false); } -fn calc_operation(app: &mut App, c: char) -> CalculatorResult<()> { - if !app.input.is_empty() { - let f = app - .input - .parse::() - .or(Err(CalculatorError::ParseError))?; - app.calculator.push(f)?; - app.input.clear(); - } - - //let op = CalculatorOperation::from_char(c)?; - app.calculator.take_input(c) - //app.calculator.op(op) -} - struct ClippyRectangle<'a> { title: &'a str, msg: &'a str,