use crate::model::cell::CellValue; /// Format a CellValue for display with number formatting options. pub fn format_value(v: Option<&CellValue>, comma: bool, decimals: u8) -> String { match v { Some(CellValue::Number(n)) => format_f64(*n, comma, decimals), Some(CellValue::Text(s)) => s.clone(), None => String::new(), } } /// Parse a number format string like ",.0" into (use_commas, decimal_places). pub fn parse_number_format(fmt: &str) -> (bool, u8) { let comma = fmt.contains(','); let decimals = fmt .rfind('.') .and_then(|i| fmt[i + 1..].parse::().ok()) .unwrap_or(0); (comma, decimals) } /// Format an f64 with optional comma grouping and decimal places. pub fn format_f64(n: f64, comma: bool, decimals: u8) -> String { let formatted = format!("{:.prec$}", n, prec = decimals as usize); if !comma { return formatted; } let (int_part, dec_part) = if let Some(dot) = formatted.find('.') { (&formatted[..dot], Some(&formatted[dot..])) } else { (&formatted[..], None) }; let is_neg = int_part.starts_with('-'); let digits = if is_neg { &int_part[1..] } else { int_part }; let mut result = String::new(); for (idx, c) in digits.chars().rev().enumerate() { if idx > 0 && idx % 3 == 0 { result.push(','); } result.push(c); } if is_neg { result.push('-'); } let mut out: String = result.chars().rev().collect(); if let Some(dec) = dec_part { out.push_str(dec); } out }