Compare commits

...

14 Commits

Author SHA1 Message Date
patrick96
3c2188ff28 Release 3.4.3
Fixes: GCC 10 Compilation (#2098), see #2097
2020-05-14 23:25:15 +02:00
Jérôme BOULMIER
d95f9309a9 Fix gcc compilation 2020-05-14 23:25:15 +02:00
patrick96
f7a1949108 Relase 3.4.2
Fixes

* `internal/i3` (and maybe others): Workspace icon map misbehaves for empty icon (#1893), see #1881
* `custom/ipc`: Clear content if hook produces no output. (#1951)
* renderer:
    * The modules on the right no longer overlap the tray or are shifted out of the bar. (#1936), see #591, #1903, #1838, #1236
    * The gradient when modules are shifted out of the bar (because there is not enough space) is now drawn correctly in all circumstances. (#1936)
* build: Fixed a compilation issue in gcc10 (#1967, polybar/xpp#20)
2019-12-27 15:15:12 +01:00
Jeremy Ong
54816fe251 Add missing <stdexcept> header
This is dependent on a PR to xpp that does the same. Newer compilers
(GCC10 in particular) are stricter about which headers provide the
std exception types.
2019-12-27 15:15:12 +01:00
patrick96
0e50a8e9e2 fix(ipc): Clear content if no output is produced
Before, if the command produced no output, the `m_output` field would
not have been overwritten and the old output was displayed.

But since this is an explicit trigger of the hook, the user would expect
the output to be updated to whatever the script produces (even if that
is nothing).

Ref: https://www.reddit.com/r/Polybar/comments/e9a8ww
2019-12-27 15:15:12 +01:00
patrick96
0782c7c514 fix(renderer): make center position more robust
The old code didn't really work when the right block was pushing against
the center block. Also `fixed-center` wasn't properly defined. I have
now fixed it to the following:

* `fixed-center = true`: The center block stays at the center of the bar
whenever possible. It can be pushed to the left if the right block takes
too much space and to the right if the left block takes too much space
* `fixed-center = false`: The center block will be in the middle between
the left and right block whenever possible. If there is not enough space
between those two, the center block will be directly to the right of the
left block and pushes out the right block
2019-12-27 15:15:12 +01:00
patrick96
838291930a fix(renderer): Falloff gradient
Before it did not take into account borders or a tray on the left.
It also sometimes rendered the gradient way to large
2019-12-27 15:15:12 +01:00
patrick96
7b78323370 fix(renderer): Correctly position right block if center is empty
The issue was that it used the position of the center module to
calculate the leftmost possible position of the block. However, if the
center module is empty that position is disastrously wrong.

Fixes #591
Fixes #1903
2019-12-27 15:15:12 +01:00
Jérôme BOULMIER
0bfaf41ac3 Include empty tokens when splitting if necessary (#1893)
Fixes #1881
2019-12-27 15:15:12 +01:00
patrick96
f08a5937a2 Release 3.4.1
Changelog

Dependencies:

We dropped `python2` as a dependency, just in time for its EOL. Now the only python dependency is `python3` (#1908).

Fixes:

* ipc:
    * Update bar when making it visible (#1889), see #1875
    * Set bar position when making it visible (#1901), see #1484, i3/i3#3834
* `internal/backlight`: Use correct brightness file for `amdgpu_bl0` (#1900), see #1870, Alexays/Waybar#335
2019-10-30 13:53:40 +01:00
patrick96
3d4a5a37be build: drop python2
Ref: https://github.com/polybar/xpp/pull/17
Fixes #1892
2019-10-30 13:53:40 +01:00
patrick96
3bd394de05 fix(backlight): Use 'brightness' with amdgpu_bl0
The amdgpu driver seems to set 'actual_brightness' wrong.

Fixes #1870
Ref: https://github.com/Alexays/Waybar/issues/335
2019-10-30 13:53:40 +01:00
patrick96
74a62e377e fix(bar): Configure window before remapping
Some WMs like i3 discard position information when unmapping the bar and
because of that the bar would be at the wrong position after being
remapped.

Fixes #1484
Ref: https://github.com/i3/i3/pull/3834
2019-10-30 13:53:40 +01:00
patrick96
a8fe49273e fix(ipc): Update bar when making bar visible
While an update was forced whenever polybar was made visible, the
`m_lastinput` variable was still set to the same value as when the bar
became hidden because updates to it were prevented.

Fixes #1875
2019-10-30 13:53:40 +01:00
20 changed files with 217 additions and 107 deletions

View File

@@ -109,7 +109,7 @@ If you are using **Gentoo**, both release and git-master versions are available
A compiler with C++14 support ([clang-3.4+](http://llvm.org/releases/download.html), [gcc-5.1+](https://gcc.gnu.org/releases.html)), [cmake 3.1+](https://cmake.org/download/), [git](https://git-scm.com/downloads)
- `cairo`
- `libxcb`
- `python2`
- `python`
- `xcb-proto`
- `xcb-util-image`
- `xcb-util-wm`

View File

@@ -68,10 +68,8 @@ set(SETTING_CONNECTION_TEST_IP "8.8.8.8"
CACHE STRING "Address to ping when testing network connection")
set(SETTING_PATH_ADAPTER "/sys/class/power_supply/%adapter%"
CACHE STRING "Path to adapter")
set(SETTING_PATH_BACKLIGHT_MAX "/sys/class/backlight/%card%/max_brightness"
CACHE STRING "Path to file containing the maximum backlight value")
set(SETTING_PATH_BACKLIGHT_VAL "/sys/class/backlight/%card%/actual_brightness"
CACHE STRING "Path to file containing the current backlight value")
set(SETTING_PATH_BACKLIGHT "/sys/class/backlight/%card%"
CACHE STRING "Path to backlight sysfs folder")
set(SETTING_PATH_BATTERY "/sys/class/power_supply/%battery%"
CACHE STRING "Path to battery")
set(SETTING_PATH_CPU_INFO "/proc/stat"

View File

@@ -108,10 +108,9 @@ namespace cairo {
}
context& operator<<(const linear_gradient& l) {
if (l.steps.size() >= 2) {
auto stops = l.steps.size();
if (stops >= 2) {
auto pattern = cairo_pattern_create_linear(l.x1, l.y1, l.x2, l.y2);
*this << pattern;
auto stops = l.steps.size();
auto step = 1.0 / (stops - 1);
auto offset = 0.0;
for (auto&& color : l.steps) {
@@ -124,6 +123,7 @@ namespace cairo {
// clang-format on
offset += step;
}
*this << pattern;
cairo_pattern_destroy(pattern);
}
return *this;

View File

@@ -74,6 +74,8 @@ class bar : public xpp::event::sink<evt::button_press, evt::expose, evt::propert
protected:
void restack_window();
void reconfigue_window();
void reconfigure_geom();
void reconfigure_pos();
void reconfigure_struts();
void reconfigure_wm_hints();

View File

@@ -2,6 +2,7 @@
#include <cerrno>
#include <cstring>
#include <stdexcept>
#include "common.hpp"

View File

@@ -64,8 +64,7 @@ static constexpr const char* BSPWM_SOCKET_PATH{"@SETTING_BSPWM_SOCKET_PATH@"};
static constexpr const char* BSPWM_STATUS_PREFIX{"@SETTING_BSPWM_STATUS_PREFIX@"};
static constexpr const char* CONNECTION_TEST_IP{"@SETTING_CONNECTION_TEST_IP@"};
static constexpr const char* PATH_ADAPTER{"@SETTING_PATH_ADAPTER@"};
static constexpr const char* PATH_BACKLIGHT_MAX{"@SETTING_PATH_BACKLIGHT_MAX@"};
static constexpr const char* PATH_BACKLIGHT_VAL{"@SETTING_PATH_BACKLIGHT_VAL@"};
static constexpr const char* PATH_BACKLIGHT{"@SETTING_PATH_BACKLIGHT@"};
static constexpr const char* PATH_BATTERY{"@SETTING_PATH_BATTERY@"};
static constexpr const char* PATH_CPU_INFO{"@SETTING_PATH_CPU_INFO@"};
static constexpr const char* PATH_MEMORY_INFO{"@SETTING_PATH_MEMORY_INFO@"};

View File

@@ -40,9 +40,9 @@ namespace socket_util {
* conn->receive(...);
* \endcode
*/
auto make_unix_connection = [](string&& path) -> unique_ptr<unix_connection> {
inline unique_ptr<unix_connection> make_unix_connection(string&& path) {
return factory_util::unique<unix_connection>(forward<string>(path));
};
}
}
POLYBAR_NS_END

View File

@@ -85,8 +85,8 @@ namespace string_util {
string utf8_truncate(string&& value, size_t len);
string join(const vector<string>& strs, const string& delim);
vector<string>& split_into(const string& s, char delim, vector<string>& container);
vector<string> split(const string& s, char delim);
std::vector<std::string> tokenize(const string& str, char delimiters);
size_t find_nth(const string& haystack, size_t pos, const string& needle, size_t nth);

Submodule lib/xpp updated: d2ff2aaba6...f70dd8bb50

View File

@@ -319,19 +319,20 @@ void bar::parse(string&& data, bool force) {
std::lock_guard<std::mutex> guard(m_mutex, std::adopt_lock);
bool unchanged = data == m_lastinput;
m_lastinput = data;
if (force) {
m_log.trace("bar: Force update");
} else if (!m_visible) {
return m_log.trace("bar: Ignoring update (invisible)");
} else if (m_opts.shaded) {
return m_log.trace("bar: Ignoring update (shaded)");
} else if (data == m_lastinput) {
} else if (unchanged) {
return m_log.trace("bar: Ignoring update (unchanged)");
return;
}
m_lastinput = data;
auto rect = m_opts.inner_area();
if (m_tray && !m_tray->settings().detached && m_tray->settings().configured_slots) {
@@ -403,6 +404,11 @@ void bar::show() {
try {
m_log.info("Showing bar window");
m_sig.emit(visibility_change{true});
/**
* First reconfigures the window so that WMs that discard some information
* when unmapping have the correct window properties (geometry etc).
*/
reconfigue_window();
m_connection.map_window_checked(m_opts.window);
m_connection.flush();
m_visible = true;
@@ -459,6 +465,22 @@ void bar::restack_window() {
}
}
void bar::reconfigue_window() {
m_log.trace("bar: Reconfigure window");
restack_window();
reconfigure_geom();
reconfigure_struts();
reconfigure_wm_hints();
}
/**
* Reconfigure window geometry
*/
void bar::reconfigure_geom() {
window win{m_connection, m_opts.window};
win.reconfigure_geom(m_opts.size.w, m_opts.size.h, m_opts.pos.x, m_opts.pos.y);
}
/**
* Reconfigure window position
*/
@@ -795,11 +817,7 @@ bool bar::on(const signals::eventqueue::start&) {
m_connection.ensure_event_mask(m_opts.window, XCB_EVENT_MASK_STRUCTURE_NOTIFY);
m_log.info("Bar window: %s", m_connection.id(m_opts.window));
restack_window();
m_log.trace("bar: Reconfigure window");
reconfigure_struts();
reconfigure_wm_hints();
reconfigue_window();
m_log.trace("bar: Map window");
m_connection.map_window_checked(m_opts.window);
@@ -809,7 +827,6 @@ bool bar::on(const signals::eventqueue::start&) {
m_sig.emit(signals::ui::update_geometry{});
// Reconfigure window position after mapping (required by Openbox)
// Required by Openbox
reconfigure_pos();
m_log.trace("bar: Draw empty bar");

View File

@@ -1,4 +1,5 @@
#include "components/renderer.hpp"
#include "cairo/context.hpp"
#include "components/config.hpp"
#include "events/signal.hpp"
@@ -343,7 +344,7 @@ void renderer::flush(alignment a) {
double w = static_cast<int>(block_w(a) + 0.5);
double h = static_cast<int>(block_h(a) + 0.5);
double xw = x + w;
bool fits{xw <= m_rect.x + m_rect.width};
bool fits{xw <= m_rect.width};
m_log.trace("renderer: flush(%i geom=%gx%g+%g+%g, falloff=%i)", static_cast<int>(a), w, h, x, y, !fits);
@@ -361,19 +362,34 @@ void renderer::flush(alignment a) {
*m_context << m_blocks[a].pattern;
m_context->paint();
if (!fits) {
// Paint falloff gradient at the end of the visible block
// to indicate that the content expands past the canvas
double fx = w - (xw - m_rect.width);
double fsize = std::max(5.0, std::min(std::abs(fx), 30.0));
m_log.trace("renderer: Drawing falloff (pos=%g, size=%g)", fx, fsize);
*m_context << cairo::linear_gradient{fx - fsize, 0.0, fx, 0.0, {0x00000000, 0xFF000000}};
m_context->paint(0.25);
}
*m_context << cairo::abspos{0.0, 0.0};
m_context->destroy(&m_blocks[a].pattern);
m_context->restore();
if (!fits) {
// Paint falloff gradient at the end of the visible block
// to indicate that the content expands past the canvas
/*
* How many pixels are hidden
*/
double overflow = xw - m_rect.width;
double visible_width = w - overflow;
/*
* Width of the falloff gradient. Depends on how much of the block is hidden
*/
double fsize = std::max(5.0, std::min(std::abs(overflow), 30.0));
m_log.trace("renderer: Drawing falloff (pos=%g, size=%g, overflow=%g)", visible_width - fsize, fsize, overflow);
m_context->save();
*m_context << cairo::translate{(double) m_rect.x, (double) m_rect.y};
*m_context << cairo::abspos{0.0, 0.0};
*m_context << cairo::rect{x + visible_width - fsize, y, fsize, h};
m_context->clip(true);
*m_context << cairo::linear_gradient{x + visible_width - fsize, y, x + visible_width, y, {0x00000000, 0xFF000000}};
m_context->paint(0.25);
m_context->restore();
}
}
/**
@@ -420,48 +436,83 @@ void renderer::flush() {
/**
* Get x position of block for given alignment
*
* The position is relative to m_rect.x (the left side of the bar w/o borders and tray)
*/
double renderer::block_x(alignment a) const {
switch (a) {
case alignment::CENTER: {
double base_pos{0.0};
double min_pos{0.0};
if (!m_fixedcenter || m_rect.width / 2.0 + block_w(a) / 2.0 > m_rect.width - block_w(alignment::RIGHT)) {
base_pos = (m_rect.width - block_w(alignment::RIGHT) + block_w(alignment::LEFT)) / 2.0;
} else {
base_pos = m_rect.width / 2.0;
}
if ((min_pos = block_w(alignment::LEFT))) {
// The leftmost x position this block can start at
double min_pos = block_w(alignment::LEFT);
if (min_pos != 0) {
min_pos += BLOCK_GAP;
}
base_pos += (m_bar.size.w - m_rect.width) / 2.0;
int border_left = m_bar.borders.at(edge::LEFT).size;
double right_width = block_w(alignment::RIGHT);
/*
* If m_rect.x is greater than the left border, then the systray is rendered on the left and we need to adjust for
* that.
* Since we cannot access any tray objects from here we need to calculate the tray size through m_rect.x
* m_rect.x is the x-position of the bar (without the tray or any borders), so if the tray is on the left,
* m_rect.x effectively is border_left + tray_width.
* So we can just subtract the tray_width = m_rect.x - border_left from the base_pos to correct for the tray being
* placed on the left
* The rightmost x position this block can end at
*
* We can't use block_x(alignment::RIGHT) because that would lead to infinite recursion
*/
if(m_rect.x > border_left) {
base_pos -= m_rect.x - border_left;
double max_pos = m_rect.width - right_width;
if (right_width != 0) {
max_pos -= BLOCK_GAP;
}
base_pos -= border_left;
/*
* x position of the center of this block
*
* With fixed-center this will be the center of the bar unless it is pushed to the left by a large right block
* Without fixed-center this will be the middle between the end of the left and the start of the right block.
*/
double base_pos{0.0};
if (m_fixedcenter) {
/*
* This is in the middle of the *bar*. Not just the middle of m_rect because this way we need to account for the
* tray.
*
* The resulting position is relative to the very left of the bar (including border and tray), so we need to
* compensate for that by subtracting m_rect.x
*/
base_pos = m_bar.size.w / 2.0 - m_rect.x;
/*
* The center block can be moved to the left if the right block is too large
*/
base_pos = std::min(base_pos, max_pos - block_w(a) / 2.0);
}
else {
base_pos = (min_pos + max_pos) / 2.0;
}
/*
* The left block always has priority (even with fixed-center = true)
*/
return std::max(base_pos - block_w(a) / 2.0, min_pos);
}
case alignment::RIGHT: {
double gap{0.0};
if (block_w(alignment::LEFT) || block_w(alignment::CENTER)) {
gap = BLOCK_GAP;
/*
* The block immediately to the left of this block
*
* Generally the center block unless it is empty.
*/
alignment left_barrier = alignment::CENTER;
if (block_w(alignment::CENTER) == 0) {
left_barrier = alignment::LEFT;
}
return std::max(m_rect.width - block_w(a), block_x(alignment::CENTER) + gap + block_w(alignment::CENTER));
// The minimum x position this block can start at
double min_pos = block_x(left_barrier) + block_w(left_barrier);
if (block_w(left_barrier) != 0) {
min_pos += BLOCK_GAP;
}
return std::max(m_rect.width - block_w(a), min_pos);
}
default:
return 0.0;

View File

@@ -40,12 +40,21 @@ namespace modules {
m_ramp = load_ramp(m_conf, name(), TAG_RAMP);
}
// Build path to the file where the current/maximum brightness value is located
m_val.filepath(string_util::replace(PATH_BACKLIGHT_VAL, "%card%", card));
m_max.filepath(string_util::replace(PATH_BACKLIGHT_MAX, "%card%", card));
// Build path to the sysfs folder the current/maximum brightness values are located
auto path_backlight = string_util::replace(PATH_BACKLIGHT, "%card%", card);
/*
* amdgpu drivers set the actual_brightness in a different scale than [0, max_brightness]
* The only sensible way is to use the 'brightness' file instead
* Ref: https://github.com/Alexays/Waybar/issues/335
*/
auto path_backlight_val = path_backlight + "/" + (card == "amdgpu_bl0"? "brightness" : "actual_brightness");
m_val.filepath(path_backlight_val);
m_max.filepath(path_backlight + "/max_brightness");
// Add inotify watch
watch(string_util::replace(PATH_BACKLIGHT_VAL, "%card%", card));
watch(path_backlight_val);
}
void backlight_module::idle() {

View File

@@ -131,7 +131,7 @@ namespace modules {
m_icons->add(DEFAULT_ICON, factory_util::shared<label>(m_conf.get(name(), DEFAULT_ICON, ""s)));
for (const auto& workspace : m_conf.get_list<string>(name(), "ws-icon", {})) {
auto vec = string_util::split(workspace, ';');
auto vec = string_util::tokenize(workspace, ';');
if (vec.size() == 2) {
m_icons->add(vec[0], factory_util::shared<label>(vec[1]));
}
@@ -224,11 +224,7 @@ namespace modules {
size_t workspace_n{0U};
for (auto&& tag : string_util::split(data, ':')) {
if (tag.empty()) {
continue;
}
auto value = !tag.empty() ? tag.substr(1) : "";
auto value = tag.substr(1);
auto mode_flag = mode::NONE;
unsigned int workspace_mask{0U};

View File

@@ -58,7 +58,7 @@ namespace modules {
m_icons->add(DEFAULT_WS_ICON, factory_util::shared<label>(m_conf.get(name(), DEFAULT_WS_ICON, ""s)));
for (const auto& workspace : m_conf.get_list<string>(name(), "ws-icon", {})) {
auto vec = string_util::split(workspace, ';');
auto vec = string_util::tokenize(workspace, ';');
if (vec.size() == 2) {
m_icons->add(vec[0], factory_util::shared<label>(vec[1]));
}

View File

@@ -1,6 +1,6 @@
#include "modules/ipc.hpp"
#include "components/ipc.hpp"
#include "components/ipc.hpp"
#include "modules/meta/base.inl"
POLYBAR_NS
@@ -112,6 +112,8 @@ namespace modules {
m_log.info("%s: Found matching hook (%s)", name(), hook->payload);
try {
// Clear the output in case the command produces no output
m_output.clear();
auto command = command_util::make_command(hook->command);
command->exec(false);
command->tail([this](string line) { m_output = line; });
@@ -123,6 +125,6 @@ namespace modules {
broadcast();
}
}
}
} // namespace modules
POLYBAR_NS_END

View File

@@ -49,7 +49,7 @@ namespace modules {
m_layout_icons->add(DEFAULT_LAYOUT_ICON, load_optional_label(m_conf, name(), DEFAULT_LAYOUT_ICON, ""s));
for (const auto& it : m_conf.get_list<string>(name(), "layout-icon", {})) {
auto vec = string_util::split(it, ';');
auto vec = string_util::tokenize(it, ';');
if (vec.size() == 2) {
m_layout_icons->add(vec[0], factory_util::shared<label>(vec[1]));
}
@@ -80,7 +80,7 @@ namespace modules {
m_indicator_icons_off = factory_util::shared<iconset>();
m_indicator_icons_on = factory_util::shared<iconset>();
auto icon_pair = string_util::split(m_conf.get(name(), DEFAULT_INDICATOR_ICON, ""s), ';');
auto icon_pair = string_util::tokenize(m_conf.get(name(), DEFAULT_INDICATOR_ICON, ""s), ';');
if(icon_pair.size() == 2) {
m_indicator_icons_off->add(DEFAULT_INDICATOR_ICON, factory_util::shared<label>(icon_pair[0]));
m_indicator_icons_on->add(DEFAULT_INDICATOR_ICON, factory_util::shared<label>(icon_pair[1]));
@@ -90,7 +90,7 @@ namespace modules {
}
for (const auto& it : m_conf.get_list<string>(name(), "indicator-icon", {})) {
auto icon_triple = string_util::split(it, ';');
auto icon_triple = string_util::tokenize(it, ';');
if (icon_triple.size() == 3) {
auto const indicator_str = string_util::lower(icon_triple[0]);
m_indicator_icons_off->add(indicator_str, factory_util::shared<label>(icon_triple[1]));

View File

@@ -71,7 +71,7 @@ namespace modules {
m_icons->add(DEFAULT_ICON, factory_util::shared<label>(m_conf.get(name(), DEFAULT_ICON, ""s)));
for (const auto& workspace : m_conf.get_list<string>(name(), "icon", {})) {
auto vec = string_util::split(workspace, ';');
auto vec = string_util::tokenize(workspace, ';');
if (vec.size() == 2) {
m_icons->add(vec[0], factory_util::shared<label>(vec[1]));
}

View File

@@ -200,27 +200,42 @@ namespace string_util {
}
/**
* Explode string by delim into container
*/
vector<string>& split_into(const string& s, char delim, vector<string>& container) {
string str;
std::stringstream buffer(s);
while (getline(buffer, str, delim)) {
container.emplace_back(str);
}
return container;
}
/**
* Explode string by delim
* Explode string by delim, ignore empty tokens
*/
vector<string> split(const string& s, char delim) {
vector<string> vec;
return split_into(s, delim, vec);
std::string::size_type pos = 0;
std::vector<std::string> result;
while ((pos = s.find_first_not_of(delim, pos)) != std::string::npos) {
auto nextpos = s.find_first_of(delim, pos);
result.emplace_back(s.substr(pos, nextpos - pos));
pos = nextpos;
}
return result;
}
/**
* Find the nth occurence of needle in haystack starting from pos
* Explode string by delim, include empty tokens
*/
std::vector<std::string> tokenize(const string& str, char delimiters) {
std::vector<std::string> tokens;
std::string::size_type lastPos = 0;
auto pos = str.find_first_of(delimiters, lastPos);
while (pos != std::string::npos && lastPos != std::string::npos) {
tokens.emplace_back(str.substr(lastPos, pos - lastPos));
lastPos = pos + 1;
pos = str.find_first_of(delimiters, lastPos);
}
tokens.emplace_back(str.substr(lastPos, pos - lastPos));
return tokens;
}
/**
* Find the nth occurrence of needle in haystack starting from pos
*/
size_t find_nth(const string& haystack, size_t pos, const string& needle, size_t nth) {
size_t found_pos = haystack.find(needle, pos);

View File

@@ -61,20 +61,40 @@ TEST(String, join) {
EXPECT_EQ("A, B, C", string_util::join({"A", "B", "C"}, ", "));
}
TEST(String, splitInto) {
vector<string> strings;
string_util::split_into("A,B,C", ',', strings);
EXPECT_EQ(3, strings.size());
EXPECT_EQ("A", strings[0]);
EXPECT_EQ("C", strings[2]);
TEST(String, split) {
{
vector<string> strings = string_util::split("A,B,C", ',');
EXPECT_EQ(3, strings.size());
EXPECT_EQ("A", strings[0]);
EXPECT_EQ("B", strings[1]);
EXPECT_EQ("C", strings[2]);
}
{
vector<string> strings = string_util::split(",A,,B,,C,", ',');
EXPECT_EQ(3, strings.size());
EXPECT_EQ("A", strings[0]);
EXPECT_EQ("B", strings[1]);
EXPECT_EQ("C", strings[2]);
}
}
TEST(String, split) {
vector<string> strings{"foo", "bar"};
vector<string> result{string_util::split("foo,bar", ',')};
EXPECT_EQ(strings.size(), result.size());
EXPECT_EQ(strings[0], result[0]);
EXPECT_EQ("bar", result[1]);
TEST(String, tokenize) {
{
vector<string> strings = string_util::tokenize("A,B,C", ',');
EXPECT_EQ(3, strings.size());
EXPECT_EQ("A", strings[0]);
EXPECT_EQ("B", strings[1]);
EXPECT_EQ("C", strings[2]);
}
{
using namespace std::string_literals;
vector<string> strings = string_util::tokenize(",A,,B,,C,", ',');
vector<string> result{""s, "A"s, ""s, "B"s, ""s, "C"s, ""s};
EXPECT_TRUE(strings == result);
}
}
TEST(String, findNth) {

View File

@@ -1,4 +1,4 @@
# Polybar version information
# Update this on every release
# This is used to create the version string if a git repo is not available
3.4.0
3.4.3