From 649a98a67952cb6f63547a504bff83d40daae220 Mon Sep 17 00:00:00 2001 From: Emiliano Deustua Date: Sat, 28 Jun 2025 16:33:14 -0500 Subject: [PATCH] feat: Add ISO 8601 calendar to clock module --- include/modules/clock.hpp | 25 +++++++++++++------------ man/waybar-clock.5.scd | 6 ++++++ src/modules/clock.cpp | 35 +++++++++++++++++++++++++---------- 3 files changed, 44 insertions(+), 22 deletions(-) diff --git a/include/modules/clock.hpp b/include/modules/clock.hpp index e34b7a8e..741996aa 100644 --- a/include/modules/clock.hpp +++ b/include/modules/clock.hpp @@ -38,18 +38,19 @@ class Clock final : public ALabel { 5 - tooltip-format */ std::map fmtMap_; - uint cldMonCols_{3}; // calendar count month columns - int cldWnLen_{3}; // calendar week number length - const int cldMonColLen_{20}; // calendar month column length - WS cldWPos_{WS::HIDDEN}; // calendar week side to print - date::months cldCurrShift_{0}; // calendar months shift - int cldShift_{1}; // calendar months shift factor - date::year_month_day cldYearShift_; // calendar Year mode. Cached ymd - std::string cldYearCached_; // calendar Year mode. Cached calendar - date::year_month cldMonShift_; // calendar Month mode. Cached ym - std::string cldMonCached_; // calendar Month mode. Cached calendar - date::day cldBaseDay_{0}; // calendar Cached day. Is used when today is changing(midnight) - std::string cldText_{""}; // calendar text to print + uint cldMonCols_{3}; // calendar count month columns + int cldWnLen_{3}; // calendar week number length + const int cldMonColLen_{20}; // calendar month column length + WS cldWPos_{WS::HIDDEN}; // calendar week side to print + date::months cldCurrShift_{0}; // calendar months shift + int cldShift_{1}; // calendar months shift factor + date::year_month_day cldYearShift_; // calendar Year mode. Cached ymd + std::string cldYearCached_; // calendar Year mode. Cached calendar + date::year_month cldMonShift_; // calendar Month mode. Cached ym + std::string cldMonCached_; // calendar Month mode. Cached calendar + date::day cldBaseDay_{0}; // calendar Cached day. Is used when today is changing(midnight) + std::string cldText_{""}; // calendar text to print + bool iso8601Calendar_{false}; // whether the calendar is in ISO8601 CldMode cldMode_{CldMode::MONTH}; auto get_calendar(const date::year_month_day& today, const date::year_month_day& ymd, const date::time_zone* tz) -> const std::string; diff --git a/man/waybar-clock.5.scd b/man/waybar-clock.5.scd index 50a5fc07..0006171e 100644 --- a/man/waybar-clock.5.scd +++ b/man/waybar-clock.5.scd @@ -126,6 +126,12 @@ View all valid format options in *strftime(3)* or have a look https://en.cpprefe :[ 1 :[ Value to scroll months/years forward/backward. Can be negative. Is configured under *on-scroll* option +|[ *iso8601* +:[ bool +:[ false +:[ When enabled, the calendar follows the ISO 8601 standard: weeks begin on + Monday, and the first week of the year is numbered 1. The default week format is + '{:%V}'. 3. Addressed by *clock: calendar: format* [- *Option* diff --git a/src/modules/clock.cpp b/src/modules/clock.cpp index a7d57437..84e4a63c 100644 --- a/src/modules/clock.cpp +++ b/src/modules/clock.cpp @@ -73,6 +73,11 @@ waybar::modules::Clock::Clock(const std::string& id, const Json::Value& config) "using instead", cfgMode); } + + if (config_[kCldPlaceholder]["iso"].isBool()) { + iso8601Calendar_ = config_[kCldPlaceholder]["iso"].asBool(); + } + if (config_[kCldPlaceholder]["weeks-pos"].isString()) { if (config_[kCldPlaceholder]["weeks-pos"].asString() == "left") cldWPos_ = WS::LEFT; if (config_[kCldPlaceholder]["weeks-pos"].asString() == "right") cldWPos_ = WS::RIGHT; @@ -99,16 +104,20 @@ waybar::modules::Clock::Clock(const std::string& id, const Json::Value& config) } else fmtMap_.insert({3, "{}"}); if (config_[kCldPlaceholder]["format"]["weeks"].isString() && cldWPos_ != WS::HIDDEN) { + const auto defaultFmt = + iso8601Calendar_ ? "{:%V}" : ((first_day_of_week() == Monday) ? "{:%W}" : "{:%U}"); fmtMap_.insert({4, std::regex_replace(config_[kCldPlaceholder]["format"]["weeks"].asString(), - std::regex("\\{\\}"), - (first_day_of_week() == Monday) ? "{:%W}" : "{:%U}")}); + std::regex("\\{\\}"), defaultFmt)}); Glib::ustring tmp{std::regex_replace(fmtMap_[4], std::regex("]+>|\\{.*\\}"), "")}; cldWnLen_ += tmp.size(); } else { - if (cldWPos_ != WS::HIDDEN) - fmtMap_.insert({4, (first_day_of_week() == Monday) ? "{:%W}" : "{:%U}"}); - else + if (cldWPos_ != WS::HIDDEN) { + const auto defaultFmt = + iso8601Calendar_ ? "{:%V}" : ((first_day_of_week() == Monday) ? "{:%W}" : "{:%U}"); + fmtMap_.insert({4, defaultFmt}); + } else { cldWnLen_ = 0; + } } if (config_[kCldPlaceholder]["mode-mon-col"].isInt()) { cldMonCols_ = config_[kCldPlaceholder]["mode-mon-col"].asInt(); @@ -204,9 +213,11 @@ const unsigned cldRowsInMonth(const year_month& ym, const weekday& firstdow) { auto cldGetWeekForLine(const year_month& ym, const weekday& firstdow, const unsigned line) -> const year_month_weekday { - unsigned index{line - 2}; - if (weekday{ym / 1} == firstdow) ++index; - return ym / firstdow[index]; + const unsigned idx = line - 2; + const std::chrono::weekday_indexed indexed_first_day_of_week = + weekday{ym / 1} == firstdow ? firstdow[idx + 1] : firstdow[idx]; + + return ym / indexed_first_day_of_week; } auto getCalendarLine(const year_month_day& currDate, const year_month ym, const unsigned line, @@ -265,7 +276,7 @@ auto getCalendarLine(const year_month_day& currDate, const year_month ym, const } // Print non-first week default: { - auto ymdTmp{cldGetWeekForLine(ym, firstdow, line)}; + const auto ymdTmp{cldGetWeekForLine(ym, firstdow, line)}; if (ymdTmp.ok()) { auto d{year_month_day{ymdTmp}.day()}; const auto dlast{(ym / last).day()}; @@ -356,8 +367,9 @@ auto waybar::modules::Clock::get_calendar(const year_month_day& today, const yea : static_cast(zoned_seconds{ tz, local_days{cldGetWeekForLine(ymTmp, firstdow, line)}}))) << ' '; - } else + } else { os << pads; + } } } @@ -481,6 +493,9 @@ using deleting_unique_ptr = std::unique_ptr>; // Computations done similarly to Linux cal utility. auto waybar::modules::Clock::first_day_of_week() -> weekday { + if (iso8601Calendar_) { + return Monday; + } #ifdef HAVE_LANGINFO_1STDAY deleting_unique_ptr::type, freelocale> posix_locale{ newlocale(LC_ALL, m_locale_.name().c_str(), nullptr)};