From cdb24f0f9453787827762f4dda9af4fb1813adce Mon Sep 17 00:00:00 2001 From: Rushmore75 Date: Tue, 11 Nov 2025 09:19:49 -0700 Subject: [PATCH] fix #4 --- src/app/app.rs | 4 +++- src/app/ctx.rs | 29 +++++++++++++++++++++++++++-- src/main.rs | 4 ++++ 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/src/app/app.rs b/src/app/app.rs index 926f4a4..8c49576 100644 --- a/src/app/app.rs +++ b/src/app/app.rs @@ -122,8 +122,10 @@ impl Widget for &App { .underline_color(Color::DarkGray) .add_modifier(Modifier::UNDERLINED); } else { + // the formula is broken + display = e.to_owned(); style = - Style::new().underline_color(Color::Red).add_modifier(Modifier::UNDERLINED) + Style::new().fg(Color::Red).underline_color(Color::Red).add_modifier(Modifier::UNDERLINED) } } } diff --git a/src/app/ctx.rs b/src/app/ctx.rs index ecd41a0..2b6a612 100644 --- a/src/app/ctx.rs +++ b/src/app/ctx.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use std::{collections::HashMap, sync::RwLock}; use evalexpr::{error::EvalexprResultValue, *}; @@ -6,6 +6,7 @@ use crate::app::calc::Grid; pub struct CallbackContext<'a, T: EvalexprNumericTypes = DefaultNumericTypes> { variables: &'a Grid, + eval_depth: RwLock, functions: HashMap>, /// True if builtin functions are disabled. @@ -15,6 +16,7 @@ pub struct CallbackContext<'a, T: EvalexprNumericTypes = DefaultNumericTypes> { impl<'a, NumericTypes: EvalexprNumericTypes> CallbackContext<'a, NumericTypes> { pub fn new(grid: &'a Grid) -> Self { Self { + eval_depth: RwLock::new(0), variables: grid, functions: Default::default(), 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::String(s) => unimplemented!("{s}"), 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) { 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}'"), + } + }, } }, } diff --git a/src/main.rs b/src/main.rs index 29dcf1d..35709d6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -15,6 +15,10 @@ fn main() -> Result<(), std::io::Error> { app.grid.set_cell("D0", "x2".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); ratatui::restore(); return res;