Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Always re-render prompt while navigating history #18

Merged
merged 2 commits into from
Nov 23, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions examples/cxx-api.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -444,8 +444,10 @@ int main( int argc_, char** argv_ ) {
rx.bind_key_internal( Replxx::KEY::DELETE, "delete_character_under_cursor" );
rx.bind_key_internal( Replxx::KEY::LEFT, "move_cursor_left" );
rx.bind_key_internal( Replxx::KEY::RIGHT, "move_cursor_right" );
rx.bind_key_internal( Replxx::KEY::UP, "history_previous" );
rx.bind_key_internal( Replxx::KEY::DOWN, "history_next" );
rx.bind_key_internal( Replxx::KEY::UP, "line_previous" );
rx.bind_key_internal( Replxx::KEY::DOWN, "line_next" );
rx.bind_key_internal( Replxx::KEY::meta( Replxx::KEY::UP ), "history_previous" );
rx.bind_key_internal( Replxx::KEY::meta( Replxx::KEY::DOWN ), "history_next" );
rx.bind_key_internal( Replxx::KEY::PAGE_UP, "history_first" );
rx.bind_key_internal( Replxx::KEY::PAGE_DOWN, "history_last" );
rx.bind_key_internal( Replxx::KEY::HOME, "move_cursor_to_begining_of_line" );
Expand Down
10 changes: 6 additions & 4 deletions include/replxx.h
Original file line number Diff line number Diff line change
Expand Up @@ -161,8 +161,10 @@ typedef enum {
REPLXX_ACTION_MOVE_CURSOR_ONE_SUBWORD_RIGHT,
REPLXX_ACTION_MOVE_CURSOR_LEFT,
REPLXX_ACTION_MOVE_CURSOR_RIGHT,
REPLXX_ACTION_HISTORY_NEXT,
REPLXX_ACTION_HISTORY_PREVIOUS,
REPLXX_ACTION_LINE_NEXT,
REPLXX_ACTION_LINE_PREVIOUS,
REPLXX_ACTION_HISTORY_MOVE_NEXT,
REPLXX_ACTION_HISTORY_MOVE_PREVIOUS,
REPLXX_ACTION_HISTORY_FIRST,
REPLXX_ACTION_HISTORY_LAST,
REPLXX_ACTION_HISTORY_RESTORE,
Expand Down Expand Up @@ -451,8 +453,8 @@ REPLXX_IMPEXP void replxx_bind_key( Replxx*, int code, key_press_handler_t handl
*
* Action names are the same as unique part of names of ReplxxAction enumerations
* but in lower case, e.g.: an action for recalling previous history line
* is \e REPLXX_ACTION_HISTORY_PREVIOUS so action name to be used in this
* interface for the same effect is "history_previous".
* is \e REPLXX_ACTION_LINE_PREVIOUS so action name to be used in this
* interface for the same effect is "line_previous".
*
* \param code - handle this key-press event with following handler.
* \param actionName - name of internal action to be invoked on key press.
Expand Down
6 changes: 4 additions & 2 deletions include/replxx.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,8 @@ public:
MOVE_CURSOR_ONE_SUBWORD_RIGHT,
MOVE_CURSOR_LEFT,
MOVE_CURSOR_RIGHT,
LINE_NEXT,
LINE_PREVIOUS,
HISTORY_NEXT,
HISTORY_PREVIOUS,
HISTORY_FIRST,
Expand Down Expand Up @@ -501,8 +503,8 @@ public:
*
* Action names are the same as names of Replxx::ACTION enumerations
* but in lower case, e.g.: an action for recalling previous history line
* is \e Replxx::ACTION::HISTORY_PREVIOUS so action name to be used in this
* interface for the same effect is "history_previous".
* is \e Replxx::ACTION::LINE_PREVIOUS so action name to be used in this
* interface for the same effect is "line_previous".
*
* \param code - handle this key-press event with following handler.
* \param actionName - name of internal action to be invoked on key press.
Expand Down
40 changes: 31 additions & 9 deletions src/replxx_impl.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ char const COMPLETE_NEXT[] = "complete_next";
char const COMPLETE_PREVIOUS[] = "complete_previous";
char const HISTORY_NEXT[] = "history_next";
char const HISTORY_PREVIOUS[] = "history_previous";
char const LINE_NEXT[] = "line_next";
char const LINE_PREVIOUS[] = "line_previous";
char const HISTORY_LAST[] = "history_last";
char const HISTORY_FIRST[] = "history_first";
char const HISTORY_RESTORE[] = "history_restore";
Expand Down Expand Up @@ -235,8 +237,10 @@ Replxx::ReplxxImpl::ReplxxImpl( FILE*, FILE*, FILE* )
_namedActions[action_names::CLEAR_SCREEN] = std::bind( &ReplxxImpl::invoke, this, Replxx::ACTION::CLEAR_SCREEN, _1 );
_namedActions[action_names::COMPLETE_NEXT] = std::bind( &ReplxxImpl::invoke, this, Replxx::ACTION::COMPLETE_NEXT, _1 );
_namedActions[action_names::COMPLETE_PREVIOUS] = std::bind( &ReplxxImpl::invoke, this, Replxx::ACTION::COMPLETE_PREVIOUS, _1 );
_namedActions[action_names::HISTORY_NEXT] = std::bind( &ReplxxImpl::invoke, this, Replxx::ACTION::HISTORY_NEXT, _1 );
_namedActions[action_names::HISTORY_PREVIOUS] = std::bind( &ReplxxImpl::invoke, this, Replxx::ACTION::HISTORY_PREVIOUS, _1 );
_namedActions[action_names::LINE_NEXT] = std::bind( &ReplxxImpl::invoke, this, Replxx::ACTION::LINE_NEXT, _1 );
_namedActions[action_names::LINE_PREVIOUS] = std::bind( &ReplxxImpl::invoke, this, Replxx::ACTION::LINE_PREVIOUS, _1 );
_namedActions[action_names::HISTORY_NEXT] = std::bind( &ReplxxImpl::invoke, this, Replxx::ACTION::HISTORY_NEXT, _1 );
_namedActions[action_names::HISTORY_PREVIOUS] = std::bind( &ReplxxImpl::invoke, this, Replxx::ACTION::HISTORY_PREVIOUS, _1 );
_namedActions[action_names::HISTORY_LAST] = std::bind( &ReplxxImpl::invoke, this, Replxx::ACTION::HISTORY_LAST, _1 );
_namedActions[action_names::HISTORY_FIRST] = std::bind( &ReplxxImpl::invoke, this, Replxx::ACTION::HISTORY_FIRST, _1 );
_namedActions[action_names::HISTORY_RESTORE] = std::bind( &ReplxxImpl::invoke, this, Replxx::ACTION::HISTORY_RESTORE, _1 );
Expand Down Expand Up @@ -300,8 +304,10 @@ Replxx::ReplxxImpl::ReplxxImpl( FILE*, FILE*, FILE* )
bind_key( Replxx::KEY::control( 'L' ), _namedActions.at( action_names::CLEAR_SCREEN ) );
bind_key( Replxx::KEY::control( 'N' ), _namedActions.at( action_names::COMPLETE_NEXT ) );
bind_key( Replxx::KEY::control( 'P' ), _namedActions.at( action_names::COMPLETE_PREVIOUS ) );
bind_key( Replxx::KEY::DOWN + 0, _namedActions.at( action_names::HISTORY_NEXT ) );
bind_key( Replxx::KEY::UP + 0, _namedActions.at( action_names::HISTORY_PREVIOUS ) );
bind_key( Replxx::KEY::DOWN + 0, _namedActions.at( action_names::LINE_NEXT ) );
bind_key( Replxx::KEY::UP + 0, _namedActions.at( action_names::LINE_PREVIOUS ) );
bind_key( Replxx::KEY::meta( Replxx::KEY::DOWN ), _namedActions.at( action_names::HISTORY_NEXT ) );
bind_key( Replxx::KEY::meta( Replxx::KEY::UP ), _namedActions.at( action_names::HISTORY_PREVIOUS ) );
bind_key( Replxx::KEY::meta( '<' ), _namedActions.at( action_names::HISTORY_FIRST ) );
bind_key( Replxx::KEY::PAGE_UP + 0, _namedActions.at( action_names::HISTORY_FIRST ) );
bind_key( Replxx::KEY::meta( '>' ), _namedActions.at( action_names::HISTORY_LAST ) );
Expand Down Expand Up @@ -352,6 +358,8 @@ Replxx::ACTION_RESULT Replxx::ReplxxImpl::invoke( Replxx::ACTION action_, char32
case ( Replxx::ACTION::MOVE_CURSOR_ONE_SUBWORD_RIGHT ): return ( action( MOVE_CURSOR | RESET_KILL_ACTION, &Replxx::ReplxxImpl::move_one_word_right<true>, code ) );
case ( Replxx::ACTION::MOVE_CURSOR_LEFT ): return ( action( MOVE_CURSOR | RESET_KILL_ACTION, &Replxx::ReplxxImpl::move_one_char_left, code ) );
case ( Replxx::ACTION::MOVE_CURSOR_RIGHT ): return ( action( MOVE_CURSOR | RESET_KILL_ACTION, &Replxx::ReplxxImpl::move_one_char_right, code ) );
case ( Replxx::ACTION::LINE_NEXT ): return ( action( MOVE_CURSOR | RESET_KILL_ACTION, &Replxx::ReplxxImpl::line_next, code ) );
case ( Replxx::ACTION::LINE_PREVIOUS ): return ( action( MOVE_CURSOR | RESET_KILL_ACTION, &Replxx::ReplxxImpl::line_previous, code ) );
case ( Replxx::ACTION::HISTORY_NEXT ): return ( action( MOVE_CURSOR | RESET_KILL_ACTION, &Replxx::ReplxxImpl::history_next, code ) );
case ( Replxx::ACTION::HISTORY_PREVIOUS ): return ( action( MOVE_CURSOR | RESET_KILL_ACTION, &Replxx::ReplxxImpl::history_previous, code ) );
case ( Replxx::ACTION::HISTORY_FIRST ): return ( action( MOVE_CURSOR | RESET_KILL_ACTION, &Replxx::ReplxxImpl::history_first, code ) );
Expand Down Expand Up @@ -966,14 +974,20 @@ int Replxx::ReplxxImpl::virtual_render( char32_t const* buffer_, int len_, int&
* Refresh the user's input line: the prompt is already onscreen and is not
* redrawn here screen position
*/
void Replxx::ReplxxImpl::refresh_line( HINT_ACTION hintAction_ ) {
void Replxx::ReplxxImpl::refresh_line( HINT_ACTION hintAction_, bool refreshPrompt_ ) {
int long long now( now_us() );
int long long duration( now - _lastRefreshTime );
if ( duration < RAPID_REFRESH_US ) {
_lastRefreshTime = now;
_refreshSkipped = true;
return;
}
if ( refreshPrompt_ )
{
_terminal.jump_cursor( 0, 0 );
_prompt.write();
_prompt._cursorRowOffset = _prompt._extraLines;
}
_refreshSkipped = false;
render( hintAction_ );
handle_hints( hintAction_ );
Expand Down Expand Up @@ -1862,7 +1876,7 @@ int Replxx::ReplxxImpl::pos_in_line( void ) const {
}

// Up, recall previous line in history
Replxx::ACTION_RESULT Replxx::ReplxxImpl::history_previous( char32_t ) {
Replxx::ACTION_RESULT Replxx::ReplxxImpl::line_previous( char32_t ) {
assert( ( _pos >= 0 ) && ( _pos <= _data.length() ) );
do {
if ( ! _hasNewlines ) {
Expand All @@ -1888,7 +1902,7 @@ Replxx::ACTION_RESULT Replxx::ReplxxImpl::history_previous( char32_t ) {
}

// Down, recall next line in history
Replxx::ACTION_RESULT Replxx::ReplxxImpl::history_next( char32_t ) {
Replxx::ACTION_RESULT Replxx::ReplxxImpl::line_next( char32_t ) {
assert( ( _pos >= 0 ) && ( _pos <= _data.length() ) );
do {
if ( ! _hasNewlines ) {
Expand Down Expand Up @@ -1919,6 +1933,14 @@ Replxx::ACTION_RESULT Replxx::ReplxxImpl::history_next( char32_t ) {
return ( history_move( false ) );
}

Replxx::ACTION_RESULT Replxx::ReplxxImpl::history_next( char32_t ) {
return ( history_move( false ) );
}

Replxx::ACTION_RESULT Replxx::ReplxxImpl::history_previous( char32_t ) {
return ( history_move( true ) );
}

Replxx::ACTION_RESULT Replxx::ReplxxImpl::history_move( bool previous_ ) {
// if not already recalling, add the current line to the history list so
// we don't have to special case it
Expand All @@ -1934,7 +1956,7 @@ Replxx::ACTION_RESULT Replxx::ReplxxImpl::history_move( bool previous_ ) {
}
_data.assign( _history.current() );
_pos = _data.length();
refresh_line();
refresh_line( HINT_ACTION::REGENERATE, true /* refreshPrompt */ );
return ( Replxx::ACTION_RESULT::CONTINUE );
}

Expand Down Expand Up @@ -2006,7 +2028,7 @@ Replxx::ACTION_RESULT Replxx::ReplxxImpl::history_jump( bool back_ ) {
_history.jump( back_ );
_data.assign( _history.current() );
_pos = _data.length();
refresh_line();
refresh_line( HINT_ACTION::REGENERATE, true /* refreshPrompt */ );
}
return ( Replxx::ACTION_RESULT::CONTINUE );
}
Expand Down
4 changes: 3 additions & 1 deletion src/replxx_impl.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,8 @@ private:
Replxx::ACTION_RESULT delete_character( char32_t );
Replxx::ACTION_RESULT backspace_character( char32_t );
Replxx::ACTION_RESULT commit_line( char32_t );
Replxx::ACTION_RESULT line_next( char32_t );
Replxx::ACTION_RESULT line_previous( char32_t );
Replxx::ACTION_RESULT history_next( char32_t );
Replxx::ACTION_RESULT history_previous( char32_t );
Replxx::ACTION_RESULT history_move( bool );
Expand Down Expand Up @@ -270,7 +272,7 @@ private:
void call_modify_callback( void );
completions_t call_completer( std::string const& input, int& ) const;
hints_t call_hinter( std::string const& input, int&, Replxx::Color& color ) const;
void refresh_line( HINT_ACTION = HINT_ACTION::REGENERATE );
void refresh_line( HINT_ACTION = HINT_ACTION::REGENERATE, bool refreshPrompt_ = false );
void move_cursor( void );
void indent( void );
int virtual_render( char32_t const*, int, int&, int&, Prompt const* = nullptr );
Expand Down
23 changes: 23 additions & 0 deletions tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -3235,6 +3235,29 @@ def test_history_scratch( self_ ):
"three\r\n",
"one\ntwo\nthree\n"
)
def test_move_up_over_multiline( self_ ):
self_.check_scenario(
"<m-up><m-up><m-up><cr><c-d>",
"<c9>ZZZ<rst><ceos><c12><c9><ceos>bbbbbbbbbbbbbbbb\r\n"
"bbbbbbbbbbbbbbbbbbbb\r\n"
"bbbbbbbbbbbbbbbbbbbb\r\n"
"bbbbbbbbbbbbbbbbbbbbbbb<rst><c24><u3><c9><yellow>123<rst><ceos><c12><c9><yellow>123<rst><ceos><c12>\r\n"
"123\r\n",
"123\nbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\nZZZ\n"
)
def test_move_down_over_multiline( self_ ):
self_.check_scenario(
"<pgup><m-down><pgup><m-down><m-down>x<cr><c-d>",
"<c9><yellow>123<rst><ceos><c12><c9><ceos>bbbbbbbbbbbbbbbbbbbbbbb\r\n"
"bbbbbbbbbbbbbbbbbbbb\r\n"
"bbbbbbbbbbbbbbbbbbbb\r\n"
"bbbbbbbbbbbbbbbb<rst><c17><u3><c9><ceos>bbbbbbbbbbbbbbbbbbbbbbb\r\n"
"bbbbbbbbbbbbbbbbbbbb\r\n"
"bbbbbbbbbbbbbbbbbbbb\r\n"
"bbbbbbbbbbbbbbbb<rst><u3><c9><c9>ZZZ<rst><ceos><c12><c9><rst><ceos><c9><c9>x<rst><ceos><c10><c9>x<rst><ceos><c10>\r\n"
"x\r\n",
"123\nbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\nZZZ\n"
)

def parseArgs( self, func, argv ):
global verbosity
Expand Down