polybar/src/tags/parser.cpp

510 lines
10 KiB
C++
Raw Normal View History

#include "tags/parser.hpp"
#include <cassert>
#include <cctype>
Add units support (POINT, PIXEL, SPACE) (#2578) * add units support (POINT, PIXEL, SPACE) for polybar - add a size_with_unit struct - add a geometry_format_values struct - move dpi initialisation from renderer.cpp to bar.cpp - add a string to size_with_unit converter - add point support (with pt) - add pixel support (with px) * Fix unit test compilation * clang-format * Better names The old names didn't really capture the purpose of the structs and function. space_type -> spacing_type space_size -> spacing_val size_type -> extent_type geometry -> extent_val geometry_format_values -> percentage_with_offset * Remove parse_size_with_unit No longer needed. The convert<spacing_val> function in config.cpp already does all the work for us and always setting the type to pixel was wrong. In addition, line-size should not be of type spacing_val but extent_val. * Cleanup I tried to address most of my comments on the old PR * Fix renderer width calculation We can't just blindly add the x difference to the width because for example the width should increase if x < width and the increase keeps x < width. Similarly, we can't just add the offset to the width. * Rename geom_format_to_pixels to percentage_with_offset_to_pixel * Cleanup * Apply suggested changes from Patrick on GitHub Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com> * Update src/components/bar.cpp Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com> * Update src/components/config.cpp Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com> * Update src/components/builder.cpp Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com> * Update src/components/builder.cpp Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com> * config: Use stod for parsing percentage * Use stof instead of strtof * units: Fix test edge cases * Remove unnecessary clang-format toggle * Use percentage_with_offset for margin-{top,bottom} * Support negative extent values * Rename unit to units and create a cpp file * Move percentage_with_offset_to_pixel unit test to units * Add unit tests for units_utils * Clarify when and how negative spacing/extent is allowed Negative spacing is never allowed and produces a config error. Extents allow negative values in theory, but only a few use-cases accept it. Only the extent value used for the `%{O}` tag and the offset value in percentage_with_offset can be negative. Everything else is capped below at 0. The final pixel value of percentage_with_offset also caps below at 0. * Fix parsing errors not being caught in config * Print a proper error message for uncaught exceptions * Cleanup module::get_output All changes preserve the existing semantics * Stop using remove_trailing_space in module::get_output Instead, we first check if the current tag is built, and only if it is, the spacing is prepended. * Remove unused imports * Restore old behavior If there are two tags and the second one isn't built (module::build returns false), the space in between them is removed. For example in the mpd module: format-online = <toggle> <label-song> foo If mpd is not running, the mpd module will return false when trying to build the `<label-song>` tag. If we don't remove the space between `<toggle>` and `<label-song>`, we end up with two spaces between `<toggle>` and `foo`. This change is to match the old behavior where at least one trailing space character was removed from the builder. * Add changelog entry * Remove unused setting * Use percentage with offset for tray-offset Co-authored-by: Jérôme BOULMIER <jerome.boulmier@outlook.fr> Co-authored-by: Joe Groocock <github@frebib.net>
2022-02-20 20:08:57 +00:00
#include "utils/units.hpp"
POLYBAR_NS
namespace tags {
bool parser::has_next_element() {
return buf_pos < buf.size() || has_next();
}
element parser::next_element() {
if (!has_next_element()) {
throw std::runtime_error("tag parser: No next element");
}
if (buf_pos >= buf.size()) {
parse_step();
}
if (buf_pos >= buf.size()) {
throw std::runtime_error("tag parser: No next element. THIS IS A BUG. (Context: '" + input + "')");
}
element e = buf[buf_pos];
buf_pos++;
if (buf_pos == buf.size()) {
buf.clear();
buf_pos = 0;
}
return e;
}
format_string parser::parse() {
format_string parsed;
while (has_next_element()) {
parsed.push_back(next_element());
}
return parsed;
}
/**
* Performs a single parse step.
*
* This means it will parse text until the next tag is reached or it will
* parse an entire %{...} tag.
*/
void parser::parse_step() {
char c;
/*
* If we have already parsed text, we can stop if we reach a tag.
*/
bool text_parsed = false;
size_t start_pos = pos;
try {
while ((c = next())) {
// TODO here we could think about how to escape an action tag
if (c == '%' && has_next() && peek() == '{') {
/*
* If we have already parsed text, encountering a tag opening means
* we can stop parsing now because we parsed at least one entire
* element (the text up to the beginning of the tag).
*/
if (text_parsed) {
// Put back the '%'
revert();
break;
}
consume('{');
consume_space();
parse_tag();
break;
} else {
push_char(c);
text_parsed = true;
}
}
} catch (error& e) {
e.set_context(input.substr(start_pos, pos - start_pos));
throw;
}
}
void parser::set(const string&& input) {
this->input = std::move(input);
pos = 0;
buf.clear();
buf_pos = 0;
}
bool parser::has_next() const {
return pos < input.size();
}
char parser::next() {
char c = peek();
pos++;
return c;
}
char parser::peek() const {
if (!has_next()) {
return EOL;
}
return input[pos];
}
/**
* Puts back a single character in the input string.
*/
void parser::revert() {
assert(pos > 0);
pos--;
}
void parser::consume(char c) {
char n = next();
if (n != c) {
throw tags::token_error(n, c);
}
}
void parser::consume_space() {
while (peek() == ' ') {
next();
}
}
/**
* Parses an entire %{....} tag.
*
* '%' and '{' were already consumed and we are currently on the first character
* inside the tag.
* At the end of this method, we should be on the closing '}' character (not
* yet consumed).
*/
void parser::parse_tag() {
if (!has_next()) {
throw token_error(EOL, "Formatting tag content");
}
while (has_next()) {
parse_single_tag_content();
int p = peek();
if (p != ' ' && p != '}') {
throw tag_end_error(p);
} else {
/**
* Consume whitespace between elements inside the tag
*/
consume_space();
if (peek() == '}') {
consume('}');
break;
}
}
}
}
/**
* Parses a single element inside a formatting tag.
*
* For example it would parse the foreground part of the following tag:
*
* %{F#ff0000 B#ff0000}
* ^ ^
* | - Pointer at the end
* |
* - Pointer at the start
*/
void parser::parse_single_tag_content() {
char c = next();
/**
* %{U...} is a special case because it produces over and underline tags.
*/
if (c == 'U') {
element e{};
e.is_tag = true;
e.tag_data.type = tag_type::FORMAT;
e.tag_data.subtype.format = syntaxtag::u;
e.tag_data.color = parse_color();
buf.emplace_back(e);
e.tag_data.subtype.format = syntaxtag::o;
buf.emplace_back(e);
return;
}
tag_type type;
tag_subtype sub;
switch (c) {
// clang-format off
case 'B': sub.format = syntaxtag::B; break;
case 'F': sub.format = syntaxtag::F; break;
case 'u': sub.format = syntaxtag::u; break;
case 'o': sub.format = syntaxtag::o; break;
case 'T': sub.format = syntaxtag::T; break;
case 'R': sub.format = syntaxtag::R; break;
case 'O': sub.format = syntaxtag::O; break;
case 'P': sub.format = syntaxtag::P; break;
case 'A': sub.format = syntaxtag::A; break;
case 'l': sub.format = syntaxtag::l; break;
case 'c': sub.format = syntaxtag::c; break;
case 'r': sub.format = syntaxtag::r; break;
case '+': sub.activation = attr_activation::ON; break;
case '-': sub.activation = attr_activation::OFF; break;
case '!': sub.activation = attr_activation::TOGGLE; break;
// clang-format on
default:
throw unrecognized_tag(c);
}
switch (c) {
case 'B':
case 'F':
case 'u':
case 'o':
case 'T':
case 'R':
case 'O':
case 'P':
case 'A':
case 'l':
case 'c':
case 'r':
type = tag_type::FORMAT;
break;
case '+':
case '-':
case '!':
type = tag_type::ATTR;
break;
default:
throw unrecognized_tag(c);
}
tag tag_data{};
tag_data.type = type;
tag_data.subtype = sub;
element e{};
e.is_tag = true;
switch (c) {
case 'B':
case 'F':
case 'u':
case 'o':
tag_data.color = parse_color();
break;
case 'T':
tag_data.font = parse_fontindex();
break;
case 'O':
tag_data.offset = parse_offset();
break;
case 'P':
tag_data.ctrl = parse_control();
break;
case 'A':
std::tie(tag_data.action, e.data) = parse_action();
break;
case '+':
case '-':
case '!':
tag_data.attr = parse_attribute();
break;
}
e.tag_data = tag_data;
buf.emplace_back(e);
}
color_value parser::parse_color() {
string s = get_tag_value();
color_value ret;
if (s.empty() || s == "-") {
ret.type = color_type::RESET;
} else {
rgba c{s};
if (!c.has_color()) {
throw color_error(s);
}
ret.type = color_type::COLOR;
ret.val = c;
}
return ret;
}
int parser::parse_fontindex() {
string s = get_tag_value();
if (s.empty() || s == "-") {
return 0;
}
try {
size_t ptr;
int ret = std::stoi(s, &ptr, 10);
if (ret < 0) {
return 0;
}
if (ptr != s.size()) {
throw font_error(s, "Font index contains non-number characters");
}
return ret;
} catch (const std::exception& err) {
throw font_error(s, err.what());
}
}
Add units support (POINT, PIXEL, SPACE) (#2578) * add units support (POINT, PIXEL, SPACE) for polybar - add a size_with_unit struct - add a geometry_format_values struct - move dpi initialisation from renderer.cpp to bar.cpp - add a string to size_with_unit converter - add point support (with pt) - add pixel support (with px) * Fix unit test compilation * clang-format * Better names The old names didn't really capture the purpose of the structs and function. space_type -> spacing_type space_size -> spacing_val size_type -> extent_type geometry -> extent_val geometry_format_values -> percentage_with_offset * Remove parse_size_with_unit No longer needed. The convert<spacing_val> function in config.cpp already does all the work for us and always setting the type to pixel was wrong. In addition, line-size should not be of type spacing_val but extent_val. * Cleanup I tried to address most of my comments on the old PR * Fix renderer width calculation We can't just blindly add the x difference to the width because for example the width should increase if x < width and the increase keeps x < width. Similarly, we can't just add the offset to the width. * Rename geom_format_to_pixels to percentage_with_offset_to_pixel * Cleanup * Apply suggested changes from Patrick on GitHub Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com> * Update src/components/bar.cpp Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com> * Update src/components/config.cpp Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com> * Update src/components/builder.cpp Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com> * Update src/components/builder.cpp Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com> * config: Use stod for parsing percentage * Use stof instead of strtof * units: Fix test edge cases * Remove unnecessary clang-format toggle * Use percentage_with_offset for margin-{top,bottom} * Support negative extent values * Rename unit to units and create a cpp file * Move percentage_with_offset_to_pixel unit test to units * Add unit tests for units_utils * Clarify when and how negative spacing/extent is allowed Negative spacing is never allowed and produces a config error. Extents allow negative values in theory, but only a few use-cases accept it. Only the extent value used for the `%{O}` tag and the offset value in percentage_with_offset can be negative. Everything else is capped below at 0. The final pixel value of percentage_with_offset also caps below at 0. * Fix parsing errors not being caught in config * Print a proper error message for uncaught exceptions * Cleanup module::get_output All changes preserve the existing semantics * Stop using remove_trailing_space in module::get_output Instead, we first check if the current tag is built, and only if it is, the spacing is prepended. * Remove unused imports * Restore old behavior If there are two tags and the second one isn't built (module::build returns false), the space in between them is removed. For example in the mpd module: format-online = <toggle> <label-song> foo If mpd is not running, the mpd module will return false when trying to build the `<label-song>` tag. If we don't remove the space between `<toggle>` and `<label-song>`, we end up with two spaces between `<toggle>` and `foo`. This change is to match the old behavior where at least one trailing space character was removed from the builder. * Add changelog entry * Remove unused setting * Use percentage with offset for tray-offset Co-authored-by: Jérôme BOULMIER <jerome.boulmier@outlook.fr> Co-authored-by: Joe Groocock <github@frebib.net>
2022-02-20 20:08:57 +00:00
extent_val parser::parse_offset() {
string s = get_tag_value();
if (s.empty()) {
Add units support (POINT, PIXEL, SPACE) (#2578) * add units support (POINT, PIXEL, SPACE) for polybar - add a size_with_unit struct - add a geometry_format_values struct - move dpi initialisation from renderer.cpp to bar.cpp - add a string to size_with_unit converter - add point support (with pt) - add pixel support (with px) * Fix unit test compilation * clang-format * Better names The old names didn't really capture the purpose of the structs and function. space_type -> spacing_type space_size -> spacing_val size_type -> extent_type geometry -> extent_val geometry_format_values -> percentage_with_offset * Remove parse_size_with_unit No longer needed. The convert<spacing_val> function in config.cpp already does all the work for us and always setting the type to pixel was wrong. In addition, line-size should not be of type spacing_val but extent_val. * Cleanup I tried to address most of my comments on the old PR * Fix renderer width calculation We can't just blindly add the x difference to the width because for example the width should increase if x < width and the increase keeps x < width. Similarly, we can't just add the offset to the width. * Rename geom_format_to_pixels to percentage_with_offset_to_pixel * Cleanup * Apply suggested changes from Patrick on GitHub Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com> * Update src/components/bar.cpp Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com> * Update src/components/config.cpp Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com> * Update src/components/builder.cpp Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com> * Update src/components/builder.cpp Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com> * config: Use stod for parsing percentage * Use stof instead of strtof * units: Fix test edge cases * Remove unnecessary clang-format toggle * Use percentage_with_offset for margin-{top,bottom} * Support negative extent values * Rename unit to units and create a cpp file * Move percentage_with_offset_to_pixel unit test to units * Add unit tests for units_utils * Clarify when and how negative spacing/extent is allowed Negative spacing is never allowed and produces a config error. Extents allow negative values in theory, but only a few use-cases accept it. Only the extent value used for the `%{O}` tag and the offset value in percentage_with_offset can be negative. Everything else is capped below at 0. The final pixel value of percentage_with_offset also caps below at 0. * Fix parsing errors not being caught in config * Print a proper error message for uncaught exceptions * Cleanup module::get_output All changes preserve the existing semantics * Stop using remove_trailing_space in module::get_output Instead, we first check if the current tag is built, and only if it is, the spacing is prepended. * Remove unused imports * Restore old behavior If there are two tags and the second one isn't built (module::build returns false), the space in between them is removed. For example in the mpd module: format-online = <toggle> <label-song> foo If mpd is not running, the mpd module will return false when trying to build the `<label-song>` tag. If we don't remove the space between `<toggle>` and `<label-song>`, we end up with two spaces between `<toggle>` and `foo`. This change is to match the old behavior where at least one trailing space character was removed from the builder. * Add changelog entry * Remove unused setting * Use percentage with offset for tray-offset Co-authored-by: Jérôme BOULMIER <jerome.boulmier@outlook.fr> Co-authored-by: Joe Groocock <github@frebib.net>
2022-02-20 20:08:57 +00:00
return ZERO_PX_EXTENT;
}
try {
Add units support (POINT, PIXEL, SPACE) (#2578) * add units support (POINT, PIXEL, SPACE) for polybar - add a size_with_unit struct - add a geometry_format_values struct - move dpi initialisation from renderer.cpp to bar.cpp - add a string to size_with_unit converter - add point support (with pt) - add pixel support (with px) * Fix unit test compilation * clang-format * Better names The old names didn't really capture the purpose of the structs and function. space_type -> spacing_type space_size -> spacing_val size_type -> extent_type geometry -> extent_val geometry_format_values -> percentage_with_offset * Remove parse_size_with_unit No longer needed. The convert<spacing_val> function in config.cpp already does all the work for us and always setting the type to pixel was wrong. In addition, line-size should not be of type spacing_val but extent_val. * Cleanup I tried to address most of my comments on the old PR * Fix renderer width calculation We can't just blindly add the x difference to the width because for example the width should increase if x < width and the increase keeps x < width. Similarly, we can't just add the offset to the width. * Rename geom_format_to_pixels to percentage_with_offset_to_pixel * Cleanup * Apply suggested changes from Patrick on GitHub Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com> * Update src/components/bar.cpp Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com> * Update src/components/config.cpp Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com> * Update src/components/builder.cpp Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com> * Update src/components/builder.cpp Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com> * config: Use stod for parsing percentage * Use stof instead of strtof * units: Fix test edge cases * Remove unnecessary clang-format toggle * Use percentage_with_offset for margin-{top,bottom} * Support negative extent values * Rename unit to units and create a cpp file * Move percentage_with_offset_to_pixel unit test to units * Add unit tests for units_utils * Clarify when and how negative spacing/extent is allowed Negative spacing is never allowed and produces a config error. Extents allow negative values in theory, but only a few use-cases accept it. Only the extent value used for the `%{O}` tag and the offset value in percentage_with_offset can be negative. Everything else is capped below at 0. The final pixel value of percentage_with_offset also caps below at 0. * Fix parsing errors not being caught in config * Print a proper error message for uncaught exceptions * Cleanup module::get_output All changes preserve the existing semantics * Stop using remove_trailing_space in module::get_output Instead, we first check if the current tag is built, and only if it is, the spacing is prepended. * Remove unused imports * Restore old behavior If there are two tags and the second one isn't built (module::build returns false), the space in between them is removed. For example in the mpd module: format-online = <toggle> <label-song> foo If mpd is not running, the mpd module will return false when trying to build the `<label-song>` tag. If we don't remove the space between `<toggle>` and `<label-song>`, we end up with two spaces between `<toggle>` and `foo`. This change is to match the old behavior where at least one trailing space character was removed from the builder. * Add changelog entry * Remove unused setting * Use percentage with offset for tray-offset Co-authored-by: Jérôme BOULMIER <jerome.boulmier@outlook.fr> Co-authored-by: Joe Groocock <github@frebib.net>
2022-02-20 20:08:57 +00:00
return units_utils::parse_extent(string{s});
} catch (const std::exception& err) {
throw offset_error(s, err.what());
}
}
controltag parser::parse_control() {
string s = get_tag_value();
if (s.empty()) {
throw control_error(s, "Control tag is empty");
}
switch (s[0]) {
case 'R':
if (s.size() != 1) {
throw control_error(s, "Control tag R has extra data");
}
return controltag::R;
case 't':
return controltag::t;
default:
throw control_error(s);
}
}
std::pair<action_value, string> parser::parse_action() {
mousebtn btn = parse_action_btn();
action_value ret;
string cmd;
if (has_next() && peek() == ':') {
ret.btn = btn == mousebtn::NONE ? mousebtn::LEFT : btn;
ret.closing = false;
cmd = parse_action_cmd();
} else {
ret.btn = btn;
ret.closing = true;
}
return {ret, cmd};
}
/**
* Parses the button index after starting an action tag.
*
* May return mousebtn::NONE if no button was given.
*/
mousebtn parser::parse_action_btn() {
if (has_next()) {
if (isdigit(peek())) {
char c = next();
int num = c - '0';
if (num < static_cast<int>(mousebtn::NONE) || num >= static_cast<int>(mousebtn::BTN_COUNT)) {
throw btn_error(string{c});
}
return static_cast<mousebtn>(num);
}
}
return mousebtn::NONE;
}
/**
* Starts at ':' and parses a complete action string.
*
* Returns the parsed action string with without escaping backslashes.
*
* Afterwards the parsers will be at the character immediately after the
* closing colon.
*/
string parser::parse_action_cmd() {
consume(':');
string s;
char prev = EOL;
while (has_next()) {
char c = next();
if (c == ':') {
if (prev == '\\') {
s.pop_back();
s.push_back(c);
} else {
break;
}
} else {
s.push_back(c);
}
prev = c;
}
return s;
}
attribute parser::parse_attribute() {
char c;
switch (c = next()) {
case 'u':
return attribute::UNDERLINE;
case 'o':
return attribute::OVERLINE;
default:
throw unrecognized_attr(c);
}
}
void parser::push_char(char c) {
if (!buf.empty() && buf_pos < buf.size() && !buf.back().is_tag) {
buf.back().data += c;
} else {
buf.emplace_back(string{c});
}
}
void parser::push_text(string&& text) {
if (text.empty()) {
return;
}
if (!buf.empty() && buf_pos < buf.size() && !buf.back().is_tag) {
buf.back().data += text;
} else {
buf.emplace_back(std::move(text));
}
}
/**
* Will read up until the end of the tag value.
*
* Afterwards the parser will be at the character directly after the tag
* value.
*
* This function just reads until it encounters a space or a closing curly
* bracket, so it is not useful for tag values that can contain these
* characters (e.g. action tags).
*/
string parser::get_tag_value() {
string s;
while (has_next() && peek() != ' ' && peek() != '}') {
s.push_back(next());
}
return s;
}
Add units support (POINT, PIXEL, SPACE) (#2578) * add units support (POINT, PIXEL, SPACE) for polybar - add a size_with_unit struct - add a geometry_format_values struct - move dpi initialisation from renderer.cpp to bar.cpp - add a string to size_with_unit converter - add point support (with pt) - add pixel support (with px) * Fix unit test compilation * clang-format * Better names The old names didn't really capture the purpose of the structs and function. space_type -> spacing_type space_size -> spacing_val size_type -> extent_type geometry -> extent_val geometry_format_values -> percentage_with_offset * Remove parse_size_with_unit No longer needed. The convert<spacing_val> function in config.cpp already does all the work for us and always setting the type to pixel was wrong. In addition, line-size should not be of type spacing_val but extent_val. * Cleanup I tried to address most of my comments on the old PR * Fix renderer width calculation We can't just blindly add the x difference to the width because for example the width should increase if x < width and the increase keeps x < width. Similarly, we can't just add the offset to the width. * Rename geom_format_to_pixels to percentage_with_offset_to_pixel * Cleanup * Apply suggested changes from Patrick on GitHub Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com> * Update src/components/bar.cpp Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com> * Update src/components/config.cpp Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com> * Update src/components/builder.cpp Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com> * Update src/components/builder.cpp Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com> * config: Use stod for parsing percentage * Use stof instead of strtof * units: Fix test edge cases * Remove unnecessary clang-format toggle * Use percentage_with_offset for margin-{top,bottom} * Support negative extent values * Rename unit to units and create a cpp file * Move percentage_with_offset_to_pixel unit test to units * Add unit tests for units_utils * Clarify when and how negative spacing/extent is allowed Negative spacing is never allowed and produces a config error. Extents allow negative values in theory, but only a few use-cases accept it. Only the extent value used for the `%{O}` tag and the offset value in percentage_with_offset can be negative. Everything else is capped below at 0. The final pixel value of percentage_with_offset also caps below at 0. * Fix parsing errors not being caught in config * Print a proper error message for uncaught exceptions * Cleanup module::get_output All changes preserve the existing semantics * Stop using remove_trailing_space in module::get_output Instead, we first check if the current tag is built, and only if it is, the spacing is prepended. * Remove unused imports * Restore old behavior If there are two tags and the second one isn't built (module::build returns false), the space in between them is removed. For example in the mpd module: format-online = <toggle> <label-song> foo If mpd is not running, the mpd module will return false when trying to build the `<label-song>` tag. If we don't remove the space between `<toggle>` and `<label-song>`, we end up with two spaces between `<toggle>` and `foo`. This change is to match the old behavior where at least one trailing space character was removed from the builder. * Add changelog entry * Remove unused setting * Use percentage with offset for tray-offset Co-authored-by: Jérôme BOULMIER <jerome.boulmier@outlook.fr> Co-authored-by: Joe Groocock <github@frebib.net>
2022-02-20 20:08:57 +00:00
} // namespace tags
POLYBAR_NS_END