#include #include "components/builder.hpp" #include "drawtypes/label.hpp" #include "utils/math.hpp" #include "utils/string.hpp" POLYBAR_NS /** * Flush contents of the builder and return built string * * This will also close any unclosed tags */ string builder::flush() { if (m_tags[syntaxtag::B]) { background_close(); } if (m_tags[syntaxtag::F]) { color_close(); } if (m_tags[syntaxtag::T]) { font_close(); } if (m_tags[syntaxtag::o]) { overline_color_close(); } if (m_tags[syntaxtag::u]) { underline_color_close(); } if ((m_attributes >> static_cast(attribute::UNDERLINE)) & 1U) { underline_close(); } if ((m_attributes >> static_cast(attribute::OVERLINE)) & 1U) { overline_close(); } while (m_tags[syntaxtag::A]) { cmd_close(); } string output = m_output.data(); // reset values m_tags.clear(); m_colors.clear(); m_output.clear(); m_fontindex = 1; return string_util::replace_all(output, string{BUILDER_SPACE_TOKEN}, " "); } /** * Insert raw text string */ void builder::append(const string& text) { m_output += text; } /** * Insert text node * * This will also parse raw syntax tags */ void builder::node(string str, bool add_space) { string::size_type n, m; string s(move(str)); if ((n = s.size()) > 2 && s[0] == '"' && s[n - 1] == '"') { s = s.substr(1, n - 2); } while (true) { if (s.empty()) { break; } else if ((n = s.find("%{F-}")) == 0) { color_close(); s.erase(0, 5); } else if ((n = s.find("%{F#")) == 0 && (m = s.find('}')) != string::npos) { if (m - n - 4 == 2) { color_alpha(s.substr(n + 3, m - 3)); } else { color(s.substr(n + 3, m - 3)); } s.erase(n, m + 1); } else if ((n = s.find("%{B-}")) == 0) { background_close(); s.erase(0, 5); } else if ((n = s.find("%{B#")) == 0 && (m = s.find('}')) != string::npos) { background(s.substr(n + 3, m - 3)); s.erase(n, m + 1); } else if ((n = s.find("%{T-}")) == 0) { font_close(); s.erase(0, 5); } else if ((n = s.find("%{T")) == 0 && (m = s.find('}')) != string::npos) { font(atoi(s.substr(n + 3, m - 3).c_str())); s.erase(n, m + 1); } else if ((n = s.find("%{U-}")) == 0) { line_color_close(); s.erase(0, 5); } else if ((n = s.find("%{u-}")) == 0) { underline_color_close(); s.erase(0, 5); } else if ((n = s.find("%{o-}")) == 0) { overline_color_close(); s.erase(0, 5); } else if ((n = s.find("%{u#")) == 0 && (m = s.find('}')) != string::npos) { underline_color(s.substr(n + 3, m - 3)); s.erase(n, m + 1); } else if ((n = s.find("%{o#")) == 0 && (m = s.find('}')) != string::npos) { overline_color(s.substr(n + 3, m - 3)); s.erase(n, m + 1); } else if ((n = s.find("%{U#")) == 0 && (m = s.find('}')) != string::npos) { line_color(s.substr(n + 3, m - 3)); s.erase(n, m + 1); } else if ((n = s.find("%{+u}")) == 0) { underline(); s.erase(0, 5); } else if ((n = s.find("%{+o}")) == 0) { overline(); s.erase(0, 5); } else if ((n = s.find("%{-u}")) == 0) { underline_close(); s.erase(0, 5); } else if ((n = s.find("%{-o}")) == 0) { overline_close(); s.erase(0, 5); } else if ((n = s.find("%{")) == 0 && (m = s.find('}')) != string::npos) { append(s.substr(n, m + 1)); s.erase(n, m + 1); } else if ((n = s.find("%{")) > 0) { append(s.substr(0, n)); s.erase(0, n); } else { break; } } if (!s.empty()) { append(s); } if (add_space) { space(); } } /** * Insert text node with specific font index * * @see builder::node */ void builder::node(string str, int font_index, bool add_space) { font(font_index); node(move(str), add_space); font_close(); } /** * Insert tags for given label */ void builder::node(const label_t& label, bool add_space) { if (!label || !*label) { return; } string text{label->get()}; if (label->m_maxlen > 0 && text.length() > label->m_maxlen) { text = text.substr(0, label->m_maxlen) + "..."; } // if ((label->m_overline.empty() && m_tags[syntaxtag::o] > 0) || (m_tags[syntaxtag::o] > 0 && label->m_margin > 0)) // overline_close(); // if ((label->m_underline.empty() && m_tags[syntaxtag::u] > 0) || (m_tags[syntaxtag::u] > 0 && label->m_margin > 0)) // underline_close(); if (label->m_margin.left > 0) { space(label->m_margin.left); } if (!label->m_overline.empty()) { overline(label->m_overline); } if (!label->m_underline.empty()) { underline(label->m_underline); } if (!label->m_background.empty()) { background(label->m_background); } if (!label->m_foreground.empty()) { color(label->m_foreground); } if (label->m_padding.left > 0) { space(label->m_padding.left); } node(text, label->m_font, add_space); if (label->m_padding.right > 0) { space(label->m_padding.right); } if (!label->m_background.empty()) { background_close(); } if (!label->m_foreground.empty()) { color_close(); } if (!label->m_underline.empty() || (label->m_margin.right > 0 && m_tags[syntaxtag::u] > 0)) { underline_close(); } if (!label->m_overline.empty() || (label->m_margin.right > 0 && m_tags[syntaxtag::o] > 0)) { overline_close(); } if (label->m_margin.right > 0) { space(label->m_margin.right); } } /** * Repeat text string n times */ void builder::node_repeat(const string& str, size_t n, bool add_space) { string text; while (n--) { text += str; } node(text, add_space); } /** * Repeat label contents n times */ void builder::node_repeat(const label_t& label, size_t n, bool add_space) { string text; while (n--) { text += label->get(); } label_t tmp{new label_t::element_type{text}}; tmp->replace_defined_values(label); node(tmp, add_space); } /** * Insert tag that will offset the contents by given pixels */ void builder::offset(int pixels) { if (pixels == 0) { return; } tag_open(syntaxtag::O, to_string(pixels)); } /** * Insert spaces */ void builder::space(int width) { if (width == DEFAULT_SPACING) { width = m_bar.spacing; } if (width <= 0) { return; } string str(width, ' '); append(str); } /** * Remove trailing space */ void builder::remove_trailing_space(int width) { if (width == DEFAULT_SPACING) { width = m_bar.spacing; } if (width <= 0) { return; } string::size_type spacing = width; string str(spacing, ' '); if (m_output.length() >= spacing && m_output.substr(m_output.length() - spacing) == str) { m_output = m_output.substr(0, m_output.length() - spacing); } } /** * Insert tag to alter the current font index */ void builder::font(int index) { if (index == 0) { return; } m_fontindex = index; tag_open(syntaxtag::T, to_string(index)); } /** * Insert tag to reset the font index */ void builder::font_close() { m_fontindex = 1; tag_close(syntaxtag::T); } /** * Insert tag to alter the current background color */ void builder::background(string color) { if (color.length() == 2 || (color.find('#') == 0 && color.length() == 3)) { string bg{background_hex()}; color = "#" + color.substr(color.length() - 2); color += bg.substr(bg.length() - (bg.length() < 6 ? 3 : 6)); } else if (color.length() >= 7 && color == "#" + string(color.length() - 1, color[1])) { color = color.substr(0, 4); } color = color_util::simplify_hex(color); m_colors[syntaxtag::B] = color; tag_open(syntaxtag::B, color); } /** * Insert tag to reset the background color */ void builder::background_close() { m_colors[syntaxtag::B] = ""; tag_close(syntaxtag::B); } /** * Insert tag to alter the current foreground color */ void builder::color(string color) { if (color.length() == 2 || (color.find('#') == 0 && color.length() == 3)) { string fg{foreground_hex()}; color = "#" + color.substr(color.length() - 2); color += fg.substr(fg.length() - (fg.length() < 6 ? 3 : 6)); } else if (color.length() >= 7 && color == "#" + string(color.length() - 1, color[1])) { color = color.substr(0, 4); } color = color_util::simplify_hex(color); m_colors[syntaxtag::F] = color; tag_open(syntaxtag::F, color); } /** * Insert tag to alter the alpha value of the default foreground color */ void builder::color_alpha(string alpha) { string val{foreground_hex()}; if (alpha.find('#') == string::npos) { alpha = "#" + alpha; } if (alpha.size() == 4) { color(alpha); return; } if (val.size() < 6 && val.size() > 2) { val.append(val.substr(val.size() - 3)); } color((alpha.substr(0, 3) + val.substr(val.size() - 6)).substr(0, 9)); } /** * Insert tag to reset the foreground color */ void builder::color_close() { m_colors[syntaxtag::F] = ""; tag_close(syntaxtag::F); } /** * Insert tag to alter the current overline/underline color */ void builder::line_color(const string& color) { overline_color(color); underline_color(color); } /** * Close overline/underline color tag */ void builder::line_color_close() { overline_color_close(); underline_color_close(); } /** * Insert tag to alter the current overline color */ void builder::overline_color(string color) { color = color_util::simplify_hex(color); m_colors[syntaxtag::o] = color; tag_open(syntaxtag::o, color); tag_open(attribute::OVERLINE); } /** * Close underline color tag */ void builder::overline_color_close() { m_colors[syntaxtag::o] = ""; tag_close(syntaxtag::o); } /** * Insert tag to alter the current underline color */ void builder::underline_color(string color) { color = color_util::simplify_hex(color); m_colors[syntaxtag::u] = color; tag_open(syntaxtag::u, color); tag_open(attribute::UNDERLINE); } /** * Close underline color tag */ void builder::underline_color_close() { tag_close(syntaxtag::u); m_colors[syntaxtag::u] = ""; } /** * Insert tag to enable the overline attribute */ void builder::overline(const string& color) { if (!color.empty()) { overline_color(color); } else { tag_open(attribute::OVERLINE); } } /** * Close overline attribute tag */ void builder::overline_close() { tag_close(attribute::OVERLINE); } /** * Insert tag to enable the underline attribute */ void builder::underline(const string& color) { if (!color.empty()) { underline_color(color); } else { tag_open(attribute::UNDERLINE); } } /** * Close underline attribute tag */ void builder::underline_close() { tag_close(attribute::UNDERLINE); } /** * Open command tag */ void builder::cmd(mousebtn index, string action, bool condition) { int button = static_cast(index); if (!condition || action.empty()) { return; } action = string_util::replace_all(action, ":", "\\:"); tag_open(syntaxtag::A, to_string(button) + ":" + action + ":"); } /** * Close command tag */ void builder::cmd_close(bool condition) { if (condition) { tag_close(syntaxtag::A); } } /** * Get default background hex string */ string builder::background_hex() { if (m_background.empty()) { m_background = color_util::hex(m_bar.background); } return m_background; } /** * Get default foreground hex string */ string builder::foreground_hex() { if (m_foreground.empty()) { m_foreground = color_util::hex(m_bar.foreground); } return m_foreground; } /** * Insert directive to change value of given tag */ void builder::tag_open(syntaxtag tag, const string& value) { if (m_tags.find(tag) == m_tags.end()) { m_tags[tag] = 0; } m_tags[tag]++; switch (tag) { case syntaxtag::NONE: break; case syntaxtag::A: append("%{A" + value + "}"); break; case syntaxtag::F: append("%{F" + value + "}"); break; case syntaxtag::B: append("%{B" + value + "}"); break; case syntaxtag::T: append("%{T" + value + "}"); break; case syntaxtag::u: append("%{u" + value + "}"); break; case syntaxtag::o: append("%{o" + value + "}"); break; case syntaxtag::R: append("%{R}"); break; case syntaxtag::O: append("%{O" + value + "}"); break; } } /** * Insert directive to use given attribute unless already set */ void builder::tag_open(attribute attr) { if ((m_attributes >> static_cast(attr)) & 1U) { return; } m_attributes |= 1U << static_cast(attr); switch (attr) { case attribute::NONE: break; case attribute::UNDERLINE: append("%{+u}"); break; case attribute::OVERLINE: append("%{+o}"); break; } } /** * Insert directive to reset given tag if it's open and closable */ void builder::tag_close(syntaxtag tag) { if (m_tags.find(tag) == m_tags.end() || !m_tags[tag]) { return; } m_tags[tag]--; switch (tag) { case syntaxtag::NONE: break; case syntaxtag::A: append("%{A}"); break; case syntaxtag::F: append("%{F-}"); break; case syntaxtag::B: append("%{B-}"); break; case syntaxtag::T: append("%{T-}"); break; case syntaxtag::u: append("%{u-}"); break; case syntaxtag::o: append("%{o-}"); break; case syntaxtag::R: break; case syntaxtag::O: break; } } /** * Insert directive to remove given attribute if set */ void builder::tag_close(attribute attr) { if (!((m_attributes >> static_cast(attr)) & 1U)) { return; } m_attributes &= ~(1U << static_cast(attr)); switch (attr) { case attribute::NONE: break; case attribute::UNDERLINE: append("%{-u}"); break; case attribute::OVERLINE: append("%{-o}"); break; } } POLYBAR_NS_END