From e6b225226d4f19577ac7c46e3bf43d97ae77c670 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Yaroslav=20de=20la=20Pe=C3=B1a=20Smirnov?=
 <yps@yaroslavps.com>
Date: Sat, 10 Oct 2020 16:04:07 +0300
Subject: Switch to superior indentation method

Also set max width of lines to 80, because I like being able to open my
code in vertical splits and fitting each window.
---
 budget/src/lib.rs      | 280 +++++++++++++++--------------
 budget/tests/budget.rs | 272 ++++++++++++++--------------
 rustfmt.toml           |   2 +
 src/main.rs            | 471 +++++++++++++++++++++++--------------------------
 4 files changed, 494 insertions(+), 531 deletions(-)
 create mode 100644 rustfmt.toml

diff --git a/budget/src/lib.rs b/budget/src/lib.rs
index 7d194c0..5013a9f 100644
--- a/budget/src/lib.rs
+++ b/budget/src/lib.rs
@@ -1,182 +1,178 @@
 use std::collections::HashMap;
-use std::io::ErrorKind;
 use std::fs;
+use std::io::ErrorKind;
 
-use toml::de::Error as DeserializerError;
-use serde::{Deserialize, Deserializer};
 use chrono::NaiveDate;
+use serde::{Deserialize, Deserializer};
+use toml::de::Error as DeserializerError;
 
 #[derive(Deserialize, PartialEq, Debug)]
 pub struct Account {
-    #[serde(deserialize_with = "deserialize_date")]
-    pub start_date: NaiveDate,
-    #[serde(deserialize_with = "deserialize_date")]
-    pub end_date: NaiveDate,
-    pub budget: f64,
-    #[serde(default)]
-    pub essential_categories: Vec<String>,
-    pub days: Vec<Day>,
+	#[serde(deserialize_with = "deserialize_date")]
+	pub start_date: NaiveDate,
+	#[serde(deserialize_with = "deserialize_date")]
+	pub end_date: NaiveDate,
+	pub budget: f64,
+	#[serde(default)]
+	pub essential_categories: Vec<String>,
+	pub days: Vec<Day>,
 }
 
 #[derive(Deserialize, PartialEq, Debug)]
 pub struct Day {
-    #[serde(deserialize_with = "deserialize_date")]
-    pub date: NaiveDate,
-    #[serde(default)]
-    pub expenses: Vec<Expense>,
+	#[serde(deserialize_with = "deserialize_date")]
+	pub date: NaiveDate,
+	#[serde(default)]
+	pub expenses: Vec<Expense>,
 }
 
 #[derive(Deserialize, PartialEq, Debug)]
 pub struct Expense {
-    pub name: String,
-    pub price: f64,
-    #[serde(default = "shared_qty_default")]
-    pub qty: u32, // unused for now, might use it the future or remove it
-    #[serde(default = "shared_qty_default")]
-    pub shared: u32,
-    #[serde(default = "recurring_default")]
-    pub recurring: bool,
-    #[serde(default)]
-    pub category: Option<String>,
+	pub name: String,
+	pub price: f64,
+	#[serde(default = "shared_qty_default")]
+	pub qty: u32, // unused for now, might use it the future or remove it
+	#[serde(default = "shared_qty_default")]
+	pub shared: u32,
+	#[serde(default = "recurring_default")]
+	pub recurring: bool,
+	#[serde(default)]
+	pub category: Option<String>,
 }
 
 #[derive(PartialEq, Debug)]
 pub struct Calculated {
-    pub all_day_average: f64,
-    pub essential_day_average: f64,
-    pub categories_day_average: HashMap<String, f64>,
-    pub essential_subtotal: f64,
-    pub categories_subtotal: HashMap<String, f64>,
-    pub total: f64,
-    pub balance: f64,
-    pub total_owed: HashMap<u32, f64>,
-    pub days_left: f64,
-    pub days_left_essential: f64,
-    pub last_day: NaiveDate,
+	pub all_day_average: f64,
+	pub essential_day_average: f64,
+	pub categories_day_average: HashMap<String, f64>,
+	pub essential_subtotal: f64,
+	pub categories_subtotal: HashMap<String, f64>,
+	pub total: f64,
+	pub balance: f64,
+	pub total_owed: HashMap<u32, f64>,
+	pub days_left: f64,
+	pub days_left_essential: f64,
+	pub last_day: NaiveDate,
 }
 
 #[derive(PartialEq, Eq, Debug)]
 pub enum ParseError {
-    IOError(ErrorKind),
-    DeserializerError(DeserializerError),
+	IOError(ErrorKind),
+	DeserializerError(DeserializerError),
 }
 
 fn shared_qty_default() -> u32 {
-    1
+	1
 }
 
 fn recurring_default() -> bool {
-    false
+	false
 }
 
 // Parse the dates from toml's Datetime to Chrono's NaiveDate
 fn deserialize_date<'de, D>(deserializer: D) -> Result<NaiveDate, D::Error>
-where D: Deserializer<'de> {
-    toml::value::Datetime::deserialize(deserializer)
-        .map(|v| {
-            let s = v.to_string();
-
-            NaiveDate::parse_from_str(&s, "%Y-%m-%d")
-        })?
-        .map_err(serde::de::Error::custom)
+where
+	D: Deserializer<'de>,
+{
+	toml::value::Datetime::deserialize(deserializer)
+		.map(|v| {
+			let s = v.to_string();
+
+			NaiveDate::parse_from_str(&s, "%Y-%m-%d")
+		})?
+		.map_err(serde::de::Error::custom)
 }
 
 pub fn parse_account(path: &str) -> Result<Account, ParseError> {
-    let contents = match fs::read_to_string(path) {
-        Ok(data) => data,
-        Err(error) => {
-            return Err(ParseError::IOError(error.kind()));
-        },
-    };
-
-    match toml::from_str::<Account>(&contents) {
-        Ok(budget) => Ok(budget),
-        Err(error) => Err(ParseError::DeserializerError(error)),
-    }
+	let contents = match fs::read_to_string(path) {
+		Ok(data) => data,
+		Err(error) => {
+			return Err(ParseError::IOError(error.kind()));
+		}
+	};
+
+	match toml::from_str::<Account>(&contents) {
+		Ok(budget) => Ok(budget),
+		Err(error) => Err(ParseError::DeserializerError(error)),
+	}
 }
 
 pub fn calculate(account: &Account) -> Option<Calculated> {
-    if account.days.is_empty() {
-        return None;
-    }
-
-    let mut calculated = Calculated {
-        all_day_average: 0.0,
-        essential_day_average: 0.0,
-        categories_day_average: HashMap::<String, f64>::new(),
-        essential_subtotal: 0.0,
-        categories_subtotal: HashMap::<String, f64>::new(),
-        total: 0.0,
-        balance: 0.0,
-        total_owed: HashMap::<u32, f64>::new(),
-        days_left: 0.0,
-        days_left_essential: 0.0,
-        last_day: account.days.last().unwrap().date,
-    };
-
-    for day in account.days.iter() {
-        if day.date > calculated.last_day {
-            calculated.last_day = day.date;
-        }
-
-        for expense in day.expenses.iter() {
-            calculated.total += expense.price;
-
-            if let Some(category) = &expense.category {
-                if let Some(category_subtotal) = 
-                calculated.categories_subtotal.get_mut(category) {
-                    *category_subtotal += expense.price;
-                } else {
-                    calculated.categories_subtotal.insert(
-                        category.to_string(),
-                        expense.price,
-                    );
-                }
-
-                if account.essential_categories.contains(category) {
-                    calculated.essential_subtotal += expense.price;
-                }
-
-                if expense.shared > 1 {
-                    let owed = 
-                        expense.price * 
-                        (expense.shared as f64 - 1.0) / 
-                        expense.shared as f64;
-
-                    if let Some(total_owed_by) = 
-                    calculated.total_owed.get_mut(&expense.shared) {
-                        *total_owed_by += owed;
-                    } else {
-                        calculated.total_owed.insert(
-                            expense.shared,
-                            owed,
-                        );
-                    }
-                }
-            }
-        }
-    }
-
-    let days_elapsed = 
-        (calculated.last_day - account.start_date).num_days() + 1;
-
-    calculated.all_day_average = calculated.total / days_elapsed as f64;
-    calculated.essential_day_average = 
-        calculated.essential_subtotal / days_elapsed as f64;
-
-    for (category, subtotal) in calculated.categories_subtotal.iter() {
-        calculated.categories_day_average
-            .insert(
-                category.clone(),
-                subtotal / days_elapsed as f64,
-            );
-    }
-
-    calculated.balance = account.budget - calculated.total;
-
-    calculated.days_left = calculated.balance / calculated.all_day_average;
-    calculated.days_left_essential = 
-        calculated.balance / calculated.essential_day_average;
-
-    Some(calculated)
+	if account.days.is_empty() {
+		return None;
+	}
+
+	let mut calculated = Calculated {
+		all_day_average: 0.0,
+		essential_day_average: 0.0,
+		categories_day_average: HashMap::<String, f64>::new(),
+		essential_subtotal: 0.0,
+		categories_subtotal: HashMap::<String, f64>::new(),
+		total: 0.0,
+		balance: 0.0,
+		total_owed: HashMap::<u32, f64>::new(),
+		days_left: 0.0,
+		days_left_essential: 0.0,
+		last_day: account.days.last().unwrap().date,
+	};
+
+	for day in account.days.iter() {
+		if day.date > calculated.last_day {
+			calculated.last_day = day.date;
+		}
+
+		for expense in day.expenses.iter() {
+			calculated.total += expense.price;
+
+			if let Some(category) = &expense.category {
+				if let Some(category_subtotal) =
+					calculated.categories_subtotal.get_mut(category)
+				{
+					*category_subtotal += expense.price;
+				} else {
+					calculated
+						.categories_subtotal
+						.insert(category.to_string(), expense.price);
+				}
+
+				if account.essential_categories.contains(category) {
+					calculated.essential_subtotal += expense.price;
+				}
+
+				if expense.shared > 1 {
+					let owed = expense.price * (expense.shared as f64 - 1.0)
+						/ expense.shared as f64;
+
+					if let Some(total_owed_by) =
+						calculated.total_owed.get_mut(&expense.shared)
+					{
+						*total_owed_by += owed;
+					} else {
+						calculated.total_owed.insert(expense.shared, owed);
+					}
+				}
+			}
+		}
+	}
+
+	let days_elapsed =
+		(calculated.last_day - account.start_date).num_days() + 1;
+
+	calculated.all_day_average = calculated.total / days_elapsed as f64;
+	calculated.essential_day_average =
+		calculated.essential_subtotal / days_elapsed as f64;
+
+	for (category, subtotal) in calculated.categories_subtotal.iter() {
+		calculated
+			.categories_day_average
+			.insert(category.clone(), subtotal / days_elapsed as f64);
+	}
+
+	calculated.balance = account.budget - calculated.total;
+
+	calculated.days_left = calculated.balance / calculated.all_day_average;
+	calculated.days_left_essential =
+		calculated.balance / calculated.essential_day_average;
+
+	Some(calculated)
 }
diff --git a/budget/tests/budget.rs b/budget/tests/budget.rs
index 6a9214d..4ed549c 100644
--- a/budget/tests/budget.rs
+++ b/budget/tests/budget.rs
@@ -5,160 +5,146 @@ use chrono::NaiveDate;
 use budget::*;
 
 #[test]
-fn can_parse_account() -> Result<(), ParseError>{
-    let should_be = Account {
-        start_date: NaiveDate::from_ymd(2020, 10, 1),
-        end_date: NaiveDate::from_ymd(2020, 10, 31),
-        budget: 420.0,
-        essential_categories: vec![
-            String::from("products"),
-            String::from("transport"),
-            String::from("utilities"),
-        ],
-        days: vec![
-            Day {
-                date: NaiveDate::from_ymd(2020, 10, 1),
-                expenses: vec![
-                    Expense {
-                        name: String::from("Potato masher"),
-                        price: 3.81,
-                        qty: 1,
-                        shared: 1,
-                        recurring: false,
-                        category: Some(String::from("supplies")),
-                    },
-                    Expense {
-                        name: String::from("Bacon"),
-                        price: 3.33,
-                        qty: 1,
-                        shared: 3,
-                        recurring: false,
-                        category: Some(String::from("products")),
-                    },
-                    Expense {
-                        name: String::from("Yoghurt"),
-                        price: 1.24,
-                        qty: 2,
-                        shared: 2,
-                        recurring: false,
-                        category: Some(String::from("products")),
-                    },
-                    Expense {
-                        name: String::from("Onion"),
-                        price: 0.15,
-                        qty: 1,
-                        shared: 1,
-                        recurring: false,
-                        category: Some(String::from("products")),
-                    },
-                    Expense {
-                        name: String::from("Chicken"),
-                        price: 2.28,
-                        qty: 1,
-                        shared: 2,
-                        recurring: false,
-                        category: Some(String::from("products")),
-                    },
-                ],
-            },
-            Day {
-                date: NaiveDate::from_ymd(2020, 10, 4),
-                expenses: Vec::<Expense>::new(),
-            },
-            Day {
-                date: NaiveDate::from_ymd(2020, 10, 2),
-                expenses: vec![
-                    Expense {
-                        name: String::from("VPS"),
-                        price: 5.0,
-                        qty: 1,
-                        shared: 1,
-                        recurring: true,
-                        category: Some(String::from("utilities")),
-                    },
-                    Expense {
-                        name: String::from("Transport card"),
-                        price: 6.9,
-                        qty: 1,
-                        shared: 1,
-                        recurring: false,
-                        category: Some(String::from("transport")),
-                    },
-                ],
-            },
-        ],
-    };
+fn can_parse_account() -> Result<(), ParseError> {
+	let should_be = Account {
+		start_date: NaiveDate::from_ymd(2020, 10, 1),
+		end_date: NaiveDate::from_ymd(2020, 10, 31),
+		budget: 420.0,
+		essential_categories: vec![
+			String::from("products"),
+			String::from("transport"),
+			String::from("utilities"),
+		],
+		days: vec![
+			Day {
+				date: NaiveDate::from_ymd(2020, 10, 1),
+				expenses: vec![
+					Expense {
+						name: String::from("Potato masher"),
+						price: 3.81,
+						qty: 1,
+						shared: 1,
+						recurring: false,
+						category: Some(String::from("supplies")),
+					},
+					Expense {
+						name: String::from("Bacon"),
+						price: 3.33,
+						qty: 1,
+						shared: 3,
+						recurring: false,
+						category: Some(String::from("products")),
+					},
+					Expense {
+						name: String::from("Yoghurt"),
+						price: 1.24,
+						qty: 2,
+						shared: 2,
+						recurring: false,
+						category: Some(String::from("products")),
+					},
+					Expense {
+						name: String::from("Onion"),
+						price: 0.15,
+						qty: 1,
+						shared: 1,
+						recurring: false,
+						category: Some(String::from("products")),
+					},
+					Expense {
+						name: String::from("Chicken"),
+						price: 2.28,
+						qty: 1,
+						shared: 2,
+						recurring: false,
+						category: Some(String::from("products")),
+					},
+				],
+			},
+			Day {
+				date: NaiveDate::from_ymd(2020, 10, 4),
+				expenses: Vec::<Expense>::new(),
+			},
+			Day {
+				date: NaiveDate::from_ymd(2020, 10, 2),
+				expenses: vec![
+					Expense {
+						name: String::from("VPS"),
+						price: 5.0,
+						qty: 1,
+						shared: 1,
+						recurring: true,
+						category: Some(String::from("utilities")),
+					},
+					Expense {
+						name: String::from("Transport card"),
+						price: 6.9,
+						qty: 1,
+						shared: 1,
+						recurring: false,
+						category: Some(String::from("transport")),
+					},
+				],
+			},
+		],
+	};
 
-    let actually_is = budget::parse_account("tests/test.toml")?;
+	let actually_is = budget::parse_account("tests/test.toml")?;
 
-    assert_eq!(actually_is, should_be);
+	assert_eq!(actually_is, should_be);
 
-    Ok(())
+	Ok(())
 }
 
 #[test]
 fn can_calculate() -> Result<(), ParseError> {
-    let mut should_be = Calculated {
-        all_day_average: 5.6775,
-        essential_day_average: 4.725,
-        categories_day_average: HashMap::<String, f64>::new(),
-        essential_subtotal: 18.9,
-        categories_subtotal: HashMap::<String, f64>::new(),
-        total: 22.71,
-        balance: 397.29,
-        total_owed: HashMap::<u32, f64>::new(),
-        days_left: 69.9762219286658,
-        days_left_essential: 84.08253968253969,
-        last_day: NaiveDate::from_ymd(2020, 10, 04),
-    };
+	let mut should_be = Calculated {
+		all_day_average: 5.6775,
+		essential_day_average: 4.725,
+		categories_day_average: HashMap::<String, f64>::new(),
+		essential_subtotal: 18.9,
+		categories_subtotal: HashMap::<String, f64>::new(),
+		total: 22.71,
+		balance: 397.29,
+		total_owed: HashMap::<u32, f64>::new(),
+		days_left: 69.9762219286658,
+		days_left_essential: 84.08253968253969,
+		last_day: NaiveDate::from_ymd(2020, 10, 04),
+	};
 
-    should_be.categories_day_average.insert(
-        "supplies".to_string(),
-        0.9525,
-    );
-    should_be.categories_day_average.insert(
-        "products".to_string(),
-        1.75,
-    );
-    should_be.categories_day_average.insert(
-        "transport".to_string(),
-        1.725,
-    );
-    should_be.categories_day_average.insert(
-        "utilities".to_string(),
-        1.25,
-    );
+	should_be
+		.categories_day_average
+		.insert("supplies".to_string(), 0.9525);
+	should_be
+		.categories_day_average
+		.insert("products".to_string(), 1.75);
+	should_be
+		.categories_day_average
+		.insert("transport".to_string(), 1.725);
+	should_be
+		.categories_day_average
+		.insert("utilities".to_string(), 1.25);
 
-    should_be.categories_subtotal.insert(
-        "supplies".to_string(),
-        3.81,
-    );
-    should_be.categories_subtotal.insert(
-        "products".to_string(),
-        7.0,
-    );
-    should_be.categories_subtotal.insert(
-        "transport".to_string(),
-        6.9,
-    );
-    should_be.categories_subtotal.insert(
-        "utilities".to_string(),
-        5.0,
-    );
+	should_be
+		.categories_subtotal
+		.insert("supplies".to_string(), 3.81);
+	should_be
+		.categories_subtotal
+		.insert("products".to_string(), 7.0);
+	should_be
+		.categories_subtotal
+		.insert("transport".to_string(), 6.9);
+	should_be
+		.categories_subtotal
+		.insert("utilities".to_string(), 5.0);
 
-    should_be.total_owed.insert(
-        2,
-        1.7599999999999998,
-    );
-    should_be.total_owed.insert(
-        3,
-        2.22,
-    );
+	should_be.total_owed.insert(2, 1.7599999999999998);
+	should_be.total_owed.insert(3, 2.22);
 
-    let account = budget::parse_account("tests/test.toml")?;
-    let actually_is = budget::calculate(&account).unwrap();
+	let account = budget::parse_account("tests/test.toml")?;
+	let actually_is = budget::calculate(&account).unwrap();
 
-    assert_eq!(actually_is, should_be);
+	assert_eq!(actually_is, should_be);
 
-    Ok(())
+	Ok(())
 }
diff --git a/rustfmt.toml b/rustfmt.toml
new file mode 100644
index 0000000..dd338c9
--- /dev/null
+++ b/rustfmt.toml
@@ -0,0 +1,2 @@
+hard_tabs = true
+max_width = 80
diff --git a/src/main.rs b/src/main.rs
index cd401e2..5341939 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,261 +1,240 @@
+use chrono::Duration;
 use clap::{
-    Arg, 
-    App, 
-    ArgMatches,
-    crate_version, 
-    crate_authors, 
-    crate_description
+	crate_authors, crate_description, crate_version, App, Arg, ArgMatches,
 };
-use chrono::Duration;
 use colored::*;
 
 use budget::*;
 
 fn main() {
-    let matches = get_cli_matches();
-
-    let no_color = matches.occurrences_of("plain") > 0;
-    let force_color = matches.occurrences_of("force-color") > 0;
-    let input = matches.value_of("INPUT").unwrap();
-
-    let account = match budget::parse_account(input) {
-        Ok(data) => data,
-        Err(error) => {
-            match error {
-                ParseError::IOError(kind) => {
-                    println!("IO error while parsing: {:?}", kind);
-                },
-                ParseError::DeserializerError(_) => {
-                    println!("Can't parse the file, invalid syntax");
-                },
-            }
-
-            ::std::process::exit(1);
-        }
-    };
-    let maybe_calculated = budget::calculate(&account);
-
-    if no_color && !force_color {
-        colored::control::set_override(false);
-    } else if force_color {
-        colored::control::set_override(true);
-    }
-
-    output(account, maybe_calculated);
+	let matches = get_cli_matches();
+
+	let no_color = matches.occurrences_of("plain") > 0;
+	let force_color = matches.occurrences_of("force-color") > 0;
+	let input = matches.value_of("INPUT").unwrap();
+
+	let account = match budget::parse_account(input) {
+		Ok(data) => data,
+		Err(error) => {
+			match error {
+				ParseError::IOError(kind) => {
+					println!("IO error while parsing: {:?}", kind);
+				}
+				ParseError::DeserializerError(_) => {
+					println!("Can't parse the file, invalid syntax");
+				}
+			}
+
+			::std::process::exit(1);
+		}
+	};
+	let maybe_calculated = budget::calculate(&account);
+
+	if no_color && !force_color {
+		colored::control::set_override(false);
+	} else if force_color {
+		colored::control::set_override(true);
+	}
+
+	output(account, maybe_calculated);
 }
 
 fn get_cli_matches() -> ArgMatches<'static> {
-    App::new("finbudg")
-        .version(crate_version!())
-        .author(crate_authors!())
-        .about(crate_description!())
-        .arg(Arg::with_name("plain")
-            .short("p")
-            .long("plain")
-            .help("Don't colorize the output. Can also be set \
-            with the NO_COLOR environment variable.")
-            .takes_value(false))
-        .arg(Arg::with_name("force-color")
-            .long("force-color")
-            .help("Forces colorized output even when piping. Takes \
+	App::new("finbudg")
+		.version(crate_version!())
+		.author(crate_authors!())
+		.about(crate_description!())
+		.arg(
+			Arg::with_name("plain")
+				.short("p")
+				.long("plain")
+				.help(
+					"Don't colorize the output. Can also be set \
+            with the NO_COLOR environment variable.",
+				)
+				.takes_value(false),
+		)
+		.arg(
+			Arg::with_name("force-color")
+				.long("force-color")
+				.help(
+					"Forces colorized output even when piping. Takes \
             precedence over --plain flag and NO_COLOR environment \
-            variable")
-            .takes_value(false))
-        .arg(Arg::with_name("INPUT")
-            .help("Expenses file in toml format to calculate from.")
-            .required(true)
-            .index(1))
-        .get_matches()
+            variable",
+				)
+				.takes_value(false),
+		)
+		.arg(
+			Arg::with_name("INPUT")
+				.help("Expenses file in toml format to calculate from.")
+				.required(true)
+				.index(1),
+		)
+		.get_matches()
 }
 
 fn output(account: Account, maybe_calculated: Option<Calculated>) {
-    println!(
-        "{}",
-        format!(
-            "Your expenses for the period of {} - {}",
-            account.start_date.format("%Y-%m-%d"),
-            account.end_date.format("%Y-%m-%d"),
-        ).cyan(),
-    );
-
-    let calculated = match maybe_calculated {
-        Some(data) => data,
-        None => {
-            println!();
-            println!("{}", "You have no expenses...".italic());
-
-            ::std::process::exit(0);
-        }
-    };
-
-    let days_until_end = account.end_date - calculated.last_day;
-
-    println!(
-        "{}", 
-        format!(
-            "Last day on entry: {}",
-            calculated.last_day.format("%Y-%m-%d"),
-        ).cyan(),
-    );
-
-    println!(
-        "{}", 
-        format!(
-            "Days until period end: {}",
-            days_until_end.num_days(),
-        ).cyan(),
-    );
-
-    if days_until_end < Duration::zero() {
-        println!();
-        println!(
-            "{}", 
-            "Your last day on entry is set after the last date of the period!"
-            .yellow(),
-        );
-        println!();
-    }
-
-    println!(
-        "{}",
-        format!(
-            "Budget: {:.2}",
-            account.budget,
-        ).cyan(),
-    );
-
-    println!();
-
-    for (category, expenses) in calculated.categories_day_average.iter() {
-        println!(
-            "Average per day in {}: {:.2}",
-            category,
-            expenses,
-        );
-    }
-
-    println!(
-        "Average per day in essential expenses: {:.2}",
-        calculated.essential_day_average,
-    );
-
-    println!(
-        "Average per day: {:.2}",
-        calculated.all_day_average,
-    );
-
-    println!();
-
-    for (category, expenses) in calculated.categories_subtotal.iter() {
-        println!(
-            "Total in {}: {:.2}",
-            category,
-            expenses,
-        );
-    }
-
-    println!(
-        "Total in essential expenses: {:.2}",
-        calculated.essential_subtotal,
-    );
-
-    println!(
-        "Total: {:.2}",
-        calculated.total,
-    );
-
-    println!();
-
-    let balance_output = format!("{:.2}", calculated.balance);
-    let balance_output = if calculated.balance > 0.0 {
-        if account.budget / calculated.balance < 10.0 {
-            balance_output.green()
-        } else {
-            balance_output.yellow()
-        }
-    } else {
-        balance_output.red()
-    };
-
-    println!("Left on balance: {}", balance_output);
-
-    println!();
-
-    for (n, owed) in calculated.total_owed.iter() {
-        println!(
-            "{} person(s) owe you in shared expenses: {:.2}",
-            n - 1,
-            owed,
-        );
-
-        if *n > 2 {
-            println!("Each owes you: {}", *owed / (*n as f64 - 1.0));
-        }
-
-        println!();
-    }
-
-    println!("Days until balance runs out:");
-
-    let days_left_output = format!(
-        "{:.2}",
-        calculated.days_left,
-    );
-    let days_left_essential_output = format!(
-        "{:.2}",
-        calculated.days_left_essential,
-    );
-
-    // TODO: also show much money would be left by the end of the period
-
-    let mut all_are_healthy = true;
-    let mut essential_are_healthy = true;
-
-    let days_left_output = 
-        if days_until_end.num_days() as f64 <= calculated.days_left {
-            days_left_output.green()
-        } else {
-            all_are_healthy = false;
-
-            days_left_output.red()
-        };
-    let days_left_essential_output = 
-        if days_until_end.num_days() as f64 <= calculated.days_left_essential {
-            days_left_essential_output.green()
-        } else {
-            essential_are_healthy = false;
-
-            days_left_essential_output.red()
-        };
-
-    println!(
-        "...taking into account all expenses: {}",
-        days_left_output,
-    );
-    println!(
-        "...taking into account only essential expenses: {}",
-        days_left_essential_output,
-    );
-    println!();
-
-    if all_are_healthy {
-        println!(
-            "{}",
-            "Your expenses are healthy, they should last you from your last \
-            day on entry through your last day of the period.".green(),
-        );
-    } else {
-        println!(
-            "{}",
-            "You are spending more than you can afford with your current \
-            budget. Try minimizing your expenses".red(),
-        );
-        if essential_are_healthy {
-            println!(
-                "{}",
-                "On the other hand, if you only spend money on essentials, \
-                you should be able keep within your budget.".yellow(),
-            );
-        }
-    }
+	println!(
+		"{}",
+		format!(
+			"Your expenses for the period of {} - {}",
+			account.start_date.format("%Y-%m-%d"),
+			account.end_date.format("%Y-%m-%d"),
+		)
+		.cyan(),
+	);
+
+	let calculated = match maybe_calculated {
+		Some(data) => data,
+		None => {
+			println!();
+			println!("{}", "You have no expenses...".italic());
+
+			::std::process::exit(0);
+		}
+	};
+
+	let days_until_end = account.end_date - calculated.last_day;
+
+	println!(
+		"{}",
+		format!(
+			"Last day on entry: {}",
+			calculated.last_day.format("%Y-%m-%d"),
+		)
+		.cyan(),
+	);
+
+	println!(
+		"{}",
+		format!("Days until period end: {}", days_until_end.num_days(),).cyan(),
+	);
+
+	if days_until_end < Duration::zero() {
+		println!();
+		println!(
+			"{}",
+			"Your last day on entry is set after the last date of the period!"
+				.yellow(),
+		);
+		println!();
+	}
+
+	println!("{}", format!("Budget: {:.2}", account.budget,).cyan(),);
+
+	println!();
+
+	for (category, expenses) in calculated.categories_day_average.iter() {
+		println!("Average per day in {}: {:.2}", category, expenses,);
+	}
+
+	println!(
+		"Average per day in essential expenses: {:.2}",
+		calculated.essential_day_average,
+	);
+
+	println!("Average per day: {:.2}", calculated.all_day_average,);
+
+	println!();
+
+	for (category, expenses) in calculated.categories_subtotal.iter() {
+		println!("Total in {}: {:.2}", category, expenses,);
+	}
+
+	println!(
+		"Total in essential expenses: {:.2}",
+		calculated.essential_subtotal,
+	);
+
+	println!("Total: {:.2}", calculated.total,);
+
+	println!();
+
+	let balance_output = format!("{:.2}", calculated.balance);
+	let balance_output = if calculated.balance > 0.0 {
+		if account.budget / calculated.balance < 10.0 {
+			balance_output.green()
+		} else {
+			balance_output.yellow()
+		}
+	} else {
+		balance_output.red()
+	};
+
+	println!("Left on balance: {}", balance_output);
+
+	println!();
+
+	for (n, owed) in calculated.total_owed.iter() {
+		println!(
+			"{} person(s) owe you in shared expenses: {:.2}",
+			n - 1,
+			owed,
+		);
+
+		if *n > 2 {
+			println!("Each owes you: {}", *owed / (*n as f64 - 1.0));
+		}
+
+		println!();
+	}
+
+	println!("Days until balance runs out:");
+
+	let days_left_output = format!("{:.2}", calculated.days_left,);
+	let days_left_essential_output =
+		format!("{:.2}", calculated.days_left_essential,);
+
+	// TODO: also show much money would be left by the end of the period
+
+	let mut all_are_healthy = true;
+	let mut essential_are_healthy = true;
+
+	let days_left_output =
+		if days_until_end.num_days() as f64 <= calculated.days_left {
+			days_left_output.green()
+		} else {
+			all_are_healthy = false;
+
+			days_left_output.red()
+		};
+	let days_left_essential_output =
+		if days_until_end.num_days() as f64 <= calculated.days_left_essential {
+			days_left_essential_output.green()
+		} else {
+			essential_are_healthy = false;
+
+			days_left_essential_output.red()
+		};
+
+	println!("...taking into account all expenses: {}", days_left_output,);
+	println!(
+		"...taking into account only essential expenses: {}",
+		days_left_essential_output,
+	);
+	println!();
+
+	if all_are_healthy {
+		println!(
+			"{}",
+			"Your expenses are healthy, they should last you from your last \
+            day on entry through your last day of the period."
+				.green(),
+		);
+	} else {
+		println!(
+			"{}",
+			"You are spending more than you can afford with your current \
+            budget. Try minimizing your expenses"
+				.red(),
+		);
+		if essential_are_healthy {
+			println!(
+				"{}",
+				"On the other hand, if you only spend money on essentials, \
+                you should be able keep within your budget."
+					.yellow(),
+			);
+		}
+	}
 }
-- 
cgit v1.2.3