aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/function.rs61
-rw-r--r--src/input.rs94
-rw-r--r--src/lib.rs122
-rw-r--r--src/main.rs24
-rw-r--r--src/ui.rs106
5 files changed, 0 insertions, 407 deletions
diff --git a/src/function.rs b/src/function.rs
deleted file mode 100644
index bb6462d..0000000
--- a/src/function.rs
+++ /dev/null
@@ -1,61 +0,0 @@
-use crate::AngleMode;
-
-pub enum Function {
- Sin, // Sine
- Cos, // Cosine
- Tan, // Tangent
- Asin, // Inverse sine
- Acos, // Inverse cosine
- Atan, // Inverse tangent
- Deg, // Convert from radians to degrees
- Rad, // Convert from degrees to radians
-}
-
-impl Function {
- pub fn parse(s: &str) -> Result<Self, ParseFunctionError> {
- match s {
- "sin" => Ok(Self::Sin),
- "cos" => Ok(Self::Cos),
- "tan" => Ok(Self::Tan),
- "asin" => Ok(Self::Asin),
- "acos" => Ok(Self::Acos),
- "atan" => Ok(Self::Atan),
- "deg" => Ok(Self::Deg),
- "rad" => Ok(Self::Rad),
- _ => Err(ParseFunctionError(s.to_string())),
- }
- }
-
- pub fn call(&self, val: f64, angle_mode: AngleMode) -> f64 {
- match self {
- Self::Sin => match angle_mode {
- AngleMode::Degrees => val.to_radians().sin(),
- AngleMode::Radians => val.sin(),
- },
- Self::Cos => match angle_mode {
- AngleMode::Degrees => val.to_radians().cos(),
- AngleMode::Radians => val.cos(),
- },
- Self::Tan => match angle_mode {
- AngleMode::Degrees => val.to_radians().tan(),
- AngleMode::Radians => val.tan(),
- },
- Self::Asin => match angle_mode {
- AngleMode::Degrees => val.asin().to_degrees(),
- AngleMode::Radians => val.asin(),
- },
- Self::Acos => match angle_mode {
- AngleMode::Degrees => val.acos().to_degrees(),
- AngleMode::Radians => val.acos(),
- },
- Self::Atan => match angle_mode {
- AngleMode::Degrees => val.atan().to_degrees(),
- AngleMode::Radians => val.atan(),
- },
- Self::Deg => val.to_degrees(),
- Self::Rad => val.to_radians(),
- }
- }
-}
-
-pub struct ParseFunctionError(String);
diff --git a/src/input.rs b/src/input.rs
deleted file mode 100644
index 2d982e5..0000000
--- a/src/input.rs
+++ /dev/null
@@ -1,94 +0,0 @@
-use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
-
-use crate::{Calculator, Constant, Function, Operator, Signal};
-
-impl Calculator {
- pub fn handle_input(&mut self, key: KeyEvent) -> Signal {
- match key.modifiers {
- KeyModifiers::CONTROL => match key.code {
- KeyCode::Char('c') => {
- return Signal::Exit;
- }
- _ => {}
- },
- KeyModifiers::SHIFT => match key.code {
- KeyCode::Char('Q') => {
- return Signal::Exit;
- }
- KeyCode::Char('J' | 'K') => self.swap(),
- KeyCode::Char('D') => {
- self.input_buffer = String::new();
- }
- KeyCode::Char('C') => self.clear(),
- KeyCode::Char('A') => {
- self.angle_mode = self.angle_mode.toggle();
- }
- KeyCode::Char('N') => {
- if self.input_buffer.len() > 0 {
- if let Ok(f) = self.input_buffer.parse::<f64>() {
- self.input_buffer = format!("{}", -f);
- }
- } else if let Some(v) = self.stack.pop() {
- self.stack.push(-v);
- }
- }
- _ => {}
- },
- KeyModifiers::NONE => match key.code {
- KeyCode::Char(c) => self.push_to_buffer(c),
- KeyCode::Backspace => {
- self.input_buffer.pop();
- }
- KeyCode::Enter => {
- if let Ok(func) = Function::parse(&self.input_buffer) {
- if let Some(val) = self.stack.pop() {
- self.stack.push(func.call(val, self.angle_mode));
- }
- } else if let Ok(c) = Constant::parse(&self.input_buffer) {
- self.stack.push(c.value());
- } else if let Ok(bu) = self.input_buffer.parse::<f64>() {
- self.stack.push(bu);
- }
- self.input_buffer = String::new();
- }
- _ => {}
- },
- _ => {}
- }
- return Signal::None;
- }
-
- fn push_to_buffer(&mut self, c: char) {
- if c == '.' && !self.input_buffer.contains('.') {
- if self.input_buffer.len() == 0 {
- self.input_buffer.push('0');
- }
- self.input_buffer.push(c);
- } else if let Ok(op) = Operator::parse(c) {
- if let Ok(c) = Constant::parse(&self.input_buffer) {
- self.stack.push(c.value());
- } else if let Ok(f) = self.input_buffer.parse::<f64>() {
- self.stack.push(f);
- }
- self.input_buffer = String::new();
- self.perform_operation(op);
- } else {
- self.input_buffer.push(c);
- }
- }
-
- fn swap(&mut self) {
- if let Some(st) = self.stack.pop() {
- if let Ok(bu) = self.input_buffer.parse::<f64>() {
- self.stack.push(bu);
- }
- self.input_buffer = format!("{}", st);
- }
- }
-
- // Clear stack and input buffer.
- fn clear(&mut self) {
- self.input_buffer = String::new();
- self.stack = Vec::new();
- }
-}
diff --git a/src/lib.rs b/src/lib.rs
deleted file mode 100644
index db316f0..0000000
--- a/src/lib.rs
+++ /dev/null
@@ -1,122 +0,0 @@
-use std::{
- f64::consts::{E, PI},
- fmt::{self, Display, Formatter},
-};
-
-mod function;
-mod input;
-pub mod ui;
-
-pub use function::Function;
-
-#[derive(Default)]
-pub struct Calculator {
- stack: Vec<f64>,
- input_buffer: String,
- angle_mode: AngleMode,
-}
-
-impl Calculator {
- 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;
- }
- };
- self.stack.push(match op {
- Operator::Add => lhs + rhs,
- Operator::Sub => lhs - rhs,
- Operator::Mul => lhs * rhs,
- Operator::Div => lhs / rhs,
- Operator::Exp => lhs.powf(rhs),
- });
- }
-}
-
-#[derive(Default, Copy, Clone, PartialEq)]
-pub enum AngleMode {
- #[default]
- Degrees,
- Radians,
-}
-
-impl AngleMode {
- fn toggle(&self) -> Self {
- match self {
- Self::Degrees => Self::Radians,
- Self::Radians => Self::Degrees,
- }
- }
-}
-
-impl Display for AngleMode {
- fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
- write!(
- f,
- "{}",
- match self {
- Self::Degrees => "deg",
- Self::Radians => "rad",
- }
- )
- }
-}
-
-enum Operator {
- Add,
- Sub,
- Mul,
- Div,
- Exp,
-}
-
-impl Operator {
- fn parse(c: char) -> Result<Self, ParseOperatorError> {
- match c {
- '+' => Ok(Self::Add),
- '-' => Ok(Self::Sub),
- '*' => Ok(Self::Mul),
- '/' => Ok(Self::Div),
- '^' => Ok(Self::Exp),
- _ => Err(ParseOperatorError(c)),
- }
- }
-}
-
-struct ParseOperatorError(char);
-
-enum Constant {
- Pi, // Archimedes’ constant (π)
- E, // Euler's number (e)
-}
-
-impl Constant {
- fn parse(s: &str) -> Result<Self, ParseConstantError> {
- match s {
- "pi" => Ok(Self::Pi),
- "e" => Ok(Self::E),
- _ => Err(ParseConstantError(s.to_string())),
- }
- }
-
- fn value(&self) -> f64 {
- match self {
- Self::Pi => PI,
- Self::E => E,
- }
- }
-}
-
-struct ParseConstantError(String);
-
-pub enum Signal {
- None,
- Exit,
-}
diff --git a/src/main.rs b/src/main.rs
deleted file mode 100644
index 85e3888..0000000
--- a/src/main.rs
+++ /dev/null
@@ -1,24 +0,0 @@
-use crossterm::event::{self, Event};
-use std::io;
-
-use pfc::{ui, Calculator, Signal};
-
-fn main() -> io::Result<()> {
- let mut terminal = ui::init_terminal()?;
- let mut calculator = Calculator::default();
-
- let result = || -> io::Result<()> {
- loop {
- terminal.draw(|f| calculator.draw(f))?;
-
- if let Event::Key(key) = event::read()? {
- if let Signal::Exit = calculator.handle_input(key) {
- return Ok(());
- }
- }
- }
- }();
-
- ui::cleanup_terminal(terminal)?;
- result
-}
diff --git a/src/ui.rs b/src/ui.rs
deleted file mode 100644
index 76ecaf5..0000000
--- a/src/ui.rs
+++ /dev/null
@@ -1,106 +0,0 @@
-use crossterm::{
- execute,
- terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
-};
-use std::io;
-use tui::{
- backend::{Backend, CrosstermBackend},
- layout::{Alignment, Constraint, Direction, Layout, Rect},
- style::{Modifier, Style},
- text::{Span, Spans},
- widgets::{Block, Borders, List, ListItem, Paragraph, Widget},
- Frame, Terminal,
-};
-
-use crate::{AngleMode, Calculator, Constant, Function};
-
-const WIDTH: u16 = 32;
-
-impl Calculator {
- pub fn draw<B: Backend>(&self, f: &mut Frame<B>) {
- let chunks = layout(self.stack.len(), f.size());
- f.render_widget(version_number_widget(), chunks[0]);
- f.render_widget(angle_mode_widget(self.angle_mode), chunks[2]);
- f.render_widget(stack_widget(&self.stack), chunks[3]);
- f.render_widget(input_buffer_widget(&self.input_buffer), chunks[4]);
- }
-}
-
-pub fn init_terminal() -> Result<Terminal<CrosstermBackend<io::Stdout>>, io::Error> {
- enable_raw_mode()?;
- let mut stdout = io::stdout();
- execute!(stdout, EnterAlternateScreen)?;
- let backend = CrosstermBackend::new(stdout);
- Terminal::new(backend)
-}
-
-pub fn cleanup_terminal<B>(mut terminal: Terminal<B>) -> Result<(), io::Error>
-where
- B: Backend + io::Write,
-{
- disable_raw_mode()?;
- execute!(terminal.backend_mut(), LeaveAlternateScreen,)?;
- terminal.show_cursor()?;
- Ok(())
-}
-
-fn layout(stack_size: usize, frame_size: Rect) -> Vec<Rect> {
- let columns = Layout::default()
- .direction(Direction::Horizontal)
- .constraints([Constraint::Length(WIDTH), Constraint::Max(u16::MAX)].as_ref())
- .split(frame_size);
-
- Layout::default()
- .direction(Direction::Vertical)
- .constraints(
- [
- Constraint::Length(1), // Version number
- Constraint::Max(u16::MAX), // Fill
- Constraint::Length(1), // Angle mode
- Constraint::Length(stack_size as u16 + 2), // Stack
- Constraint::Length(3), // Input buffer
- ]
- .as_ref(),
- )
- .split(columns[0])
-}
-
-fn angle_mode_widget(angle_mode: AngleMode) -> impl Widget {
- Paragraph::new(format!("{}", angle_mode)).alignment(Alignment::Right)
-}
-
-fn stack_widget(stack: &Vec<f64>) -> impl Widget {
- List::new(
- stack
- .iter()
- .map(|f| ListItem::new(format!(" {}", f)))
- .collect::<Vec<ListItem>>(),
- )
- .block(Block::default().borders(Borders::ALL))
-}
-
-fn input_buffer_widget(input_buffer: &str) -> impl Widget {
- Paragraph::new(Spans::from(vec![
- Span::raw(">"),
- Span::styled(
- format!(" {}", input_buffer),
- input_buffer_style(input_buffer),
- ),
- ]))
- .block(Block::default().borders(Borders::ALL))
-}
-
-fn version_number_widget() -> impl Widget {
- Paragraph::new(format!("pfc-{}", option_env!("CARGO_PKG_VERSION").unwrap()))
- .alignment(Alignment::Center)
-}
-
-fn input_buffer_style(input_buffer: &str) -> Style {
- if let Ok(_) = Function::parse(&input_buffer) {
- Style::default().add_modifier(Modifier::BOLD)
- } else if let Ok(_) = Constant::parse(&input_buffer) {
- Style::default().add_modifier(Modifier::BOLD)
- } else {
- Style::default()
- }
-}