diff --git a/src/format.rs b/src/format.rs new file mode 100644 index 0000000..ed31509 --- /dev/null +++ b/src/format.rs @@ -0,0 +1,50 @@ +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 +} diff --git a/src/main.rs b/src/main.rs index b1d1adf..642f343 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,6 @@ mod command; mod draw; +mod format; mod formula; mod import; mod model; diff --git a/src/persistence/mod.rs b/src/persistence/mod.rs index 2912448..4052e29 100644 --- a/src/persistence/mod.rs +++ b/src/persistence/mod.rs @@ -458,17 +458,7 @@ pub fn export_csv(model: &Model, view_name: &str, path: &Path) -> Result<()> { out.push(','); } let row_values: Vec = (0..layout.col_count()) - .map(|ci| { - if layout.is_records_mode() { - layout.records_display(ri, ci).unwrap_or_default() - } else { - layout - .cell_key(ri, ci) - .and_then(|key| model.evaluate_aggregated(&key, &layout.none_cats)) - .map(|v| v.to_string()) - .unwrap_or_default() - } - }) + .map(|ci| layout.display_text(model, ri, ci, false, 0)) .collect(); out.push_str(&row_values.join(",")); out.push('\n');