mirror of
				https://github.com/lov3b/ecb-rates.git
				synced 2025-10-31 05:10:25 +01:00 
			
		
		
		
	Header description
This commit is contained in:
		
							
								
								
									
										51
									
								
								src/header_description.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								src/header_description.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,51 @@ | ||||
| use colored::Colorize; | ||||
| use std::fmt::Display; | ||||
|  | ||||
| use crate::DEFAULT_WIDTH; | ||||
|  | ||||
| pub struct HeaderDescription<'a> { | ||||
|     header_description: [&'a str; 2], | ||||
| } | ||||
|  | ||||
| impl<'a> HeaderDescription<'a> { | ||||
|     pub fn new() -> Self { | ||||
|         Self { | ||||
|             header_description: ["EUR", /*"\u{2217}"*/ "ALL"], // Unicode is ∗ | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub fn invert(&mut self) { | ||||
|         self.header_description.swap(0, 1); | ||||
|     } | ||||
|  | ||||
|     pub fn replace_eur(&mut self, currency: &'a str) { | ||||
|         self.header_description[0] = currency; | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<'a> Display for HeaderDescription<'a> { | ||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||||
|         let width = DEFAULT_WIDTH - 2; | ||||
|         let formatted = format!( | ||||
|             "{} {} {}", | ||||
|             self.header_description[0].purple().bold(), | ||||
|             "to".italic(), | ||||
|             self.header_description[1].purple().bold() | ||||
|         ); | ||||
|         let unformatted_len = | ||||
|             self.header_description[0].len() + self.header_description[1].len() + 4; | ||||
|         let left_padding = " ".repeat((width - unformatted_len) / 2); | ||||
|  | ||||
|         let vertical = "═".repeat(width); | ||||
|         writeln!(f, " ╔{}╗", &vertical)?; | ||||
|         writeln!( | ||||
|             f, | ||||
|             "  {}{}{} ", | ||||
|             &left_padding, | ||||
|             formatted, | ||||
|             " ".repeat(width - left_padding.len() - unformatted_len) | ||||
|         )?; | ||||
|         writeln!(f, " ╚{}╝\n", &vertical)?; | ||||
|         Ok(()) | ||||
|     } | ||||
| } | ||||
| @@ -1,5 +1,6 @@ | ||||
| pub mod cache; | ||||
| pub mod cli; | ||||
| mod header_description; | ||||
| mod holiday; | ||||
| pub mod models; | ||||
| pub mod os; | ||||
| @@ -7,9 +8,11 @@ pub mod parsing; | ||||
| pub mod table; | ||||
| pub mod utils_calc; | ||||
|  | ||||
| pub use header_description::HeaderDescription; | ||||
| pub use holiday::Hollidays; | ||||
|  | ||||
| const APP_NAME: &'static str = "ECB-rates"; | ||||
| const DEFAULT_WIDTH: usize = 20; | ||||
|  | ||||
| pub mod ecb_url { | ||||
|     pub const TODAY: &'static str = "https://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml"; | ||||
|   | ||||
							
								
								
									
										18
									
								
								src/main.rs
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								src/main.rs
									
									
									
									
									
								
							| @@ -1,5 +1,6 @@ | ||||
| use clap::Parser as _; | ||||
| use ecb_rates::cache::{Cache, CacheLine}; | ||||
| use ecb_rates::HeaderDescription; | ||||
| use reqwest::{Client, IntoUrl}; | ||||
| use std::process::ExitCode; | ||||
|  | ||||
| @@ -17,11 +18,12 @@ async fn get_and_parse(url: impl IntoUrl) -> anyhow::Result<Vec<ExchangeRateResu | ||||
|  | ||||
| #[tokio::main(flavor = "current_thread")] | ||||
| async fn main() -> ExitCode { | ||||
|     let cli = Cli::parse(); | ||||
|     let mut cli = Cli::parse(); | ||||
|     if cli.force_color { | ||||
|         colored::control::set_override(true); | ||||
|     } | ||||
|  | ||||
|     let mut header_description = HeaderDescription::new(); | ||||
|     let use_cache = !cli.no_cache; | ||||
|     let mut cache = if use_cache { Cache::load() } else { None }; | ||||
|     let cache_ok = cache.as_ref().map_or_else( | ||||
| @@ -72,7 +74,9 @@ async fn main() -> ExitCode { | ||||
|         parsed | ||||
|     }; | ||||
|  | ||||
|     if let Some(currency) = cli.perspective.map(|s| s.to_uppercase()) { | ||||
|     cli.perspective = cli.perspective.map(|s| s.to_uppercase()); | ||||
|     if let Some(currency) = cli.perspective.as_ref() { | ||||
|         header_description.replace_eur(¤cy); | ||||
|         let error_occured = change_perspective(&mut parsed, ¤cy).is_none(); | ||||
|         if error_occured { | ||||
|             eprintln!("The currency wasn't in the data from the ECB!"); | ||||
| @@ -82,6 +86,7 @@ async fn main() -> ExitCode { | ||||
|  | ||||
|     if cli.should_invert { | ||||
|         invert_rates(&mut parsed); | ||||
|         header_description.invert(); | ||||
|     } | ||||
|  | ||||
|     round(&mut parsed, cli.max_decimals); | ||||
| @@ -119,7 +124,8 @@ async fn main() -> ExitCode { | ||||
|             }; | ||||
|             to_string_json(&json_values).expect("Failed to parse content as JSON") | ||||
|         } | ||||
|         FormatOption::Plain => parsed | ||||
|         FormatOption::Plain => { | ||||
|             let rates = parsed | ||||
|                 .iter() | ||||
|                 .map(|x| { | ||||
|                     let mut t: TableRef = x.into(); | ||||
| @@ -130,7 +136,11 @@ async fn main() -> ExitCode { | ||||
|                     t.to_string() | ||||
|                 }) | ||||
|                 .collect::<Vec<_>>() | ||||
|             .join("\n"), | ||||
|                 .join("\n"); | ||||
|             let mut s = header_description.to_string(); | ||||
|             s.push_str(&rates); | ||||
|             s | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     println!("{}", &output); | ||||
|   | ||||
| @@ -7,6 +7,7 @@ pub fn helper_table_print<T: TableGet>( | ||||
|     table: &T, | ||||
| ) -> std::fmt::Result { | ||||
|     let width = table.get_width(); | ||||
|     let left_offset = " ".repeat(table.get_left_offset()); | ||||
|  | ||||
|     if let Some(header) = table.get_header() { | ||||
|         let middle_padding_amount = (width - header.len()) / 2; | ||||
| @@ -14,7 +15,8 @@ pub fn helper_table_print<T: TableGet>( | ||||
|         let middle_padding = " ".repeat(middle_padding_amount); | ||||
|         writeln!( | ||||
|             f, | ||||
|             "{}{}{}", | ||||
|             "{}{}{}{}", | ||||
|             &left_offset, | ||||
|             middle_padding, | ||||
|             header.bold().cyan(), | ||||
|             middle_padding | ||||
| @@ -27,19 +29,27 @@ pub fn helper_table_print<T: TableGet>( | ||||
|     let right_padding = " ".repeat(right_padding_amount); | ||||
|     writeln!( | ||||
|         f, | ||||
|         "{}{}{}", | ||||
|         "{}{}{}{}", | ||||
|         &left_offset, | ||||
|         column_left.bold().yellow(), | ||||
|         right_padding, | ||||
|         column_right.bold().yellow() | ||||
|     )?; | ||||
|     writeln!(f, "{}", "-".repeat(width))?; | ||||
|     writeln!(f, "{}{}", &left_offset, "-".repeat(width))?; | ||||
|  | ||||
|     for (left, right) in table.get_rows().iter() { | ||||
|         let left_str = left.as_ref(); | ||||
|         let right_str = right.to_string(); | ||||
|         let padding_amount = width.saturating_sub(left_str.len() + right_str.len()); | ||||
|         let padding = " ".repeat(padding_amount); | ||||
|         writeln!(f, "{}{}{}", left_str.bold().green(), padding, right_str)?; | ||||
|         writeln!( | ||||
|             f, | ||||
|             "{}{}{}{}", | ||||
|             &left_offset, | ||||
|             left_str.bold().green(), | ||||
|             padding, | ||||
|             right_str | ||||
|         )?; | ||||
|     } | ||||
|  | ||||
|     Ok(()) | ||||
|   | ||||
| @@ -7,4 +7,5 @@ pub trait TableGet { | ||||
|     fn get_column_right(&self) -> &str; | ||||
|     fn get_rows(&self) -> &Vec<(Self::RowLeftRef, f64)>; | ||||
|     fn get_width(&self) -> usize; | ||||
|     fn get_left_offset(&self) -> usize; | ||||
| } | ||||
|   | ||||
| @@ -2,6 +2,7 @@ use std::fmt::Display; | ||||
|  | ||||
| use crate::cli::SortBy; | ||||
| use crate::models::ExchangeRateResult; | ||||
| use crate::DEFAULT_WIDTH; | ||||
|  | ||||
| use super::table_display::helper_table_print; | ||||
| use super::{TableGet, TableTrait}; | ||||
| @@ -13,6 +14,7 @@ pub struct Table { | ||||
|     pub(super) rows: Vec<(String, f64)>, | ||||
|     pub color: bool, | ||||
|     pub width: usize, | ||||
|     pub left_offset: usize, | ||||
| } | ||||
|  | ||||
| impl<'a> TableTrait<'a> for Table { | ||||
| @@ -32,7 +34,8 @@ impl<'a> TableTrait<'a> for Table { | ||||
|             column_right, | ||||
|             rows: Vec::new(), | ||||
|             color: false, | ||||
|             width: 21, | ||||
|             width: DEFAULT_WIDTH, | ||||
|             left_offset: 1, | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @@ -74,6 +77,10 @@ impl TableGet for Table { | ||||
|     fn get_width(&self) -> usize { | ||||
|         self.width | ||||
|     } | ||||
|      | ||||
|     fn get_left_offset(&self) -> usize { | ||||
|         self.left_offset | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl From<ExchangeRateResult> for Table { | ||||
|   | ||||
| @@ -2,6 +2,7 @@ use std::fmt::Display; | ||||
|  | ||||
| use crate::cli::SortBy; | ||||
| use crate::models::ExchangeRateResult; | ||||
| use crate::DEFAULT_WIDTH; | ||||
|  | ||||
| use super::table_display::helper_table_print; | ||||
| use super::table_getter::TableGet; | ||||
| @@ -15,6 +16,7 @@ pub struct TableRef<'a> { | ||||
|     rows: Vec<(&'a str, f64)>, | ||||
|     pub color: bool, | ||||
|     pub width: usize, | ||||
|     pub left_offset: usize, | ||||
| } | ||||
|  | ||||
| impl<'a> TableTrait<'a> for TableRef<'a> { | ||||
| @@ -34,7 +36,8 @@ impl<'a> TableTrait<'a> for TableRef<'a> { | ||||
|             column_right, | ||||
|             rows: Vec::new(), | ||||
|             color: false, | ||||
|             width: 21, | ||||
|             width: DEFAULT_WIDTH, | ||||
|             left_offset: 1, | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @@ -75,6 +78,10 @@ impl<'a> TableGet for TableRef<'a> { | ||||
|     fn get_width(&self) -> usize { | ||||
|         self.width | ||||
|     } | ||||
|      | ||||
|     fn get_left_offset(&self) -> usize { | ||||
|         self.left_offset | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<'a> From<&'a ExchangeRateResult> for TableRef<'a> { | ||||
| @@ -109,6 +116,7 @@ impl<'a> From<&'a Table> for TableRef<'a> { | ||||
|             rows, | ||||
|             color: table.color, | ||||
|             width: table.width, | ||||
|             left_offset: table.left_offset, | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user