diff options
Diffstat (limited to 'src/frontend/terminaloverlay.cc')
-rw-r--r-- | src/frontend/terminaloverlay.cc | 794 |
1 files changed, 377 insertions, 417 deletions
diff --git a/src/frontend/terminaloverlay.cc b/src/frontend/terminaloverlay.cc index d8a3872..38f71b2 100644 --- a/src/frontend/terminaloverlay.cc +++ b/src/frontend/terminaloverlay.cc @@ -40,11 +40,9 @@ using namespace Overlay; -void ConditionalOverlayCell::apply( Framebuffer &fb, uint64_t confirmed_epoch, int row, bool flag ) const +void ConditionalOverlayCell::apply( Framebuffer& fb, uint64_t confirmed_epoch, int row, bool flag ) const { - if ( (!active) - || (row >= fb.ds.get_height()) - || (col >= fb.ds.get_width()) ) { + if ( ( !active ) || ( row >= fb.ds.get_height() ) || ( col >= fb.ds.get_width() ) ) { return; } @@ -58,33 +56,33 @@ void ConditionalOverlayCell::apply( Framebuffer &fb, uint64_t confirmed_epoch, i if ( unknown ) { if ( flag && ( col != fb.ds.get_width() - 1 ) ) { - fb.get_mutable_cell( row, col )->get_renditions().set_attribute(Renditions::underlined, true); + fb.get_mutable_cell( row, col )->get_renditions().set_attribute( Renditions::underlined, true ); } return; } if ( *fb.get_cell( row, col ) != replacement ) { - *(fb.get_mutable_cell( row, col )) = replacement; + *( fb.get_mutable_cell( row, col ) ) = replacement; if ( flag ) { fb.get_mutable_cell( row, col )->get_renditions().set_attribute( Renditions::underlined, true ); } } } -Validity ConditionalOverlayCell::get_validity( const Framebuffer &fb, int row, - uint64_t early_ack __attribute__((unused)), - uint64_t late_ack ) const +Validity ConditionalOverlayCell::get_validity( const Framebuffer& fb, + int row, + uint64_t early_ack __attribute__( ( unused ) ), + uint64_t late_ack ) const { if ( !active ) { return Inactive; } - if ( (row >= fb.ds.get_height()) - || (col >= fb.ds.get_width()) ) { + if ( ( row >= fb.ds.get_height() ) || ( col >= fb.ds.get_width() ) ) { return IncorrectOrExpired; } - const Cell ¤t = *( fb.get_cell( row, col ) ); + const Cell& current = *( fb.get_cell( row, col ) ); /* see if it hasn't been updated yet */ if ( late_ack < expiration_frame ) { @@ -103,7 +101,7 @@ Validity ConditionalOverlayCell::get_validity( const Framebuffer &fb, int row, std::vector<Cell>::const_iterator it = original_contents.begin(); for ( ; it != original_contents.end(); it++ ) { if ( it->contents_match( replacement ) ) - break; + break; } if ( it == original_contents.end() ) { return Correct; @@ -113,23 +111,21 @@ Validity ConditionalOverlayCell::get_validity( const Framebuffer &fb, int row, return IncorrectOrExpired; } -Validity ConditionalCursorMove::get_validity( const Framebuffer &fb, - uint64_t early_ack __attribute((unused)), - uint64_t late_ack ) const +Validity ConditionalCursorMove::get_validity( const Framebuffer& fb, + uint64_t early_ack __attribute( ( unused ) ), + uint64_t late_ack ) const { if ( !active ) { return Inactive; } - if ( (row >= fb.ds.get_height()) - || (col >= fb.ds.get_width()) ) { + if ( ( row >= fb.ds.get_height() ) || ( col >= fb.ds.get_width() ) ) { // fprintf( stderr, "Crazy cursor (%d,%d)!\n", row, col ); return IncorrectOrExpired; } if ( late_ack >= expiration_frame ) { - if ( (fb.ds.get_cursor_col() == col) - && (fb.ds.get_cursor_row() == row) ) { + if ( ( fb.ds.get_cursor_col() == col ) && ( fb.ds.get_cursor_row() == row ) ) { return Correct; } return IncorrectOrExpired; @@ -138,7 +134,7 @@ Validity ConditionalCursorMove::get_validity( const Framebuffer &fb, return Pending; } -void ConditionalCursorMove::apply( Framebuffer &fb, uint64_t confirmed_epoch ) const +void ConditionalCursorMove::apply( Framebuffer& fb, uint64_t confirmed_epoch ) const { if ( !active ) { return; @@ -157,29 +153,24 @@ void ConditionalCursorMove::apply( Framebuffer &fb, uint64_t confirmed_epoch ) c } NotificationEngine::NotificationEngine() - : last_word_from_server( timestamp() ), - last_acked_state( timestamp() ), - escape_key_string(), - message(), - message_is_network_error( false ), - message_expiration( -1 ), - show_quit_keystroke( true ) + : last_word_from_server( timestamp() ), last_acked_state( timestamp() ), escape_key_string(), message(), + message_is_network_error( false ), message_expiration( -1 ), show_quit_keystroke( true ) {} -static std::string human_readable_duration( int num_seconds, const std::string &seconds_abbr ) { - char tmp[ 128 ]; +static std::string human_readable_duration( int num_seconds, const std::string& seconds_abbr ) +{ + char tmp[128]; if ( num_seconds < 60 ) { snprintf( tmp, 128, "%d %s", num_seconds, seconds_abbr.c_str() ); } else if ( num_seconds < 3600 ) { snprintf( tmp, 128, "%d:%02d", num_seconds / 60, num_seconds % 60 ); } else { - snprintf( tmp, 128, "%d:%02d:%02d", num_seconds / 3600, - (num_seconds / 60) % 60, num_seconds % 60 ); + snprintf( tmp, 128, "%d:%02d:%02d", num_seconds / 3600, ( num_seconds / 60 ) % 60, num_seconds % 60 ); } return tmp; } -void NotificationEngine::apply( Framebuffer &fb ) const +void NotificationEngine::apply( Framebuffer& fb ) const { uint64_t now = timestamp(); @@ -204,55 +195,60 @@ void NotificationEngine::apply( Framebuffer &fb ) const notification_bar.append( 0x20 ); for ( int i = 0; i < fb.ds.get_width(); i++ ) { - *(fb.get_mutable_cell( 0, i )) = notification_bar; + *( fb.get_mutable_cell( 0, i ) ) = notification_bar; } /* write message */ - wchar_t tmp[ 128 ]; + wchar_t tmp[128]; /* We want to prefer the "last contact" message if we simply haven't heard from the server in a while, but print the "last reply" message if the problem is uplink-only. */ - double since_heard = (double)(now - last_word_from_server) / 1000.0; - double since_ack = (double)(now - last_acked_state) / 1000.0; + double since_heard = (double)( now - last_word_from_server ) / 1000.0; + double since_ack = (double)( now - last_acked_state ) / 1000.0; const char server_message[] = "contact"; const char reply_message[] = "reply"; double time_elapsed = since_heard; - const char *explanation = server_message; + const char* explanation = server_message; - if ( reply_late( now ) && (!server_late( now )) ) { + if ( reply_late( now ) && ( !server_late( now ) ) ) { time_elapsed = since_ack; explanation = reply_message; } const static char blank[] = ""; - const char *keystroke_str = show_quit_keystroke ? escape_key_string.c_str() : blank; + const char* keystroke_str = show_quit_keystroke ? escape_key_string.c_str() : blank; - if ( message.empty() && (!time_expired) ) { + if ( message.empty() && ( !time_expired ) ) { return; } if ( message.empty() && time_expired ) { - swprintf( tmp, 128, L"mosh: Last %s %s ago.%s", explanation, - human_readable_duration( static_cast<int>( time_elapsed ), - "seconds" ).c_str(), - keystroke_str ); - } else if ( (!message.empty()) && (!time_expired) ) { + swprintf( tmp, + 128, + L"mosh: Last %s %s ago.%s", + explanation, + human_readable_duration( static_cast<int>( time_elapsed ), "seconds" ).c_str(), + keystroke_str ); + } else if ( ( !message.empty() ) && ( !time_expired ) ) { swprintf( tmp, 128, L"mosh: %ls%s", message.c_str(), keystroke_str ); } else { - swprintf( tmp, 128, L"mosh: %ls (%s without %s.)%s", message.c_str(), - human_readable_duration( static_cast<int>( time_elapsed ), - "s" ).c_str(), - explanation, keystroke_str ); + swprintf( tmp, + 128, + L"mosh: %ls (%s without %s.)%s", + message.c_str(), + human_readable_duration( static_cast<int>( time_elapsed ), "s" ).c_str(), + explanation, + keystroke_str ); } std::wstring string_to_draw( tmp ); int overlay_col = 0; - Cell *combining_cell = fb.get_mutable_cell( 0, 0 ); + Cell* combining_cell = fb.get_mutable_cell( 0, 0 ); /* We unfortunately duplicate the terminal's logic for how to render a Unicode sequence into graphemes */ for ( std::wstring::const_iterator i = string_to_draw.begin(); i != string_to_draw.end(); i++ ) { @@ -262,42 +258,42 @@ void NotificationEngine::apply( Framebuffer &fb ) const wchar_t ch = *i; int chwidth = ch == L'\0' ? -1 : wcwidth( ch ); - Cell *this_cell = 0; + Cell* this_cell = 0; switch ( chwidth ) { - case 1: /* normal character */ - case 2: /* wide character */ - this_cell = fb.get_mutable_cell( 0, overlay_col ); - fb.reset_cell( this_cell ); - this_cell->get_renditions().set_attribute(Renditions::bold, true); - this_cell->get_renditions().set_foreground_color( 7 ); - this_cell->get_renditions().set_background_color( 4 ); - - this_cell->append( ch ); - this_cell->set_wide( chwidth == 2 ); - combining_cell = this_cell; - - overlay_col += chwidth; - break; - case 0: /* combining character */ - if ( !combining_cell ) { - break; - } - - if ( combining_cell->empty() ) { - assert( !combining_cell->get_wide() ); - combining_cell->set_fallback( true ); - overlay_col++; - } - - if ( !combining_cell->full() ) { - combining_cell->append( ch ); - } - break; - case -1: /* unprintable character */ - break; - default: - assert( !"unexpected character width from wcwidth()" ); + case 1: /* normal character */ + case 2: /* wide character */ + this_cell = fb.get_mutable_cell( 0, overlay_col ); + fb.reset_cell( this_cell ); + this_cell->get_renditions().set_attribute( Renditions::bold, true ); + this_cell->get_renditions().set_foreground_color( 7 ); + this_cell->get_renditions().set_background_color( 4 ); + + this_cell->append( ch ); + this_cell->set_wide( chwidth == 2 ); + combining_cell = this_cell; + + overlay_col += chwidth; + break; + case 0: /* combining character */ + if ( !combining_cell ) { + break; + } + + if ( combining_cell->empty() ) { + assert( !combining_cell->get_wide() ); + combining_cell->set_fallback( true ); + overlay_col++; + } + + if ( !combining_cell->full() ) { + combining_cell->append( ch ); + } + break; + case -1: /* unprintable character */ + break; + default: + assert( !"unexpected character width from wcwidth()" ); } } } @@ -306,7 +302,7 @@ void NotificationEngine::adjust_message( void ) { if ( timestamp() >= message_expiration ) { message.clear(); - } + } } int NotificationEngine::wait_time( void ) const @@ -330,7 +326,7 @@ int NotificationEngine::wait_time( void ) const return next_expiry; } -void OverlayManager::apply( Framebuffer &fb ) +void OverlayManager::apply( Framebuffer& fb ) { predictions.cull( fb ); predictions.apply( fb ); @@ -339,67 +335,54 @@ void OverlayManager::apply( Framebuffer &fb ) title.apply( fb ); } -void TitleEngine::set_prefix( const std::wstring &s ) +void TitleEngine::set_prefix( const std::wstring& s ) { prefix = Terminal::Framebuffer::title_type( s.begin(), s.end() ); } -void ConditionalOverlayRow::apply( Framebuffer &fb, uint64_t confirmed_epoch, bool flag ) const +void ConditionalOverlayRow::apply( Framebuffer& fb, uint64_t confirmed_epoch, bool flag ) const { - for ( overlay_cells_type::const_iterator it = overlay_cells.begin(); - it != overlay_cells.end(); - it++ ) { + for ( overlay_cells_type::const_iterator it = overlay_cells.begin(); it != overlay_cells.end(); it++ ) { it->apply( fb, confirmed_epoch, row_num, flag ); } } -void PredictionEngine::apply( Framebuffer &fb ) const +void PredictionEngine::apply( Framebuffer& fb ) const { - if ( (display_preference == Never) || !( srtt_trigger - || glitch_trigger - || (display_preference == Always) - || (display_preference == Experimental) ) ){ + if ( ( display_preference == Never ) + || !( srtt_trigger || glitch_trigger || ( display_preference == Always ) + || ( display_preference == Experimental ) ) ) { return; } - for ( cursors_type::const_iterator it = cursors.begin(); - it != cursors.end(); - it++ ) { + for ( cursors_type::const_iterator it = cursors.begin(); it != cursors.end(); it++ ) { it->apply( fb, confirmed_epoch ); } - for ( overlays_type::const_iterator it = overlays.begin(); - it != overlays.end(); - it++ ) { + for ( overlays_type::const_iterator it = overlays.begin(); it != overlays.end(); it++ ) { it->apply( fb, confirmed_epoch, flagging ); } } -void PredictionEngine::kill_epoch( uint64_t epoch, const Framebuffer &fb ) +void PredictionEngine::kill_epoch( uint64_t epoch, const Framebuffer& fb ) { - for( cursors_type::iterator it = cursors.begin(); it != cursors.end(); ) { + for ( cursors_type::iterator it = cursors.begin(); it != cursors.end(); ) { cursors_type::iterator it_next = it; it_next++; - if ( it->tentative( epoch - 1 )) { + if ( it->tentative( epoch - 1 ) ) { cursors.erase( it ); } it = it_next; } - cursors.push_back( ConditionalCursorMove( local_frame_sent + 1, - fb.ds.get_cursor_row(), - fb.ds.get_cursor_col(), - prediction_epoch ) ); + cursors.push_back( ConditionalCursorMove( + local_frame_sent + 1, fb.ds.get_cursor_row(), fb.ds.get_cursor_col(), prediction_epoch ) ); cursor().active = true; - for ( overlays_type::iterator i = overlays.begin(); - i != overlays.end(); - i++ ) { - for ( overlay_cells_type::iterator j = i->overlay_cells.begin(); - j != i->overlay_cells.end(); - j++ ) { + for ( overlays_type::iterator i = overlays.begin(); i != overlays.end(); i++ ) { + for ( overlay_cells_type::iterator j = i->overlay_cells.begin(); j != i->overlay_cells.end(); j++ ) { if ( j->tentative( epoch - 1 ) ) { - j->reset(); + j->reset(); } } } @@ -416,35 +399,30 @@ void PredictionEngine::reset( void ) // fprintf( stderr, "RESETTING\n" ); } -void PredictionEngine::init_cursor( const Framebuffer &fb ) +void PredictionEngine::init_cursor( const Framebuffer& fb ) { if ( cursors.empty() ) { /* initialize new cursor prediction */ - - cursors.push_back( ConditionalCursorMove( local_frame_sent + 1, - fb.ds.get_cursor_row(), - fb.ds.get_cursor_col(), - prediction_epoch ) ); + + cursors.push_back( ConditionalCursorMove( + local_frame_sent + 1, fb.ds.get_cursor_row(), fb.ds.get_cursor_col(), prediction_epoch ) ); cursor().active = true; } else if ( cursor().tentative_until_epoch != prediction_epoch ) { - cursors.push_back( ConditionalCursorMove( local_frame_sent + 1, - cursor().row, - cursor().col, - prediction_epoch ) ); + cursors.push_back( + ConditionalCursorMove( local_frame_sent + 1, cursor().row, cursor().col, prediction_epoch ) ); cursor().active = true; } } -void PredictionEngine::cull( const Framebuffer &fb ) +void PredictionEngine::cull( const Framebuffer& fb ) { if ( display_preference == Never ) { return; } - if ( (last_height != fb.ds.get_height()) - || (last_width != fb.ds.get_width()) ) { + if ( ( last_height != fb.ds.get_height() ) || ( last_width != fb.ds.get_width() ) ) { last_height = fb.ds.get_height(); last_width = fb.ds.get_width(); reset(); @@ -455,9 +433,8 @@ void PredictionEngine::cull( const Framebuffer &fb ) /* control srtt_trigger with hysteresis */ if ( send_interval > SRTT_TRIGGER_HIGH ) { srtt_trigger = true; - } else if ( srtt_trigger && - (send_interval <= SRTT_TRIGGER_LOW) /* 20 ms is current minimum value */ - && (!active()) ) { /* only turn off when no predictions being shown */ + } else if ( srtt_trigger && ( send_interval <= SRTT_TRIGGER_LOW ) /* 20 ms is current minimum value */ + && ( !active() ) ) { /* only turn off when no predictions being shown */ srtt_trigger = false; } @@ -479,113 +456,107 @@ void PredictionEngine::cull( const Framebuffer &fb ) while ( i != overlays.end() ) { overlays_type::iterator inext = i; inext++; - if ( (i->row_num < 0) || (i->row_num >= fb.ds.get_height()) ) { + if ( ( i->row_num < 0 ) || ( i->row_num >= fb.ds.get_height() ) ) { overlays.erase( i ); i = inext; continue; } - for ( overlay_cells_type::iterator j = i->overlay_cells.begin(); - j != i->overlay_cells.end(); - j++ ) { - switch ( j->get_validity( fb, i->row_num, - local_frame_acked, local_frame_late_acked ) ) { - case IncorrectOrExpired: - if ( j->tentative( confirmed_epoch ) ) { - - /* - fprintf( stderr, "Bad tentative prediction in row %d, col %d (think %lc, actually %lc)\n", - i->row_num, j->col, - j->replacement.debug_contents(), - fb.get_cell( i->row_num, j->col )->debug_contents() - ); - */ - - if ( display_preference == Experimental ) { - j->reset(); - } else { - kill_epoch( j->tentative_until_epoch, fb ); - } - /* - if ( j->display_time != uint64_t(-1) ) { - fprintf( stderr, "TIMING %ld - %ld (TENT)\n", time(NULL), now - j->display_time ); - } - */ - } else { - /* - fprintf( stderr, "[%d=>%d] Killing prediction in row %d, col %d (think %lc, actually %lc)\n", - (int)local_frame_acked, (int)j->expiration_frame, - i->row_num, j->col, - j->replacement.debug_contents(), - fb.get_cell( i->row_num, j->col )->debug_contents() ); - */ - /* - if ( j->display_time != uint64_t(-1) ) { - fprintf( stderr, "TIMING %ld - %ld\n", time(NULL), now - j->display_time ); - } - */ - - if ( display_preference == Experimental ) { - j->reset(); - } else { - reset(); - return; - } - } - break; - case Correct: - /* - if ( j->display_time != uint64_t(-1) ) { - fprintf( stderr, "TIMING %ld + %ld\n", now, now - j->display_time ); - } - */ - - if ( j->tentative_until_epoch > confirmed_epoch ) { - confirmed_epoch = j->tentative_until_epoch; - - /* - fprintf( stderr, "%lc in (%d,%d) confirms epoch %lu (predicting in epoch %lu)\n", - j->replacement.debug_contents(), i->row_num, j->col, - confirmed_epoch, prediction_epoch ); - */ - - } - - /* When predictions come in quickly, slowly take away the glitch trigger. */ - if ( now - j->prediction_time < GLITCH_THRESHOLD - && ( glitch_trigger > 0 && now - GLITCH_REPAIR_MININTERVAL >= last_quick_confirmation ) ) { - glitch_trigger--; - last_quick_confirmation = now; - } - - /* match rest of row to the actual renditions */ - { - const Renditions &actual_renditions = fb.get_cell( i->row_num, j->col )->get_renditions(); - for ( overlay_cells_type::iterator k = j; - k != i->overlay_cells.end(); - k++ ) { - k->replacement.get_renditions() = actual_renditions; - } - } - - /* fallthrough */ - case CorrectNoCredit: - j->reset(); - - break; - case Pending: - /* When a prediction takes a long time to be confirmed, we - activate the predictions even if SRTT is low */ - if ( (now - j->prediction_time) >= GLITCH_FLAG_THRESHOLD ) { - glitch_trigger = GLITCH_REPAIR_COUNT * 2; /* display and underline */ - } else if ( ((now - j->prediction_time) >= GLITCH_THRESHOLD) - && (glitch_trigger < GLITCH_REPAIR_COUNT) ) { - glitch_trigger = GLITCH_REPAIR_COUNT; /* just display */ - } - - break; - default: - break; + for ( overlay_cells_type::iterator j = i->overlay_cells.begin(); j != i->overlay_cells.end(); j++ ) { + switch ( j->get_validity( fb, i->row_num, local_frame_acked, local_frame_late_acked ) ) { + case IncorrectOrExpired: + if ( j->tentative( confirmed_epoch ) ) { + + /* + fprintf( stderr, "Bad tentative prediction in row %d, col %d (think %lc, actually %lc)\n", + i->row_num, j->col, + j->replacement.debug_contents(), + fb.get_cell( i->row_num, j->col )->debug_contents() + ); + */ + + if ( display_preference == Experimental ) { + j->reset(); + } else { + kill_epoch( j->tentative_until_epoch, fb ); + } + /* + if ( j->display_time != uint64_t(-1) ) { + fprintf( stderr, "TIMING %ld - %ld (TENT)\n", time(NULL), now - j->display_time ); + } + */ + } else { + /* + fprintf( stderr, "[%d=>%d] Killing prediction in row %d, col %d (think %lc, actually %lc)\n", + (int)local_frame_acked, (int)j->expiration_frame, + i->row_num, j->col, + j->replacement.debug_contents(), + fb.get_cell( i->row_num, j->col )->debug_contents() ); + */ + /* + if ( j->display_time != uint64_t(-1) ) { + fprintf( stderr, "TIMING %ld - %ld\n", time(NULL), now - j->display_time ); + } + */ + + if ( display_preference == Experimental ) { + j->reset(); + } else { + reset(); + return; + } + } + break; + case Correct: + /* + if ( j->display_time != uint64_t(-1) ) { + fprintf( stderr, "TIMING %ld + %ld\n", now, now - j->display_time ); + } + */ + + if ( j->tentative_until_epoch > confirmed_epoch ) { + confirmed_epoch = j->tentative_until_epoch; + + /* + fprintf( stderr, "%lc in (%d,%d) confirms epoch %lu (predicting in epoch %lu)\n", + j->replacement.debug_contents(), i->row_num, j->col, + confirmed_epoch, prediction_epoch ); + */ + } + + /* When predictions come in quickly, slowly take away the glitch trigger. */ + if ( now - j->prediction_time < GLITCH_THRESHOLD + && ( glitch_trigger > 0 && now - GLITCH_REPAIR_MININTERVAL >= last_quick_confirmation ) ) { + glitch_trigger--; + last_quick_confirmation = now; + } + + /* match rest of row to the actual renditions */ + { + const Renditions& actual_renditions = fb.get_cell( i->row_num, j->col )->get_renditions(); + for ( overlay_cells_type::iterator k = j; k != i->overlay_cells.end(); k++ ) { + k->replacement.get_renditions() = actual_renditions; + } + } + + /* fallthrough */ + case CorrectNoCredit: + j->reset(); + + break; + case Pending: + /* When a prediction takes a long time to be confirmed, we + activate the predictions even if SRTT is low */ + if ( ( now - j->prediction_time ) >= GLITCH_FLAG_THRESHOLD ) { + glitch_trigger = GLITCH_REPAIR_COUNT * 2; /* display and underline */ + } else if ( ( ( now - j->prediction_time ) >= GLITCH_THRESHOLD ) + && ( glitch_trigger < GLITCH_REPAIR_COUNT ) ) { + glitch_trigger = GLITCH_REPAIR_COUNT; /* just display */ + } + + break; + default: + break; } } @@ -593,9 +564,8 @@ void PredictionEngine::cull( const Framebuffer &fb ) } /* go through cursor predictions */ - if ( !cursors.empty() - && cursor().get_validity( fb, - local_frame_acked, local_frame_late_acked ) == IncorrectOrExpired ) { + if ( !cursors.empty() + && cursor().get_validity( fb, local_frame_acked, local_frame_late_acked ) == IncorrectOrExpired ) { /* fprintf( stderr, "Sadly, we're predicting (%d,%d) vs. (%d,%d) [tau: %ld, expiration_time=%ld, now=%ld]\n", cursor().row, cursor().col, @@ -615,8 +585,7 @@ void PredictionEngine::cull( const Framebuffer &fb ) /* NB: switching from list to another STL container could break this code. So we don't use the cursors_type typedef. */ - for ( std::list<ConditionalCursorMove>::iterator it = cursors.begin(); - it != cursors.end(); ) { + for ( std::list<ConditionalCursorMove>::iterator it = cursors.begin(); it != cursors.end(); ) { if ( it->get_validity( fb, local_frame_acked, local_frame_late_acked ) != Pending ) { it = cursors.erase( it ); } else { @@ -625,7 +594,7 @@ void PredictionEngine::cull( const Framebuffer &fb ) } } -ConditionalOverlayRow & PredictionEngine::get_or_make_row( int row_num, int num_cols ) +ConditionalOverlayRow& PredictionEngine::get_or_make_row( int row_num, int num_cols ) { overlays_type::iterator it; @@ -643,13 +612,13 @@ ConditionalOverlayRow & PredictionEngine::get_or_make_row( int row_num, int num_ r.overlay_cells.reserve( num_cols ); for ( int i = 0; i < num_cols; i++ ) { r.overlay_cells.push_back( ConditionalOverlayCell( 0, i, prediction_epoch ) ); - assert( r.overlay_cells[ i ].col == i ); + assert( r.overlay_cells[i].col == i ); } overlays.push_back( r ); return overlays.back(); } -void PredictionEngine::new_user_byte( char the_byte, const Framebuffer &fb ) +void PredictionEngine::new_user_byte( char the_byte, const Framebuffer& fb ) { if ( display_preference == Never ) { return; @@ -663,8 +632,7 @@ void PredictionEngine::new_user_byte( char the_byte, const Framebuffer &fb ) uint64_t now = timestamp(); /* translate application-mode cursor control function to ANSI cursor control sequence */ - if ( (last_byte == 0x1b) - && (the_byte == 'O') ) { + if ( ( last_byte == 0x1b ) && ( the_byte == 'O' ) ) { the_byte = '['; } last_byte = the_byte; @@ -672,14 +640,12 @@ void PredictionEngine::new_user_byte( char the_byte, const Framebuffer &fb ) Parser::Actions actions; parser.input( the_byte, actions ); - for ( Parser::Actions::iterator it = actions.begin(); - it != actions.end(); - it++ ) { + for ( Parser::Actions::iterator it = actions.begin(); it != actions.end(); it++ ) { Parser::Action& act = **it; /* fprintf( stderr, "Action: %s (%lc)\n", - act->name().c_str(), act->char_present ? act->ch : L'_' ); + act->name().c_str(), act->char_present ? act->ch : L'_' ); */ const std::type_info& type_act = typeid( act ); @@ -694,174 +660,174 @@ void PredictionEngine::new_user_byte( char the_byte, const Framebuffer &fb ) /* XXX handle wide characters */ if ( ch == 0x7f ) { /* backspace */ - // fprintf( stderr, "Backspace.\n" ); - ConditionalOverlayRow &the_row = get_or_make_row( cursor().row, fb.ds.get_width() ); - - if ( cursor().col > 0 ) { - cursor().col--; - cursor().expire( local_frame_sent + 1, now ); - - 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 ); - 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; - } else { - cell.unknown = false; - cell.replacement = next_cell.replacement; - } - } else { - cell.unknown = false; - cell.replacement = *next_cell_actual; - } - } else { - cell.unknown = true; - } - } - } - } - } else if ( (ch < 0x20) || (wcwidth( ch ) != 1) ) { - /* unknown print */ - become_tentative(); - // fprintf( stderr, "Unknown print 0x%x\n", ch ); + // fprintf( stderr, "Backspace.\n" ); + ConditionalOverlayRow& the_row = get_or_make_row( cursor().row, fb.ds.get_width() ); + + if ( cursor().col > 0 ) { + cursor().col--; + cursor().expire( local_frame_sent + 1, now ); + + 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 ); + 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; + } else { + cell.unknown = false; + cell.replacement = next_cell.replacement; + } + } else { + cell.unknown = false; + cell.replacement = *next_cell_actual; + } + } else { + cell.unknown = true; + } + } + } + } + } else if ( ( ch < 0x20 ) || ( wcwidth( ch ) != 1 ) ) { + /* unknown print */ + become_tentative(); + // fprintf( stderr, "Unknown print 0x%x\n", ch ); } else { - assert( cursor().row >= 0 ); - assert( cursor().col >= 0 ); - assert( cursor().row < fb.ds.get_height() ); - assert( cursor().col < fb.ds.get_width() ); - - ConditionalOverlayRow &the_row = get_or_make_row( cursor().row, fb.ds.get_width() ); - - if ( cursor().col + 1 >= fb.ds.get_width() ) { - /* prediction in the last column is tricky */ - /* e.g., emacs will show wrap character, shell will just put the character there */ - become_tentative(); - } - - /* do the insert */ - int rightmost_column = predict_overwrite ? cursor().col : 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; - cell.tentative_until_epoch = prediction_epoch; - cell.expire( local_frame_sent + 1, now ); - cell.original_contents.push_back( *fb.get_cell( cursor().row, i ) ); - - ConditionalOverlayCell &prev_cell = the_row.overlay_cells[ i - 1 ]; - const Cell *prev_cell_actual = fb.get_cell( cursor().row, i - 1 ); - - if ( i == fb.ds.get_width() - 1 ) { - cell.unknown = true; - } else if ( prev_cell.active ) { - if ( prev_cell.unknown ) { - cell.unknown = true; - } else { - cell.unknown = false; - cell.replacement = prev_cell.replacement; - } - } else { - cell.unknown = false; - cell.replacement = *prev_cell_actual; - } - } - - 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.replacement.get_renditions() = fb.ds.get_renditions(); - - /* heuristic: match renditions of character to the left */ - if ( cursor().col > 0 ) { - ConditionalOverlayCell &prev_cell = the_row.overlay_cells[ cursor().col - 1 ]; - const Cell *prev_cell_actual = fb.get_cell( cursor().row, cursor().col - 1 ); - if ( prev_cell.active && (!prev_cell.unknown) ) { - cell.replacement.get_renditions() = prev_cell.replacement.get_renditions(); - } else { - cell.replacement.get_renditions() = prev_cell_actual->get_renditions(); - } - } - - cell.replacement.clear(); - cell.replacement.append( ch ); - cell.original_contents.push_back( *fb.get_cell( cursor().row, cursor().col ) ); - - /* - fprintf( stderr, "[%d=>%d] Predicting %lc in row %d, col %d [tue: %lu]\n", - (int)local_frame_acked, (int)cell.expiration_frame, - ch, cursor().row, cursor().col, - cell.tentative_until_epoch ); - */ - - cursor().expire( local_frame_sent + 1, now ); - - /* do we need to wrap? */ - if ( cursor().col < fb.ds.get_width() - 1 ) { - cursor().col++; - } else { - become_tentative(); - newline_carriage_return( fb ); - } + assert( cursor().row >= 0 ); + assert( cursor().col >= 0 ); + assert( cursor().row < fb.ds.get_height() ); + assert( cursor().col < fb.ds.get_width() ); + + ConditionalOverlayRow& the_row = get_or_make_row( cursor().row, fb.ds.get_width() ); + + if ( cursor().col + 1 >= fb.ds.get_width() ) { + /* prediction in the last column is tricky */ + /* e.g., emacs will show wrap character, shell will just put the character there */ + become_tentative(); + } + + /* do the insert */ + int rightmost_column = predict_overwrite ? cursor().col : 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; + cell.tentative_until_epoch = prediction_epoch; + cell.expire( local_frame_sent + 1, now ); + cell.original_contents.push_back( *fb.get_cell( cursor().row, i ) ); + + ConditionalOverlayCell& prev_cell = the_row.overlay_cells[i - 1]; + const Cell* prev_cell_actual = fb.get_cell( cursor().row, i - 1 ); + + if ( i == fb.ds.get_width() - 1 ) { + cell.unknown = true; + } else if ( prev_cell.active ) { + if ( prev_cell.unknown ) { + cell.unknown = true; + } else { + cell.unknown = false; + cell.replacement = prev_cell.replacement; + } + } else { + cell.unknown = false; + cell.replacement = *prev_cell_actual; + } + } + + 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.replacement.get_renditions() = fb.ds.get_renditions(); + + /* heuristic: match renditions of character to the left */ + if ( cursor().col > 0 ) { + ConditionalOverlayCell& prev_cell = the_row.overlay_cells[cursor().col - 1]; + const Cell* prev_cell_actual = fb.get_cell( cursor().row, cursor().col - 1 ); + if ( prev_cell.active && ( !prev_cell.unknown ) ) { + cell.replacement.get_renditions() = prev_cell.replacement.get_renditions(); + } else { + cell.replacement.get_renditions() = prev_cell_actual->get_renditions(); + } + } + + cell.replacement.clear(); + cell.replacement.append( ch ); + cell.original_contents.push_back( *fb.get_cell( cursor().row, cursor().col ) ); + + /* + fprintf( stderr, "[%d=>%d] Predicting %lc in row %d, col %d [tue: %lu]\n", |