use crossterm::event::{self, Event, KeyCode, KeyEvent, KeyModifiers}; use std::io; use tui::{ backend::Backend, layout::{Constraint, Direction, Layout}, widgets::Paragraph, Frame, Terminal, }; use pfc::{ui, Operator}; enum Signal { None, Exit, } #[derive(Default)] struct App { stack: Vec, input_buffer: String, } impl App { fn handle_input(&mut self, key: KeyEvent) -> Signal { match key.modifiers { KeyModifiers::CONTROL => match key.code { KeyCode::Char('c') => { return Signal::Exit; } _ => {} }, KeyModifiers::NONE => match key.code { KeyCode::Char('q') => { return Signal::Exit; } KeyCode::Char(c) => { if c.is_ascii_digit() { self.input_buffer.push(c); } else if c == '.' && !self.input_buffer.contains('.') { self.input_buffer.push(c); } else if let Ok(op) = Operator::parse(c) { self.stack.push(self.input_buffer.parse::().unwrap()); self.input_buffer = String::new(); self.perform_operation(op); } } KeyCode::Enter => { self.stack.push(self.input_buffer.parse::().unwrap()); self.input_buffer = String::new(); } KeyCode::Backspace => { self.input_buffer.pop(); } _ => {} }, _ => {} } return Signal::None; } fn draw(&self, f: &mut Frame) { let chunks = Layout::default() .direction(Direction::Vertical) .constraints([Constraint::Percentage(100)].as_ref()) .split(f.size()); f.render_widget(Paragraph::new(self.input_buffer.as_str()), chunks[0]); } fn perform_operation(&mut self, op: Operator) { let rhs = match self.stack.pop() { Some(f) => f, None => { return; } }; let lhs = match self.stack.pop() { Some(f) => f, None => { return; } }; match op { Operator::Add => self.stack.push(lhs + rhs), Operator::Sub => self.stack.push(lhs - rhs), Operator::Mul => self.stack.push(lhs * rhs), Operator::Div => self.stack.push(lhs / rhs), } } } fn main() -> io::Result<()> { let app = App::default(); let mut terminal = ui::init_terminal()?; let result = run(app, &mut terminal); ui::cleanup_terminal(terminal)?; result } fn run(mut app: App, terminal: &mut Terminal) -> io::Result<()> { loop { terminal.draw(|f| app.draw(f))?; if let Event::Key(key) = event::read()? { if let Signal::Exit = app.handle_input(key) { return Ok(()); } } } }