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
This commit is contained in:
Viktar Lukashonak 2022-12-10 14:02:15 +03:00
parent c5babb4c44
commit 57ad7f9536
No known key found for this signature in database
GPG Key ID: 08A413AA87200A6F
2 changed files with 45 additions and 41 deletions

View File

@ -33,6 +33,8 @@ class Clock : public ALabel {
bool handleScroll(GdkEventScroll* e); bool handleScroll(GdkEventScroll* e);
std::string weeks_format_;
int weeks_format_left_gaps{0};
auto calendar_text(const waybar_time& wtime) -> std::string; auto calendar_text(const waybar_time& wtime) -> std::string;
auto weekdays_header(const date::weekday& first_dow, std::ostream& os) -> void; auto weekdays_header(const date::weekday& first_dow, std::ostream& os) -> void;
auto first_day_of_week() -> date::weekday; auto first_day_of_week() -> date::weekday;

View File

@ -6,6 +6,7 @@
#include <ctime> #include <ctime>
#include <iomanip> #include <iomanip>
#include <sstream> #include <sstream>
#include <regex>
#include <type_traits> #include <type_traits>
#include "util/ustring_clen.hpp" #include "util/ustring_clen.hpp"
@ -74,6 +75,13 @@ waybar::modules::Clock::Clock(const std::string& id, const Json::Value& config)
locale_ = std::locale(""); 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(".*<b>|</b>.*|\\{.?+\\}"), "").length();
} else {
weeks_format_ = "";
}
thread_ = [this] { thread_ = [this] {
dp.emit(); dp.emit();
auto now = std::chrono::system_clock::now(); 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} ? date::day{0}
: ymd.day()}; : ymd.day()};
const date::year_month ym{ymd.year(), ymd.month()}; const date::year_month ym{ymd.year(), ymd.month()};
const auto weeks_format{config_["format-calendar-weeks"].isString() const auto first_dow = first_day_of_week();
? config_["format-calendar-weeks"].asString()
: ""};
std::stringstream os; std::stringstream os;
const date::weekday first_week_day = first_day_of_week();
enum class WeeksPlacement { enum class WeeksSide {
LEFT, LEFT,
RIGHT, RIGHT,
HIDDEN, HIDDEN,
}; };
WeeksPlacement weeks_pos = WeeksPlacement::HIDDEN; WeeksSide weeks_pos = WeeksSide::HIDDEN;
if (config_["calendar-weeks-pos"].isString()) { if (config_["calendar-weeks-pos"].isString()) {
if (config_["calendar-weeks-pos"].asString() == "left") { if (config_["calendar-weeks-pos"].asString() == "left") {
weeks_pos = WeeksPlacement::LEFT; weeks_pos = WeeksSide::LEFT;
// Add paddings before the header // 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") { } 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. // First week day prefixed with spaces if needed.
auto first_month_day = date::weekday(ym / 1); date::sys_days print_wd{ym/1};
int empty_days = (first_week_day - first_month_day).count() + 1; auto wd{date::weekday{print_wd}};
date::sys_days last_week_day{static_cast<date::sys_days>(ym / 1) + date::days{7 - empty_days}}; 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*/ /* Print weeknumber on the left for the first row*/
if (weeks_pos == WeeksPlacement::LEFT) { if (weeks_pos == WeeksSide::LEFT) {
os << fmt::format(weeks_format, date::format("%U", last_week_day)) << ' '; os << fmt::format(weeks_format_, print_wd) << ' ';
last_week_day += date::weeks{1};
} }
if (empty_days > 0) { if (empty_days > 0) {
os << std::string(empty_days * 3 - 1, ' '); os << std::string(empty_days * 3 - 1, ' ');
} }
const auto last_day = (ym / date::literals::last).day(); 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) { for (auto d{date::day{1}}; d <= last_day; ++d, ++wd) {
if (weekday != first_week_day) { if (wd != first_dow) {
os << ' '; os << ' ';
} else if (unsigned(d) != 1) { } else if (unsigned(d)!= 1) {
last_week_day -= date::days{1}; if (weeks_pos == WeeksSide::RIGHT) {
if (weeks_pos == WeeksPlacement::RIGHT) { os << ' ' << fmt::format(weeks_format_, print_wd);
os << ' ';
os << fmt::format(weeks_format, date::format("%U", last_week_day));
} }
os << "\n"; os << '\n';
if (weeks_pos == WeeksPlacement::LEFT) { print_wd = {ym/d};
os << fmt::format(weeks_format, date::format("%U", last_week_day));
os << ' '; 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 (d == curr_day) {
if (config_["today-format"].isString()) { if (config_["today-format"].isString()) {
auto today_format = config_["today-format"].asString(); 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); os << date::format("%e", d);
} }
/*Print weeks on the right when the endings with spaces*/ /*Print weeks on the right when the endings with spaces*/
if (weeks_pos == WeeksPlacement::RIGHT && d == last_day) { if (weeks_pos == WeeksSide::RIGHT && d == last_day) {
last_week_day -= date::days{1}; empty_days = 6 - (wd.c_encoding() - first_dow.c_encoding());
empty_days = 6 - (weekday - first_week_day).count(); if (empty_days > 0) {
os << std::string(empty_days * 3 + 1, ' '); os << std::string(empty_days * 3, ' ');
os << fmt::format(weeks_format, date::format("%U", last_week_day)); }
last_week_day += date::days{1};
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, ' '); const std::string pad(2 - clen, ' ');
res << pad << wd_ustring; res << pad << wd_ustring;
} while (++wd != first_week_day); } while (++wd != first_week_day);
res << "\n"; res << '\n';
if (config_["format-calendar-weekdays"].isString()) { if (config_["format-calendar-weekdays"].isString()) {
os << fmt::format(config_["format-calendar-weekdays"].asString(), res.str()); 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(); timezone = date::current_zone();
} }
wtime = {locale_, date::make_zoned(timezone, date::floor<std::chrono::seconds>(*now))}; wtime = {locale_, date::make_zoned(timezone, date::floor<std::chrono::seconds>(*now))};
os << fmt::format(format_, wtime) << "\n"; os << fmt::format(format_, wtime) << '\n';
} }
return os.str(); return os.str();
} }