use std::collections::BTreeMap; use itertools::Itertools; use crate::data::{Root, SourceFile, Span, Spanned}; use super::{LedgerEntry, Transaction}; fn print_transaction(root: &Root, tx: &Transaction, padding: usize) { println!( "{}: {}", tx.datestamp, tx.title.as_deref().unwrap_or("") ); if !tx.annotations.is_empty() { println!( " {}", tx.annotations.iter().map(|a| format!("[{a}]")).join(" ") ); } let force_show = tx.changes.iter().unique_by(|b| *b.account).count() > 1; for change in &tx.changes { let spacer = if change.amount.is_sign_positive() { " " } else { "" }; let balance = if let Some(bal) = change.balance { format!(" = {bal}") } else { String::new() }; if Some(change.unit.as_ref()) == root.account_spec(*change.account).unwrap().unit.as_ref() && !force_show { println!(" - {:padding$}: {spacer}{}{balance}", change.account, change.amount,); } else { println!( " - {:padding$}: {spacer}{}{balance} {}", change.account, change.amount, change.unit, ); } } // empty line afterwards println!(); } fn print_comment(c: &Spanned) { println!("{c}"); } pub fn print_ledger<'l>(root: &Root, entries: impl Iterator) { let mut ordering = BTreeMap::>::new(); entries.for_each(|e| { ordering .entry(e.span().context) .or_default() .insert(e.span(), &e); }); let Some(padding) = root.spec_root.accounts.keys().map(|k| k.len()).max() else { // no accounts return; }; for (filename, entries) in ordering { println!( "==== file {} ====", std::path::Path::new(filename.as_ref()).display() ); for (_span, le) in entries { match le { LedgerEntry::Transaction(tx) => print_transaction(root, tx, padding), LedgerEntry::Comment(c) => print_comment(c), } } } }