refactor: make Model::formulas private, expose read-only accessor
Previously `pub formulas: Vec<Formula>` allowed any code to call `model.formulas.push(formula)` directly, bypassing the dedup logic in `add_formula` that enforces the (target, target_category) uniqueness invariant. Making the field private means the only mutation paths are `add_formula` and `remove_formula`, both of which maintain the invariant. A `pub fn formulas(&self) -> &[Formula]` accessor preserves read access for the UI and tests. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@ -14,7 +14,7 @@ pub struct Model {
|
|||||||
pub name: String,
|
pub name: String,
|
||||||
pub categories: IndexMap<String, Category>,
|
pub categories: IndexMap<String, Category>,
|
||||||
pub data: DataStore,
|
pub data: DataStore,
|
||||||
pub formulas: Vec<Formula>,
|
formulas: Vec<Formula>,
|
||||||
pub views: IndexMap<String, View>,
|
pub views: IndexMap<String, View>,
|
||||||
pub active_view: String,
|
pub active_view: String,
|
||||||
next_category_id: CategoryId,
|
next_category_id: CategoryId,
|
||||||
@ -86,6 +86,10 @@ impl Model {
|
|||||||
self.formulas.retain(|f| !(f.target == target && f.target_category == target_category));
|
self.formulas.retain(|f| !(f.target == target && f.target_category == target_category));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn formulas(&self) -> &[Formula] {
|
||||||
|
&self.formulas
|
||||||
|
}
|
||||||
|
|
||||||
pub fn active_view(&self) -> Option<&View> {
|
pub fn active_view(&self) -> Option<&View> {
|
||||||
self.views.get(&self.active_view)
|
self.views.get(&self.active_view)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -595,7 +595,7 @@ impl App {
|
|||||||
|
|
||||||
fn handle_formula_panel_key(&mut self, key: KeyEvent) -> Result<()> {
|
fn handle_formula_panel_key(&mut self, key: KeyEvent) -> Result<()> {
|
||||||
// Clamp cursor in case the formula list shrank since it was last set.
|
// Clamp cursor in case the formula list shrank since it was last set.
|
||||||
let flen = self.model.formulas.len();
|
let flen = self.model.formulas().len();
|
||||||
if flen == 0 { self.formula_cursor = 0; }
|
if flen == 0 { self.formula_cursor = 0; }
|
||||||
else { self.formula_cursor = self.formula_cursor.min(flen - 1); }
|
else { self.formula_cursor = self.formula_cursor.min(flen - 1); }
|
||||||
|
|
||||||
@ -605,8 +605,8 @@ impl App {
|
|||||||
self.mode = AppMode::FormulaEdit { buffer: String::new() };
|
self.mode = AppMode::FormulaEdit { buffer: String::new() };
|
||||||
}
|
}
|
||||||
KeyCode::Char('d') | KeyCode::Delete => {
|
KeyCode::Char('d') | KeyCode::Delete => {
|
||||||
if self.formula_cursor < self.model.formulas.len() {
|
if self.formula_cursor < self.model.formulas().len() {
|
||||||
let f = &self.model.formulas[self.formula_cursor];
|
let f = &self.model.formulas()[self.formula_cursor];
|
||||||
let target = f.target.clone();
|
let target = f.target.clone();
|
||||||
let target_category = f.target_category.clone();
|
let target_category = f.target_category.clone();
|
||||||
command::dispatch(&mut self.model, &Command::RemoveFormula { target, target_category });
|
command::dispatch(&mut self.model, &Command::RemoveFormula { target, target_category });
|
||||||
@ -618,7 +618,7 @@ impl App {
|
|||||||
if self.formula_cursor > 0 { self.formula_cursor -= 1; }
|
if self.formula_cursor > 0 { self.formula_cursor -= 1; }
|
||||||
}
|
}
|
||||||
KeyCode::Down | KeyCode::Char('j') => {
|
KeyCode::Down | KeyCode::Char('j') => {
|
||||||
if self.formula_cursor + 1 < self.model.formulas.len() { self.formula_cursor += 1; }
|
if self.formula_cursor + 1 < self.model.formulas().len() { self.formula_cursor += 1; }
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -36,7 +36,7 @@ impl<'a> Widget for FormulaPanel<'a> {
|
|||||||
let inner = block.inner(area);
|
let inner = block.inner(area);
|
||||||
block.render(area, buf);
|
block.render(area, buf);
|
||||||
|
|
||||||
let formulas = &self.model.formulas;
|
let formulas = self.model.formulas();
|
||||||
|
|
||||||
if formulas.is_empty() {
|
if formulas.is_empty() {
|
||||||
buf.set_string(inner.x, inner.y,
|
buf.set_string(inner.x, inner.y,
|
||||||
|
|||||||
Reference in New Issue
Block a user