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