Start work on formatting options
This commit is contained in:
parent
062cd97609
commit
85ea8ca776
11
src/calc.rs
11
src/calc.rs
@ -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()? {
|
||||||
|
106
src/main.rs
106
src/main.rs
@ -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) => {
|
||||||
|
// TODO: There has to be a better way than making strings each time
|
||||||
|
let display_mode_str = match &app.app_settings.display_mode {
|
||||||
|
DisplayMode::Default(None) => String::from("[d]"),
|
||||||
|
DisplayMode::Default(Some(c)) => format!("[d({})]", c),
|
||||||
|
DisplayMode::Scientific(p) => format!("[s({})]", p),
|
||||||
|
DisplayMode::Engineering => String::from("[e]"),
|
||||||
|
};
|
||||||
|
|
||||||
|
vec![
|
||||||
Span::raw("Press "),
|
Span::raw("Press "),
|
||||||
Span::styled("q", Style::default().add_modifier(Modifier::BOLD)),
|
Span::styled("q", Style::default().add_modifier(Modifier::BOLD)),
|
||||||
Span::raw(" to exit, "),
|
Span::raw(" to exit, "),
|
||||||
Span::styled("h", Style::default().add_modifier(Modifier::BOLD)),
|
Span::styled("h", Style::default().add_modifier(Modifier::BOLD)),
|
||||||
Span::raw(" for help"),
|
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)
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user