From 53099b216ce1100731b487567f060ac534f0d3a6 Mon Sep 17 00:00:00 2001 From: Daniel Bertalan Date: Thu, 3 Jun 2021 17:26:25 +0200 Subject: [PATCH] LibVT: Implement bright color support Previously, we only used bright colors when the bold attribute was set. We now have the option to set it via escape sequences. We also needed to make the bold text behavior optional, as some color schemes do weird things with it. For example, Solarized uses it for various shades of gray, so bold green would turn into a light shade of gray. The following new escape sequences are supported: - `CSI 90;m` to `CSI 97;m`: set bright foreground color - `CSI 100;m` to `CSI 107;m`: set bright background color --- Base/res/terminal-colors/Default.ini | 9 +++++++ Userland/Libraries/LibVT/Color.h | 12 +++++++++ Userland/Libraries/LibVT/Terminal.cpp | 30 ++++++++++++++++----- Userland/Libraries/LibVT/TerminalWidget.cpp | 14 ++++++---- Userland/Libraries/LibVT/TerminalWidget.h | 3 ++- 5 files changed, 56 insertions(+), 12 deletions(-) diff --git a/Base/res/terminal-colors/Default.ini b/Base/res/terminal-colors/Default.ini index e5a9b73860..f71538de2f 100644 --- a/Base/res/terminal-colors/Default.ini +++ b/Base/res/terminal-colors/Default.ini @@ -1,7 +1,14 @@ +[Options] +; Specifies whether bold text is displayed using bright colors. +ShowBoldTextAsBright=true + +; Default text and background colors [Primary] Background=#000000 Foreground=#ffffff +; Normal named colors +; These correspond to ANSI colors 0-7. [Normal] Black=#000000 Red=#cc0000 @@ -12,6 +19,8 @@ Magenta=#75507b Cyan=#06989a White=#eeeec +; Bright named colors +; These correspond to ANSI colors 8-15. [Bright] Black=#555753 Red=#ef2929 diff --git a/Userland/Libraries/LibVT/Color.h b/Userland/Libraries/LibVT/Color.h index a180965933..5e8a6b4b94 100644 --- a/Userland/Libraries/LibVT/Color.h +++ b/Userland/Libraries/LibVT/Color.h @@ -83,6 +83,18 @@ public: return m_value.as_named; } + constexpr Color to_bright() const + { + if (is_named()) { + auto numeric_value = static_cast(as_named()); + if (numeric_value < 8) + return Color::named(static_cast(numeric_value + 8)); + return *this; + } else { + return *this; + } + } + constexpr bool operator==(const Color& other) const { if (m_kind != other.kind()) diff --git a/Userland/Libraries/LibVT/Terminal.cpp b/Userland/Libraries/LibVT/Terminal.cpp index e6229857f2..214b979e9b 100644 --- a/Userland/Libraries/LibVT/Terminal.cpp +++ b/Userland/Libraries/LibVT/Terminal.cpp @@ -267,9 +267,7 @@ void Terminal::SGR(Parameters params) case 36: case 37: // Foreground color - if (m_current_state.attribute.flags & Attribute::Bold) - param += 8; - m_current_state.attribute.foreground_color = Color::named((Color::ANSIColor)(param - 30)); + m_current_state.attribute.foreground_color = Color::named(static_cast(param - 30)); break; case 39: // reset foreground @@ -284,14 +282,34 @@ void Terminal::SGR(Parameters params) case 46: case 47: // Background color - if (m_current_state.attribute.flags & Attribute::Bold) - param += 8; - m_current_state.attribute.background_color = Color::named((Color::ANSIColor)(param - 40)); + m_current_state.attribute.background_color = Color::named(static_cast(param - 40)); break; case 49: // reset background m_current_state.attribute.background_color = Attribute::default_background_color; break; + case 90: + case 91: + case 92: + case 93: + case 94: + case 95: + case 96: + case 97: + // Bright foreground color + m_current_state.attribute.foreground_color = Color::named(static_cast(8 + param - 90)); + break; + case 100: + case 101: + case 102: + case 103: + case 104: + case 105: + case 106: + case 107: + // Bright background color + m_current_state.attribute.background_color = Color::named(static_cast(8 + param - 100)); + break; default: dbgln("FIXME: SGR: p: {}", param); } diff --git a/Userland/Libraries/LibVT/TerminalWidget.cpp b/Userland/Libraries/LibVT/TerminalWidget.cpp index f010e8ed69..520855ce6e 100644 --- a/Userland/Libraries/LibVT/TerminalWidget.cpp +++ b/Userland/Libraries/LibVT/TerminalWidget.cpp @@ -277,7 +277,7 @@ void TerminalWidget::paint_event(GUI::PaintEvent& event) if (visual_beep_active) painter.clear_rect(frame_inner_rect(), terminal_color_to_rgb(VT::Color::named(VT::Color::ANSIColor::Red))); else - painter.clear_rect(frame_inner_rect(), terminal_color_to_rgb(VT::Color::named(VT::Color::ANSIColor::Black)).with_alpha(m_opacity)); + painter.clear_rect(frame_inner_rect(), terminal_color_to_rgb(VT::Color::named(VT::Color::ANSIColor::DefaultBackground)).with_alpha(m_opacity)); invalidate_cursor(); int rows_from_history = 0; @@ -334,7 +334,8 @@ void TerminalWidget::paint_event(GUI::PaintEvent& event) auto attribute = line.attribute_at(column); auto character_rect = glyph_rect(visual_row, column); auto cell_rect = character_rect.inflated(0, m_line_spacing); - auto text_color = terminal_color_to_rgb(should_reverse_fill_for_cursor_or_selection ? attribute.effective_background_color() : attribute.effective_foreground_color()); + auto text_color_before_bold_change = should_reverse_fill_for_cursor_or_selection ? attribute.effective_background_color() : attribute.effective_foreground_color(); + auto text_color = terminal_color_to_rgb(m_show_bold_text_as_bright ? text_color_before_bold_change.to_bright() : text_color_before_bold_change); if ((!visual_beep_active && !has_only_one_background_color) || should_reverse_fill_for_cursor_or_selection) painter.clear_rect(cell_rect, terminal_color_to_rgb(should_reverse_fill_for_cursor_or_selection ? attribute.effective_foreground_color() : attribute.effective_background_color())); @@ -360,6 +361,7 @@ void TerminalWidget::paint_event(GUI::PaintEvent& event) if (underline_style == UnderlineStyle::Solid) { if (attribute.href_id == m_active_href_id && m_hovered_href_id == m_active_href_id) text_color = palette().active_link(); + painter.draw_line(cell_rect.bottom_left(), cell_rect.bottom_right(), text_color); } else if (underline_style == UnderlineStyle::Dotted) { auto dotted_line_color = text_color.darkened(0.6f); @@ -398,7 +400,8 @@ void TerminalWidget::paint_event(GUI::PaintEvent& event) && visual_row == row_with_cursor && column == m_terminal.cursor_column(); should_reverse_fill_for_cursor_or_selection |= selection_contains({ first_row_from_history + visual_row, (int)column }); - auto text_color = terminal_color_to_rgb(should_reverse_fill_for_cursor_or_selection ? attribute.effective_background_color() : attribute.effective_foreground_color()); + auto text_color_before_bold_change = should_reverse_fill_for_cursor_or_selection ? attribute.effective_background_color() : attribute.effective_foreground_color(); + auto text_color = terminal_color_to_rgb(m_show_bold_text_as_bright ? text_color_before_bold_change.to_bright() : text_color_before_bold_change); u32 code_point = line.code_point(column); if (code_point == ' ') @@ -1162,6 +1165,8 @@ void TerminalWidget::set_color_scheme(const StringView& name) auto color_config = Core::ConfigFile::open(String::formatted("/res/terminal-colors/{}.ini", name)); + m_show_bold_text_as_bright = color_config->read_bool_entry("Options", "ShowBoldTextAsBright", true); + auto default_background = Gfx::Color::from_string(color_config->read_entry("Primary", "Background")); if (default_background.has_value()) m_default_background_color = default_background.value(); @@ -1196,7 +1201,7 @@ Gfx::IntSize TerminalWidget::widget_size_for_font(const Gfx::Font& font) const }; } -Gfx::Color TerminalWidget::terminal_color_to_rgb(VT::Color color) +constexpr Gfx::Color TerminalWidget::terminal_color_to_rgb(VT::Color color) const { switch (color.kind()) { case VT::Color::Kind::RGB: @@ -1253,5 +1258,4 @@ void TerminalWidget::send_non_user_input(const ReadonlyBytes& bytes) VERIFY_NOT_REACHED(); } } - } diff --git a/Userland/Libraries/LibVT/TerminalWidget.h b/Userland/Libraries/LibVT/TerminalWidget.h index 5d4307e651..73ef382d69 100644 --- a/Userland/Libraries/LibVT/TerminalWidget.h +++ b/Userland/Libraries/LibVT/TerminalWidget.h @@ -89,7 +89,7 @@ public: GUI::Menu& context_menu() { return *m_context_menu; } - Gfx::Color terminal_color_to_rgb(VT::Color); + constexpr Gfx::Color terminal_color_to_rgb(VT::Color) const; void set_font_and_resize_to_fit(const Gfx::Font&); @@ -164,6 +164,7 @@ private: unsigned m_colors[256]; Gfx::Color m_default_foreground_color; Gfx::Color m_default_background_color; + bool m_show_bold_text_as_bright { true }; String m_color_scheme_name;