diff --git a/Cargo.lock b/Cargo.lock index 1c03173..7fe55df 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -189,7 +189,7 @@ dependencies = [ "encode_unicode", "lazy_static", "libc", - "unicode-width", + "unicode-width 0.1.14", "windows-sys 0.52.0", ] @@ -1407,6 +1407,12 @@ version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" +[[package]] +name = "unicode-width" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" + [[package]] name = "untrusted" version = "0.9.0" @@ -1729,6 +1735,7 @@ dependencies = [ "strum", "strum_macros", "tokio", + "unicode-width 0.2.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index d51d443..b4d3b6f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,6 +39,7 @@ strum = "0.26" strum_macros = "0.26" tokio = { version = "1", features = ["macros", "rt-multi-thread"] } scopeguard = "1.2" +unicode-width = "0.2" [profile.release] strip = true diff --git a/src/modules/display/current.rs b/src/modules/display/current.rs index fd2d0d6..28bd490 100644 --- a/src/modules/display/current.rs +++ b/src/modules/display/current.rs @@ -8,7 +8,7 @@ use super::{ gui_config::ConfigurableColor, hourly::HourlyForecast, product::{Product, MIN_CELL_WIDTH, MIN_WIDTH}, - utils::lang_len_diff, + utils::pad_string_to_width, weathercode::WeatherCode, wind::WindDirection, }; @@ -50,19 +50,19 @@ impl Current { hourly_forecast, } = self; + let gui = ¶ms.config.gui; let Dimensions { width, cell_width } = dimensions; - let (gui, lang) = (¶ms.config.gui, ¶ms.config.language); + let width_no_border_pad = width - 2; // Border Top println!("{}", &Edge::Top.fmt(width, &gui.border).plain_or_bright_black(&gui.color)); // Address / Title println!( - "{} {: ^width$} {}", + "{} {} {}", Border::L.fmt(&gui.border).plain_or_bright_black(&gui.color), - style(&address).bold(), + style(pad_string_to_width(&address, width_no_border_pad)).bold(), Border::R.fmt(&gui.border).plain_or_bright_black(&gui.color), - width = width - 2 - lang_len_diff(&address, lang) ); // Separator @@ -76,24 +76,23 @@ impl Current { .plain_or_bright_black(&gui.color), ); - // Temperature & Weathercode println!( - "{} {: WIDTH$} {}", + "{} {}{} {}", Border::L.fmt(&gui.border).plain_or_bright_black(&gui.color), - style(&temperature_and_weathercode).bold(), + style(pad_string_to_width( + &temperature_and_weathercode, + width_no_border_pad - date.width() + )) + .bold(), date, Border::R.fmt(&gui.border).plain_or_bright_black(&gui.color), - WIDTH = WIDTH - - 3 - lang_len_diff(&wmo_code.interpretation, lang) - - temperature_and_weathercode.chars().count() - - lang_len_diff(&date, lang) ); // Apparent Temperature & Sun Rise & Sun Set let sunrise_and_sunset = format!("{sunrise} {sunset}"); println!( - "{} {} {: >WIDTH$} {}", + "{} {}{} {}", Border::L.fmt(&gui.border).plain_or_bright_black(&gui.color), - apparent_temp_max_min, + pad_string_to_width(&apparent_temp_max_min, width_no_border_pad - sunrise_and_sunset.width()), sunrise_and_sunset, Border::R.fmt(&gui.border).plain_or_bright_black(&gui.color), - WIDTH = WIDTH - - 3 - lang_len_diff(¶ms.texts.weather.feels_like, lang) - - apparent_temp_max_min.chars().count() ); // Hourly Forecast diff --git a/src/modules/display/historical.rs b/src/modules/display/historical.rs index c33f1a1..6ad2d5b 100644 --- a/src/modules/display/historical.rs +++ b/src/modules/display/historical.rs @@ -1,6 +1,7 @@ use anyhow::Result; use chrono::NaiveDate; use dialoguer::console::style; +use unicode_width::UnicodeWidthStr; use crate::modules::{ config::Config, @@ -15,7 +16,7 @@ use super::{ gui_config::ConfigurableColor, hourly::HourlyForecast, product::Product, - utils::lang_len_diff, + utils::pad_string_to_width, weathercode::WeatherCode, }; @@ -45,18 +46,18 @@ impl HistoricalWeather { hourly_forecast, } = self; - let (gui, lang) = (¶ms.config.gui, ¶ms.config.language); + let gui = ¶ms.config.gui; + let width_no_border_pad = WIDTH - 2; // Border Top println!("{}", &Edge::Top.fmt(WIDTH, &gui.border).plain_or_bright_black(&gui.color)); // Address / Title println!( - "{} {: ^WIDTH$} {}", + "{} {} {}", Border::L.fmt(&gui.border).plain_or_bright_black(&gui.color), - style(&address).bold(), + style(pad_string_to_width(&address, width_no_border_pad)).bold(), Border::R.fmt(&gui.border).plain_or_bright_black(&gui.color), - WIDTH = WIDTH - 2 - lang_len_diff(&address, lang) ); // Separator @@ -76,28 +77,25 @@ impl HistoricalWeather { wmo_code.icon, wmo_code.interpretation, temp_max_min, precipitation_sum ); println!( - "{} {} {: >WIDTH$} {}", + "{} {}{} {}", Border::L.fmt(&gui.border).plain_or_bright_black(&gui.color), - style(&temperature_and_weathercode).bold(), + style(pad_string_to_width( + &temperature_and_weathercode, + width_no_border_pad - date.width() + )) + .bold(), date, Border::R.fmt(&gui.border).plain_or_bright_black(&gui.color), - WIDTH = WIDTH - - 3 - lang_len_diff(&wmo_code.interpretation, lang) - - temperature_and_weathercode.chars().count() - - lang_len_diff(&date, lang) ); // Apparent Temperature & Sun Rise & Sun Set let sunrise_and_sunset = format!("{sunrise} {sunset}"); println!( - "{} {} {: >WIDTH$} {}", + "{} {}{} {}", Border::L.fmt(&gui.border).plain_or_bright_black(&gui.color), - apparent_temp_max_min, + pad_string_to_width(&apparent_temp_max_min, width_no_border_pad - sunrise_and_sunset.width()), sunrise_and_sunset, Border::R.fmt(&gui.border).plain_or_bright_black(&gui.color), - WIDTH = WIDTH - - 3 - lang_len_diff(¶ms.texts.weather.felt_like, lang) - - apparent_temp_max_min.chars().count() ); // Hourly Overview diff --git a/src/modules/display/hourly.rs b/src/modules/display/hourly.rs index bca5eb6..5e77f48 100644 --- a/src/modules/display/hourly.rs +++ b/src/modules/display/hourly.rs @@ -15,7 +15,7 @@ use super::{ graph::Graph, gui_config::ConfigurableColor, product::Product, - utils::{lang_len_diff, style_number}, + utils::{pad_string_to_width, style_number}, weathercode::WeatherCode, }; @@ -48,6 +48,7 @@ impl HourlyForecast { } = self; let (units, gui) = (¶ms.config.units, ¶ms.config.gui); + let width_no_border_pad = WIDTH - 2; // Blank Line println!( @@ -68,11 +69,10 @@ impl HourlyForecast { // Hourly Forecast Heading println!( - "{} {: { } } -pub fn lang_len_diff(input: &str, lang: &str) -> usize { - match &lang[..2] { - "zh" => { - let re = Regex::new(r"\p{Han}").unwrap(); - re.find_iter(input).count() - } - "ko" => { - let re = Regex::new(r"[\u3131-\uD79D\w]").unwrap(); - let nu = Regex::new(r"[-]?\d+(\.\d+)?").unwrap(); - re.find_iter(input).count() - nu.find_iter(input).count() - } - "ja" => { - let re = Regex::new(r"[ぁ-んァ-ン\w]").unwrap(); - let nu = Regex::new(r"[-]?\d+(\.\d+)?").unwrap(); - re.find_iter(input).count() - nu.find_iter(input).count() - } - _ => 0, +pub fn pad_string_to_width(s: &str, total_width: usize) -> String { + let current_width = s.width(); // Effective width of the string + if current_width >= total_width { + s.to_string() // No padding needed if already wide enough + } else { + let padding = total_width - current_width; + format!("{}{}", s, " ".repeat(padding)) } } diff --git a/src/modules/display/week.rs b/src/modules/display/week.rs index 5435982..ab03204 100644 --- a/src/modules/display/week.rs +++ b/src/modules/display/week.rs @@ -1,6 +1,7 @@ use anyhow::Result; use chrono::NaiveDate; use serde::{Deserialize, Serialize}; +use unicode_width::UnicodeWidthStr; use crate::modules::{localization::Locales, params::Params}; @@ -9,7 +10,7 @@ use super::{ current::Dimensions, gui_config::ConfigurableColor, product::{Product, MIN_CELL_WIDTH}, - utils::lang_len_diff, + utils::pad_string_to_width, weathercode::WeatherCode, }; @@ -29,13 +30,14 @@ pub struct ForecastDay { impl Week { pub fn render(self, params: &Params, current_dimensions: Option) { let forecast = self; - let (mut width, mut cell_width) = (forecast.width + 10, MIN_CELL_WIDTH); - let (gui, lang) = (¶ms.config.gui, ¶ms.config.language); + let gui = ¶ms.config.gui; + let (mut width, mut cell_width) = (forecast.width + 10, MIN_CELL_WIDTH); if let Some(dims) = current_dimensions { cell_width = std::cmp::max(cell_width, dims.cell_width); width = std::cmp::max(width, dims.width); } + let width_no_border_pad = width - 2; // Border Top println!("{}", &Edge::Top.fmt(width, &gui.border).plain_or_bright_black(&gui.color)); @@ -43,36 +45,21 @@ impl Week { let mut chunks = forecast.days.chunks(1).peekable(); let mut n = 0; - let date_len = forecast.days[0].date.chars().count() - lang_len_diff(&forecast.days[0].date, lang); while let Some(_) = chunks.next() { let forecast_day = format!( - "{: width$}", - forecast.days[n].date, - forecast.days[n].weather, + "{}{}{}", + pad_string_to_width(&forecast.days[n].date, cell_width), + pad_string_to_width( + &forecast.days[n].weather, + width_no_border_pad - forecast.days[n].interpretation.width() - cell_width + ), forecast.days[n].interpretation, - width = width - - if date_len < 11 { 11 } else { date_len } - - forecast.days[n].weather.len() - - lang_len_diff(&forecast.days[n].interpretation, lang) - - if &lang[..2] == "zh" || &lang[..2] == "ja" || &lang[..2] == "ko" { - 2 - } else { - 0 - } - if cell_width == MIN_CELL_WIDTH { - 2 - } else { - 2 + cell_width - MIN_CELL_WIDTH - } ); println!( - "{} {: width { width = day_width; }