Reset all tags at the end of a module

The %{PR} tag is introduced for this. It resets all colors as well as
the activation of the underline and overline and font.

This has become necessary because we don't track what raw tags a user
injects into the formatting string and otherwise their raw tags could
bleed through.

This doesn't touch action tags because even before raw action tags
weren't being tracked. Action tags also have the requirement that they
have to be used in pairs, so closing them prematurely could break things
(for example with click actions for the entire bar)
This commit is contained in:
patrick96 2019-01-12 14:51:54 +01:00 committed by Patrick Ziegler
parent 928cd92a4f
commit 57d364a2fc
10 changed files with 105 additions and 9 deletions

View File

@ -20,6 +20,7 @@ class builder {
public:
explicit builder(const bar_settings& bar);
void reset();
string flush();
void append(string text);
void node(string str, bool add_space = false);
@ -49,6 +50,7 @@ class builder {
void overline_close();
void underline(const string& color = "");
void underline_close();
void control(controltag tag);
void cmd(mousebtn index, string action, bool condition = true);
void cmd(mousebtn index, string action, const label_t& label);
void cmd_close(bool condition = true);

View File

@ -7,6 +7,7 @@ POLYBAR_NS
class signal_emitter;
enum class attribute;
enum class controltag;
enum class mousebtn;
struct bar_settings;
@ -33,6 +34,7 @@ class parser {
attribute parse_attr(const char attr);
mousebtn parse_action_btn(const string& data);
string parse_action_cmd(string&& data);
controltag parse_control(const string& data);
private:
signal_emitter& m_sig;

View File

@ -36,7 +36,7 @@ class renderer
signals::parser::change_font, signals::parser::change_alignment, signals::parser::reverse_colors,
signals::parser::offset_pixel, signals::parser::attribute_set, signals::parser::attribute_unset,
signals::parser::attribute_toggle, signals::parser::action_begin, signals::parser::action_end,
signals::parser::text> {
signals::parser::text, signals::parser::control> {
public:
using make_type = unique_ptr<renderer>;
static make_type make(const bar_settings& bar);
@ -85,6 +85,7 @@ class renderer
bool on(const signals::parser::action_begin& evt);
bool on(const signals::parser::action_end& evt);
bool on(const signals::parser::text& evt);
bool on(const signals::parser::control& evt);
protected:
struct reserve_area {

View File

@ -37,6 +37,18 @@ enum class syntaxtag {
R, // flip colors
o, // overline color
u, // underline color
P, // Polybar control tag
};
/**
* Values for polybar control tags
*
* %{P...} tags are tags for internal polybar control commands, they are not
* part of the public interface
*/
enum class controltag {
NONE = 0,
R, // Reset all open tags (B, F, T, o, u). Used at module edges
};
enum class mousebtn { NONE = 0, LEFT, MIDDLE, RIGHT, SCROLL_UP, SCROLL_DOWN, DOUBLE_LEFT, DOUBLE_MIDDLE, DOUBLE_RIGHT };

View File

@ -12,6 +12,7 @@ POLYBAR_NS
// fwd
enum class mousebtn;
enum class syntaxtag;
enum class controltag;
enum class alignment;
enum class attribute;
@ -179,6 +180,9 @@ namespace signals {
struct text : public detail::value_signal<text, string> {
using base_type::base_type;
};
struct control : public detail::value_signal<control, controltag> {
using base_type::base_type;
};
}
}

View File

@ -59,6 +59,7 @@ namespace signals {
struct action_begin;
struct action_end;
struct text;
struct control;
}
}

View File

@ -80,6 +80,11 @@ namespace modules {
if (m_changed) {
m_log.info("%s: Rebuilding cache", name());
m_cache = CAST_MOD(Impl)->get_output();
// Make sure builder is really empty
m_builder->flush();
// Add a reset tag after the module
m_builder->control(controltag::R);
m_cache += m_builder->flush();
m_changed = false;
}
return m_cache;

View File

@ -9,25 +9,37 @@
POLYBAR_NS
builder::builder(const bar_settings& bar) : m_bar(bar) {
reset();
}
void builder::reset() {
/* Add all values as keys so that we never have to check if a key exists in
* the map
*/
m_tags.clear();
m_tags[syntaxtag::NONE] = 0;
m_tags[syntaxtag::A] = 0;
m_tags[syntaxtag::B] = 0;
m_tags[syntaxtag::F] = 0;
m_tags[syntaxtag::T] = 0;
m_tags[syntaxtag::R] = 0;
m_tags[syntaxtag::o] = 0;
m_tags[syntaxtag::u] = 0;
m_tags[syntaxtag::P] = 0;
m_colors.clear();
m_colors[syntaxtag::B] = string();
m_colors[syntaxtag::F] = string();
m_colors[syntaxtag::o] = string();
m_colors[syntaxtag::u] = string();
m_attrs.clear();
m_attrs[attribute::NONE] = false;
m_attrs[attribute::UNDERLINE] = false;
m_attrs[attribute::OVERLINE] = false;
m_output.clear();
m_fontindex = 1;
}
/**
@ -64,11 +76,7 @@ string builder::flush() {
string output{m_output};
// reset values
m_tags.clear();
m_colors.clear();
m_output.clear();
m_fontindex = 1;
reset();
return output;
}
@ -404,6 +412,24 @@ void builder::underline_close() {
tag_close(attribute::UNDERLINE);
}
/**
* Add a polybar control tag
*/
void builder::control(controltag tag) {
string str;
switch (tag) {
case controltag::R:
str = "R";
break;
default:
break;
}
if(!str.empty()) {
tag_open(syntaxtag::P, str);
}
}
/**
* Open command tag
*/
@ -504,6 +530,9 @@ void builder::tag_open(syntaxtag tag, const string& value) {
case syntaxtag::O:
append("%{O" + value + "}");
break;
case syntaxtag::P:
append("%{P" + value + "}");
break;
}
}
@ -540,8 +569,6 @@ void builder::tag_close(syntaxtag tag) {
m_tags[tag]--;
switch (tag) {
case syntaxtag::NONE:
break;
case syntaxtag::A:
append("%{A}");
break;
@ -560,8 +587,9 @@ void builder::tag_close(syntaxtag tag) {
case syntaxtag::o:
append("%{o-}");
break;
case syntaxtag::NONE:
case syntaxtag::R:
break;
case syntaxtag::P:
case syntaxtag::O:
break;
}

View File

@ -187,6 +187,11 @@ void parser::codeblock(string&& data, const bar_settings& bar) {
break;
}
// Internal Polybar control tags
case 'P':
m_sig.emit(control{parse_control(value)});
break;
default:
throw unrecognized_token("Unrecognized token '" + string{tag} + "'");
}
@ -292,4 +297,19 @@ string parser::parse_action_cmd(string&& data) {
return data.substr(1, end - 1);
}
controltag parser::parse_control(const string& data) {
if(data.length() != 1) {
return controltag::NONE;
}
switch(data[0]) {
case 'R':
return controltag::R;
break;
default:
return controltag::NONE;
break;
}
}
POLYBAR_NS_END

View File

@ -2,6 +2,7 @@
#include "cairo/context.hpp"
#include "components/config.hpp"
#include "events/signal.hpp"
#include "events/signal_emitter.hpp"
#include "events/signal_receiver.hpp"
#include "utils/factory.hpp"
#include "utils/file.hpp"
@ -827,4 +828,24 @@ bool renderer::on(const signals::parser::text& evt) {
return true;
}
bool renderer::on(const signals::parser::control& evt) {
auto ctrl = evt.cast();
switch(ctrl) {
case controltag::R:
m_bg = m_bar.background;
m_fg = m_bar.foreground;
m_ul = m_bar.underline.color;
m_ol = m_bar.overline.color;
m_font = 0;
m_attr.reset();
break;
case controltag::NONE:
break;
}
return true;
}
POLYBAR_NS_END