From 57ad7f9536c7f08255a6a04efc164f3375d6f822 Mon Sep 17 00:00:00 2001 From: Viktar Lukashonak Date: Sat, 10 Dec 2022 14:02:15 +0300 Subject: [PATCH] ISSUE#1877 Calendar week numbers 1. Let's do code simplier 2. Week format using regexp. Needs when user provide additional characters in format string and need to align week days according 3. Week format has got default formats: ":%U",":%V" 4. Week number is based on the first day of the week now. The output is the same as of date library now. 5. Avoiding of unnecessary operations --- include/modules/clock.hpp | 2 + src/modules/clock.cpp | 84 ++++++++++++++++++++------------------- 2 files changed, 45 insertions(+), 41 deletions(-) diff --git a/include/modules/clock.hpp b/include/modules/clock.hpp index 08ab05e0..e97f05f3 100644 --- a/include/modules/clock.hpp +++ b/include/modules/clock.hpp @@ -33,6 +33,8 @@ class Clock : public ALabel { bool handleScroll(GdkEventScroll* e); + std::string weeks_format_; + int weeks_format_left_gaps{0}; auto calendar_text(const waybar_time& wtime) -> std::string; auto weekdays_header(const date::weekday& first_dow, std::ostream& os) -> void; auto first_day_of_week() -> date::weekday; diff --git a/src/modules/clock.cpp b/src/modules/clock.cpp index a40d4128..d6a9570b 100644 --- a/src/modules/clock.cpp +++ b/src/modules/clock.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include "util/ustring_clen.hpp" @@ -74,6 +75,13 @@ waybar::modules::Clock::Clock(const std::string& id, const Json::Value& config) locale_ = std::locale(""); } + if (config_["format-calendar-weeks"].isString()) { + weeks_format_ = std::regex_replace(config_["format-calendar-weeks"].asString(), std::regex("\\{\\}"), (first_day_of_week() == date::Monday) ? "{:%V}" : "{:%U}"); + weeks_format_left_gaps = std::regex_replace(weeks_format_, std::regex(".*|.*|\\{.?+\\}"), "").length(); + } else { + weeks_format_ = ""; + } + thread_ = [this] { dp.emit(); auto now = std::chrono::system_clock::now(); @@ -180,70 +188,63 @@ auto waybar::modules::Clock::calendar_text(const waybar_time& wtime) -> std::str ? date::day{0} : ymd.day()}; const date::year_month ym{ymd.year(), ymd.month()}; - const auto weeks_format{config_["format-calendar-weeks"].isString() - ? config_["format-calendar-weeks"].asString() - : ""}; + const auto first_dow = first_day_of_week(); std::stringstream os; - const date::weekday first_week_day = first_day_of_week(); - enum class WeeksPlacement { + enum class WeeksSide { LEFT, RIGHT, HIDDEN, }; - WeeksPlacement weeks_pos = WeeksPlacement::HIDDEN; + WeeksSide weeks_pos = WeeksSide::HIDDEN; if (config_["calendar-weeks-pos"].isString()) { if (config_["calendar-weeks-pos"].asString() == "left") { - weeks_pos = WeeksPlacement::LEFT; + weeks_pos = WeeksSide::LEFT; // Add paddings before the header - os << std::string(4, ' '); + os << std::string(3 + weeks_format_left_gaps, ' '); } else if (config_["calendar-weeks-pos"].asString() == "right") { - weeks_pos = WeeksPlacement::RIGHT; + weeks_pos = WeeksSide::RIGHT; } } - weekdays_header(first_week_day, os); + weekdays_header(first_dow, os); - // First week prefixed with spaces if needed. - auto first_month_day = date::weekday(ym / 1); - int empty_days = (first_week_day - first_month_day).count() + 1; - date::sys_days last_week_day{static_cast(ym / 1) + date::days{7 - empty_days}}; + // First week day prefixed with spaces if needed. + date::sys_days print_wd{ym/1}; + auto wd{date::weekday{print_wd}}; + auto empty_days = (wd - first_dow).count(); - if (first_week_day == date::Monday) { - last_week_day -= date::days{1}; - } /* Print weeknumber on the left for the first row*/ - if (weeks_pos == WeeksPlacement::LEFT) { - os << fmt::format(weeks_format, date::format("%U", last_week_day)) << ' '; - last_week_day += date::weeks{1}; + if (weeks_pos == WeeksSide::LEFT) { + os << fmt::format(weeks_format_, print_wd) << ' '; } if (empty_days > 0) { os << std::string(empty_days * 3 - 1, ' '); } + const auto last_day = (ym / date::literals::last).day(); - auto weekday = first_month_day; - for (auto d = date::day(1); d <= last_day; ++d, ++weekday) { - if (weekday != first_week_day) { + + for (auto d{date::day{1}}; d <= last_day; ++d, ++wd) { + if (wd != first_dow) { os << ' '; - } else if (unsigned(d) != 1) { - last_week_day -= date::days{1}; - if (weeks_pos == WeeksPlacement::RIGHT) { - os << ' '; - os << fmt::format(weeks_format, date::format("%U", last_week_day)); + } else if (unsigned(d)!= 1) { + if (weeks_pos == WeeksSide::RIGHT) { + os << ' ' << fmt::format(weeks_format_, print_wd); } - os << "\n"; + os << '\n'; - if (weeks_pos == WeeksPlacement::LEFT) { - os << fmt::format(weeks_format, date::format("%U", last_week_day)); - os << ' '; + print_wd = {ym/d}; + + if (weeks_pos == WeeksSide::LEFT) { + os << fmt::format(weeks_format_, print_wd) << ' '; } - last_week_day += date::weeks{1} + date::days{1}; } + if (d == curr_day) { if (config_["today-format"].isString()) { auto today_format = config_["today-format"].asString(); @@ -257,12 +258,13 @@ auto waybar::modules::Clock::calendar_text(const waybar_time& wtime) -> std::str os << date::format("%e", d); } /*Print weeks on the right when the endings with spaces*/ - if (weeks_pos == WeeksPlacement::RIGHT && d == last_day) { - last_week_day -= date::days{1}; - empty_days = 6 - (weekday - first_week_day).count(); - os << std::string(empty_days * 3 + 1, ' '); - os << fmt::format(weeks_format, date::format("%U", last_week_day)); - last_week_day += date::days{1}; + if (weeks_pos == WeeksSide::RIGHT && d == last_day) { + empty_days = 6 - (wd.c_encoding() - first_dow.c_encoding()); + if (empty_days > 0) { + os << std::string(empty_days * 3, ' '); + } + + os << ' ' << fmt::format(weeks_format_, print_wd); } } @@ -291,7 +293,7 @@ auto waybar::modules::Clock::weekdays_header(const date::weekday& first_week_day const std::string pad(2 - clen, ' '); res << pad << wd_ustring; } while (++wd != first_week_day); - res << "\n"; + res << '\n'; if (config_["format-calendar-weekdays"].isString()) { os << fmt::format(config_["format-calendar-weekdays"].asString(), res.str()); @@ -315,7 +317,7 @@ auto waybar::modules::Clock::timezones_text(std::chrono::system_clock::time_poin timezone = date::current_zone(); } wtime = {locale_, date::make_zoned(timezone, date::floor(*now))}; - os << fmt::format(format_, wtime) << "\n"; + os << fmt::format(format_, wtime) << '\n'; } return os.str(); }