This commit is contained in:
2025-11-11 09:19:49 -07:00
parent 6753e2ddd6
commit cdb24f0f94
3 changed files with 34 additions and 3 deletions

View File

@@ -122,8 +122,10 @@ impl Widget for &App {
.underline_color(Color::DarkGray) .underline_color(Color::DarkGray)
.add_modifier(Modifier::UNDERLINED); .add_modifier(Modifier::UNDERLINED);
} else { } else {
// the formula is broken
display = e.to_owned();
style = style =
Style::new().underline_color(Color::Red).add_modifier(Modifier::UNDERLINED) Style::new().fg(Color::Red).underline_color(Color::Red).add_modifier(Modifier::UNDERLINED)
} }
} }
} }

View File

@@ -1,4 +1,4 @@
use std::collections::HashMap; use std::{collections::HashMap, sync::RwLock};
use evalexpr::{error::EvalexprResultValue, *}; use evalexpr::{error::EvalexprResultValue, *};
@@ -6,6 +6,7 @@ use crate::app::calc::Grid;
pub struct CallbackContext<'a, T: EvalexprNumericTypes = DefaultNumericTypes> { pub struct CallbackContext<'a, T: EvalexprNumericTypes = DefaultNumericTypes> {
variables: &'a Grid, variables: &'a Grid,
eval_depth: RwLock<usize>,
functions: HashMap<String, Function<T>>, functions: HashMap<String, Function<T>>,
/// True if builtin functions are disabled. /// True if builtin functions are disabled.
@@ -15,6 +16,7 @@ pub struct CallbackContext<'a, T: EvalexprNumericTypes = DefaultNumericTypes> {
impl<'a, NumericTypes: EvalexprNumericTypes> CallbackContext<'a, NumericTypes> { impl<'a, NumericTypes: EvalexprNumericTypes> CallbackContext<'a, NumericTypes> {
pub fn new(grid: &'a Grid) -> Self { pub fn new(grid: &'a Grid) -> Self {
Self { Self {
eval_depth: RwLock::new(0),
variables: grid, variables: grid,
functions: Default::default(), functions: Default::default(),
without_builtin_functions: false, without_builtin_functions: false,
@@ -45,9 +47,32 @@ impl<'a> Context for CallbackContext<'a, DefaultNumericTypes> {
super::calc::CellType::Number(n) => return Some(Value::Float(n.to_owned())), super::calc::CellType::Number(n) => return Some(Value::Float(n.to_owned())),
super::calc::CellType::String(s) => unimplemented!("{s}"), super::calc::CellType::String(s) => unimplemented!("{s}"),
super::calc::CellType::Equation(eq) => { super::calc::CellType::Equation(eq) => {
if let Ok(mut depth) = self.eval_depth.write() {
*depth += 1;
}
if let Ok(depth) = self.eval_depth.read() {
if *depth > 10 {
return None
}
} else {
// It would be unsafe to continue to process without knowing how
// deep we've gone.
return None
}
match eval_with_context(&eq[1..], self) { match eval_with_context(&eq[1..], self) {
Ok(e) => return Some(e), Ok(e) => return Some(e),
Err(e) => panic!("{e} \"{eq}\""), Err(e) => {
match e {
EvalexprError::VariableIdentifierNotFound(_) => {
// If the variable isn't found, that's ~~probably~~ because
// of recursive reference, considering all references
// are grabbed straight from the table.
return None
},
e => panic!("> Error {e}\n> Equation: '{eq}'"),
}
},
} }
}, },
} }

View File

@@ -15,6 +15,10 @@ fn main() -> Result<(), std::io::Error> {
app.grid.set_cell("D0", "x2".to_string()); app.grid.set_cell("D0", "x2".to_string());
app.grid.set_cell("D1", "=C1*2".to_string()); app.grid.set_cell("D1", "=C1*2".to_string());
app.grid.set_cell("A4", "Recursive references don't break anything!".to_string());
app.grid.set_cell("A5", "=B5".to_string());
app.grid.set_cell("B5", "=A5".to_string());
let res = app.run(term); let res = app.run(term);
ratatui::restore(); ratatui::restore();
return res; return res;