From 48f6b1695c3afaeed7dfe7f80169cad4ae51b012 Mon Sep 17 00:00:00 2001 From: "Kang.Jianbin" Date: Fri, 27 Oct 2017 02:47:24 +0800 Subject: [PATCH 1/6] Add true color support. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implement true color support define in: https://en.wikipedia.org/wiki/ANSI_escape_code The sequence is: ESC[ … 38;2;;; … m Select RGB foreground color ESC[ … 48;2;;; … m Select RGB background color --- src/terminal/terminalframebuffer.cc | 22 ++++++++++++++++++++-- src/terminal/terminalframebuffer.h | 14 +++++++++++--- src/terminal/terminalfunctions.cc | 21 +++++++++++++++++++++ 3 files changed, 52 insertions(+), 5 deletions(-) diff --git a/src/terminal/terminalframebuffer.cc b/src/terminal/terminalframebuffer.cc index a4b90ea..eafdd20 100644 --- a/src/terminal/terminalframebuffer.cc +++ b/src/terminal/terminalframebuffer.cc @@ -517,6 +517,8 @@ void Renditions::set_foreground_color( int num ) { if ( (0 <= num) && (num <= 255) ) { foreground_color = 30 + num; + } else if ( is_true_color( num ) ) { + foreground_color = num; } } @@ -524,6 +526,8 @@ void Renditions::set_background_color( int num ) { if ( (0 <= num) && (num <= 255) ) { background_color = 40 + num; + } else if ( is_true_color( num ) ) { + background_color = num; } } @@ -556,13 +560,27 @@ std::string Renditions::sgr( void ) const ret.append( "m" ); - if ( foreground_color > 37 ) { /* use 256-color set */ + if ( is_true_color( foreground_color ) ) { + char col[64]; + snprintf( col, 64, "\033[38;2;%d;%d;%dm", + (foreground_color >> 16) & 0xff, + (foreground_color >> 8) & 0xff, + foreground_color & 0xff); + ret.append( col ); + } else if ( foreground_color > 37 ) { /* use 256-color set */ char col[ 64 ]; snprintf( col, 64, "\033[38;5;%dm", foreground_color - 30 ); ret.append( col ); } - if ( background_color > 47 ) { /* use 256-color set */ + if ( is_true_color( background_color ) ) { + char col[64]; + snprintf( col, 64, "\033[48;2;%d;%d;%dm", + (background_color >> 16) & 0xff, + (background_color >> 8) & 0xff, + background_color & 0xff); + ret.append( col ); + } else if ( background_color > 47 ) { /* use 256-color set */ char col[ 64 ]; snprintf( col, 64, "\033[48;5;%dm", background_color - 40 ); ret.append( col ); diff --git a/src/terminal/terminalframebuffer.h b/src/terminal/terminalframebuffer.h index ca669ab..2b7cb7f 100644 --- a/src/terminal/terminalframebuffer.h +++ b/src/terminal/terminalframebuffer.h @@ -55,9 +55,9 @@ namespace Terminal { public: typedef enum { bold, faint, italic, underlined, blink, inverse, invisible, SIZE } attribute_type; - // all together, a 32 bit word now... - unsigned int foreground_color : 12; - unsigned int background_color : 12; + static const unsigned int true_color_mask = 0x80000000; + unsigned int foreground_color; + unsigned int background_color; private: unsigned int attributes : 8; @@ -68,6 +68,14 @@ namespace Terminal { void set_rendition( color_type num ); std::string sgr( void ) const; + static unsigned int make_true_color( unsigned int r, unsigned int g, unsigned int b ) { + return true_color_mask | (r << 16) | (g << 8) | b; + } + + static bool is_true_color(unsigned int color) { + return (color & true_color_mask) != 0; + } + bool operator==( const Renditions &x ) const { return ( attributes == x.attributes ) diff --git a/src/terminal/terminalfunctions.cc b/src/terminal/terminalfunctions.cc index 22bf4f0..126986d 100644 --- a/src/terminal/terminalfunctions.cc +++ b/src/terminal/terminalfunctions.cc @@ -414,6 +414,27 @@ static void CSI_SGR( Framebuffer *fb, Dispatcher *dispatch ) i += 2; continue; } + + /* True color support: ESC[ ... [34]8;2;;; ... m */ + if ( (rendition == 38 || rendition == 48) && + (dispatch->param_count() - i >= 5) && + (dispatch->getparam( i+1, -1 ) == 2)) { + unsigned int red = dispatch->getparam(i+2, 0); + unsigned int green = dispatch->getparam(i+3, 0); + unsigned int blue = dispatch->getparam(i+4, 0); + unsigned int color; + + color = Renditions::make_true_color( red, green, blue ); + + if ( rendition == 38 ) { + fb->ds.set_foreground_color( color ); + } else { + fb->ds.set_background_color( color ); + } + i += 4; + continue; + } + fb->ds.add_rendition( rendition ); } } From fcf95b2451df98064b0681fe33887a1842f9ddd4 Mon Sep 17 00:00:00 2001 From: John Hood Date: Sun, 29 Oct 2017 13:46:59 -0400 Subject: [PATCH 2/6] Make Terminal::Renditions smaller, and its members private. --- src/frontend/terminaloverlay.cc | 8 ++++---- src/terminal/terminalframebuffer.h | 13 ++++++++----- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/frontend/terminaloverlay.cc b/src/frontend/terminaloverlay.cc index 26d81cb..bb8c157 100644 --- a/src/frontend/terminaloverlay.cc +++ b/src/frontend/terminaloverlay.cc @@ -206,8 +206,8 @@ void NotificationEngine::apply( Framebuffer &fb ) const /* draw bar across top of screen */ Cell notification_bar( 0 ); - notification_bar.get_renditions().foreground_color = 37; - notification_bar.get_renditions().background_color = 44; + notification_bar.get_renditions().set_foreground_color( 37 ); + notification_bar.get_renditions().set_background_color( 44 ); notification_bar.append( 0x20 ); for ( int i = 0; i < fb.ds.get_width(); i++ ) { @@ -276,8 +276,8 @@ void NotificationEngine::apply( Framebuffer &fb ) const this_cell = fb.get_mutable_cell( 0, overlay_col ); fb.reset_cell( this_cell ); this_cell->get_renditions().set_attribute(Renditions::bold, true); - this_cell->get_renditions().foreground_color = 37; - this_cell->get_renditions().background_color = 44; + this_cell->get_renditions().set_foreground_color( 37 ); + this_cell->get_renditions().set_background_color( 44 ); this_cell->append( ch ); this_cell->set_wide( chwidth == 2 ); diff --git a/src/terminal/terminalframebuffer.h b/src/terminal/terminalframebuffer.h index 2b7cb7f..274047f 100644 --- a/src/terminal/terminalframebuffer.h +++ b/src/terminal/terminalframebuffer.h @@ -55,11 +55,11 @@ namespace Terminal { public: typedef enum { bold, faint, italic, underlined, blink, inverse, invisible, SIZE } attribute_type; - static const unsigned int true_color_mask = 0x80000000; - unsigned int foreground_color; - unsigned int background_color; private: - unsigned int attributes : 8; + static const uint64_t true_color_mask = 0x1000000; + uint64_t foreground_color : 25; + uint64_t background_color : 25; + uint64_t attributes : 8; public: Renditions( color_type s_background ); @@ -76,6 +76,9 @@ namespace Terminal { return (color & true_color_mask) != 0; } + unsigned int get_foreground_color() const { return foreground_color; } + unsigned int get_background_color() const { return background_color; } + bool operator==( const Renditions &x ) const { return ( attributes == x.attributes ) @@ -329,7 +332,7 @@ namespace Terminal { void add_rendition( color_type x ) { renditions.set_rendition( x ); } const Renditions& get_renditions( void ) const { return renditions; } Renditions& get_renditions( void ) { return renditions; } - int get_background_rendition( void ) const { return renditions.background_color; } + int get_background_rendition( void ) const { return renditions.get_background_color(); } void save_cursor( void ); void restore_cursor( void ); From a0fb1cfe7a39d39abce6fff71b72143cc2141730 Mon Sep 17 00:00:00 2001 From: John Hood Date: Mon, 6 Nov 2017 09:30:57 -0500 Subject: [PATCH 3/6] Overlays were getting set to the wrong colors. Fix. --- src/frontend/terminaloverlay.cc | 8 ++++---- src/terminal/terminalframebuffer.h | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/frontend/terminaloverlay.cc b/src/frontend/terminaloverlay.cc index bb8c157..27eef05 100644 --- a/src/frontend/terminaloverlay.cc +++ b/src/frontend/terminaloverlay.cc @@ -206,8 +206,8 @@ void NotificationEngine::apply( Framebuffer &fb ) const /* draw bar across top of screen */ Cell notification_bar( 0 ); - notification_bar.get_renditions().set_foreground_color( 37 ); - notification_bar.get_renditions().set_background_color( 44 ); + notification_bar.get_renditions().set_foreground_color( 7 ); + notification_bar.get_renditions().set_background_color( 4 ); notification_bar.append( 0x20 ); for ( int i = 0; i < fb.ds.get_width(); i++ ) { @@ -276,8 +276,8 @@ void NotificationEngine::apply( Framebuffer &fb ) const this_cell = fb.get_mutable_cell( 0, overlay_col ); fb.reset_cell( this_cell ); this_cell->get_renditions().set_attribute(Renditions::bold, true); - this_cell->get_renditions().set_foreground_color( 37 ); - this_cell->get_renditions().set_background_color( 44 ); + this_cell->get_renditions().set_foreground_color( 7 ); + this_cell->get_renditions().set_background_color( 4 ); this_cell->append( ch ); this_cell->set_wide( chwidth == 2 ); diff --git a/src/terminal/terminalframebuffer.h b/src/terminal/terminalframebuffer.h index 274047f..1b9d846 100644 --- a/src/terminal/terminalframebuffer.h +++ b/src/terminal/terminalframebuffer.h @@ -76,8 +76,8 @@ namespace Terminal { return (color & true_color_mask) != 0; } - unsigned int get_foreground_color() const { return foreground_color; } - unsigned int get_background_color() const { return background_color; } + // unsigned int get_foreground_rendition() const { return foreground_color; } + unsigned int get_background_rendition() const { return background_color; } bool operator==( const Renditions &x ) const { @@ -332,7 +332,7 @@ namespace Terminal { void add_rendition( color_type x ) { renditions.set_rendition( x ); } const Renditions& get_renditions( void ) const { return renditions; } Renditions& get_renditions( void ) { return renditions; } - int get_background_rendition( void ) const { return renditions.get_background_color(); } + int get_background_rendition( void ) const { return renditions.get_background_rendition(); } void save_cursor( void ); void restore_cursor( void ); From 6b1f6efee06c2a36019c638eb70044d7c386ba5b Mon Sep 17 00:00:00 2001 From: John Hood Date: Sun, 29 Oct 2017 14:02:05 -0400 Subject: [PATCH 4/6] Minor SGR printf type signedness fixes. --- src/terminal/terminalframebuffer.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/terminal/terminalframebuffer.cc b/src/terminal/terminalframebuffer.cc index eafdd20..29ee38c 100644 --- a/src/terminal/terminalframebuffer.cc +++ b/src/terminal/terminalframebuffer.cc @@ -547,14 +547,14 @@ std::string Renditions::sgr( void ) const && (foreground_color <= 37) ) { /* ANSI foreground color */ char col[ 8 ]; - snprintf( col, 8, ";%d", foreground_color ); + snprintf( col, 8, ";%u", static_cast( foreground_color ) ); ret.append( col ); } if ( background_color && (background_color <= 47) ) { char col[ 8 ]; - snprintf( col, 8, ";%d", background_color ); + snprintf( col, 8, ";%u", static_cast( background_color ) ); ret.append( col ); } @@ -562,27 +562,27 @@ std::string Renditions::sgr( void ) const if ( is_true_color( foreground_color ) ) { char col[64]; - snprintf( col, 64, "\033[38;2;%d;%d;%dm", + snprintf( col, 64, "\033[38;2;%u;%u;%um", (foreground_color >> 16) & 0xff, (foreground_color >> 8) & 0xff, foreground_color & 0xff); ret.append( col ); } else if ( foreground_color > 37 ) { /* use 256-color set */ char col[ 64 ]; - snprintf( col, 64, "\033[38;5;%dm", foreground_color - 30 ); + snprintf( col, 64, "\033[38;5;%um", foreground_color - 30 ); ret.append( col ); } if ( is_true_color( background_color ) ) { char col[64]; - snprintf( col, 64, "\033[48;2;%d;%d;%dm", + snprintf( col, 64, "\033[48;2;%u;%u;%um", (background_color >> 16) & 0xff, (background_color >> 8) & 0xff, background_color & 0xff); ret.append( col ); } else if ( background_color > 47 ) { /* use 256-color set */ char col[ 64 ]; - snprintf( col, 64, "\033[48;5;%dm", background_color - 40 ); + snprintf( col, 64, "\033[48;5;%um", background_color - 40 ); ret.append( col ); } From ed492c6922ee6ce6553904e8a399d365eb6eee3f Mon Sep 17 00:00:00 2001 From: John Hood Date: Mon, 6 Nov 2017 10:14:25 -0500 Subject: [PATCH 5/6] Make Renditions::sgr() more compact in both code and output. --- src/terminal/terminalframebuffer.cc | 60 +++++++++++------------------ 1 file changed, 23 insertions(+), 37 deletions(-) diff --git a/src/terminal/terminalframebuffer.cc b/src/terminal/terminalframebuffer.cc index 29ee38c..a15faee 100644 --- a/src/terminal/terminalframebuffer.cc +++ b/src/terminal/terminalframebuffer.cc @@ -534,6 +534,7 @@ void Renditions::set_background_color( int num ) std::string Renditions::sgr( void ) const { std::string ret; + char col[64]; ret.append( "\033[0" ); if ( get_attribute( bold ) ) ret.append( ";1" ); @@ -543,49 +544,34 @@ std::string Renditions::sgr( void ) const if ( get_attribute( inverse ) ) ret.append( ";7" ); if ( get_attribute( invisible ) ) ret.append( ";8" ); - if ( foreground_color - && (foreground_color <= 37) ) { - /* ANSI foreground color */ - char col[ 8 ]; - snprintf( col, 8, ";%u", static_cast( foreground_color ) ); + if ( foreground_color ) { + if ( is_true_color( foreground_color ) ) { + snprintf( col, sizeof( col ), ";38;2;%u;%u;%u", + (foreground_color >> 16) & 0xff, + (foreground_color >> 8) & 0xff, + foreground_color & 0xff); + } else if ( foreground_color > 37 ) { /* use 256-color set */ + snprintf( col, sizeof( col ), ";38;5;%u", foreground_color - 30 ); + } else { /* ANSI foreground color */ + snprintf( col, sizeof( col ), ";%u", static_cast( foreground_color ) ); + } ret.append( col ); } - - if ( background_color - && (background_color <= 47) ) { - char col[ 8 ]; - snprintf( col, 8, ";%u", static_cast( background_color ) ); + if ( background_color ) { + if ( is_true_color( background_color ) ) { + snprintf( col, sizeof( col ), ";48;2;%u;%u;%u", + (background_color >> 16) & 0xff, + (background_color >> 8) & 0xff, + background_color & 0xff); + } else if ( background_color > 47 ) { /* use 256-color set */ + snprintf( col, sizeof( col ), ";48;5;%u", background_color - 40 ); + } else { /* ANSI background color */ + snprintf( col, sizeof( col ), ";%u", static_cast( background_color ) ); + } ret.append( col ); } - ret.append( "m" ); - if ( is_true_color( foreground_color ) ) { - char col[64]; - snprintf( col, 64, "\033[38;2;%u;%u;%um", - (foreground_color >> 16) & 0xff, - (foreground_color >> 8) & 0xff, - foreground_color & 0xff); - ret.append( col ); - } else if ( foreground_color > 37 ) { /* use 256-color set */ - char col[ 64 ]; - snprintf( col, 64, "\033[38;5;%um", foreground_color - 30 ); - ret.append( col ); - } - - if ( is_true_color( background_color ) ) { - char col[64]; - snprintf( col, 64, "\033[48;2;%u;%u;%um", - (background_color >> 16) & 0xff, - (background_color >> 8) & 0xff, - background_color & 0xff); - ret.append( col ); - } else if ( background_color > 47 ) { /* use 256-color set */ - char col[ 64 ]; - snprintf( col, 64, "\033[48;5;%um", background_color - 40 ); - ret.append( col ); - } - return ret; } From f95b03ab1604c534f88bd44fd3d2a79aa4f0537e Mon Sep 17 00:00:00 2001 From: John Hood Date: Mon, 6 Nov 2017 10:19:54 -0500 Subject: [PATCH 6/6] Fix issue with incorrect true-color background erase colors. --- src/terminal/terminalframebuffer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/terminal/terminalframebuffer.h b/src/terminal/terminalframebuffer.h index 1b9d846..0e69bda 100644 --- a/src/terminal/terminalframebuffer.h +++ b/src/terminal/terminalframebuffer.h @@ -49,7 +49,7 @@ namespace Terminal { using shared::shared_ptr; using shared::make_shared; - typedef uint16_t color_type; + typedef uint32_t color_type; class Renditions { public: