Skip to content

Commit

Permalink
undercurl/underline color support
Browse files Browse the repository at this point in the history
  • Loading branch information
jdrouhard committed Aug 20, 2023
1 parent 66d4653 commit aff5e1c
Show file tree
Hide file tree
Showing 6 changed files with 183 additions and 57 deletions.
10 changes: 3 additions & 7 deletions src/terminal/parserstate.cc
Original file line number Diff line number Diff line change
Expand Up @@ -171,18 +171,14 @@ Transition CSI_Entry::input_state_rule( wchar_t ch ) const
return Transition( std::make_shared<CSI_Dispatch>(), &family->s_Ground );
}

if ( ( ( 0x30 <= ch ) && ( ch <= 0x39 ) ) || ( ch == 0x3B ) ) {
if ( ( ( 0x30 <= ch ) && ( ch <= 0x39 ) ) || ( ch == 0x3A ) || ( ch == 0x3B ) ) {
return Transition( std::make_shared<Param>(), &family->s_CSI_Param );
}

if ( ( 0x3C <= ch ) && ( ch <= 0x3F ) ) {
return Transition( std::make_shared<Collect>(), &family->s_CSI_Param );
}

if ( ch == 0x3A ) {
return Transition( &family->s_CSI_Ignore );
}

if ( ( 0x20 <= ch ) && ( ch <= 0x2F ) ) {
return Transition( std::make_shared<Collect>(), &family->s_CSI_Intermediate );
}
Expand All @@ -196,11 +192,11 @@ Transition CSI_Param::input_state_rule( wchar_t ch ) const
return Transition( std::make_shared<Execute>() );
}

if ( ( ( 0x30 <= ch ) && ( ch <= 0x39 ) ) || ( ch == 0x3B ) ) {
if ( ( ( 0x30 <= ch ) && ( ch <= 0x39 ) ) || ( ch == 0x3A ) || ( ch == 0x3B ) ) {
return Transition( std::make_shared<Param>() );
}

if ( ( ch == 0x3A ) || ( ( 0x3C <= ch ) && ( ch <= 0x3F ) ) ) {
if ( ( 0x3C <= ch ) && ( ch <= 0x3F ) ) {
return Transition( &family->s_CSI_Ignore );
}

Expand Down
90 changes: 54 additions & 36 deletions src/terminal/terminaldispatcher.cc
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ Dispatcher::Dispatcher()
void Dispatcher::newparamchar( const Parser::Param* act )
{
assert( act->char_present );
assert( ( act->ch == ';' ) || ( ( act->ch >= '0' ) && ( act->ch <= '9' ) ) );
assert( ( act->ch == ';' ) || ( act->ch == ':' ) || ( ( act->ch >= '0' ) && ( act->ch <= '9' ) ) );
if ( params.length() < 100 ) {
/* enough for 16 five-char params plus 15 semicolons */
params.push_back( act->ch );
Expand Down Expand Up @@ -87,64 +87,82 @@ void Dispatcher::parse_params( void )

while ( 1 ) {
const char* segment_end = strchr( segment_begin, ';' );
if ( segment_end == NULL ) {
break;
}

errno = 0;
char* endptr;
long val = strtol( segment_begin, &endptr, 10 );
if ( endptr == segment_begin ) {
val = -1;
}
Param p( 0 );

bool first = true;
bool valid = false;
while ( 1 ) {
const char* ext_end = strchr( segment_begin, ':' );

if ( val > PARAM_MAX || errno == ERANGE ) {
val = -1;
errno = 0;
char* endptr;
long val = strtol( segment_begin, &endptr, 10 );
if ( endptr == segment_begin ) {
val = -1;
}

if ( val > PARAM_MAX || errno == ERANGE ) {
val = -1;
errno = 0;
}

if ( errno == 0 || segment_begin == endptr ) {
if ( first ) {
p.val = val;
valid = true;
} else {
p.exts.push_back( val );
}
}

first = false;

if ( ext_end == NULL || ( segment_end && ext_end > segment_end ) ) {
break;
}

segment_begin = ext_end + 1;
}

if ( errno == 0 || segment_begin == endptr ) {
parsed_params.push_back( val );
if ( valid ) {
parsed_params.push_back( p );
}

segment_begin = segment_end + 1;
}

/* get last param */
errno = 0;
char* endptr;
long val = strtol( segment_begin, &endptr, 10 );
if ( endptr == segment_begin ) {
val = -1;
}

if ( val > PARAM_MAX || errno == ERANGE ) {
val = -1;
errno = 0;
}
if ( segment_end == NULL ) {
break;
}

if ( errno == 0 || segment_begin == endptr ) {
parsed_params.push_back( val );
segment_begin = segment_end + 1;
}

parsed = true;
}

int Dispatcher::getparam( size_t N, int defaultval )
{
int ret = defaultval;
return getparamext( N, defaultval ).val;
}

Dispatcher::Param const& Dispatcher::getparamext( size_t N, int defaultval )
{
if ( !parsed ) {
parse_params();
}

static Param notfound( defaultval );
notfound.val = defaultval;

Param* ret = &notfound;

if ( parsed_params.size() > N ) {
ret = parsed_params[N];
ret = &parsed_params[N];
}

if ( ret < 1 )
ret = defaultval;
if ( ret->val < 1 )
ret->val = defaultval;

return ret;
return *ret;
}

int Dispatcher::param_count( void )
Expand Down
14 changes: 13 additions & 1 deletion src/terminal/terminaldispatcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,20 @@ DispatchRegistry& get_global_dispatch_registry( void );

class Dispatcher
{
public:
struct Param
{
Param( int val ) : val( val ) {}

int val {};
std::vector<int> exts;

bool operator==( Param const& other ) const { return val == other.val && exts == other.exts; }
};

private:
std::string params;
std::vector<int> parsed_params;
std::vector<Param> parsed_params;
bool parsed;

std::string dispatch_chars;
Expand All @@ -107,6 +118,7 @@ class Dispatcher

Dispatcher();
int getparam( size_t N, int defaultval );
Param const& getparamext( size_t N, int defaultval );
int param_count( void );

void newparamchar( const Parser::Param* act );
Expand Down
56 changes: 53 additions & 3 deletions src/terminal/terminalframebuffer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -449,15 +449,15 @@ void DrawState::resize( int s_width, int s_height )
}

Renditions::Renditions( color_type s_background )
: foreground_color( 0 ), background_color( s_background ), attributes( 0 )
: foreground_color( 0 ), background_color( s_background ), underline_color( 0 ), attributes( 0 )
{}

/* This routine cannot be used to set a color beyond the 16-color set. */
void Renditions::set_rendition( color_type num )
{
if ( num == 0 ) {
clear_attributes();
foreground_color = background_color = 0;
foreground_color = background_color = underline_color = 0;
return;
}

Expand All @@ -467,6 +467,9 @@ void Renditions::set_rendition( color_type num )
} else if ( num == 49 ) {
background_color = 0;
return;
} else if ( num == 59 ) {
underline_color = 0;
return;
}

if ( ( 30 <= num ) && ( num <= 37 ) ) { /* foreground color in 8-color set */
Expand Down Expand Up @@ -500,8 +503,16 @@ void Renditions::set_rendition( color_type num )
set_attribute( italic, value );
break;
case 4:
case 401:
set_attribute( underlined, true );
break;
case 24:
set_attribute( underlined, value );
case 400:
set_attribute( underlined, false );
set_attribute( underline_double, false );
set_attribute( underline_curl, false );
set_attribute( underline_dotted, false );
set_attribute( underline_dashed, false );
break;
case 5:
case 25:
Expand All @@ -519,6 +530,19 @@ void Renditions::set_rendition( color_type num )
case 29:
set_attribute( strikethrough, value );
break;

case 402:
set_attribute( underline_double, true );
break;
case 403:
set_attribute( underline_curl, true );
break;
case 404:
set_attribute( underline_dotted, true );
break;
case 405:
set_attribute( underline_dashed, true );
break;
default:
break; /* ignore unknown rendition */
}
Expand All @@ -542,6 +566,11 @@ void Renditions::set_background_color( int num )
}
}

void Renditions::set_underline_color( int num )
{
underline_color = num;
}

std::string Renditions::sgr( void ) const
{
std::string ret;
Expand All @@ -564,6 +593,14 @@ std::string Renditions::sgr( void ) const
ret.append( ";8" );
if ( get_attribute( strikethrough ) )
ret.append( ";9" );
if ( get_attribute( underline_double ) )
ret.append( ";4:2" );
if ( get_attribute( underline_curl ) )
ret.append( ";4:3" );
if ( get_attribute( underline_dotted ) )
ret.append( ";4:4" );
if ( get_attribute( underline_dashed ) )
ret.append( ";4:5" );

if ( foreground_color ) {
// Since foreground_color is a 25-bit field, it is promoted to an int when
Expand Down Expand Up @@ -607,6 +644,19 @@ std::string Renditions::sgr( void ) const
}
ret.append( col );
}
if ( underline_color ) {
if ( is_true_color( underline_color ) ) {
snprintf( col,
sizeof( col ),
";58:2::%d:%d:%d",
( underline_color >> 16 ) & 0xff,
( underline_color >> 8 ) & 0xff,
underline_color & 0xff );
} else {
snprintf( col, sizeof( col ), ";58:5:%d", underline_color );
}
ret.append( col );
}
ret.append( "m" );

return ret;
Expand Down
16 changes: 11 additions & 5 deletions src/terminal/terminalframebuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,19 +71,24 @@ class Renditions
inverse,
invisible,
strikethrough,
SIZE
underline_double,
underline_curl,
underline_dotted,
underline_dashed,
} attribute_type;

private:
static const uint64_t true_color_mask = 0x1000000;
uint64_t foreground_color : 25;
uint64_t background_color : 25;
uint64_t attributes : 8;
uint32_t foreground_color;
uint32_t background_color;
uint32_t underline_color;
uint16_t attributes;

public:
Renditions( color_type s_background );
void set_foreground_color( int num );
void set_background_color( int num );
void set_underline_color( int num );
void set_rendition( color_type num );
std::string sgr( void ) const;

Expand All @@ -100,7 +105,7 @@ class Renditions
bool operator==( const Renditions& x ) const
{
return ( attributes == x.attributes ) && ( foreground_color == x.foreground_color )
&& ( background_color == x.background_color );
&& ( background_color == x.background_color ) && ( underline_color == x.underline_color );
}
void set_attribute( attribute_type attr, bool val )
{
Expand Down Expand Up @@ -348,6 +353,7 @@ class DrawState

void set_foreground_color( int x ) { renditions.set_foreground_color( x ); }
void set_background_color( int x ) { renditions.set_background_color( x ); }
void set_underline_color( int x ) { renditions.set_underline_color( x ); }
void add_rendition( color_type x ) { renditions.set_rendition( x ); }
const Renditions& get_renditions( void ) const { return renditions; }
Renditions& get_renditions( void ) { return renditions; }
Expand Down
Loading

0 comments on commit aff5e1c

Please sign in to comment.