diff options
| author | mo khan <mo@mokhan.ca> | 2025-06-26 18:56:07 -0600 |
|---|---|---|
| committer | mo khan <mo@mokhan.ca> | 2025-06-26 18:56:07 -0600 |
| commit | 620fbf3f7515493c6b67032088a032c8bc6a1bc0 (patch) | |
| tree | cbe29a9d74b6634374ea4289ddbfba8002fb8ea5 | |
| parent | 6f748dba5cec3509e01875deac3db4866912f02f (diff) | |
fix: prevent TUI crash from NaN/infinite float formatting
- Add is_finite() checks before formatting all float values
- Handle NaN and infinite values by defaulting to 0.0
- Fixes crash when pressing Tab with invalid financial data
- Ensures robust handling of edge cases in calculations
This prevents the "formatting trait implementation returned an error"
panic when displaying views with invalid floating point values.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
| -rw-r--r-- | src/tui/dashboard.rs | 17 | ||||
| -rw-r--r-- | src/tui/ui.rs | 13 |
2 files changed, 18 insertions, 12 deletions
diff --git a/src/tui/dashboard.rs b/src/tui/dashboard.rs index 5eed457..3c4d979 100644 --- a/src/tui/dashboard.rs +++ b/src/tui/dashboard.rs @@ -52,7 +52,7 @@ fn draw_net_worth(f: &mut Frame, app: &App, area: Rect) { Line::from(vec![ Span::raw("$"), Span::styled( - format!("{:.0}", app.net_worth), + format!("{:.0}", if app.net_worth.is_finite() { app.net_worth } else { 0.0 }), Style::default() .fg(Color::Green) .add_modifier(Modifier::BOLD), @@ -60,13 +60,16 @@ fn draw_net_worth(f: &mut Frame, app: &App, area: Rect) { ]), Line::from(vec![ Span::styled( - format!("↑ ${:.0} ({:+.1}%)", net_worth_change, change_pct), + format!("↑ ${:.0} ({:+.1}%)", + if net_worth_change.is_finite() { net_worth_change } else { 0.0 }, + if change_pct.is_finite() { change_pct } else { 0.0 } + ), Style::default().fg(Color::Green), ), ]), Line::from(""), - Line::from(format!("💵 Cash: ${:.0}", app.cash_balance)), - Line::from(format!("📈 Invest: ${:.0}", app.investment_balance)), + Line::from(format!("💵 Cash: ${:.0}", if app.cash_balance.is_finite() { app.cash_balance } else { 0.0 })), + Line::from(format!("📈 Invest: ${:.0}", if app.investment_balance.is_finite() { app.investment_balance } else { 0.0 })), ]; let net_worth = Paragraph::new(net_worth_text) @@ -108,7 +111,7 @@ fn draw_cash_flow(f: &mut Frame, app: &App, area: Rect) { .block(Block::default()) .gauge_style(Style::default().fg(Color::Green)) .ratio(income_ratio) - .label(format!("Income: ${:.0}", app.income)); + .label(format!("Income: ${:.0}", if app.income.is_finite() { app.income } else { 0.0 })); // Expenses bar let expense_ratio = if max_value > 0.0 { app.expenses / max_value } else { 0.0 }; @@ -116,7 +119,7 @@ fn draw_cash_flow(f: &mut Frame, app: &App, area: Rect) { .block(Block::default()) .gauge_style(Style::default().fg(Color::Red)) .ratio(expense_ratio) - .label(format!("Expenses: ${:.0}", app.expenses)); + .label(format!("Expenses: ${:.0}", if app.expenses.is_finite() { app.expenses } else { 0.0 })); // Net bar let net_ratio = if max_value > 0.0 { net.abs() / max_value } else { 0.0 }; @@ -124,7 +127,7 @@ fn draw_cash_flow(f: &mut Frame, app: &App, area: Rect) { .block(Block::default()) .gauge_style(Style::default().fg(if net >= 0.0 { Color::Cyan } else { Color::Magenta })) .ratio(net_ratio) - .label(format!("Net: {:+.0}", net)); + .label(format!("Net: {:+.0}", if net.is_finite() { net } else { 0.0 })); // Render frame and gauges let frame = Block::default() diff --git a/src/tui/ui.rs b/src/tui/ui.rs index dba989a..ceb66b4 100644 --- a/src/tui/ui.rs +++ b/src/tui/ui.rs @@ -132,7 +132,7 @@ fn draw_budgets(f: &mut Frame, app: &App, area: Rect) { Line::from(vec![ Span::raw(format!("{:<15} ", category)), Span::styled(bar, Style::default().fg(status_color)), - Span::raw(format!(" ${:.0}/${:.0}", spent, budget)), + Span::raw(format!(" ${:.0}/${:.0}", spent.max(0.0), budget.max(0.0))), ]) }) .collect(); @@ -152,12 +152,15 @@ fn draw_investments(f: &mut Frame, app: &App, area: Rect) { let gain_pct = if total_book > 0.0 { (total_gain / total_book) * 100.0 } else { 0.0 }; let investment_text = vec![ - Line::from(format!("Total Market Value: ${:.2}", total_value)), - Line::from(format!("Total Book Value: ${:.2}", total_book)), + Line::from(format!("Total Market Value: ${:.2}", if total_value.is_finite() { total_value } else { 0.0 })), + Line::from(format!("Total Book Value: ${:.2}", if total_book.is_finite() { total_book } else { 0.0 })), Line::from(vec![ Span::raw("Unrealized Gain: "), Span::styled( - format!("${:.2} ({:+.1}%)", total_gain, gain_pct), + format!("${:.2} ({:+.1}%)", + if total_gain.is_finite() { total_gain } else { 0.0 }, + if gain_pct.is_finite() { gain_pct } else { 0.0 } + ), Style::default().fg(if total_gain >= 0.0 { Color::Green } else { Color::Red }), ), ]), @@ -171,7 +174,7 @@ fn draw_investments(f: &mut Frame, app: &App, area: Rect) { " {} ({:?}): ${:.2}", portfolio.account_id, portfolio.account_type, - portfolio.total_market_value + if portfolio.total_market_value.is_finite() { portfolio.total_market_value } else { 0.0 } ))); } |
