2016-11-24 18:24:47 +00:00
|
|
|
#include <cassert>
|
|
|
|
|
2016-11-02 19:22:45 +00:00
|
|
|
#include "components/parser.hpp"
|
2016-11-21 14:07:00 +00:00
|
|
|
#include "components/types.hpp"
|
2016-12-05 19:41:00 +00:00
|
|
|
#include "events/signal.hpp"
|
|
|
|
#include "events/signal_emitter.hpp"
|
2017-01-13 19:03:08 +00:00
|
|
|
#include "settings.hpp"
|
2016-12-26 08:40:15 +00:00
|
|
|
#include "utils/color.hpp"
|
2017-01-11 02:07:28 +00:00
|
|
|
#include "utils/factory.hpp"
|
|
|
|
#include "utils/file.hpp"
|
2016-11-02 19:22:45 +00:00
|
|
|
#include "utils/math.hpp"
|
2016-12-15 16:14:56 +00:00
|
|
|
#include "utils/memory.hpp"
|
2016-11-02 19:22:45 +00:00
|
|
|
#include "utils/string.hpp"
|
|
|
|
|
2016-11-19 05:22:44 +00:00
|
|
|
POLYBAR_NS
|
2016-11-02 19:22:45 +00:00
|
|
|
|
2016-12-05 19:41:00 +00:00
|
|
|
using namespace signals::parser;
|
|
|
|
|
2016-12-20 04:05:43 +00:00
|
|
|
/**
|
|
|
|
* Create instance
|
|
|
|
*/
|
|
|
|
parser::make_type parser::make() {
|
|
|
|
return factory_util::unique<parser>(signal_emitter::make());
|
|
|
|
}
|
|
|
|
|
2016-11-24 18:24:47 +00:00
|
|
|
/**
|
|
|
|
* Construct parser instance
|
|
|
|
*/
|
2016-12-20 04:05:43 +00:00
|
|
|
parser::parser(signal_emitter& emitter) : m_sig(emitter) {}
|
2016-11-21 14:07:00 +00:00
|
|
|
|
2016-11-02 19:22:45 +00:00
|
|
|
/**
|
2016-11-24 18:24:47 +00:00
|
|
|
* Process input string
|
2016-11-02 19:22:45 +00:00
|
|
|
*/
|
2016-12-20 04:05:43 +00:00
|
|
|
void parser::parse(const bar_settings& bar, string data) {
|
2016-12-14 04:17:18 +00:00
|
|
|
while (!data.empty()) {
|
|
|
|
size_t pos{string::npos};
|
2016-11-24 18:24:47 +00:00
|
|
|
|
2016-11-25 12:55:15 +00:00
|
|
|
if (data.compare(0, 2, "%{") == 0 && (pos = data.find('}')) != string::npos) {
|
2016-12-20 04:05:43 +00:00
|
|
|
codeblock(data.substr(2, pos - 2), bar);
|
2016-11-02 19:22:45 +00:00
|
|
|
data.erase(0, pos + 1);
|
2016-12-14 04:17:18 +00:00
|
|
|
} else if ((pos = data.find("%{")) != string::npos) {
|
2016-11-02 19:22:45 +00:00
|
|
|
data.erase(0, text(data.substr(0, pos)));
|
2016-12-14 04:17:18 +00:00
|
|
|
} else {
|
2016-12-15 16:14:56 +00:00
|
|
|
data.erase(0, text(data.substr(0)));
|
2016-11-02 19:22:45 +00:00
|
|
|
}
|
|
|
|
}
|
2016-11-25 03:10:26 +00:00
|
|
|
|
2017-04-26 16:52:45 +00:00
|
|
|
m_fg = std::stack<unsigned int>();
|
|
|
|
m_bg = std::stack<unsigned int>();
|
|
|
|
m_ul = std::stack<unsigned int>();
|
|
|
|
m_ol = std::stack<unsigned int>();
|
2017-04-26 17:25:42 +00:00
|
|
|
m_fonts = std::stack<int>();
|
2017-04-26 16:52:45 +00:00
|
|
|
|
2016-11-25 03:10:26 +00:00
|
|
|
if (!m_actions.empty()) {
|
|
|
|
throw unclosed_actionblocks(to_string(m_actions.size()) + " unclosed action block(s)");
|
|
|
|
}
|
2016-11-02 19:22:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2016-11-24 18:24:47 +00:00
|
|
|
* Process contents within tag blocks, i.e: %{...}
|
2016-11-02 19:22:45 +00:00
|
|
|
*/
|
2016-12-20 04:05:43 +00:00
|
|
|
void parser::codeblock(string&& data, const bar_settings& bar) {
|
2016-11-02 19:22:45 +00:00
|
|
|
size_t pos;
|
|
|
|
|
|
|
|
while (data.length()) {
|
2016-12-14 05:51:07 +00:00
|
|
|
data = string_util::ltrim(move(data), ' ');
|
2016-11-02 19:22:45 +00:00
|
|
|
|
2016-11-25 12:55:15 +00:00
|
|
|
if (data.empty()) {
|
2016-11-02 19:22:45 +00:00
|
|
|
break;
|
2016-11-25 12:55:15 +00:00
|
|
|
}
|
2016-11-02 19:22:45 +00:00
|
|
|
|
2016-11-24 18:24:47 +00:00
|
|
|
char tag{data[0]};
|
2016-11-02 19:22:45 +00:00
|
|
|
string value;
|
|
|
|
|
|
|
|
// Remove the tag
|
|
|
|
data.erase(0, 1);
|
|
|
|
|
2016-11-25 12:55:15 +00:00
|
|
|
if ((pos = data.find_first_of(" }")) != string::npos) {
|
2016-11-02 19:22:45 +00:00
|
|
|
value = data.substr(0, pos);
|
2016-11-25 12:55:15 +00:00
|
|
|
} else {
|
2016-11-02 19:22:45 +00:00
|
|
|
value = data;
|
2016-11-25 12:55:15 +00:00
|
|
|
}
|
2016-11-02 19:22:45 +00:00
|
|
|
|
|
|
|
switch (tag) {
|
2017-04-25 18:26:48 +00:00
|
|
|
case 'B': {
|
2017-05-17 21:11:06 +00:00
|
|
|
m_sig.emit(change_background{parse_color(m_bg, value, bar.background)});
|
2016-11-02 19:22:45 +00:00
|
|
|
break;
|
2017-04-25 18:26:48 +00:00
|
|
|
}
|
2016-11-02 19:22:45 +00:00
|
|
|
|
2017-04-25 18:26:48 +00:00
|
|
|
case 'F': {
|
2017-04-26 17:25:02 +00:00
|
|
|
m_sig.emit(change_foreground{parse_color(m_fg, value, bar.foreground)});
|
2016-11-24 18:24:47 +00:00
|
|
|
break;
|
2017-04-25 18:26:48 +00:00
|
|
|
}
|
2016-11-24 18:24:47 +00:00
|
|
|
|
|
|
|
case 'T':
|
2016-12-05 19:41:00 +00:00
|
|
|
m_sig.emit(change_font{parse_fontindex(value)});
|
2016-11-02 19:22:45 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 'U':
|
2017-04-26 17:25:02 +00:00
|
|
|
m_sig.emit(change_underline{parse_color(m_ul, value, bar.underline.color)});
|
|
|
|
m_sig.emit(change_overline{parse_color(m_ol, value, bar.overline.color)});
|
2016-11-02 19:22:45 +00:00
|
|
|
break;
|
|
|
|
|
2016-11-24 18:24:47 +00:00
|
|
|
case 'u':
|
2017-04-26 17:25:02 +00:00
|
|
|
m_sig.emit(change_underline{parse_color(m_ul, value, bar.underline.color)});
|
2016-11-02 19:22:45 +00:00
|
|
|
break;
|
|
|
|
|
2016-11-24 18:24:47 +00:00
|
|
|
case 'o':
|
2017-04-26 17:25:02 +00:00
|
|
|
m_sig.emit(change_overline{parse_color(m_ol, value, bar.overline.color)});
|
2016-11-24 18:24:47 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 'R':
|
2017-05-17 21:11:06 +00:00
|
|
|
m_sig.emit(reverse_colors{});
|
2016-11-02 19:22:45 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 'O':
|
2017-01-19 10:11:28 +00:00
|
|
|
m_sig.emit(offset_pixel{static_cast<int>(std::atoi(value.c_str()))});
|
2016-11-02 19:22:45 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 'l':
|
2016-12-05 19:41:00 +00:00
|
|
|
m_sig.emit(change_alignment{alignment::LEFT});
|
2016-11-02 19:22:45 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 'c':
|
2016-12-05 19:41:00 +00:00
|
|
|
m_sig.emit(change_alignment{alignment::CENTER});
|
2016-11-02 19:22:45 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 'r':
|
2016-12-05 19:41:00 +00:00
|
|
|
m_sig.emit(change_alignment{alignment::RIGHT});
|
2016-11-02 19:22:45 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case '+':
|
2016-12-05 19:41:00 +00:00
|
|
|
m_sig.emit(attribute_set{parse_attr(value[0])});
|
2016-11-02 19:22:45 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case '-':
|
2016-12-05 19:41:00 +00:00
|
|
|
m_sig.emit(attribute_unset{parse_attr(value[0])});
|
2016-11-24 18:24:47 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case '!':
|
2016-12-05 19:41:00 +00:00
|
|
|
m_sig.emit(attribute_toggle{parse_attr(value[0])});
|
2016-11-02 19:22:45 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 'A':
|
|
|
|
if (isdigit(data[0]) || data[0] == ':') {
|
2016-12-14 04:17:18 +00:00
|
|
|
value = parse_action_cmd(data.substr(data[0] != ':' ? 1 : 0));
|
2016-11-02 19:22:45 +00:00
|
|
|
mousebtn btn = parse_action_btn(data);
|
|
|
|
m_actions.push_back(static_cast<int>(btn));
|
2016-12-05 19:41:00 +00:00
|
|
|
m_sig.emit(action_begin{action{btn, value}});
|
2016-11-02 19:22:45 +00:00
|
|
|
|
|
|
|
// make sure we strip the correct length (btn+wrapping colons)
|
2016-11-25 12:55:15 +00:00
|
|
|
if (value[0] != ':') {
|
2016-11-02 19:22:45 +00:00
|
|
|
value += "0";
|
2016-11-25 12:55:15 +00:00
|
|
|
}
|
2016-11-02 19:22:45 +00:00
|
|
|
value += "::";
|
|
|
|
} else if (!m_actions.empty()) {
|
2016-12-05 19:41:00 +00:00
|
|
|
m_sig.emit(action_end{parse_action_btn(value)});
|
2016-11-02 19:22:45 +00:00
|
|
|
m_actions.pop_back();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2016-11-25 03:10:26 +00:00
|
|
|
throw unrecognized_token("Unrecognized token '" + string{tag} + "'");
|
2016-11-02 19:22:45 +00:00
|
|
|
}
|
|
|
|
|
2016-11-25 12:55:15 +00:00
|
|
|
if (!data.empty()) {
|
2016-11-02 19:22:45 +00:00
|
|
|
data.erase(0, !value.empty() ? value.length() : 1);
|
2016-11-25 12:55:15 +00:00
|
|
|
}
|
2016-11-02 19:22:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2016-11-24 18:24:47 +00:00
|
|
|
* Process text contents
|
2016-11-02 19:22:45 +00:00
|
|
|
*/
|
2016-12-14 04:17:18 +00:00
|
|
|
size_t parser::text(string&& data) {
|
2017-01-13 10:04:43 +00:00
|
|
|
#ifdef DEBUG_WHITESPACE
|
|
|
|
string::size_type p;
|
|
|
|
while ((p = data.find(' ')) != string::npos) {
|
|
|
|
data.replace(p, 1, "-"s);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2017-01-19 04:38:42 +00:00
|
|
|
m_sig.emit(signals::parser::text{forward<string>(data)});
|
|
|
|
return data.size();
|
2016-11-02 19:22:45 +00:00
|
|
|
}
|
|
|
|
|
2017-04-25 18:26:48 +00:00
|
|
|
/**
|
|
|
|
* Determine color using passed stack and input value
|
|
|
|
*/
|
2017-04-26 17:25:02 +00:00
|
|
|
unsigned int parser::parse_color(std::stack<unsigned int>& color_stack, string& value, unsigned int fallback) {
|
2017-04-25 18:26:48 +00:00
|
|
|
if (!color_stack.empty() && !value.empty() && value[0] == '-') {
|
|
|
|
color_stack.pop();
|
|
|
|
}
|
2017-04-26 17:25:02 +00:00
|
|
|
auto parsed_value = parse_color_string(value, !color_stack.empty() ? color_stack.top() : fallback);
|
2017-05-17 21:11:59 +00:00
|
|
|
if (!value.empty() && value[0] != '-' && (color_stack.empty() || (parsed_value != color_stack.top()))) {
|
2017-04-25 18:26:48 +00:00
|
|
|
color_stack.push(parsed_value);
|
|
|
|
}
|
|
|
|
return parsed_value;
|
|
|
|
}
|
|
|
|
|
2016-11-02 19:22:45 +00:00
|
|
|
/**
|
2016-11-24 18:24:47 +00:00
|
|
|
* Process color hex string and convert it to the correct value
|
2016-11-02 19:22:45 +00:00
|
|
|
*/
|
2017-04-26 17:25:02 +00:00
|
|
|
unsigned int parser::parse_color_string(const string& s, unsigned int fallback) {
|
2017-01-27 12:46:27 +00:00
|
|
|
if (!s.empty() && s[0] != '-') {
|
|
|
|
return color_util::parse(s, fallback);
|
2016-11-25 12:55:15 +00:00
|
|
|
}
|
2017-01-27 12:46:27 +00:00
|
|
|
return fallback;
|
2016-11-02 19:22:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2016-11-24 18:24:47 +00:00
|
|
|
* Process font index and convert it to the correct value
|
2016-11-02 19:22:45 +00:00
|
|
|
*/
|
2017-04-26 17:25:42 +00:00
|
|
|
int parser::parse_fontindex(const string& value) {
|
|
|
|
auto font_index = 0;
|
|
|
|
auto reset = value.empty() || value[0] == '-';
|
|
|
|
|
|
|
|
if (reset && !m_fonts.empty()) {
|
|
|
|
m_fonts.pop();
|
|
|
|
} else if (!reset) {
|
|
|
|
try {
|
|
|
|
font_index = std::stoul(value, nullptr, 10);
|
|
|
|
m_fonts.push(font_index);
|
|
|
|
return font_index;
|
|
|
|
} catch (const std::invalid_argument& err) {
|
|
|
|
return font_index;
|
|
|
|
}
|
2016-11-21 14:07:00 +00:00
|
|
|
}
|
|
|
|
|
2017-04-26 17:25:42 +00:00
|
|
|
if (!m_fonts.empty()) {
|
|
|
|
return m_fonts.top();
|
|
|
|
} else {
|
|
|
|
return font_index;
|
2016-11-21 14:07:00 +00:00
|
|
|
}
|
2016-11-02 19:22:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2016-11-24 18:24:47 +00:00
|
|
|
* Process attribute token and convert it to the correct value
|
2016-11-02 19:22:45 +00:00
|
|
|
*/
|
2016-11-24 18:24:47 +00:00
|
|
|
attribute parser::parse_attr(const char attr) {
|
|
|
|
switch (attr) {
|
2016-11-02 19:22:45 +00:00
|
|
|
case 'o':
|
2016-11-24 18:24:47 +00:00
|
|
|
return attribute::OVERLINE;
|
2016-11-02 19:22:45 +00:00
|
|
|
case 'u':
|
2016-11-24 18:24:47 +00:00
|
|
|
return attribute::UNDERLINE;
|
|
|
|
default:
|
2016-11-25 03:10:26 +00:00
|
|
|
throw unrecognized_token("Unrecognized attribute '" + string{attr} + "'");
|
2016-11-02 19:22:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2016-11-24 18:24:47 +00:00
|
|
|
* Process action button token and convert it to the correct value
|
2016-11-02 19:22:45 +00:00
|
|
|
*/
|
2016-12-14 04:17:18 +00:00
|
|
|
mousebtn parser::parse_action_btn(const string& data) {
|
2016-11-25 12:55:15 +00:00
|
|
|
if (data[0] == ':') {
|
2016-11-02 19:22:45 +00:00
|
|
|
return mousebtn::LEFT;
|
2016-11-25 12:55:15 +00:00
|
|
|
} else if (isdigit(data[0])) {
|
2016-11-02 19:22:45 +00:00
|
|
|
return static_cast<mousebtn>(data[0] - '0');
|
2016-11-25 12:55:15 +00:00
|
|
|
} else if (!m_actions.empty()) {
|
2016-11-02 19:22:45 +00:00
|
|
|
return static_cast<mousebtn>(m_actions.back());
|
2016-11-25 12:55:15 +00:00
|
|
|
} else {
|
2016-11-02 19:22:45 +00:00
|
|
|
return mousebtn::NONE;
|
2016-11-25 12:55:15 +00:00
|
|
|
}
|
2016-11-02 19:22:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2016-11-24 18:24:47 +00:00
|
|
|
* Process action command string
|
2016-11-02 19:22:45 +00:00
|
|
|
*/
|
2016-12-14 04:17:18 +00:00
|
|
|
string parser::parse_action_cmd(string&& data) {
|
|
|
|
if (data[0] != ':') {
|
2016-11-21 14:07:00 +00:00
|
|
|
return "";
|
2016-11-25 12:55:15 +00:00
|
|
|
}
|
2016-12-14 04:17:18 +00:00
|
|
|
|
|
|
|
size_t end{1};
|
2016-12-01 13:30:46 +00:00
|
|
|
while ((end = data.find(':', end)) != string::npos && data[end - 1] == '\\') {
|
|
|
|
end++;
|
|
|
|
}
|
2016-12-14 04:17:18 +00:00
|
|
|
|
2016-12-01 13:30:46 +00:00
|
|
|
if (end == string::npos) {
|
2016-11-21 14:07:00 +00:00
|
|
|
return "";
|
2016-11-25 12:55:15 +00:00
|
|
|
}
|
2016-12-14 04:17:18 +00:00
|
|
|
|
|
|
|
return data.substr(1, end - 1);
|
2016-11-02 19:22:45 +00:00
|
|
|
}
|
|
|
|
|
2016-11-19 05:22:44 +00:00
|
|
|
POLYBAR_NS_END
|