Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/terminal/terminal.cc
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ void Emulator::print( const Parser::Print* act )
this_cell->append( ch );
this_cell->set_wide( chwidth == 2 ); /* chwidth had better be 1 or 2 here */
fb.apply_renditions_to_cell( this_cell );
fb.apply_hyperlink_to_cell( this_cell );

if ( chwidth == 2 && fb.ds.get_cursor_col() + 1 < fb.ds.get_width() ) { /* erase overlapped cell */
fb.reset_cell( fb.get_mutable_cell( fb.ds.get_cursor_row(), fb.ds.get_cursor_col() + 1 ) );
Expand Down
2 changes: 1 addition & 1 deletion src/terminal/terminaldispatcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ class Dispatcher
bool parsed;

std::string dispatch_chars;
std::vector<wchar_t> OSC_string; /* only used to set the window title */
std::vector<wchar_t> OSC_string;

void parse_params( void );

Expand Down
38 changes: 31 additions & 7 deletions src/terminal/terminaldisplay.cc
Original file line number Diff line number Diff line change
Expand Up @@ -130,10 +130,12 @@ std::string Display::new_frame( bool initialized, const Framebuffer& last, const
initialized = false;
frame.cursor_x = frame.cursor_y = 0;
frame.current_rendition = initial_rendition();
frame.current_hyperlink = Hyperlink();
} else {
frame.cursor_x = frame.last_frame.ds.get_cursor_col();
frame.cursor_y = frame.last_frame.ds.get_cursor_row();
frame.current_rendition = frame.last_frame.ds.get_renditions();
frame.current_hyperlink = frame.last_frame.ds.get_hyperlink();
}

/* is cursor visibility initialized? */
Expand Down Expand Up @@ -203,6 +205,7 @@ std::string Display::new_frame( bool initialized, const Framebuffer& last, const
blank_row = std::make_shared<Row>( w, c );
}
frame.update_rendition( initial_rendition(), true );
frame.update_hyperlink( Hyperlink(), true );

int top_margin = 0;
int bottom_margin = top_margin + lines_scrolled + scroll_height - 1;
Expand Down Expand Up @@ -269,6 +272,8 @@ std::string Display::new_frame( bool initialized, const Framebuffer& last, const

/* have renditions changed? */
frame.update_rendition( f.ds.get_renditions(), !initialized );
/* has hyperlink changed? */
frame.update_hyperlink( f.ds.get_hyperlink(), !initialized );

/* has bracketed paste mode changed? */
if ( ( !initialized ) || ( f.ds.bracketed_paste != frame.last_frame.ds.bracketed_paste ) ) {
Expand Down Expand Up @@ -334,6 +339,7 @@ bool Display::put_row( bool initialized,
if ( wrap ) {
const Cell& cell = cells.at( 0 );
frame.update_rendition( cell.get_renditions() );
frame.update_hyperlink( cell.get_hyperlink() );
frame.append_cell( cell );
frame_x += cell.get_width();
frame.cursor_x += cell.get_width();
Expand All @@ -349,6 +355,7 @@ bool Display::put_row( bool initialized,
int clear_count = 0;
bool wrote_last_cell = false;
Renditions blank_renditions = initial_rendition();
Hyperlink blank_hyperlink;

/* iterate for every cell */
while ( frame_x < row_width ) {
Expand All @@ -365,8 +372,9 @@ bool Display::put_row( bool initialized,
if ( cell.empty() ) {
if ( !clear_count ) {
blank_renditions = cell.get_renditions();
blank_hyperlink = cell.get_hyperlink();
}
if ( cell.get_renditions() == blank_renditions ) {
if ( cell.get_renditions() == blank_renditions && cell.get_hyperlink() == blank_hyperlink ) {
/* Remember run of blank cells */
clear_count++;
frame_x++;
Expand All @@ -379,8 +387,8 @@ bool Display::put_row( bool initialized,
/* Move to the right position. */
frame.append_silent_move( frame_y, frame_x - clear_count );
frame.update_rendition( blank_renditions );
bool can_use_erase = has_bce || ( frame.current_rendition == initial_rendition() );
if ( can_use_erase && has_ech && clear_count > 4 ) {
frame.update_hyperlink( blank_hyperlink );
if ( can_use_erase( frame ) && has_ech && clear_count > 4 ) {
snprintf( tmp, 64, "\033[%dX", clear_count );
frame.append( tmp );
} else {
Expand All @@ -392,6 +400,7 @@ bool Display::put_row( bool initialized,
// we restart counting and continue here
if ( cell.empty() ) {
blank_renditions = cell.get_renditions();
blank_hyperlink = cell.get_hyperlink();
clear_count = 1;
frame_x++;
continue;
Expand All @@ -413,6 +422,7 @@ bool Display::put_row( bool initialized,
}
frame.append_silent_move( frame_y, frame_x );
frame.update_rendition( cell.get_renditions() );
frame.update_hyperlink( cell.get_hyperlink() );
frame.append_cell( cell );
frame_x += cell_width;
frame.cursor_x += cell_width;
Expand All @@ -428,9 +438,9 @@ bool Display::put_row( bool initialized,
/* Move to the right position. */
frame.append_silent_move( frame_y, frame_x - clear_count );
frame.update_rendition( blank_renditions );
frame.update_hyperlink( blank_hyperlink );

bool can_use_erase = has_bce || ( frame.current_rendition == initial_rendition() );
if ( can_use_erase && !wrap_this ) {
if ( can_use_erase( frame ) && !wrap_this ) {
frame.append( "\033[K" );
} else {
frame.append( clear_count, ' ' );
Expand Down Expand Up @@ -458,9 +468,14 @@ bool Display::put_row( bool initialized,
return false;
}

bool Display::can_use_erase( const FrameState& frame ) const
{
return has_bce || ( frame.current_rendition == initial_rendition() && frame.current_hyperlink.empty() );
}

FrameState::FrameState( const Framebuffer& s_last )
: str(), cursor_x( 0 ), cursor_y( 0 ), current_rendition( 0 ), cursor_visible( s_last.ds.cursor_visible ),
last_frame( s_last )
: str(), cursor_x( 0 ), cursor_y( 0 ), current_rendition( 0 ), current_hyperlink(),
cursor_visible( s_last.ds.cursor_visible ), last_frame( s_last )
{
/* Preallocate for better performance. Make a guess-- doesn't matter for correctness */
str.reserve( last_frame.ds.get_width() * last_frame.ds.get_height() * 4 );
Expand Down Expand Up @@ -514,3 +529,12 @@ void FrameState::update_rendition( const Renditions& r, bool force )
current_rendition = r;
}
}

void FrameState::update_hyperlink( const Hyperlink& h, bool force )
{
if ( force || current_hyperlink != h ) {
/* print hyperlink */
append_string( h.osc8() );
current_hyperlink = h;
}
}
4 changes: 4 additions & 0 deletions src/terminal/terminaldisplay.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ class FrameState

int cursor_x, cursor_y;
Renditions current_rendition;
Hyperlink current_hyperlink;
bool cursor_visible;

const Framebuffer& last_frame;
Expand All @@ -60,6 +61,7 @@ class FrameState
void append_silent_move( int y, int x );
void append_move( int y, int x );
void update_rendition( const Renditions& r, bool force = false );
void update_hyperlink( const Hyperlink& h, bool force = false );
};

class Display
Expand All @@ -81,6 +83,8 @@ class Display
const Row& old_row,
bool wrap ) const;

bool can_use_erase( const FrameState& frame ) const;

public:
std::string open() const;
std::string close() const;
Expand Down
42 changes: 40 additions & 2 deletions src/terminal/terminalframebuffer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,14 @@
using namespace Terminal;

Cell::Cell( color_type background_color )
: contents(), renditions( background_color ), wide( false ), fallback( false ), wrap( false )
: contents(), renditions( background_color ), hyperlink(), wide( false ), fallback( false ), wrap( false )
{}

void Cell::reset( color_type background_color )
{
contents.clear();
renditions = Renditions( background_color );
hyperlink = Hyperlink();
wide = false;
fallback = false;
wrap = false;
Expand All @@ -62,7 +63,7 @@ void DrawState::reinitialize_tabs( unsigned int start )
DrawState::DrawState( int s_width, int s_height )
: width( s_width ), height( s_height ), cursor_col( 0 ), cursor_row( 0 ), combining_char_col( 0 ),
combining_char_row( 0 ), default_tabs( true ), tabs( s_width ), scrolling_region_top_row( 0 ),
scrolling_region_bottom_row( height - 1 ), renditions( 0 ), save(), next_print_will_wrap( false ),
scrolling_region_bottom_row( height - 1 ), renditions( 0 ), hyperlink(), save(), next_print_will_wrap( false ),
origin_mode( false ), auto_wrap_mode( true ), insert_mode( false ), cursor_visible( true ),
reverse_video( false ), bracketed_paste( false ), mouse_reporting_mode( MOUSE_REPORTING_NONE ),
mouse_focus_event( false ), mouse_alternate_scroll( false ), mouse_encoding_mode( MOUSE_ENCODING_DEFAULT ),
Expand Down Expand Up @@ -268,6 +269,14 @@ void Framebuffer::apply_renditions_to_cell( Cell* cell )
cell->set_renditions( ds.get_renditions() );
}

void Framebuffer::apply_hyperlink_to_cell( Cell* cell )
{
if ( !cell ) {
cell = get_mutable_cell();
}
cell->set_hyperlink( ds.get_hyperlink() );
}

SavedCursor::SavedCursor()
: cursor_col( 0 ), cursor_row( 0 ), renditions( 0 ), auto_wrap_mode( true ), origin_mode( false )
{}
Expand Down Expand Up @@ -390,6 +399,7 @@ void Framebuffer::soft_reset( void )
ds.application_mode_cursor_keys = false;
ds.set_scrolling_region( 0, ds.get_height() - 1 );
ds.add_rendition( 0 );
ds.set_hyperlink( Hyperlink() );
ds.clear_saved_cursor();
}

Expand Down Expand Up @@ -594,6 +604,34 @@ std::string Renditions::sgr( void ) const
return ret;
}

bool Hyperlink::operator==( const Hyperlink& x ) const
{
if ( rep == x.rep ) {
return true;
}
if ( rep == nullptr || x.rep == nullptr ) {
return false;
}

return rep->url == x.rep->url && rep->params == x.rep->params;
}

std::string Hyperlink::osc8() const
{
std::string ret;

ret.append( "\033]8;" );

if ( *this )
ret.append( rep->params );
ret.append( ";" );
if ( *this )
ret.append( rep->url );

ret.append( "\033\\" );
return ret;
}

void Row::reset( color_type background_color )
{
gen = get_gen();
Expand Down
39 changes: 37 additions & 2 deletions src/terminal/terminalframebuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
#include <list>
#include <memory>
#include <string>
#include <utility>
#include <vector>

/* Terminal framebuffer */
Expand Down Expand Up @@ -98,12 +99,39 @@ class Renditions
void clear_attributes() { attributes = 0; }
};

class Hyperlink
Comment thread
zedinosaur marked this conversation as resolved.
{
public:
Hyperlink() : rep( nullptr ) {}
Hyperlink( std::string params, std::string url )
: rep( url.empty() ? nullptr : std::make_shared<Rep>( Rep { std::move( params ), std::move( url ) } ) )
{}

std::string osc8() const;

bool empty() const { return rep == nullptr; }
operator bool() const { return !empty(); }

bool operator==( const Hyperlink& x ) const;

bool operator!=( const Hyperlink& x ) const { return !operator==( x ); }

private:
struct Rep
{
std::string params;
std::string url;
};
std::shared_ptr<Rep> rep;
};

class Cell
{
private:
typedef std::string content_type; /* can be std::string, std::vector<uint8_t>, or __gnu_cxx::__vstring */
content_type contents;
Renditions renditions;
Hyperlink hyperlink;
unsigned int wide : 1; /* 0 = narrow, 1 = wide */
unsigned int fallback : 1; /* first character is combining character */
unsigned int wrap : 1;
Expand All @@ -119,7 +147,7 @@ class Cell
bool operator==( const Cell& x ) const
{
return ( ( contents == x.contents ) && ( fallback == x.fallback ) && ( wide == x.wide )
&& ( renditions == x.renditions ) && ( wrap == x.wrap ) );
&& ( renditions == x.renditions ) && ( hyperlink == x.hyperlink ) && ( wrap == x.wrap ) );
}

bool operator!=( const Cell& x ) const { return !operator==( x ); }
Expand Down Expand Up @@ -198,6 +226,8 @@ class Cell
}

/* Other accessors */
const Hyperlink& get_hyperlink() const { return hyperlink; }
void set_hyperlink( Hyperlink l ) { hyperlink = std::move( l ); }
const Renditions& get_renditions( void ) const { return renditions; }
Renditions& get_renditions( void ) { return renditions; }
void set_renditions( const Renditions& r ) { renditions = r; }
Expand Down Expand Up @@ -271,6 +301,7 @@ class DrawState
int scrolling_region_top_row, scrolling_region_bottom_row;

Renditions renditions;
Hyperlink hyperlink;

SavedCursor save;

Expand Down Expand Up @@ -332,6 +363,9 @@ class DrawState
int limit_top( void ) const;
int limit_bottom( void ) const;

const Hyperlink& get_hyperlink() const { return hyperlink; }
void set_hyperlink( Hyperlink x ) { hyperlink = std::move( x ); }

void set_foreground_color( int x ) { renditions.set_foreground_color( x ); }
void set_background_color( int x ) { renditions.set_background_color( x ); }
void add_rendition( color_type x ) { renditions.set_rendition( x ); }
Expand All @@ -355,7 +389,7 @@ class DrawState
&& ( reverse_video == x.reverse_video ) && ( renditions == x.renditions )
&& ( bracketed_paste == x.bracketed_paste ) && ( mouse_reporting_mode == x.mouse_reporting_mode )
&& ( mouse_focus_event == x.mouse_focus_event ) && ( mouse_alternate_scroll == x.mouse_alternate_scroll )
&& ( mouse_encoding_mode == x.mouse_encoding_mode );
&& ( mouse_encoding_mode == x.mouse_encoding_mode ) && hyperlink == x.hyperlink;
}
};

Expand Down Expand Up @@ -448,6 +482,7 @@ class Framebuffer
Cell* get_combining_cell( void );

void apply_renditions_to_cell( Cell* cell );
void apply_hyperlink_to_cell( Cell* cell );

void insert_line( int before_row, int count );
void delete_line( int row, int count );
Expand Down
Loading
Loading