From 2f0a94cb65a734ea1478691bb90c66c680770b59 Mon Sep 17 00:00:00 2001 From: John Hood Date: Sun, 7 Jun 2015 04:44:21 -0400 Subject: [PATCH 1/2] 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 | 9 +++++++ src/frontend/mosh-client.cc | 6 ++++- src/frontend/stmclient.h | 5 +++- src/frontend/terminaloverlay.cc | 48 +++++++++++++++++++++------------ src/frontend/terminaloverlay.h | 5 +++- 5 files changed, 53 insertions(+), 20 deletions(-) diff --git a/scripts/mosh b/scripts/mosh index 7a0b3ef..e02a2f5 100755 --- a/scripts/mosh +++ b/scripts/mosh @@ -46,6 +46,8 @@ my $server = 'mosh-server'; my $predict = undef; +my $overwrite = 0; + my $port_request = undef; my $ssh = 'ssh'; @@ -67,6 +69,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 + -p NUM --port=NUM server-side UDP port --ssh=COMMAND ssh command to run when setting up session @@ -126,6 +130,7 @@ sub ip_and_sockaddr { GetOptions( 'client=s' => \$client, 'server=s' => \$server, 'predict=s' => \$predict, + 'overwrite|o!' => \$overwrite, 'port=i' => \$port_request, 'a' => sub { $predict = 'always' }, 'n' => sub { $predict = 'never' }, @@ -148,6 +153,10 @@ if ( defined $predict ) { predict_check( $predict, 0 ); } +if ( $overwrite ) { + $ENV{ "MOSH_PREDICTION_OVERWRITE" } = "yes"; +} + if ( defined $port_request ) { if ( $port_request =~ m{^[0-9]+$} and $port_request >= 0 diff --git a/src/frontend/mosh-client.cc b/src/frontend/mosh-client.cc index 2273854..fb470b7 100644 --- a/src/frontend/mosh-client.cc +++ b/src/frontend/mosh-client.cc @@ -126,6 +126,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" ); @@ -141,7 +145,7 @@ int main( int argc, char *argv[] ) set_native_locale(); try { - STMClient client( ip, port, key, predict_mode ); + STMClient client( ip, port, key, predict_mode, predict_overwrite ); client.init(); try { diff --git a/src/frontend/stmclient.h b/src/frontend/stmclient.h index d939dcf..7bdacb4 100644 --- a/src/frontend/stmclient.h +++ b/src/frontend/stmclient.h @@ -75,7 +75,7 @@ class STMClient { } public: - STMClient( const char *s_ip, int s_port, const char *s_key, const char *predict_mode ) + STMClient( const char *s_ip, int s_port, const char *s_key, const char *predict_mode, const char *predict_overwrite ) : ip( s_ip ), port( s_port ), key( s_key ), saved_termios(), raw_termios(), window_size(), @@ -103,6 +103,9 @@ class STMClient { 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 0d0cbcb..9538368 100644 --- a/src/frontend/terminaloverlay.cc +++ b/src/frontend/terminaloverlay.cc @@ -662,32 +662,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 ) ); + 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 ]; + + 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; + 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; } } } @@ -710,7 +723,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 0fd0c85..2c2c985 100644 --- a/src/frontend/terminaloverlay.h +++ b/src/frontend/terminaloverlay.h @@ -251,6 +251,7 @@ namespace Overlay { private: DisplayPreference display_preference; + bool predict_overwrite; bool active( void ) const; @@ -261,6 +262,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 ); @@ -291,7 +293,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 ) { } }; From ac2ac8b59aa9451821187bf1671c5c75eeec04fc Mon Sep 17 00:00:00 2001 From: John Hood Date: Wed, 2 Aug 2017 21:29:20 -0400 Subject: [PATCH 2/2] Rename and document --predict-overwrite. --- man/mosh-client.1 | 32 +++++++++++++++++++++++++ man/mosh.1 | 59 +++++++++++++++++++++++++++++++++++++++++++++++ scripts/mosh | 4 ++-- 3 files changed, 93 insertions(+), 2 deletions(-) diff --git a/man/mosh-client.1 b/man/mosh-client.1 index 89a37e1..add384b 100644 --- a/man/mosh-client.1 +++ b/man/mosh-client.1 @@ -49,6 +49,38 @@ directly. With the \-c option, \fBmosh-client\fP instead prints the number of colors of the terminal given by the TERM environment variable. +The \-v option will print some debugging information on standard +error. More instances of this flag will result in more debugging +information. If standard error is not redirected from the terminal, +the display will be corrupted and quickly become unusable. + +.SH ENVIRONMENT VARIABLES + +.TP +.B MOSH_KEY +This variable must be set, and must contain a Base64-encoded cryptographic key from +.BR mosh-server (1). + +.TP +.B MOSH_ESCAPE_KEY +See +.BR mosh (1). + +.TP +.B MOSH_PREDICTION_DISPLAY +Controls local echo as described in +.BR mosh (1). + +.TP +.B MOSH_PREDICTION_OVERWRITE +Controls local echo insert/overwrite as described in +.BR mosh (1). + +.TP +.B MOSH_TITLE_NOPREFIX +See +.BR mosh (1). + .SH SEE ALSO .BR mosh (1), .BR mosh-server (1). diff --git a/man/mosh.1 b/man/mosh.1 index 0292ab0..9c5646f 100644 --- a/man/mosh.1 +++ b/man/mosh.1 @@ -121,8 +121,67 @@ Synonym for \-\-predict=always Synonym for \-\-predict=never .TP + .B \-p \fINUM\fP, \-\-port=\fINUM\fP Use a particular server-side UDP port, for example, if this is the + +.B \-\-predict\-overwrite\fP +When prediction is enabled, do not insert speculative local echo +before existing text, but overwrite it instead. + +The MOSH_PREDICTION_OVERWRITE environment variable also enables this +if its value is 'yes'. + +.TP +.B \-o +Synonym for \-\-predict\-overwrite + +.TP +.B \-\-family=inet +Only use IPv4 for the SSH connection and Mosh session. + +.TP +.B \-\-family=inet6 +Only use IPv6 for the SSH connection and Mosh session. This and the +following modes require Perl's IO::Socket::IP or IO::Socket::INET6 +modules. + +.TP +.B \-\-family=auto +Autodetect IPv4 or IPv6 for hosts that only have addresses +in a single family. Hosts with both IPv4 and IPv6 addresses will +raise an error, and require re-invocation of \fBmosh\fP with another +\fB\-\-family\fP option. + +.TP +.B \-\-family=all +Choose an address from all available IPv4 or IPv6 address, even for +dual-stack hosts. This is the most convenient option, but requires +dual-stack connectivity, and Mosh 1.2.5 or later on the server, when +roaming with dual-stack servers. + +.TP +.B \-\-family=prefer-inet +Similar to \fB\-\-family=all\fP, but attempt connects to the IPv4 +addresses first. This is the default. + +.TP +.B \-\-family=prefer-inet6 +Similar to \fB\-\-family=all\fP, but attempt connects to the IPv6 +addresses first. + +.TP +.B \-4 +Synonym for \-\-family=inet + +.TP +.B \-6 +Synonym for \-\-family=inet6 + +.TP +.B \-p \fIPORT\fP[:\fIPORT2\fP], \-\-port=\fIPORT\fP[:\fIPORT2\fP] +Use a particular server-side UDP port or port range, +for example, if this is the only port that is forwarded through a firewall to the server. Otherwise, \fBmosh\fP will choose a port between 60000 and 61000. diff --git a/scripts/mosh b/scripts/mosh index e02a2f5..02ef11c 100755 --- a/scripts/mosh +++ b/scripts/mosh @@ -69,7 +69,7 @@ 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 +-o --predict-overwrite prediction overwrites instead of inserting -p NUM --port=NUM server-side UDP port @@ -130,7 +130,7 @@ sub ip_and_sockaddr { GetOptions( 'client=s' => \$client, 'server=s' => \$server, 'predict=s' => \$predict, - 'overwrite|o!' => \$overwrite, + 'predict-overwrite|o!' => \$overwrite, 'port=i' => \$port_request, 'a' => sub { $predict = 'always' }, 'n' => sub { $predict = 'never' },