diff options
Diffstat (limited to 'gdb/ui-style.c')
-rw-r--r-- | gdb/ui-style.c | 353 |
1 files changed, 273 insertions, 80 deletions
diff --git a/gdb/ui-style.c b/gdb/ui-style.c index 952102e..f0a8e81 100644 --- a/gdb/ui-style.c +++ b/gdb/ui-style.c @@ -17,6 +17,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "ui-style.h" +#include "gdb_curses.h" #include "gdbsupport/gdb_regex.h" /* A regular expression that is used for matching ANSI terminal escape @@ -46,119 +47,250 @@ static const char ansi_regex_text[] = static regex_t ansi_regex; -/* This maps bright colors to RGB triples. The index is the bright - color index, starting with bright black. The values come from - xterm. */ - -static const uint8_t bright_colors[][3] = { - { 127, 127, 127 }, /* Black. */ - { 255, 0, 0 }, /* Red. */ - { 0, 255, 0 }, /* Green. */ - { 255, 255, 0 }, /* Yellow. */ - { 92, 92, 255 }, /* Blue. */ - { 255, 0, 255 }, /* Magenta. */ - { 0, 255, 255 }, /* Cyan. */ - { 255, 255, 255 } /* White. */ +/* This maps 8-color palette to RGB triples. The values come from + plain linux terminal. */ + +static const uint8_t palette_8colors[][3] = { + { 1, 1, 1 }, /* Black. */ + { 222, 56, 43 }, /* Red. */ + { 57, 181, 74 }, /* Green. */ + { 255, 199, 6 }, /* Yellow. */ + { 0, 111, 184 }, /* Blue. */ + { 118, 38, 113 }, /* Magenta. */ + { 44, 181, 233 }, /* Cyan. */ + { 204, 204, 204 }, /* White. */ +}; + +/* This maps 16-color palette to RGB triples. The values come from xterm. */ + +static const uint8_t palette_16colors[][3] = { + { 0, 0, 0 }, /* Black. */ + { 205, 0, 0 }, /* Red. */ + { 0, 205, 0 }, /* Green. */ + { 205, 205, 0 }, /* Yellow. */ + { 0, 0, 238 }, /* Blue. */ + { 205, 0, 205 }, /* Magenta. */ + { 0, 205, 205 }, /* Cyan. */ + { 229, 229, 229 }, /* White. */ + { 127, 127, 127 }, /* Bright Black. */ + { 255, 0, 0 }, /* Bright Red. */ + { 0, 255, 0 }, /* Bright Green. */ + { 255, 255, 0 }, /* Bright Yellow. */ + { 92, 92, 255 }, /* Bright Blue. */ + { 255, 0, 255 }, /* Bright Magenta. */ + { 0, 255, 255 }, /* Bright Cyan. */ + { 255, 255, 255 } /* Bright White. */ }; /* See ui-style.h. */ +/* Must correspond to ui_file_style::basic_color. */ +const std::vector<const char *> ui_file_style::basic_color_enums = { + "none", + "black", + "red", + "green", + "yellow", + "blue", + "magenta", + "cyan", + "white", + nullptr +}; -bool +/* Returns text representation of a basic COLOR. */ + +static const char * +basic_color_name (int color) +{ + int pos = color - ui_file_style::NONE; + if (0 <= pos && pos < ui_file_style::basic_color_enums.size ()) + if (const char *s = ui_file_style::basic_color_enums[pos]) + return s; + error (_("Basic color %d has no name."), color); +} + +/* See ui-style.h. */ + +void ui_file_style::color::append_ansi (bool is_fg, std::string *str) const { - if (m_simple) - { - if (m_value >= BLACK && m_value <= WHITE) - str->append (std::to_string (m_value + (is_fg ? 30 : 40))); - else if (m_value > WHITE && m_value <= WHITE + 8) - str->append (std::to_string (m_value - WHITE + (is_fg ? 90 : 100))); - else if (m_value != -1) - { - str->append (is_fg ? "38;5;" : "48;5;"); - str->append (std::to_string (m_value)); - } - else - return false; - } - else + if (m_color_space == color_space::MONOCHROME) + str->append (is_fg ? "39" : "49"); + else if (is_basic ()) + str->append (std::to_string (m_value + (is_fg ? 30 : 40))); + else if (m_color_space == color_space::AIXTERM_16COLOR) + str->append (std::to_string (m_value - WHITE - 1 + (is_fg ? 90 : 100))); + else if (m_color_space == color_space::XTERM_256COLOR) + str->append (is_fg ? "38;5;" : "48;5;").append (std::to_string (m_value)); + else if (m_color_space == color_space::RGB_24BIT) { + // See ISO/IEC 8613-6 (or ITU T.416) 13.1.8 Select Graphic Rendition (SGR) str->append (is_fg ? "38;2;" : "48;2;"); str->append (std::to_string (m_red) + ";" + std::to_string (m_green) + ";" + std::to_string (m_blue)); } - return true; + else + gdb_assert_not_reached ("no valid ansi representation of the color"); } /* See ui-style.h. */ +std::string +ui_file_style::color::to_ansi (bool is_fg) const +{ + std::string s = "\033["; + append_ansi (is_fg, &s); + s.push_back ('m'); + return s; +} -void -ui_file_style::color::get_rgb (uint8_t *rgb) const +/* See ui-style.h. */ + +std::string +ui_file_style::color::to_string () const { - if (m_simple) + if (m_color_space == color_space::RGB_24BIT) { - /* Can't call this for a basic color or NONE -- those will end - up in the assert below. */ - if (m_value >= 8 && m_value <= 15) - memcpy (rgb, bright_colors[m_value - 8], 3 * sizeof (uint8_t)); - else if (m_value >= 16 && m_value <= 231) - { - int value = m_value; - value -= 16; - /* This obscure formula seems to be what terminals actually - do. */ - int component = value / 36; - rgb[0] = component == 0 ? 0 : (55 + component * 40); - value %= 36; - component = value / 6; - rgb[1] = component == 0 ? 0 : (55 + component * 40); - value %= 6; - rgb[2] = value == 0 ? 0 : (55 + value * 40); - } - else if (m_value >= 232) - { - uint8_t v = (m_value - 232) * 10 + 8; - rgb[0] = v; - rgb[1] = v; - rgb[2] = v; - } - else - gdb_assert_not_reached ("get_rgb called on invalid color"); + char s[64]; + snprintf (s, sizeof s, "#%02X%02X%02X", m_red, m_green, m_blue); + return s; } + else if (is_none () || is_basic ()) + return basic_color_name (m_value); else + return std::to_string (get_value ()); +} + +/* See ui-style.h. */ + +void +ui_file_style::color::get_rgb (uint8_t *rgb) const +{ + if (m_color_space == color_space::RGB_24BIT) { rgb[0] = m_red; rgb[1] = m_green; rgb[2] = m_blue; } + else if (m_color_space == color_space::ANSI_8COLOR + && 0 <= m_value && m_value <= 7) + memcpy (rgb, palette_8colors[m_value], 3 * sizeof (uint8_t)); + else if (m_color_space == color_space::AIXTERM_16COLOR + && 0 <= m_value && m_value <= 15) + memcpy (rgb, palette_16colors[m_value], 3 * sizeof (uint8_t)); + else if (m_color_space != color_space::XTERM_256COLOR) + gdb_assert_not_reached ("get_rgb called on invalid color"); + else if (0 <= m_value && m_value <= 15) + memcpy (rgb, palette_16colors[m_value], 3 * sizeof (uint8_t)); + else if (m_value >= 16 && m_value <= 231) + { + int value = m_value; + value -= 16; + /* This obscure formula seems to be what terminals actually + do. */ + int component = value / 36; + rgb[0] = component == 0 ? 0 : (55 + component * 40); + value %= 36; + component = value / 6; + rgb[1] = component == 0 ? 0 : (55 + component * 40); + value %= 6; + rgb[2] = value == 0 ? 0 : (55 + value * 40); + } + else if (232 <= m_value && m_value <= 255) + { + uint8_t v = (m_value - 232) * 10 + 8; + rgb[0] = v; + rgb[1] = v; + rgb[2] = v; + } + else + gdb_assert_not_reached ("get_rgb called on invalid color"); } /* See ui-style.h. */ -std::string -ui_file_style::to_ansi () const +ui_file_style::color +ui_file_style::color::approximate (const std::vector<color_space> &spaces) const { - std::string result ("\033["); - bool need_semi = m_foreground.append_ansi (true, &result); - if (!m_background.is_none ()) + if (spaces.empty () || is_none ()) + return NONE; + + color_space target_space = color_space::MONOCHROME; + for (color_space sp : spaces) + if (sp == m_color_space) + return *this; + else if (sp > target_space) + target_space = sp; + + if (target_space == color_space::RGB_24BIT) { - if (need_semi) - result.push_back (';'); - m_background.append_ansi (false, &result); - need_semi = true; + uint8_t rgb[3]; + get_rgb (rgb); + return color (rgb[0], rgb[1], rgb[2]); + } + + int target_size = 0; + switch (target_space) + { + case color_space::ANSI_8COLOR: + target_size = 8; + break; + case color_space::AIXTERM_16COLOR: + target_size = 16; + break; + case color_space::XTERM_256COLOR: + target_size = 256; + break; } - if (m_intensity != NORMAL) + + if (is_simple() && m_value < target_size) + return color (target_space, m_value); + + color result = NONE; + int best_distance = std::numeric_limits<int>::max (); + uint8_t rgb[3]; + get_rgb (rgb); + + for (int i = 0; i < target_size; ++i) { - if (need_semi) - result.push_back (';'); - result.append (std::to_string (m_intensity)); - need_semi = true; + uint8_t c_rgb[3]; + color c (target_space, i); + c.get_rgb (c_rgb); + int d_red = std::abs (rgb[0] - c_rgb[0]); + int d_green = std::abs (rgb[1] - c_rgb[1]); + int d_blue = std::abs (rgb[2] - c_rgb[2]); + int dist = d_red * d_red + d_green * d_green + d_blue * d_blue; + if (dist < best_distance) + { + best_distance = dist; + result = c; + } } - if (m_reverse) + + return result; +} + +/* See ui-style.h. */ + +std::string +ui_file_style::to_ansi () const +{ + std::string result ("\033["); + if (!is_default ()) { - if (need_semi) - result.push_back (';'); - result.push_back ('7'); + m_foreground.append_ansi (true, &result); + result.push_back (';'); + m_background.append_ansi (false, &result); + result.push_back (';'); + if (m_intensity == NORMAL) + result.append ("22"); + else + result.append (std::to_string (m_intensity)); + result.push_back (';'); + if (m_reverse) + result.push_back ('7'); + else + result.append ("27"); } result.push_back ('m'); return result; @@ -315,9 +447,11 @@ ui_file_style::parse (const char *buf, size_t *n_read) case 35: case 36: case 37: + m_foreground = color (value - 30); + break; /* Note: not 38. */ case 39: - m_foreground = color (value - 30); + m_foreground = NONE; break; case 40: @@ -328,9 +462,11 @@ ui_file_style::parse (const char *buf, size_t *n_read) case 45: case 46: case 47: + m_background = color (value - 40); + break; /* Note: not 48. */ case 49: - m_background = color (value - 40); + m_background = NONE; break; case 90: @@ -412,3 +548,60 @@ _initialize_ui_style () error. */ gdb_assert (code == 0); } + +/* See ui-style.h. */ + +const std::vector<color_space> & +colorsupport () +{ + static const std::vector<color_space> value = [] + { + std::vector<color_space> result = {color_space::MONOCHROME}; + + int colors = tgetnum ("Co"); + if (colors >= 8) + result.push_back (color_space::ANSI_8COLOR); + if (colors >= 16) + result.push_back (color_space::AIXTERM_16COLOR); + if (colors >= 256) + result.push_back (color_space::XTERM_256COLOR); + + const char *colorterm = getenv ("COLORTERM"); + if (colorterm != nullptr && (!strcmp (colorterm, "truecolor") + || !strcmp (colorterm, "24bit"))) + result.push_back (color_space::RGB_24BIT); + + return result; + } (); + return value; +} + +const char * +color_space_name (color_space c) +{ + switch (c) + { + case color_space::MONOCHROME: return "monochrome"; + case color_space::ANSI_8COLOR: return "ansi_8color"; + case color_space::AIXTERM_16COLOR: return "aixterm_16color"; + case color_space::XTERM_256COLOR: return "xterm_256color"; + case color_space::RGB_24BIT: return "rgb_24bit"; + } + gdb_assert_not_reached ("color_space_name called on invalid color"); +} + +bool +color_space_safe_cast (color_space *result, long c) +{ + switch (static_cast<color_space>(c)) + { + case color_space::MONOCHROME: + case color_space::ANSI_8COLOR: + case color_space::AIXTERM_16COLOR: + case color_space::XTERM_256COLOR: + case color_space::RGB_24BIT: + *result = static_cast<color_space>(c); + return true; + } + return false; +} |