Start work on formatting options

This commit is contained in:
Austen Adler 2021-05-03 00:48:25 -04:00
parent 062cd97609
commit 85ea8ca776
2 changed files with 116 additions and 9 deletions

View File

@ -333,7 +333,7 @@ impl<'a> Calculator<'a> {
push: OpArgs::Unary(f), push: OpArgs::Unary(f),
}) })
} }
fn pop(&mut self) -> CalculatorResult<f64> { pub fn pop(&mut self) -> CalculatorResult<f64> {
let f = self.checked_get(0)?; let f = self.checked_get(0)?;
self.direct_state_change(CalculatorStateChange { self.direct_state_change(CalculatorStateChange {
pop: OpArgs::Unary(f), pop: OpArgs::Unary(f),
@ -341,6 +341,15 @@ impl<'a> Calculator<'a> {
})?; })?;
Ok(f) Ok(f)
} }
pub fn pop_usize(&mut self) -> CalculatorResult<usize> {
let f = self.checked_get(0)?;
let ret = usize::from(f as usize);
self.direct_state_change(CalculatorStateChange {
pop: OpArgs::Unary(f),
push: OpArgs::None,
})?;
Ok(ret)
}
pub fn op(&mut self, op: CalculatorOperation) -> CalculatorResult<()> { pub fn op(&mut self, op: CalculatorOperation) -> CalculatorResult<()> {
// Dup is special -- don't actually run it if l needs to be flushed // Dup is special -- don't actually run it if l needs to be flushed
if self.flush_l()? { if self.flush_l()? {

View File

@ -27,7 +27,18 @@ struct Dimensions {
height: u16, height: u16,
} }
enum DisplayMode {
Default(Option<char>),
Scientific(usize),
Engineering,
}
struct AppSettings {
display_mode: DisplayMode,
}
enum AppState { enum AppState {
AppSettings,
Calculator, Calculator,
Help, Help,
} }
@ -37,6 +48,7 @@ struct App<'a> {
error_msg: Option<String>, error_msg: Option<String>,
state: AppState, state: AppState,
current_macro: Option<char>, current_macro: Option<char>,
app_settings: AppSettings,
} }
impl<'a> Default for App<'a> { impl<'a> Default for App<'a> {
@ -46,6 +58,9 @@ impl<'a> Default for App<'a> {
error_msg: None, error_msg: None,
state: AppState::Calculator, state: AppState::Calculator,
current_macro: None, current_macro: None,
app_settings: AppSettings {
display_mode: DisplayMode::Default(None),
},
} }
} }
} }
@ -80,13 +95,24 @@ fn main() -> Result<(), Box<dyn Error>> {
Span::raw("Error: "), Span::raw("Error: "),
Span::styled(e, Style::default().add_modifier(Modifier::RAPID_BLINK)), Span::styled(e, Style::default().add_modifier(Modifier::RAPID_BLINK)),
], ],
(None, AppState::Calculator) => vec![ (None, AppState::Calculator) => {
Span::raw("Press "), // TODO: There has to be a better way than making strings each time
Span::styled("q", Style::default().add_modifier(Modifier::BOLD)), let display_mode_str = match &app.app_settings.display_mode {
Span::raw(" to exit, "), DisplayMode::Default(None) => String::from("[d]"),
Span::styled("h", Style::default().add_modifier(Modifier::BOLD)), DisplayMode::Default(Some(c)) => format!("[d({})]", c),
Span::raw(" for help"), DisplayMode::Scientific(p) => format!("[s({})]", p),
], DisplayMode::Engineering => String::from("[e]"),
};
vec![
Span::raw("Press "),
Span::styled("q", Style::default().add_modifier(Modifier::BOLD)),
Span::raw(" to exit, "),
Span::styled("h", Style::default().add_modifier(Modifier::BOLD)),
Span::raw(" for help - "),
Span::raw(display_mode_str),
]
}
(None, _) => vec![ (None, _) => vec![
Span::raw("Press "), Span::raw("Press "),
Span::styled("<esc>", Style::default().add_modifier(Modifier::BOLD)), Span::styled("<esc>", Style::default().add_modifier(Modifier::BOLD)),
@ -106,7 +132,16 @@ fn main() -> Result<(), Box<dyn Error>> {
.enumerate() .enumerate()
.rev() .rev()
.map(|(i, m)| { .map(|(i, m)| {
let content = vec![Spans::from(Span::raw(format!("{}: {}", i, m)))]; let content = vec![Spans::from(Span::raw(
match &app.app_settings.display_mode {
DisplayMode::Default(None) => format!("{:>2}: {}", i, *m),
DisplayMode::Default(Some(c)) => fmt_separated(i, *m, *c),
DisplayMode::Scientific(precision) => fmt_scientific(i, *m, *precision),
DisplayMode::Engineering => {
format!("{:>2}: {}", i, m)
}
},
))];
ListItem::new(content) ListItem::new(content)
}) })
.collect(); .collect();
@ -134,6 +169,22 @@ fn main() -> Result<(), Box<dyn Error>> {
); );
match (&app.state, app.calculator.get_state()) { match (&app.state, app.calculator.get_state()) {
(AppState::AppSettings, _) => {
draw_clippy_rect(
ClippyRectangle {
title: "App Settings",
msg: "\
d => Default\n\
, => Default (comma separated)\n\
s => Scientific\n\
S => Scientific (stack precision)\n\
e => Engineering\n\
E => Engineering (stack precision)\n\
",
},
f,
);
}
(AppState::Help, _) => { (AppState::Help, _) => {
draw_clippy_rect( draw_clippy_rect(
ClippyRectangle { ClippyRectangle {
@ -248,6 +299,9 @@ fn handle_key(app: &mut App, events: &Events, key: Key) -> CalculatorResult<bool
Key::Char('h') => { Key::Char('h') => {
app.state = AppState::Help; app.state = AppState::Help;
} }
Key::Ctrl('s') => {
app.state = AppState::AppSettings;
}
Key::Char('\n') | Key::Char(' ') => { Key::Char('\n') | Key::Char(' ') => {
app.calculator.take_input(' ')?; app.calculator.take_input(' ')?;
} }
@ -265,6 +319,20 @@ fn handle_key(app: &mut App, events: &Events, key: Key) -> CalculatorResult<bool
} }
_ => {} _ => {}
}, },
(AppState::AppSettings, _) => match key {
Key::Esc | Key::Char('q') => {
app.state = AppState::Calculator;
app.calculator.cancel()?;
}
Key::Char('d') => app.app_settings.display_mode = DisplayMode::Default(None),
Key::Char(',') => app.app_settings.display_mode = DisplayMode::Default(Some(',')),
Key::Char('s') => app.app_settings.display_mode = DisplayMode::Scientific(3),
Key::Char('S') => {
app.app_settings.display_mode = DisplayMode::Scientific(app.calculator.pop_usize()?)
}
Key::Char('e') => app.app_settings.display_mode = DisplayMode::Engineering,
_ => {}
},
(AppState::Help, _) => match key { (AppState::Help, _) => match key {
Key::Esc | Key::Char('q') => { Key::Esc | Key::Char('q') => {
app.state = AppState::Calculator; app.state = AppState::Calculator;
@ -336,3 +404,33 @@ fn draw_clippy_rect<T: std::io::Write>(c: ClippyRectangle, f: &mut Frame<Termion
.block(Block::default().borders(Borders::ALL).title(c.title)); .block(Block::default().borders(Borders::ALL).title(c.title));
f.render_widget(help_message, area); f.render_widget(help_message, area);
} }
fn fmt_scientific(i: usize, f: f64, precision: usize) -> String {
let mut ret = format!("{:.precision$e}", f, precision = precision);
let exp = ret.split_off(ret.find('e').unwrap_or(0));
let (pow_sign, exp) = if exp.starts_with("e-") {
('-', &exp[2..])
} else {
('+', &exp[1..])
};
let sign = if !ret.starts_with('-') { " " } else { "" };
format!(
"{:>2}: {}{}e{}{:0>pad$}",
i,
sign,
ret,
pow_sign,
exp,
pad = 2
)
}
fn fmt_separated(i: usize, f: f64, sep: char) -> String {
let mut ret = f.to_string();
let start = if ret.starts_with('-') { 1 } else { 0 };
let end = ret.find('.').unwrap_or(ret.len());
for i in 0..((end - start).div_euclid(3)) {
ret.insert(end - start - (i + 1) * 3, sep);
}
format!("{:>2}: {}", i, ret)
}