From c40fd3a902e238a4d6e2920ff874927b08ee1628 Mon Sep 17 00:00:00 2001 From: AnotherTest Date: Sun, 10 May 2020 12:27:36 +0430 Subject: [PATCH] LibLine: Support RGB colors This also patches Userland/js. --- Libraries/LibLine/Editor.cpp | 26 +++++++++++-- Libraries/LibLine/Style.h | 72 +++++++++++++++++++++++------------- Userland/js.cpp | 14 +++---- 3 files changed, 75 insertions(+), 37 deletions(-) diff --git a/Libraries/LibLine/Editor.cpp b/Libraries/LibLine/Editor.cpp index 438bca11a7..1e101acc97 100644 --- a/Libraries/LibLine/Editor.cpp +++ b/Libraries/LibLine/Editor.cpp @@ -545,7 +545,7 @@ String Editor::get_line(const String& prompt) // only apply colour to the selection if something is *actually* added to the buffer if (m_last_shown_suggestion_was_complete && index == current_suggestion_index) { - vt_apply_style({ Style::Foreground(Style::Color::Blue) }); + vt_apply_style({ Style::Foreground(Style::XtermColor::Blue) }); fflush(stdout); } @@ -973,15 +973,33 @@ Style Editor::find_applicable_style(size_t offset) const return {}; } +String Style::Background::to_vt_escape() const +{ + if (m_is_rgb) { + return String::format("\033[48;2;%d;%d;%dm", m_rgb_color[0], m_rgb_color[1], m_rgb_color[2]); + } else { + return String::format("\033[%dm", (u8)m_xterm_color + 40); + } +} + +String Style::Foreground::to_vt_escape() const +{ + if (m_is_rgb) { + return String::format("\033[38;2;%d;%d;%dm", m_rgb_color[0], m_rgb_color[1], m_rgb_color[2]); + } else { + return String::format("\033[%dm", (u8)m_xterm_color + 30); + } +} + void Editor::vt_apply_style(const Style& style) { printf( - "\033[%d;%d;%d;%d;%dm", + "\033[%d;%d;%dm%s%s", style.bold() ? 1 : 22, style.underline() ? 4 : 24, style.italic() ? 3 : 23, - (int)style.foreground() + 30, - (int)style.background() + 40); + style.background().to_vt_escape().characters(), + style.foreground().to_vt_escape().characters()); } void Editor::vt_clear_lines(size_t count_above, size_t count_below) diff --git a/Libraries/LibLine/Style.h b/Libraries/LibLine/Style.h index cbd43f814b..f18f727f78 100644 --- a/Libraries/LibLine/Style.h +++ b/Libraries/LibLine/Style.h @@ -25,13 +25,15 @@ */ #pragma once +#include +#include #include namespace Line { class Style { public: - enum class Color : int { + enum class XtermColor : int { Default = 9, Black = 0, Red, @@ -41,15 +43,6 @@ public: Magenta, Cyan, White, - // TODO: it appears that we do not support these SGR options - BrightBlack = 60, - BrightRed, - BrightGreen, - BrightYellow, - BrightBlue, - BrightMagenta, - BrightCyan, - BrightWhite, }; struct UnderlineTag { @@ -58,19 +51,46 @@ public: }; struct ItalicTag { }; - struct Background { - explicit Background(Color color) - : m_color(color) + struct Color { + explicit Color(XtermColor color) + : m_xterm_color(color) + , m_is_rgb(false) { } - Color m_color; + Color(u8 r, u8 g, u8 b) + : m_rgb_color({ r, g, b }) + , m_is_rgb(true) + { + } + + XtermColor m_xterm_color { XtermColor::Default }; + Vector m_rgb_color; + bool m_is_rgb { false }; }; - struct Foreground { - explicit Foreground(Color color) - : m_color(color) + + struct Background : public Color { + explicit Background(XtermColor color) + : Color(color) { } - Color m_color; + Background(u8 r, u8 g, u8 b) + : Color(r, g, b) + { + } + String to_vt_escape() const; + }; + + struct Foreground : public Color { + explicit Foreground(XtermColor color) + : Color(color) + { + } + Foreground(u8 r, u8 g, u8 b) + : Color(r, g, b) + { + } + + String to_vt_escape() const; }; static constexpr UnderlineTag Underline {}; @@ -78,31 +98,31 @@ public: static constexpr ItalicTag Italic {}; // prepare for the horror of templates - template + template Style(const T& style_arg, Rest... rest) : Style(rest...) { set(style_arg); } - Style() {} + Style() { } bool underline() const { return m_underline; } bool bold() const { return m_bold; } bool italic() const { return m_italic; } - Color background() const { return m_background; } - Color foreground() const { return m_foreground; } + Background background() const { return m_background; } + Foreground foreground() const { return m_foreground; } void set(const ItalicTag&) { m_italic = true; } void set(const BoldTag&) { m_bold = true; } void set(const UnderlineTag&) { m_underline = true; } - void set(const Background& bg) { m_background = bg.m_color; } - void set(const Foreground& fg) { m_foreground = fg.m_color; } + void set(const Background& bg) { m_background = bg; } + void set(const Foreground& fg) { m_foreground = fg; } private: bool m_underline { false }; bool m_bold { false }; bool m_italic { false }; - Color m_background { Color::Default }; - Color m_foreground { Color::Default }; + Background m_background { XtermColor::Default }; + Foreground m_foreground { XtermColor::Default }; }; } diff --git a/Userland/js.cpp b/Userland/js.cpp index 14e080e27a..ed5ddb3c56 100644 --- a/Userland/js.cpp +++ b/Userland/js.cpp @@ -541,10 +541,10 @@ int main(int argc, char** argv) switch (token.type()) { case JS::TokenType::Invalid: case JS::TokenType::Eof: - stylize({ start, end }, { Line::Style::Foreground(Line::Style::Color::Red), Line::Style::Underline }); + stylize({ start, end }, { Line::Style::Foreground(Line::Style::XtermColor::Red), Line::Style::Underline }); break; case JS::TokenType::NumericLiteral: - stylize({ start, end }, { Line::Style::Foreground(Line::Style::Color::Magenta) }); + stylize({ start, end }, { Line::Style::Foreground(Line::Style::XtermColor::Magenta) }); break; case JS::TokenType::StringLiteral: case JS::TokenType::TemplateLiteralStart: @@ -552,7 +552,7 @@ int main(int argc, char** argv) case JS::TokenType::TemplateLiteralString: case JS::TokenType::RegexLiteral: case JS::TokenType::UnterminatedStringLiteral: - stylize({ start, end }, { Line::Style::Foreground(Line::Style::Color::Green), Line::Style::Bold }); + stylize({ start, end }, { Line::Style::Foreground(Line::Style::XtermColor::Green), Line::Style::Bold }); break; case JS::TokenType::BracketClose: case JS::TokenType::BracketOpen: @@ -609,7 +609,7 @@ int main(int argc, char** argv) break; case JS::TokenType::BoolLiteral: case JS::TokenType::NullLiteral: - stylize({ start, end }, { Line::Style::Foreground(Line::Style::Color::Yellow), Line::Style::Bold }); + stylize({ start, end }, { Line::Style::Foreground(Line::Style::XtermColor::Yellow), Line::Style::Bold }); break; case JS::TokenType::Class: case JS::TokenType::Const: @@ -627,7 +627,7 @@ int main(int argc, char** argv) case JS::TokenType::Typeof: case JS::TokenType::Var: case JS::TokenType::Void: - stylize({ start, end }, { Line::Style::Foreground(Line::Style::Color::Blue), Line::Style::Bold }); + stylize({ start, end }, { Line::Style::Foreground(Line::Style::XtermColor::Blue), Line::Style::Bold }); break; case JS::TokenType::Await: case JS::TokenType::Case: @@ -642,10 +642,10 @@ int main(int argc, char** argv) case JS::TokenType::Try: case JS::TokenType::While: case JS::TokenType::Yield: - stylize({ start, end }, { Line::Style::Foreground(Line::Style::Color::Cyan), Line::Style::Italic }); + stylize({ start, end }, { Line::Style::Foreground(Line::Style::XtermColor::Cyan), Line::Style::Italic }); break; case JS::TokenType::Identifier: - stylize({ start, end }, { Line::Style::Foreground(Line::Style::Color::White), Line::Style::Bold }); + stylize({ start, end }, { Line::Style::Foreground(Line::Style::XtermColor::White), Line::Style::Bold }); default: break; }