#ifdef _WIN32 #include #include #include #if _MSC_VER < 1900 && defined (_MSC_VER) #define snprintf _snprintf // Microsoft headers use underscores in some names #endif #define strcasecmp _stricmp #define strdup _strdup #define write _write #define STDIN_FILENO 0 #else /* _WIN32 */ #include #endif /* _WIN32 */ #include "prompt.hxx" #include "util.hxx" namespace replxx { Prompt::Prompt( Terminal& terminal_ ) : _extraLines( 0 ) , _lastLinePosition( 0 ) , _previousInputLen( 0 ) , _previousLen( 0 ) , _screenColumns( 0 ) , _terminal( terminal_ ) { } void Prompt::write() { _terminal.write32( _text.get(), _byteCount ); } void Prompt::update_screen_columns( void ) { _screenColumns = _terminal.get_screen_columns(); } void Prompt::set_text( UnicodeString const& text_ ) { update_screen_columns(); // strip control characters from the prompt -- we do allow newline _text = text_; UnicodeString::const_iterator in( text_.begin() ); UnicodeString::iterator out( _text.begin() ); int len = 0; int x = 0; bool const strip = !tty::out; while (in != text_.end()) { char32_t c = *in; if ('\n' == c || !is_control_code(c)) { *out = c; ++out; ++in; ++len; if ('\n' == c || ++x >= _screenColumns) { x = 0; ++_extraLines; _lastLinePosition = len; } } else if (c == '\x1b') { if ( strip ) { // jump over control chars ++in; if (*in == '[') { ++in; while ( ( in != text_.end() ) && ( ( *in == ';' ) || ( ( ( *in >= '0' ) && ( *in <= '9' ) ) ) ) ) { ++in; } if (*in == 'm') { ++in; } } } else { // copy control chars *out = *in; ++out; ++in; if (*in == '[') { *out = *in; ++out; ++in; while ( ( in != text_.end() ) && ( ( *in == ';' ) || ( ( ( *in >= '0' ) && ( *in <= '9' ) ) ) ) ) { *out = *in; ++out; ++in; } if (*in == 'm') { *out = *in; ++out; ++in; } } } } else { ++in; } } _characterCount = len; _byteCount = static_cast(out - _text.begin()); _indentation = len - _lastLinePosition; _cursorRowOffset = _extraLines; } // Used with DynamicPrompt (history search) // const UnicodeString forwardSearchBasePrompt("(i-search)`"); const UnicodeString reverseSearchBasePrompt("(reverse-i-search)`"); const UnicodeString endSearchBasePrompt("': "); UnicodeString previousSearchText; // remembered across invocations of replxx_input() DynamicPrompt::DynamicPrompt( Terminal& terminal_, int initialDirection ) : Prompt( terminal_ ) , _searchText() , _direction( initialDirection ) { update_screen_columns(); _cursorRowOffset = 0; const UnicodeString* basePrompt = (_direction > 0) ? &forwardSearchBasePrompt : &reverseSearchBasePrompt; size_t promptStartLength = basePrompt->length(); _characterCount = static_cast(promptStartLength + endSearchBasePrompt.length()); _byteCount = _characterCount; _lastLinePosition = _characterCount; // TODO fix this, we are asssuming // that the history prompt won't wrap (!) _previousLen = _characterCount; _text.assign( *basePrompt ).append( endSearchBasePrompt ); calculate_screen_position( 0, 0, screen_columns(), _characterCount, _indentation, _extraLines ); } void DynamicPrompt::updateSearchPrompt(void) { const UnicodeString* basePrompt = (_direction > 0) ? &forwardSearchBasePrompt : &reverseSearchBasePrompt; size_t promptStartLength = basePrompt->length(); _characterCount = static_cast(promptStartLength + _searchText.length() + endSearchBasePrompt.length()); _byteCount = _characterCount; _text.assign( *basePrompt ).append( _searchText ).append( endSearchBasePrompt ); } }