From 8aac3cc92724c2787d885ca6cfc0855c64e7afe7 Mon Sep 17 00:00:00 2001 From: John Hood Date: Sun, 7 Jun 2015 04:44:21 -0400 Subject: [PATCH] Allow non-inserting prediction. This may be useful for users who find prediction's activity right of the cursor distracting. Prediction underscoring is still a little weird sometimes, it replays a history of known/unknown changes as acks come in from the server. --- scripts/mosh.pl | 8 ++++++ src/frontend/mosh-client.cc | 6 ++++- src/frontend/stmclient.h | 5 +++- src/frontend/terminaloverlay.cc | 48 +++++++++++++++++++++------------ src/frontend/terminaloverlay.h | 5 +++- 5 files changed, 52 insertions(+), 20 deletions(-) diff --git a/scripts/mosh.pl b/scripts/mosh.pl index e6c890e..044994d 100755 --- a/scripts/mosh.pl +++ b/scripts/mosh.pl @@ -65,6 +65,8 @@ my $server = 'mosh-server'; my $predict = undef; +my $overwrite = 0; + my $bind_ip = undef; my $use_remote_ip = 'proxy'; @@ -97,6 +99,8 @@ qq{Usage: $0 [options] [--] [user@]host [command...] -n --predict=never never use local echo --predict=experimental aggressively echo even when incorrect +-o --overwrite prediction overwrites instead of inserting + -4 --family=inet use IPv4 only -6 --family=inet6 use IPv6 only --family=auto autodetect network type for single-family hosts only @@ -150,6 +154,7 @@ sub predict_check { GetOptions( 'client=s' => \$client, 'server=s' => \$server, 'predict=s' => \$predict, + 'overwrite|o!' => \$overwrite, 'port=s' => \$port_request, 'a' => sub { $predict = 'always' }, 'n' => sub { $predict = 'never' }, @@ -200,6 +205,9 @@ if (!$have_ipv6) { # Force IPv4. $family = "inet"; } +if ( $overwrite ) { + $ENV{ "MOSH_PREDICTION_OVERWRITE" } = "yes"; +} if ( defined $port_request ) { if ( $port_request =~ m{^(\d+)(:(\d+))?$} ) { diff --git a/src/frontend/mosh-client.cc b/src/frontend/mosh-client.cc index 71ee9d8..a84ce1d 100644 --- a/src/frontend/mosh-client.cc +++ b/src/frontend/mosh-client.cc @@ -175,6 +175,10 @@ int main( int argc, char *argv[] ) char *predict_mode = getenv( "MOSH_PREDICTION_DISPLAY" ); /* can be NULL */ + /* Read prediction insertion preference */ + char *predict_overwrite = getenv( "MOSH_PREDICTION_OVERWRITE" ); + /* can be NULL */ + char *key = strdup( env_key ); if ( key == NULL ) { perror( "strdup" ); @@ -191,7 +195,7 @@ int main( int argc, char *argv[] ) bool success = false; try { - STMClient client( ip, desired_port, key, predict_mode, verbose ); + STMClient client( ip, desired_port, key, predict_mode, verbose, predict_overwrite ); client.init(); try { diff --git a/src/frontend/stmclient.h b/src/frontend/stmclient.h index 7703bbb..4d98b53 100644 --- a/src/frontend/stmclient.h +++ b/src/frontend/stmclient.h @@ -84,7 +84,7 @@ private: void resume( void ); /* restore state after SIGCONT */ public: - STMClient( const char *s_ip, const char *s_port, const char *s_key, const char *predict_mode, unsigned int s_verbose ) + STMClient( const char *s_ip, const char *s_port, const char *s_key, const char *predict_mode, unsigned int s_verbose, const char *predict_overwrite ) : ip( s_ip ? s_ip : "" ), port( s_port ? s_port : "" ), key( s_key ? s_key : "" ), escape_key( 0x1E ), escape_pass_key( '^' ), escape_pass_key2( '^' ), @@ -117,6 +117,9 @@ public: exit( 1 ); } } + if ( predict_overwrite && !strcmp( predict_overwrite, "yes" ) ) { + overlays.get_prediction_engine().set_predict_overwrite( true ); + } } void init( void ); diff --git a/src/frontend/terminaloverlay.cc b/src/frontend/terminaloverlay.cc index 26d81cb..f5cb29c 100644 --- a/src/frontend/terminaloverlay.cc +++ b/src/frontend/terminaloverlay.cc @@ -698,32 +698,45 @@ void PredictionEngine::new_user_byte( char the_byte, const Framebuffer &fb ) cursor().col--; cursor().expire( local_frame_sent + 1, now ); - for ( int i = cursor().col; i < fb.ds.get_width(); i++ ) { - ConditionalOverlayCell &cell = the_row.overlay_cells[ i ]; - + if ( predict_overwrite ) { + ConditionalOverlayCell &cell = the_row.overlay_cells[ cursor().col ]; cell.reset_with_orig(); cell.active = true; cell.tentative_until_epoch = prediction_epoch; cell.expire( local_frame_sent + 1, now ); - cell.original_contents.push_back( *fb.get_cell( cursor().row, i ) ); - - if ( i + 2 < fb.ds.get_width() ) { - ConditionalOverlayCell &next_cell = the_row.overlay_cells[ i + 1 ]; - const Cell *next_cell_actual = fb.get_cell( cursor().row, i + 1 ); + const Cell orig_cell = *fb.get_cell(); + cell.original_contents.push_back( orig_cell ); + cell.replacement = orig_cell; + cell.replacement.clear(); + cell.replacement.append(' '); + } else { + for ( int i = cursor().col; i < fb.ds.get_width(); i++ ) { + ConditionalOverlayCell &cell = the_row.overlay_cells[ i ]; - if ( next_cell.active ) { - if ( next_cell.unknown ) { - cell.unknown = true; + cell.reset_with_orig(); + cell.active = true; + cell.tentative_until_epoch = prediction_epoch; + cell.expire( local_frame_sent + 1, now ); + cell.original_contents.push_back( *fb.get_cell( cursor().row, i ) ); + + if ( i + 2 < fb.ds.get_width() ) { + ConditionalOverlayCell &next_cell = the_row.overlay_cells[ i + 1 ]; + const Cell *next_cell_actual = fb.get_cell( cursor().row, i + 1 ); + + if ( next_cell.active ) { + if ( next_cell.unknown ) { + cell.unknown = true; + } else { + cell.unknown = false; + cell.replacement = next_cell.replacement; + } } else { cell.unknown = false; - cell.replacement = next_cell.replacement; + cell.replacement = *next_cell_actual; } } else { - cell.unknown = false; - cell.replacement = *next_cell_actual; + cell.unknown = true; } - } else { - cell.unknown = true; } } } @@ -746,7 +759,8 @@ void PredictionEngine::new_user_byte( char the_byte, const Framebuffer &fb ) } /* do the insert */ - for ( int i = fb.ds.get_width() - 1; i > cursor().col; i-- ) { + int rightmost_column = predict_overwrite ? cursor().col + 1 : fb.ds.get_width() - 1; + for ( int i = rightmost_column; i > cursor().col; i-- ) { ConditionalOverlayCell &cell = the_row.overlay_cells[ i ]; cell.reset_with_orig(); cell.active = true; diff --git a/src/frontend/terminaloverlay.h b/src/frontend/terminaloverlay.h index ecd16f7..a76fb20 100644 --- a/src/frontend/terminaloverlay.h +++ b/src/frontend/terminaloverlay.h @@ -262,6 +262,7 @@ namespace Overlay { private: DisplayPreference display_preference; + bool predict_overwrite; bool active( void ) const; @@ -272,6 +273,7 @@ namespace Overlay { public: void set_display_preference( DisplayPreference s_pref ) { display_preference = s_pref; } + void set_predict_overwrite( bool overwrite ) { predict_overwrite = overwrite; } void apply( Framebuffer &fb ) const; void new_user_byte( char the_byte, const Framebuffer &fb ); @@ -302,7 +304,8 @@ namespace Overlay { last_quick_confirmation( 0 ), send_interval( 250 ), last_height( 0 ), last_width( 0 ), - display_preference( Adaptive ) + display_preference( Adaptive ), + predict_overwrite( false ) { } };