Use method 1 for macro undos

This commit is contained in:
Austen Adler 2021-04-29 22:08:33 -04:00
parent e9ef4db202
commit 0e69681ab8

View File

@ -20,6 +20,7 @@ enum OpArgs {
struct CalculatorStateChange {
pop: OpArgs,
push: OpArgs,
within_macro: bool,
}
pub struct Calculator<'a> {
@ -171,6 +172,12 @@ impl<'a> Calculator<'a> {
// The macro needs to run in normal mode
self.state = CalculatorState::Normal;
// Add a no-op undo event as a stopgap for undo/redo operations (fixes undo after multiple macros running)
// self.direct_state_change(CalculatorStateChange {
// pop: OpArgs::None,
// push: OpArgs::None,
// within_macro: self.within_macro(),
// })?;
// Record that we are running macro c
self.active_macros.insert(c);
for c in value.chars() {
@ -271,36 +278,6 @@ impl<'a> Calculator<'a> {
self.registers.iter()
}
// pub fn push_constant(&mut self, key: char) -> CalculatorResult<()> {
// match self.constants.get(&key) {
// Some(CalculatorConstant { value, .. }) => {
// let value = *value;
// self.push(value)
// }
// None => Err(CalculatorError::NoSuchConstant(key)),
// }
// }
// pub fn push_register(&mut self, key: char) -> CalculatorResult<()> {
// match self.registers.get(&key) {
// Some(f) => {
// let f = *f;
// self.push(f)
// }
// None => Err(CalculatorError::NoSuchRegister),
// }
// }
// pub fn save_register(&mut self, key: char) -> CalculatorResult<()> {
// let f = self.pop()?;
// self.registers.insert(key, f);
// Ok(())
// }
// pub fn get_macro(&mut self, key: char) -> Result<&CalculatorMacro<'a>, CalculatorError> {
// match self.macros.get(&key) {
// Some(m) => Ok(m),
// None => Err(CalculatorError::NoSuchMacro(key)),
// }
// }
pub fn flush_l(&mut self) -> CalculatorResult<bool> {
if self.l.is_empty() {
Ok(false)
@ -311,10 +288,14 @@ impl<'a> Calculator<'a> {
Ok(true)
}
}
fn within_macro(&self) -> bool {
!self.active_macros.is_empty()
}
fn push(&mut self, f: f64) -> CalculatorResult<()> {
self.direct_state_change(CalculatorStateChange {
pop: OpArgs::None,
push: OpArgs::Unary(f),
within_macro: self.within_macro(),
})
}
fn pop(&mut self) -> CalculatorResult<f64> {
@ -322,6 +303,7 @@ impl<'a> Calculator<'a> {
self.direct_state_change(CalculatorStateChange {
pop: OpArgs::Unary(f),
push: OpArgs::None,
within_macro: self.within_macro(),
})?;
Ok(f)
}
@ -366,18 +348,50 @@ impl<'a> Calculator<'a> {
CalculatorOperation::Pow => self.binary_op(|[a, b]| OpArgs::Unary(b.powf(a))),
CalculatorOperation::E => self.binary_op(|[a, b]| OpArgs::Unary(b * 10.0f64.powf(a))),
CalculatorOperation::Undo => {
let s = self
.undo_buf
.pop()
.ok_or_else(|| CalculatorError::EmptyHistory(String::from("undo")))?;
return self.apply_state_change(s, false);
let mut undone_already = false;
loop {
if undone_already {
let s = self
.undo_buf
.last()
.ok_or_else(|| CalculatorError::EmptyHistory(String::from("undo")))?;
if !s.within_macro {
return Ok(());
}
}
let s = self
.undo_buf
.pop()
.ok_or_else(|| CalculatorError::EmptyHistory(String::from("undo")))?;
let stop = !s.within_macro;
self.apply_state_change(s, false)?;
if stop {
return Ok(());
}
undone_already = true;
}
}
CalculatorOperation::Redo => {
let s = self
.redo_buf
.pop()
.ok_or_else(|| CalculatorError::EmptyHistory(String::from("redo")))?;
return self.apply_state_change(s, true);
let mut redone_already = false;
loop {
let s = match self.redo_buf.pop() {
None => {
if redone_already {
return Ok(());
}
return Err(CalculatorError::EmptyHistory(String::from("redo")));
}
Some(s) => {
let stop = !s.within_macro;
self.apply_state_change(s, true)?;
if stop {
return Ok(());
}
redone_already = true;
}
};
}
}
// Macros are a no-op as an operator
CalculatorOperation::Macro(_) => {
@ -399,6 +413,7 @@ impl<'a> Calculator<'a> {
Ok(CalculatorStateChange {
pop: OpArgs::Unary(*arg),
push: op(*arg),
within_macro: self.within_macro(),
})
}
fn binary_op(
@ -418,6 +433,7 @@ impl<'a> Calculator<'a> {
Ok(CalculatorStateChange {
pop: OpArgs::Binary(args),
push: op(args),
within_macro: self.within_macro(),
})
}