2020-12-17 19:37:28 +00:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include "common.hpp"
|
|
|
|
#include "errors.hpp"
|
|
|
|
#include "tags/types.hpp"
|
|
|
|
|
|
|
|
POLYBAR_NS
|
|
|
|
|
|
|
|
namespace tags {
|
|
|
|
|
|
|
|
static constexpr char EOL = '\0';
|
|
|
|
|
|
|
|
class error : public application_error {
|
|
|
|
public:
|
|
|
|
using application_error::application_error;
|
|
|
|
|
|
|
|
explicit error(const string& msg) : application_error(msg), msg(msg) {}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Context string that contains the text region where the parser error
|
|
|
|
* happened.
|
|
|
|
*/
|
|
|
|
void set_context(const string& ctxt) {
|
|
|
|
msg.append(" (Context: '" + ctxt + "')");
|
|
|
|
}
|
|
|
|
|
2021-01-04 09:38:43 +00:00
|
|
|
virtual const char* what() const noexcept override {
|
2020-12-17 19:37:28 +00:00
|
|
|
return msg.c_str();
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
string msg;
|
|
|
|
};
|
|
|
|
|
|
|
|
#define DEFINE_INVALID_ERROR(class_name, name) \
|
|
|
|
class class_name : public error { \
|
|
|
|
public: \
|
|
|
|
explicit class_name(const string& val) : error("Invalid " name ": '" + val + "'") {} \
|
|
|
|
explicit class_name(const string& val, const string& what) \
|
|
|
|
: error("Invalid " name ": '" + val + "' (reason: '" + what + "')") {} \
|
|
|
|
}
|
|
|
|
|
|
|
|
DEFINE_INVALID_ERROR(color_error, "color");
|
|
|
|
DEFINE_INVALID_ERROR(font_error, "font index");
|
|
|
|
DEFINE_INVALID_ERROR(control_error, "control tag");
|
|
|
|
DEFINE_INVALID_ERROR(offset_error, "offset");
|
|
|
|
DEFINE_INVALID_ERROR(btn_error, "button id");
|
|
|
|
#undef DEFINE_INVALID_ERROR
|
|
|
|
|
|
|
|
class token_error : public error {
|
|
|
|
public:
|
|
|
|
explicit token_error(char token, char expected) : token_error(string{token}, string{expected}) {}
|
|
|
|
explicit token_error(char token, const string& expected) : token_error(string{token}, expected) {}
|
|
|
|
explicit token_error(const string& token, const string& expected)
|
|
|
|
: error("Expected '" + expected + "' but found '" +
|
|
|
|
(token.size() == 1 && token.at(0) == EOL ? "<End Of Line>" : token) + "'") {}
|
|
|
|
};
|
|
|
|
|
|
|
|
class unrecognized_tag : public error {
|
|
|
|
public:
|
|
|
|
explicit unrecognized_tag(char tag) : error("Unrecognized formatting tag '%{" + string{tag} + "}'") {}
|
|
|
|
};
|
|
|
|
|
|
|
|
class unrecognized_attr : public error {
|
|
|
|
public:
|
|
|
|
explicit unrecognized_attr(char attr) : error("Unrecognized attribute '" + string{attr} + "'") {}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Thrown when we expect the end of a tag (either } or a space in a compound
|
|
|
|
* tag.
|
|
|
|
*/
|
|
|
|
class tag_end_error : public error {
|
|
|
|
public:
|
|
|
|
explicit tag_end_error(char token)
|
|
|
|
: error("Expected the end of a tag ('}' or ' ') but found '" +
|
|
|
|
(token == EOL ? "<End Of Line>" : string{token}) + "'") {}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Recursive-descent parser for polybar's formatting tags.
|
|
|
|
*
|
|
|
|
* An input string is parsed into a list of elements, each element is either
|
|
|
|
* a piece of text or a single formatting tag.
|
|
|
|
*
|
|
|
|
* The elements can either be retrieved one-by-one with next_element() or all
|
|
|
|
* at once with parse().
|
|
|
|
*/
|
|
|
|
class parser {
|
|
|
|
public:
|
|
|
|
/**
|
|
|
|
* Resets the parser state and sets the new string to parse
|
|
|
|
*/
|
|
|
|
void set(const string&& input);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Whether a call to next_element() suceeds.
|
|
|
|
*/
|
|
|
|
bool has_next_element();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Parses at least one element (if available) and returns the first parsed
|
|
|
|
* element.
|
|
|
|
*/
|
|
|
|
element next_element();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Parses the remaining string and returns all parsed elements.
|
|
|
|
*/
|
|
|
|
format_string parse();
|
|
|
|
|
|
|
|
protected:
|
|
|
|
void parse_step();
|
|
|
|
|
|
|
|
bool has_next() const;
|
|
|
|
char next();
|
|
|
|
char peek() const;
|
|
|
|
void revert();
|
|
|
|
|
|
|
|
void consume(char c);
|
|
|
|
void consume_space();
|
|
|
|
|
|
|
|
void parse_tag();
|
|
|
|
|
|
|
|
void parse_single_tag_content();
|
|
|
|
|
|
|
|
color_value parse_color();
|
|
|
|
int parse_fontindex();
|
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 parse_offset();
|
2020-12-17 19:37:28 +00:00
|
|
|
controltag parse_control();
|
|
|
|
std::pair<action_value, string> parse_action();
|
|
|
|
mousebtn parse_action_btn();
|
|
|
|
string parse_action_cmd();
|
|
|
|
attribute parse_attribute();
|
|
|
|
|
|
|
|
void push_char(char c);
|
|
|
|
void push_text(string&& text);
|
|
|
|
|
|
|
|
string get_tag_value();
|
|
|
|
|
|
|
|
private:
|
|
|
|
string input;
|
|
|
|
size_t pos = 0;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Buffers elements that have been parsed but not yet returned to the user.
|
|
|
|
*/
|
|
|
|
format_string buf{};
|
|
|
|
/**
|
|
|
|
* Index into buf so that we don't have to call vector.erase everytime.
|
|
|
|
*
|
|
|
|
* Only buf[buf_pos, buf.end()) contain valid elements
|
|
|
|
*/
|
|
|
|
size_t buf_pos;
|
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace tags
|
|
|
|
|
|
|
|
POLYBAR_NS_END
|