diff --git a/src/terminal/terminalframebuffer.cc b/src/terminal/terminalframebuffer.cc index 37af871..e0007b4 100644 --- a/src/terminal/terminalframebuffer.cc +++ b/src/terminal/terminalframebuffer.cc @@ -214,14 +214,23 @@ void DrawState::clear_tab( int col ) tabs[ col ] = false; } -int DrawState::get_next_tab( void ) const +int DrawState::get_next_tab( int count ) const { - for ( int i = cursor_col + 1; i < width; i++ ) { - if ( tabs[ i ] ) { - return i; + if ( count >= 0 ) { + for ( int i = cursor_col + 1; i < width; i++ ) { + if ( tabs[ i ] && --count == 0 ) { + return i; + } } + return -1; + } else { + for ( int i = cursor_col - 1; i > 0; i-- ) { + if ( tabs[ i ] && ++count == 0 ) { + return i; + } + } + return 0; } - return -1; } void DrawState::set_scrolling_region( int top, int bottom ) diff --git a/src/terminal/terminalframebuffer.h b/src/terminal/terminalframebuffer.h index 51cc16f..35db77f 100644 --- a/src/terminal/terminalframebuffer.h +++ b/src/terminal/terminalframebuffer.h @@ -286,7 +286,7 @@ namespace Terminal { 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 ) const; + int get_next_tab( int count ) const; void set_scrolling_region( int top, int bottom ); diff --git a/src/terminal/terminalfunctions.cc b/src/terminal/terminalfunctions.cc index 2880a3b..6a9ff3f 100644 --- a/src/terminal/terminalfunctions.cc +++ b/src/terminal/terminalfunctions.cc @@ -201,9 +201,9 @@ static void Ctrl_NEL( Framebuffer *fb, Dispatcher *dispatch __attribute((unused) static Function func_Ctrl_NEL( CONTROL, "\x85", Ctrl_NEL ); /* horizontal tab */ -static void Ctrl_HT( Framebuffer *fb, Dispatcher *dispatch __attribute((unused)) ) +static void HT_n( Framebuffer *fb, size_t count ) { - int col = fb->ds.get_next_tab(); + int col = fb->ds.get_next_tab( count ); if ( col == -1 ) { /* no tabs, go to end of line */ col = fb->ds.get_width() - 1; } @@ -216,8 +216,27 @@ static void Ctrl_HT( Framebuffer *fb, Dispatcher *dispatch __attribute((unused)) fb->ds.next_print_will_wrap = wrap_state_save; } +static void Ctrl_HT( Framebuffer *fb, Dispatcher *dispatch __attribute((unused)) ) +{ + HT_n( fb, 1 ); +} static Function func_Ctrl_HT( CONTROL, "\x09", Ctrl_HT, false ); +static void CSI_CxT( Framebuffer *fb, Dispatcher *dispatch ) +{ + int param = dispatch->getparam( 0, 1 ); + if ( dispatch->get_dispatch_chars()[ 0 ] == 'Z' ) { + param = -param; + } + if ( param == 0 ) { + return; + } + HT_n( fb, param ); +} + +static Function func_CSI_CHT( CSI, "I", CSI_CxT, false ); +static Function func_CSI_CBT( CSI, "Z", CSI_CxT, false ); + /* horizontal tab set */ static void Ctrl_HTS( Framebuffer *fb, Dispatcher *dispatch __attribute((unused)) ) { diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am index 4d3e2e2..28c16dc 100644 --- a/src/tests/Makefile.am +++ b/src/tests/Makefile.am @@ -33,8 +33,7 @@ check_PROGRAMS = ocb-aes encrypt-decrypt base64 TESTS = ocb-aes encrypt-decrypt base64 $(displaytests) XFAIL_TESTS = \ e2e-failure.test \ - emulation-attributes-256color8.test \ - emulation-back-tab.test + emulation-attributes-256color8.test base64_vector.cc: $(srcdir)/genbase64.pl $(AM_V_GEN)echo '#include "base64_vector.h"' > base64_vector.cc || rm base64_vector.cc diff --git a/src/tests/emulation-back-tab.test b/src/tests/emulation-back-tab.test index f407415..7c45901 100755 --- a/src/tests/emulation-back-tab.test +++ b/src/tests/emulation-back-tab.test @@ -27,17 +27,29 @@ fi baseline() { printf 'hello, wurld\033[Zo\n' + printf 'hello, wurld\033[2Zo\n' + printf 'hello, wurld\033[99Z9\n' + printf 'hello, wurld\033[It\n' + printf '\033[99I#\n' } post() { - if grep -q 'hello, world' $(basename $0).d/baseline.capture; then - exit 0 - fi + # Basic previously-failing case. if grep -q 'hello, wurldo' $(basename $0).d/baseline.capture; then exit 1 fi - exit 99 + if ! grep -q 'hello, world' $(basename $0).d/baseline.capture; then + exit 99 + fi + # New test cases for new code. + if ! grep -q 'oello, wurld' $(basename $0).d/baseline.capture || + ! grep -q '9ello, wurld' $(basename $0).d/baseline.capture || + ! grep -q 'hello, wurld t' $(basename $0).d/baseline.capture || + ! grep -E -q '^ {79}#$' $(basename $0).d/baseline.capture; then + exit 1 + fi + exit 0 } case $1 in