Skip to content

Commit

Permalink
🐛 reimplement padding width calculation to fix border placement for l…
Browse files Browse the repository at this point in the history
…anguages with varying unicode character widths (#367)
  • Loading branch information
ttytm authored Oct 3, 2024
1 parent 8bbcfae commit a964606
Show file tree
Hide file tree
Showing 8 changed files with 84 additions and 109 deletions.
9 changes: 8 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
48 changes: 21 additions & 27 deletions src/modules/display/current.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
Expand Down Expand Up @@ -50,19 +50,19 @@ impl Current {
hourly_forecast,
} = self;

let gui = &params.config.gui;
let Dimensions { width, cell_width } = dimensions;
let (gui, lang) = (&params.config.gui, &params.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
Expand All @@ -76,44 +76,38 @@ impl Current {
.plain_or_bright_black(&gui.color),
);

// Temperature & Weathercode
println!(
"{} {: <width$} {}",
"{} {} {}",
Border::L.fmt(&gui.border).plain_or_bright_black(&gui.color),
style(wmo_code.icon.to_string() + " " + &wmo_code.interpretation + ", " + &temperature).bold(),
style(pad_string_to_width(
&(wmo_code.icon.to_string() + " " + &wmo_code.interpretation + ", " + &temperature),
width_no_border_pad
))
.bold(),
Border::R.fmt(&gui.border).plain_or_bright_black(&gui.color),
width = width - 2 - lang_len_diff(&wmo_code.interpretation, lang)
);

// Apparent Temperature
println!(
"{} {: <width$} {}",
"{} {} {}",
Border::L.fmt(&gui.border).plain_or_bright_black(&gui.color),
apparent_temperature,
pad_string_to_width(&apparent_temperature, width_no_border_pad),
Border::R.fmt(&gui.border).plain_or_bright_black(&gui.color),
width = width - 2 - lang_len_diff(&apparent_temperature, lang)
// manually account for displacepment of this row until improving the lang_len_diff regex
+ if &lang[..2] == "ja" || &lang[..2] == "ko" { 2 } else { 0 }
);

// Blank Line
println!("{}", Separator::Blank.fmt(width, &gui.border).plain_or_bright_black(&gui.color));

// Humidity & Dewpoint
println!(
"{} {: <width$} {}",
"{} {}{} {}",
Border::L.fmt(&gui.border).plain_or_bright_black(&gui.color),
format!(
"{: <cell_width$} {}",
humidity,
dewpoint,
cell_width = cell_width
- lang_len_diff(&humidity, lang)
- if &lang[..2] == "ja" || &lang[..2] == "ko" { 0 } else { 1 }
),
pad_string_to_width(&humidity, cell_width),
// NOTE: When using the Thai language, an apparent combining character issue was observed
// with the dew point, resulting in the border being displaced by one space or the border
// color being removed in some terminal/font configurations.
pad_string_to_width(&dewpoint, width_no_border_pad - cell_width),
Border::R.fmt(&gui.border).plain_or_bright_black(&gui.color),
width = width - 2 - lang_len_diff(&humidity, lang) - lang_len_diff(&dewpoint, lang)
+ if &lang[..2] == "ja" || &lang[..2] == "ko" { 3 } else { 0 }
);

// Wind & Pressure
Expand All @@ -123,7 +117,7 @@ impl Current {
wind,
pressure,
Border::R.fmt(&gui.border).plain_or_bright_black(&gui.color),
width = width - 2 - cell_width
width = width_no_border_pad - cell_width
);

// Sunrise & Sunset
Expand All @@ -133,7 +127,7 @@ impl Current {
sunrise,
sunset,
Border::R.fmt(&gui.border).plain_or_bright_black(&gui.color),
width = width - 2 - cell_width
width = width_no_border_pad - cell_width
);

// Hourly Forecast
Expand Down
30 changes: 14 additions & 16 deletions src/modules/display/day.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use anyhow::Result;
use chrono::{Duration, Local};
use dialoguer::console::style;
use unicode_width::UnicodeWidthStr;

use crate::modules::{display::hourly::WIDTH, localization::Locales, params::Params, units::Time};

Expand All @@ -9,7 +10,7 @@ use super::{
gui_config::ConfigurableColor,
hourly::HourlyForecast,
product::Product,
utils::lang_len_diff,
utils::pad_string_to_width,
weathercode::WeatherCode,
};

Expand Down Expand Up @@ -39,18 +40,18 @@ impl Day {
hourly_forecast,
} = self;

let (gui, lang) = (&params.config.gui, &params.config.language);
let gui = &params.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
Expand All @@ -70,28 +71,25 @@ impl Day {
wmo_code.icon, wmo_code.interpretation, temp_max_min, precipitation_probability_max
);
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(&params.texts.weather.feels_like, lang)
- apparent_temp_max_min.chars().count()
);

// Hourly Forecast
Expand Down
30 changes: 14 additions & 16 deletions src/modules/display/historical.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use anyhow::Result;
use chrono::NaiveDate;
use dialoguer::console::style;
use unicode_width::UnicodeWidthStr;

use crate::modules::{
config::Config,
Expand All @@ -15,7 +16,7 @@ use super::{
gui_config::ConfigurableColor,
hourly::HourlyForecast,
product::Product,
utils::lang_len_diff,
utils::pad_string_to_width,
weathercode::WeatherCode,
};

Expand Down Expand Up @@ -45,18 +46,18 @@ impl HistoricalWeather {
hourly_forecast,
} = self;

let (gui, lang) = (&params.config.gui, &params.config.language);
let gui = &params.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
Expand All @@ -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(&params.texts.weather.felt_like, lang)
- apparent_temp_max_min.chars().count()
);

// Hourly Overview
Expand Down
8 changes: 4 additions & 4 deletions src/modules/display/hourly.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};

Expand Down Expand Up @@ -48,6 +48,7 @@ impl HourlyForecast {
} = self;

let (units, gui) = (&params.config.units, &params.config.gui);
let width_no_border_pad = WIDTH - 2;

// Blank Line
println!(
Expand All @@ -68,11 +69,10 @@ impl HourlyForecast {

// Hourly Forecast Heading
println!(
"{} {: <WIDTH$} {}",
"{} {} {}",
Border::L.fmt(&gui.border).plain_or_bright_black(&gui.color),
style(&heading).bold(),
style(pad_string_to_width(&heading, width_no_border_pad)).bold(),
Border::R.fmt(&gui.border).plain_or_bright_black(&gui.color),
WIDTH = WIDTH - 2 - lang_len_diff(&heading, &params.config.language)
);

// Day Max/Mix Temperature + Max Precipitation
Expand Down
25 changes: 8 additions & 17 deletions src/modules/display/utils.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use regex::Regex;
use unicode_width::UnicodeWidthStr;

use crate::modules::display::product::Product;

Expand Down Expand Up @@ -26,23 +27,13 @@ impl Product<'_> {
}
}

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))
}
}

Expand Down
Loading

0 comments on commit a964606

Please sign in to comment.