diff --git a/src/terminal/terminalframebuffer.cc b/src/terminal/terminalframebuffer.cc index 541479d..da790af 100644 --- a/src/terminal/terminalframebuffer.cc +++ b/src/terminal/terminalframebuffer.cc @@ -32,19 +32,25 @@ void Cell::reset( int background_color ) wrap = false; } +void DrawState::reinitialize_tabs( unsigned int start ) +{ + assert( default_tabs ); + for ( unsigned int i = start; i < tabs.size(); i++ ) { + tabs[ i ] = ( (i % 8) == 0 ); + } +} + 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 ), tabs( s_width ), + 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 ), origin_mode( false ), auto_wrap_mode( true ), insert_mode( false ), cursor_visible( true ), reverse_video( false ), application_mode_cursor_keys( false ) { - for ( int i = 0; i < width; i++ ) { - tabs[ i ] = ( (i % 8) == 0 ); - } + reinitialize_tabs( 0 ); } Framebuffer::Framebuffer( int s_width, int s_height ) @@ -204,19 +210,6 @@ int DrawState::limit_bottom( void ) return origin_mode ? scrolling_region_bottom_row : height - 1; } -std::vector DrawState::get_tabs( void ) -{ - std::vector ret; - - for ( int i = 0; i < width; i++ ) { - if ( tabs[ i ] ) { - ret.push_back( i ); - } - } - - return ret; -} - void Framebuffer::apply_renditions_to_current_cell( void ) { get_mutable_cell()->renditions = ds.get_renditions(); @@ -361,17 +354,16 @@ void DrawState::resize( int s_width, int s_height ) scrolling_region_bottom_row = s_height - 1; } + tabs.resize( s_width ); + if ( default_tabs ) { + reinitialize_tabs( width ); + } + width = s_width; height = s_height; snap_cursor_to_border(); - /* reset tab stops */ - tabs = std::vector< bool >( width ); - for ( int i = 0; i < width; i++ ) { - tabs[ i ] = ( (i % 8) == 0 ); - } - /* saved cursor will be snapped to border on restore */ /* invalidate combining char cell if necessary */ diff --git a/src/terminal/terminalframebuffer.h b/src/terminal/terminalframebuffer.h index bd1b09b..e11c51a 100644 --- a/src/terminal/terminalframebuffer.h +++ b/src/terminal/terminalframebuffer.h @@ -157,8 +157,11 @@ namespace Terminal { int cursor_col, cursor_row; int combining_char_col, combining_char_row; + bool default_tabs; std::vector tabs; + void reinitialize_tabs( unsigned int start ); + int scrolling_region_top_row, scrolling_region_bottom_row; Renditions renditions; @@ -189,10 +192,10 @@ namespace Terminal { void set_tab( void ); void clear_tab( int col ); + void clear_default_tabs( void ) { default_tabs = false; } + /* Default tabs can't be restored without resetting the draw state. */ int get_next_tab( void ); - std::vector get_tabs( void ); - void set_scrolling_region( int top, int bottom ); int get_scrolling_region_top_row( void ) const { return scrolling_region_top_row; } diff --git a/src/terminal/terminalfunctions.cc b/src/terminal/terminalfunctions.cc index f46e608..72ff03d 100644 --- a/src/terminal/terminalfunctions.cc +++ b/src/terminal/terminalfunctions.cc @@ -191,13 +191,20 @@ void Ctrl_HT( Framebuffer *fb, Dispatcher *dispatch __attribute((unused)) ) { int col = fb->ds.get_next_tab(); if ( col == -1 ) { /* no tabs, go to end of line */ - fb->ds.move_col( fb->ds.get_width() - 1 ); + /* A horizontal tab is the only operation that (1) can keep the wrap + flag but (2) starts a new grapheme. */ + if ( fb->ds.get_cursor_col() == fb->ds.get_width() - 1 ) { + fb->ds.move_col( fb->ds.get_width() - 1, false ); + fb->ds.move_col( 1, true, true ); + } else { + fb->ds.move_col( fb->ds.get_width() - 1, false ); + } } else { - fb->ds.move_col( col ); + fb->ds.move_col( col, false ); } } -static Function func_Ctrl_HT( CONTROL, "\x09", Ctrl_HT ); +static Function func_Ctrl_HT( CONTROL, "\x09", Ctrl_HT, false ); /* horizontal tab set */ void Ctrl_HTS( Framebuffer *fb, Dispatcher *dispatch __attribute((unused)) ) @@ -216,6 +223,7 @@ void CSI_TBC( Framebuffer *fb, Dispatcher *dispatch ) fb->ds.clear_tab( fb->ds.get_cursor_col() ); break; case 3: /* clear all tab stops */ + fb->ds.clear_default_tabs(); for ( int x = 0; x < fb->ds.get_width(); x++ ) { fb->ds.clear_tab( x ); }