Use method 1 for macro undos
This commit is contained in:
parent
e9ef4db202
commit
0e69681ab8
96
src/calc.rs
96
src/calc.rs
@ -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(),
|
||||
})
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user