use colored::Colorize;
use super::util::{format_amount, print_spaces};
use crate::loader::Journal;
use crate::parser::posting::Posting;
use crate::parser::transaction::{State, Transaction};
const GAP: usize = 4;
pub fn run(journal: &Journal) {
let account_max = max_account_width(journal);
let amount_max = max_amount_width(journal);
let mut iter = journal.transactions.iter().peekable();
while let Some(lt) = iter.next() {
let tx = <.value;
print_header(tx);
for lp in &tx.postings {
print_posting(&lp.value, account_max, amount_max, &journal.precisions);
}
if iter.peek().is_some() {
println!();
}
}
}
fn print_header(tx: &Transaction) {
let marker = match tx.state {
State::Cleared => " * ".green().to_string(),
State::Uncleared => " ".to_string(),
State::Pending => " ! ".yellow().to_string(),
};
let code = tx
.code
.as_deref()
.map(|c| format!("({}) ", c).yellow().to_string())
.unwrap_or_default();
println!("{}{}{}{}", tx.date, marker, code, tx.description.bold());
for comment in &tx.comments {
print_spaces(GAP);
println!("{}", format!("; {}", comment.value.text).dimmed());
}
}
fn print_posting(
p: &Posting,
account_max: usize,
amount_max: usize,
precisions: &std::collections::HashMap<String, usize>,
) {
let display = render_account(p);
let display_width = display.chars().count();
print_spaces(GAP);
print!("{}", display.blue());
if let Some(amount) = &p.amount {
print_spaces(account_max.saturating_sub(display_width) + GAP);
let formatted = format_amount(&amount.commodity, &amount.value, precisions);
print_spaces(amount_max.saturating_sub(formatted.chars().count()));
if amount.value.is_negative() {
print!("{}", formatted.red());
} else {
print!("{}", formatted);
}
}
println!();
for comment in &p.comments {
print_spaces(GAP);
println!("{}", format!("; {}", comment.value.text).dimmed());
}
}
fn render_account(p: &Posting) -> String {
if p.is_virtual {
format!("({})", p.account)
} else {
p.account.clone()
}
}
fn max_account_width(journal: &Journal) -> usize {
journal
.transactions
.iter()
.flat_map(|tx| tx.value.postings.iter())
.map(|lp| render_account(&lp.value).chars().count())
.max()
.unwrap_or(0)
}
fn max_amount_width(journal: &Journal) -> usize {
journal
.transactions
.iter()
.flat_map(|tx| tx.value.postings.iter())
.filter_map(|lp| {
lp.value.amount.as_ref().map(|a| {
format_amount(&a.commodity, &a.value, &journal.precisions)
.chars()
.count()
})
})
.max()
.unwrap_or(0)
}