use super::align::FormatLine;
#[cfg(test)]
use super::align::render_lines;
use super::{FormatConfig, escape_string, format_meta_value};
use crate::{
Amount, Balance, Close, Commodity, Custom, Document, Event, Metadata, Note, Open, Pad, Price,
Query,
};
use std::fmt::Write;
pub(super) fn metadata_lines(meta: &Metadata, indent: &str, out: &mut Vec<FormatLine>) {
let mut keys: Vec<_> = meta.keys().collect();
keys.sort();
for key in keys {
out.push(FormatLine::Plain(format!(
"{indent}{}: {}",
key,
format_meta_value(&meta[key])
)));
}
}
fn amount_split(amount: &Amount) -> (String, String) {
(amount.number.to_string(), amount.currency.to_string())
}
pub fn format_balance_lines(bal: &Balance, config: &FormatConfig) -> Vec<FormatLine> {
let (number, mut suffix) = amount_split(&bal.amount);
if let Some(tol) = &bal.tolerance {
write!(suffix, " ~ {tol}").expect("write to String is infallible");
}
let mut lines = vec![FormatLine::Aligned {
prefix: format!("{} balance {}", bal.date, bal.account),
number,
suffix,
}];
metadata_lines(&bal.meta, &config.indent, &mut lines);
lines
}
pub fn format_price_lines(price: &Price, config: &FormatConfig) -> Vec<FormatLine> {
let (number, suffix) = amount_split(&price.amount);
let mut lines = vec![FormatLine::Aligned {
prefix: format!("{} price {}", price.date, price.currency),
number,
suffix,
}];
metadata_lines(&price.meta, &config.indent, &mut lines);
lines
}
pub fn format_open_lines(open: &Open, config: &FormatConfig) -> Vec<FormatLine> {
let mut header = format!("{} open {}", open.date, open.account);
if !open.currencies.is_empty() {
write!(header, " {}", open.currencies.join(",")).expect("write to String is infallible");
}
if let Some(booking) = &open.booking {
write!(header, " \"{booking}\"").expect("write to String is infallible");
}
let mut lines = vec![FormatLine::Plain(header)];
metadata_lines(&open.meta, &config.indent, &mut lines);
lines
}
pub fn format_close_lines(close: &Close, config: &FormatConfig) -> Vec<FormatLine> {
let mut lines = vec![FormatLine::Plain(format!(
"{} close {}",
close.date, close.account
))];
metadata_lines(&close.meta, &config.indent, &mut lines);
lines
}
pub fn format_commodity_lines(comm: &Commodity, config: &FormatConfig) -> Vec<FormatLine> {
let mut lines = vec![FormatLine::Plain(format!(
"{} commodity {}",
comm.date, comm.currency
))];
metadata_lines(&comm.meta, &config.indent, &mut lines);
lines
}
pub fn format_pad_lines(pad: &Pad, config: &FormatConfig) -> Vec<FormatLine> {
let mut lines = vec![FormatLine::Plain(format!(
"{} pad {} {}",
pad.date, pad.account, pad.source_account
))];
metadata_lines(&pad.meta, &config.indent, &mut lines);
lines
}
pub fn format_event_lines(event: &Event, config: &FormatConfig) -> Vec<FormatLine> {
let mut lines = vec![FormatLine::Plain(format!(
"{} event \"{}\" \"{}\"",
event.date,
escape_string(&event.event_type),
escape_string(&event.value)
))];
metadata_lines(&event.meta, &config.indent, &mut lines);
lines
}
pub fn format_query_lines(query: &Query, config: &FormatConfig) -> Vec<FormatLine> {
let mut lines = vec![FormatLine::Plain(format!(
"{} query \"{}\" \"{}\"",
query.date,
escape_string(&query.name),
escape_string(&query.query)
))];
metadata_lines(&query.meta, &config.indent, &mut lines);
lines
}
pub fn format_note_lines(note: &Note, config: &FormatConfig) -> Vec<FormatLine> {
let mut lines = vec![FormatLine::Plain(format!(
"{} note {} \"{}\"",
note.date,
note.account,
escape_string(¬e.comment)
))];
metadata_lines(¬e.meta, &config.indent, &mut lines);
lines
}
pub fn format_document_lines(doc: &Document, config: &FormatConfig) -> Vec<FormatLine> {
let mut lines = vec![FormatLine::Plain(format!(
"{} document {} \"{}\"",
doc.date,
doc.account,
escape_string(&doc.path)
))];
metadata_lines(&doc.meta, &config.indent, &mut lines);
lines
}
pub fn format_custom_lines(custom: &Custom, config: &FormatConfig) -> Vec<FormatLine> {
let mut header = format!(
"{} custom \"{}\"",
custom.date,
escape_string(&custom.custom_type)
);
for value in &custom.values {
write!(header, " {}", format_meta_value(value)).expect("write to String is infallible");
}
let mut lines = vec![FormatLine::Plain(header)];
metadata_lines(&custom.meta, &config.indent, &mut lines);
lines
}
macro_rules! string_wrapper {
($(#[$m:meta])* $name:ident, $lines:ident, $ty:ty) => {
#[cfg(test)]
$(#[$m])*
pub(super) fn $name(value: &$ty, config: &FormatConfig) -> String {
render_lines(&$lines(value, config), &config.alignment)
}
};
}
string_wrapper!(
format_balance, format_balance_lines, Balance);
string_wrapper!(
format_price, format_price_lines, Price);
string_wrapper!(
format_open, format_open_lines, Open);
string_wrapper!(
format_close, format_close_lines, Close);
string_wrapper!(
format_commodity, format_commodity_lines, Commodity);
string_wrapper!(
format_pad, format_pad_lines, Pad);
string_wrapper!(
format_event, format_event_lines, Event);
string_wrapper!(
format_query, format_query_lines, Query);
string_wrapper!(
format_note, format_note_lines, Note);
string_wrapper!(
format_document, format_document_lines, Document);
string_wrapper!(
format_custom, format_custom_lines, Custom);