From f4d2ca27364134f22c366a5dfd0e47579006c63e Mon Sep 17 00:00:00 2001 From: Guillaume Maudoux Date: Tue, 24 Sep 2019 11:21:28 +0200 Subject: [PATCH] custom formatter for numbers in 'pow' units format --- include/util/format.hpp | 81 +++++++++++++++++++++++++++++++++++++++-- meson.build | 1 - src/modules/disk.cpp | 34 +++++++++++++---- src/modules/network.cpp | 2 +- src/util/format.cpp | 26 ------------- 5 files changed, 105 insertions(+), 39 deletions(-) delete mode 100644 src/util/format.cpp diff --git a/include/util/format.hpp b/include/util/format.hpp index 74c504fe..0147701b 100644 --- a/include/util/format.hpp +++ b/include/util/format.hpp @@ -1,9 +1,84 @@ #pragma once -#include +#include -namespace waybar::util { +class pow_format { + public: + pow_format(long long val, std::string&& unit, bool binary = false): + val_(val), unit_(unit), binary_(binary) { }; -std::string pow_format(unsigned long long value, const std::string &unit, bool binary = false); + long long val_; + std::string unit_; + bool binary_; +}; + +namespace fmt { + template <> + struct formatter { + char spec = 0; + int width = 0; + + template + constexpr auto parse(ParseContext& ctx) -> decltype (ctx.begin()) { + auto it = ctx.begin(), end = ctx.end(); + if (it != end && *it == ':') ++it; + if (*it == '>' || *it == '<' || *it == '=') { + spec = *it; + ++it; + } + if (it == end || *it == '}') return it; + if ('0' <= *it && *it <= '9') { + // We ignore it for now, but keep it for compatibility with + // existing configs where the format for pow_format'ed numbers was + // 'string' and specifications such as {:>9} were valid. + // The rationale for ignoring it is that the only reason to specify + // an alignment and a with is to get a fixed width bar, and ">" is + // sufficient in this implementation. + width = parse_nonnegative_int(it, end, ctx); + } + return it; + } + + template + auto format(const pow_format& s, FormatContext &ctx) -> decltype (ctx.out()) { + const char* units[] = { "", "k", "M", "G", "T", "P", nullptr}; + + auto base = s.binary_ ? 1024ull : 1000ll; + auto fraction = (double) s.val_; + + int pow; + for (pow = 0; units[pow+1] != nullptr && fraction / base >= 1; ++pow) { + fraction /= base; + } + + auto max_width = 4 // coeff in {:.3g} format + + 1 // prefix from units array + + s.binary_ // for the 'i' in GiB. + + s.unit_.length(); + + const char * format; + std::string string; + switch (spec) { + case '>': + return format_to(ctx.out(), "{:>{}}", fmt::format("{}", s), max_width); + case '<': + return format_to(ctx.out(), "{:<{}}", fmt::format("{}", s), max_width); + case '=': + format = "{coefficient:<4.3g}{padding}{prefix}{unit}"; + break; + case 0: + default: + format = "{coefficient:.3g}{prefix}{unit}"; + break; + } + return format_to(ctx.out(), format + , fmt::arg("coefficient", fraction) + , fmt::arg("prefix", std::string() + units[pow] + ((s.binary_ && pow) ? "i" : "")) + , fmt::arg("unit", s.unit_) + , fmt::arg("padding", pow ? "" : s.binary_ ? " " : " ") + ); + } + }; } + diff --git a/meson.build b/meson.build index b0d99b93..a9d44eeb 100644 --- a/meson.build +++ b/meson.build @@ -91,7 +91,6 @@ src_files = files( 'src/modules/disk.cpp', 'src/modules/idle_inhibitor.cpp', 'src/modules/temperature.cpp', - 'src/util/format.cpp', 'src/main.cpp', 'src/bar.cpp', 'src/client.cpp' diff --git a/src/modules/disk.cpp b/src/modules/disk.cpp index 859a45a2..811fe729 100644 --- a/src/modules/disk.cpp +++ b/src/modules/disk.cpp @@ -44,15 +44,33 @@ auto waybar::modules::Disk::update() -> void { return; } - label_.set_markup(fmt::format(format_, - stats.f_bavail * 100 / stats.f_blocks, - fmt::arg("free", pow_format(stats.f_bavail * stats.f_bsize, "B", true)), - fmt::arg("percentage_free", stats.f_bavail * 100 / stats.f_blocks), - fmt::arg("used", pow_format((stats.f_blocks - stats.f_bavail) * stats.f_bsize, "B", true)), - fmt::arg("percentage_used", (stats.f_blocks - stats.f_bavail) * 100 / stats.f_blocks) - )); + auto free = pow_format(stats.f_bavail * stats.f_bsize, "B", true); + auto used = pow_format((stats.f_blocks - stats.f_bavail) * stats.f_bsize, "B", true); + auto total = pow_format(stats.f_blocks * stats.f_bsize, "B", true); + + label_.set_markup(fmt::format(format_ + , stats.f_bavail * 100 / stats.f_blocks + , fmt::arg("free", free) + , fmt::arg("percentage_free", stats.f_bavail * 100 / stats.f_blocks) + , fmt::arg("used", used) + , fmt::arg("percentage_used", (stats.f_blocks - stats.f_bavail) * 100 / stats.f_blocks) + , fmt::arg("total", total) + , fmt::arg("path", path_) + )); if (tooltipEnabled()) { - label_.set_tooltip_text(fmt::format("{} used", pow_format(stats.f_bavail * stats.f_bsize, "B", true))); + std::string tooltip_format = "{used} used out of {total} on {path} ({percentage_used}%)"; + if (config_["tooltip-format"].isString()) { + tooltip_format = config_["tooltip-format"].asString(); + } + label_.set_tooltip_text(fmt::format(tooltip_format + , stats.f_bavail * 100 / stats.f_blocks + , fmt::arg("free", free) + , fmt::arg("percentage_free", stats.f_bavail * 100 / stats.f_blocks) + , fmt::arg("used", used) + , fmt::arg("percentage_used", (stats.f_blocks - stats.f_bavail) * 100 / stats.f_blocks) + , fmt::arg("total", total) + , fmt::arg("path", path_) + )); } event_box_.show(); } diff --git a/src/modules/network.cpp b/src/modules/network.cpp index 3e2fe9cf..ba196cff 100644 --- a/src/modules/network.cpp +++ b/src/modules/network.cpp @@ -515,7 +515,7 @@ bool waybar::modules::Network::checkInterface(struct ifinfomsg *rtif, std::strin return false; } -int waybar::modules::Network::getPreferredIface(int skip_idx, bool wait = true) const { +int waybar::modules::Network::getPreferredIface(int skip_idx, bool wait) const { int ifid = -1; if (config_["interface"].isString()) { ifid = if_nametoindex(config_["interface"].asCString()); diff --git a/src/util/format.cpp b/src/util/format.cpp deleted file mode 100644 index 249c8cd8..00000000 --- a/src/util/format.cpp +++ /dev/null @@ -1,26 +0,0 @@ -#include - -namespace waybar::util { - -std::string pow_format(unsigned long long value, const std::string &unit, bool binary = false) { - auto base = binary ? 1024ull : 1000ull; - const char* units[] = { "", "k", "M", "G", "T", "P", nullptr}; - auto fraction = (double) value; - - int pow; - for (pow = 0; units[pow+1] != nullptr && fraction / base >= 2; ++pow) { - fraction /= base; - } - - std::ostringstream ss; - if (pow > 0) { - auto quotient = (unsigned long long) fraction; - auto remainder = (unsigned long long) ((fraction - quotient) * 10); - ss << quotient << "." << remainder << units[pow] << (binary ? "i" : "") << unit; - } else { - ss << value << unit; - } - return ss.str(); -}; - -}