Compare commits
14 Commits
pulseaudio
...
3.4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3c2188ff28 | ||
|
|
d95f9309a9 | ||
|
|
f7a1949108 | ||
|
|
54816fe251 | ||
|
|
0e50a8e9e2 | ||
|
|
0782c7c514 | ||
|
|
838291930a | ||
|
|
7b78323370 | ||
|
|
0bfaf41ac3 | ||
|
|
f08a5937a2 | ||
|
|
3d4a5a37be | ||
|
|
3bd394de05 | ||
|
|
74a62e377e | ||
|
|
a8fe49273e |
@@ -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`
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "common.hpp"
|
||||
|
||||
|
||||
@@ -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@"};
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
2
lib/xpp
2
lib/xpp
Submodule lib/xpp updated: d2ff2aaba6...f70dd8bb50
@@ -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");
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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};
|
||||
|
||||
|
||||
@@ -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]));
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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]));
|
||||
|
||||
@@ -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]));
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user