Skip to content

Commit

Permalink
Expand model to support multiline mode.
Browse files Browse the repository at this point in the history
  • Loading branch information
AmokHuginnsson committed May 26, 2021
1 parent 2c87a94 commit 9aa077e
Show file tree
Hide file tree
Showing 6 changed files with 35 additions and 15 deletions.
1 change: 1 addition & 0 deletions include/replxx.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ enum { REPLXX_KEY_ENTER = REPLXX_KEY_CONTROL( 'M' ) };
*/
typedef enum {
REPLXX_ACTION_INSERT_CHARACTER,
REPLXX_ACTION_NEW_LINE,
REPLXX_ACTION_DELETE_CHARACTER_UNDER_CURSOR,
REPLXX_ACTION_DELETE_CHARACTER_LEFT_OF_CURSOR,
REPLXX_ACTION_KILL_TO_END_OF_LINE,
Expand Down
1 change: 1 addition & 0 deletions include/replxx.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ public:
*/
enum class ACTION {
INSERT_CHARACTER,
NEW_LINE,
DELETE_CHARACTER_UNDER_CURSOR,
DELETE_CHARACTER_LEFT_OF_CURSOR,
KILL_TO_END_OF_LINE,
Expand Down
33 changes: 20 additions & 13 deletions src/replxx_impl.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ namespace {
namespace action_names {

char const INSERT_CHARACTER[] = "insert_character";
char const NEW_LINE[] = "new_line";
char const MOVE_CURSOR_TO_BEGINING_OF_LINE[] = "move_cursor_to_begining_of_line";
char const MOVE_CURSOR_TO_END_OF_LINE[] = "move_cursor_to_end_of_line";
char const MOVE_CURSOR_LEFT[] = "move_cursor_left";
Expand Down Expand Up @@ -142,11 +143,11 @@ class IOModeGuard {
Replxx::ReplxxImpl::ReplxxImpl( FILE*, FILE*, FILE* )
: _utf8Buffer()
, _data()
, _pos( 0 )
, _charWidths()
, _display()
, _displayInputLength( 0 )
, _hint()
, _pos( 0 )
, _prefix( 0 )
, _hintSelection( -1 )
, _history()
Expand Down Expand Up @@ -190,6 +191,7 @@ Replxx::ReplxxImpl::ReplxxImpl( FILE*, FILE*, FILE* )
, _mutex() {
using namespace std::placeholders;
_namedActions[action_names::INSERT_CHARACTER] = std::bind( &ReplxxImpl::invoke, this, Replxx::ACTION::INSERT_CHARACTER, _1 );
_namedActions[action_names::NEW_LINE] = std::bind( &ReplxxImpl::invoke, this, Replxx::ACTION::NEW_LINE, _1 );
_namedActions[action_names::MOVE_CURSOR_TO_BEGINING_OF_LINE] = std::bind( &ReplxxImpl::invoke, this, Replxx::ACTION::MOVE_CURSOR_TO_BEGINING_OF_LINE, _1 );
_namedActions[action_names::MOVE_CURSOR_TO_END_OF_LINE] = std::bind( &ReplxxImpl::invoke, this, Replxx::ACTION::MOVE_CURSOR_TO_END_OF_LINE, _1 );
_namedActions[action_names::MOVE_CURSOR_LEFT] = std::bind( &ReplxxImpl::invoke, this, Replxx::ACTION::MOVE_CURSOR_LEFT, _1 );
Expand Down Expand Up @@ -280,7 +282,7 @@ Replxx::ReplxxImpl::ReplxxImpl( FILE*, FILE*, FILE* )
bind_key( 127, _namedActions.at( action_names::DELETE_CHARACTER_UNDER_CURSOR ) );
bind_key( Replxx::KEY::DELETE + 0, _namedActions.at( action_names::DELETE_CHARACTER_UNDER_CURSOR ) );
bind_key( Replxx::KEY::BACKSPACE + 0, _namedActions.at( action_names::DELETE_CHARACTER_LEFT_OF_CURSOR ) );
bind_key( Replxx::KEY::control( 'J' ), _namedActions.at( action_names::COMMIT_LINE ) );
bind_key( Replxx::KEY::control( 'J' ), _namedActions.at( action_names::NEW_LINE ) );
bind_key( Replxx::KEY::ENTER + 0, _namedActions.at( action_names::COMMIT_LINE ) );
bind_key( Replxx::KEY::control( 'L' ), _namedActions.at( action_names::CLEAR_SCREEN ) );
bind_key( Replxx::KEY::control( 'N' ), _namedActions.at( action_names::COMPLETE_NEXT ) );
Expand Down Expand Up @@ -314,14 +316,15 @@ Replxx::ReplxxImpl::~ReplxxImpl( void ) {
Replxx::ACTION_RESULT Replxx::ReplxxImpl::invoke( Replxx::ACTION action_, char32_t code ) {
switch ( action_ ) {
case ( Replxx::ACTION::INSERT_CHARACTER ): return ( action( RESET_KILL_ACTION | HISTORY_RECALL_MOST_RECENT, &Replxx::ReplxxImpl::insert_character, code ) );
case ( Replxx::ACTION::NEW_LINE ): return ( action( RESET_KILL_ACTION | HISTORY_RECALL_MOST_RECENT, &Replxx::ReplxxImpl::new_line, code ) );
case ( Replxx::ACTION::DELETE_CHARACTER_UNDER_CURSOR ): return ( action( RESET_KILL_ACTION | HISTORY_RECALL_MOST_RECENT, &Replxx::ReplxxImpl::delete_character, code ) );
case ( Replxx::ACTION::DELETE_CHARACTER_LEFT_OF_CURSOR ): return ( action( RESET_KILL_ACTION | HISTORY_RECALL_MOST_RECENT, &Replxx::ReplxxImpl::backspace_character, code ) );
case ( Replxx::ACTION::KILL_TO_END_OF_LINE ): return ( action( WANT_REFRESH | SET_KILL_ACTION | HISTORY_RECALL_MOST_RECENT, &Replxx::ReplxxImpl::kill_to_end_of_line, code ) );
case ( Replxx::ACTION::KILL_TO_BEGINING_OF_LINE ): return ( action( SET_KILL_ACTION | HISTORY_RECALL_MOST_RECENT, &Replxx::ReplxxImpl::kill_to_begining_of_line, code ) );
case ( Replxx::ACTION::KILL_TO_END_OF_WORD ): return ( action( SET_KILL_ACTION | HISTORY_RECALL_MOST_RECENT, &Replxx::ReplxxImpl::kill_word_to_right<false>, code ) );
case ( Replxx::ACTION::KILL_TO_BEGINING_OF_WORD ): return ( action( SET_KILL_ACTION | HISTORY_RECALL_MOST_RECENT, &Replxx::ReplxxImpl::kill_word_to_left<false>, code ) );
case ( Replxx::ACTION::KILL_TO_END_OF_SUBWORD ): return ( action( SET_KILL_ACTION | HISTORY_RECALL_MOST_RECENT, &Replxx::ReplxxImpl::kill_word_to_right<true>, code ) );
case ( Replxx::ACTION::KILL_TO_BEGINING_OF_SUBWORD ): return ( action( SET_KILL_ACTION | HISTORY_RECALL_MOST_RECENT, &Replxx::ReplxxImpl::kill_word_to_left<true>, code ) );
case ( Replxx::ACTION::KILL_TO_END_OF_SUBWORD ): return ( action( SET_KILL_ACTION | HISTORY_RECALL_MOST_RECENT, &Replxx::ReplxxImpl::kill_word_to_right<true>, code ) );
case ( Replxx::ACTION::KILL_TO_BEGINING_OF_SUBWORD ): return ( action( SET_KILL_ACTION | HISTORY_RECALL_MOST_RECENT, &Replxx::ReplxxImpl::kill_word_to_left<true>, code ) );
case ( Replxx::ACTION::KILL_TO_WHITESPACE_ON_LEFT ): return ( action( SET_KILL_ACTION | HISTORY_RECALL_MOST_RECENT, &Replxx::ReplxxImpl::kill_to_whitespace_to_left, code ) );
case ( Replxx::ACTION::YANK ): return ( action( HISTORY_RECALL_MOST_RECENT, &Replxx::ReplxxImpl::yank, code ) );
case ( Replxx::ACTION::YANK_CYCLE ): return ( action( HISTORY_RECALL_MOST_RECENT, &Replxx::ReplxxImpl::yank_cycle, code ) );
Expand All @@ -330,8 +333,8 @@ Replxx::ACTION_RESULT Replxx::ReplxxImpl::invoke( Replxx::ACTION action_, char32
case ( Replxx::ACTION::MOVE_CURSOR_TO_END_OF_LINE ): return ( action( WANT_REFRESH, &Replxx::ReplxxImpl::go_to_end_of_line, code ) );
case ( Replxx::ACTION::MOVE_CURSOR_ONE_WORD_LEFT ): return ( action( RESET_KILL_ACTION, &Replxx::ReplxxImpl::move_one_word_left<false>, code ) );
case ( Replxx::ACTION::MOVE_CURSOR_ONE_WORD_RIGHT ): return ( action( RESET_KILL_ACTION, &Replxx::ReplxxImpl::move_one_word_right<false>, code ) );
case ( Replxx::ACTION::MOVE_CURSOR_ONE_SUBWORD_LEFT ): return ( action( RESET_KILL_ACTION, &Replxx::ReplxxImpl::move_one_word_left<true>, code ) );
case ( Replxx::ACTION::MOVE_CURSOR_ONE_SUBWORD_RIGHT ): return ( action( RESET_KILL_ACTION, &Replxx::ReplxxImpl::move_one_word_right<true>, code ) );
case ( Replxx::ACTION::MOVE_CURSOR_ONE_SUBWORD_LEFT ): return ( action( RESET_KILL_ACTION, &Replxx::ReplxxImpl::move_one_word_left<true>, code ) );
case ( Replxx::ACTION::MOVE_CURSOR_ONE_SUBWORD_RIGHT ): return ( action( RESET_KILL_ACTION, &Replxx::ReplxxImpl::move_one_word_right<true>, code ) );
case ( Replxx::ACTION::MOVE_CURSOR_LEFT ): return ( action( RESET_KILL_ACTION, &Replxx::ReplxxImpl::move_one_char_left, code ) );
case ( Replxx::ACTION::MOVE_CURSOR_RIGHT ): return ( action( RESET_KILL_ACTION, &Replxx::ReplxxImpl::move_one_char_right, code ) );
case ( Replxx::ACTION::HISTORY_NEXT ): return ( action( RESET_KILL_ACTION, &Replxx::ReplxxImpl::history_next, code ) );
Expand All @@ -345,9 +348,9 @@ Replxx::ACTION_RESULT Replxx::ReplxxImpl::invoke( Replxx::ACTION action_, char32
case ( Replxx::ACTION::CAPITALIZE_WORD ): return ( action( RESET_KILL_ACTION | HISTORY_RECALL_MOST_RECENT, &Replxx::ReplxxImpl::capitalize_word<false>, code ) );
case ( Replxx::ACTION::LOWERCASE_WORD ): return ( action( RESET_KILL_ACTION | HISTORY_RECALL_MOST_RECENT, &Replxx::ReplxxImpl::lowercase_word<false>, code ) );
case ( Replxx::ACTION::UPPERCASE_WORD ): return ( action( RESET_KILL_ACTION | HISTORY_RECALL_MOST_RECENT, &Replxx::ReplxxImpl::uppercase_word<false>, code ) );
case ( Replxx::ACTION::CAPITALIZE_SUBWORD ): return ( action( RESET_KILL_ACTION | HISTORY_RECALL_MOST_RECENT, &Replxx::ReplxxImpl::capitalize_word<true>, code ) );
case ( Replxx::ACTION::LOWERCASE_SUBWORD ): return ( action( RESET_KILL_ACTION | HISTORY_RECALL_MOST_RECENT, &Replxx::ReplxxImpl::lowercase_word<true>, code ) );
case ( Replxx::ACTION::UPPERCASE_SUBWORD ): return ( action( RESET_KILL_ACTION | HISTORY_RECALL_MOST_RECENT, &Replxx::ReplxxImpl::uppercase_word<true>, code ) );
case ( Replxx::ACTION::CAPITALIZE_SUBWORD ): return ( action( RESET_KILL_ACTION | HISTORY_RECALL_MOST_RECENT, &Replxx::ReplxxImpl::capitalize_word<true>, code ) );
case ( Replxx::ACTION::LOWERCASE_SUBWORD ): return ( action( RESET_KILL_ACTION | HISTORY_RECALL_MOST_RECENT, &Replxx::ReplxxImpl::lowercase_word<true>, code ) );
case ( Replxx::ACTION::UPPERCASE_SUBWORD ): return ( action( RESET_KILL_ACTION | HISTORY_RECALL_MOST_RECENT, &Replxx::ReplxxImpl::uppercase_word<true>, code ) );
case ( Replxx::ACTION::TRANSPOSE_CHARACTERS ): return ( action( RESET_KILL_ACTION | HISTORY_RECALL_MOST_RECENT, &Replxx::ReplxxImpl::transpose_characters, code ) );
case ( Replxx::ACTION::TOGGLE_OVERWRITE_MODE ): return ( action( NOOP, &Replxx::ReplxxImpl::toggle_overwrite_mode, code ) );
#ifndef _WIN32
Expand Down Expand Up @@ -674,7 +677,7 @@ void Replxx::ReplxxImpl::render( char32_t ch ) {
if ( ch == Replxx::KEY::ESCAPE ) {
_display.push_back( '^' );
_display.push_back( '[' );
} else if ( is_control_code( ch ) ) {
} else if ( is_control_code( ch ) && ( ch != '\n' ) ) {
_display.push_back( '^' );
_display.push_back( control_to_human( ch ) );
} else {
Expand Down Expand Up @@ -1306,7 +1309,7 @@ Replxx::ACTION_RESULT Replxx::ReplxxImpl::insert_character( char32_t c ) {
* beep on unknown Ctrl and/or Meta keys
* don't insert control characters
*/
if ( ( c >= static_cast<int>( Replxx::KEY::BASE ) ) || is_control_code( c ) ) {
if ( ( c >= static_cast<int>( Replxx::KEY::BASE ) ) || ( is_control_code( c ) && ( c != '\n' ) ) ) {
beep();
return ( Replxx::ACTION_RESULT::CONTINUE );
}
Expand Down Expand Up @@ -1346,6 +1349,11 @@ Replxx::ACTION_RESULT Replxx::ReplxxImpl::insert_character( char32_t c ) {
return ( Replxx::ACTION_RESULT::CONTINUE );
}

// ctrl-J/linefeed/newline
Replxx::ACTION_RESULT Replxx::ReplxxImpl::new_line( char32_t ) {
return ( insert_character( '\n' ) );
}

// ctrl-A, HOME: move cursor to start of line
Replxx::ACTION_RESULT Replxx::ReplxxImpl::go_to_begining_of_line( char32_t ) {
_pos = 0;
Expand Down Expand Up @@ -1654,8 +1662,7 @@ Replxx::ACTION_RESULT Replxx::ReplxxImpl::backspace_character( char32_t ) {
return ( Replxx::ACTION_RESULT::CONTINUE );
}

// ctrl-J/linefeed/newline, accept line
// ctrl-M/return/enter
// ctrl-M/return/enter, accept line
Replxx::ACTION_RESULT Replxx::ReplxxImpl::commit_line( char32_t ) {
// we need one last refresh with the cursor at the end of the line
// so we don't display the next prompt over the previous input line
Expand Down
4 changes: 3 additions & 1 deletion src/replxx_impl.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ public:
}
};
typedef std::vector<Completion> completions_t;
typedef std::vector<UnicodeString> data_t;
typedef std::vector<UnicodeString> hints_t;
typedef std::unique_ptr<char[]> utf8_buffer_t;
typedef std::unique_ptr<char32_t[]> input_buffer_t;
Expand Down Expand Up @@ -103,11 +104,11 @@ private:
private:
mutable Utf8String _utf8Buffer;
UnicodeString _data;
int _pos; // character position in buffer ( 0 <= _pos <= _data[_line].length() )
char_widths_t _charWidths; // character widths from mk_wcwidth()
display_t _display;
int _displayInputLength;
UnicodeString _hint;
int _pos; // character position in buffer ( 0 <= _pos <= _len )
int _prefix; // prefix length used in common prefix search
int _hintSelection; // Currently selected hint.
History _history;
Expand Down Expand Up @@ -197,6 +198,7 @@ private:
int get_input_line( void );
Replxx::ACTION_RESULT action( action_trait_t, key_press_handler_raw_t const&, char32_t );
Replxx::ACTION_RESULT insert_character( char32_t );
Replxx::ACTION_RESULT new_line( char32_t );
Replxx::ACTION_RESULT go_to_begining_of_line( char32_t );
Replxx::ACTION_RESULT go_to_end_of_line( char32_t );
Replxx::ACTION_RESULT move_one_char_left( char32_t );
Expand Down
9 changes: 9 additions & 0 deletions src/unicodestring.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,15 @@ public:
assign( src );
}

explicit UnicodeString( UnicodeString const& other, int offset, int len = -1 )
: _data() {
_data.insert(
_data.end(),
other._data.begin() + offset,
len > 0 ? other._data.begin() + offset + len : other._data.end()
);
}

explicit UnicodeString( char const* src )
: _data() {
assign( src );
Expand Down
2 changes: 1 addition & 1 deletion tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -1045,7 +1045,7 @@ def test_history_unique( self_ ):
command = ReplxxTests._cSample_ + " u0 q1"
)
self_.check_scenario(
rapid( "/history\n/unique\n/history\n<c-d>" ),
rapid( "/history<cr>/unique<cr>/history<cr><c-d>" ),
"<c9>/<rst><ceos><c10><c9>/history<rst><ceos><c17>\r\n"
" 0: a\r\n"
" 1: b\r\n"
Expand Down

0 comments on commit 9aa077e

Please sign in to comment.