1 #ifdef _WIN32
2
3 #include <conio.h>
4 #include <windows.h>
5 #include <io.h>
6 #if _MSC_VER < 1900 && defined (_MSC_VER)
7 #define snprintf _snprintf // Microsoft headers use underscores in some names
8 #endif
9 #define strcasecmp _stricmp
10 #define strdup _strdup
11 #define write _write
12 #define STDIN_FILENO 0
13
14 #else /* _WIN32 */
15
16 #include <unistd.h>
17
18 #endif /* _WIN32 */
19
20 #include "prompt.hxx"
21 #include "util.hxx"
22
23 namespace replxx {
24
Prompt(Terminal & terminal_)25 Prompt::Prompt( Terminal& terminal_ )
26 : _extraLines( 0 )
27 , _lastLinePosition( 0 )
28 , _previousInputLen( 0 )
29 , _previousLen( 0 )
30 , _screenColumns( 0 )
31 , _terminal( terminal_ ) {
32 }
33
write()34 void Prompt::write() {
35 _terminal.write32( _text.get(), _byteCount );
36 }
37
update_screen_columns(void)38 void Prompt::update_screen_columns( void ) {
39 _screenColumns = _terminal.get_screen_columns();
40 }
41
set_text(UnicodeString const & text_)42 void Prompt::set_text( UnicodeString const& text_ ) {
43 _extraLines = 0;
44 _lastLinePosition = 0;
45 _previousInputLen = 0;
46 _previousLen = 0;
47 _screenColumns = 0;
48 update_screen_columns();
49 // strip control characters from the prompt -- we do allow newline
50 _text = text_;
51 UnicodeString::const_iterator in( text_.begin() );
52 UnicodeString::iterator out( _text.begin() );
53
54 int len = 0;
55 int x = 0;
56
57 bool const strip = !tty::out;
58
59 while (in != text_.end()) {
60 char32_t c = *in;
61 if ('\n' == c || !is_control_code(c)) {
62 *out = c;
63 ++out;
64 ++in;
65 ++len;
66 if ('\n' == c || ++x >= _screenColumns) {
67 x = 0;
68 ++_extraLines;
69 _lastLinePosition = len;
70 }
71 } else if (c == '\x1b') {
72 if ( strip ) {
73 // jump over control chars
74 ++in;
75 if (*in == '[') {
76 ++in;
77 while ( ( in != text_.end() ) && ( ( *in == ';' ) || ( ( ( *in >= '0' ) && ( *in <= '9' ) ) ) ) ) {
78 ++in;
79 }
80 if (*in == 'm') {
81 ++in;
82 }
83 }
84 } else {
85 // copy control chars
86 *out = *in;
87 ++out;
88 ++in;
89 if (*in == '[') {
90 *out = *in;
91 ++out;
92 ++in;
93 while ( ( in != text_.end() ) && ( ( *in == ';' ) || ( ( ( *in >= '0' ) && ( *in <= '9' ) ) ) ) ) {
94 *out = *in;
95 ++out;
96 ++in;
97 }
98 if (*in == 'm') {
99 *out = *in;
100 ++out;
101 ++in;
102 }
103 }
104 }
105 } else {
106 ++in;
107 }
108 }
109 _characterCount = len;
110 _byteCount = static_cast<int>(out - _text.begin());
111
112 _indentation = len - _lastLinePosition;
113 _cursorRowOffset = _extraLines;
114 }
115
116 // Used with DynamicPrompt (history search)
117 //
118 const UnicodeString forwardSearchBasePrompt("(i-search)`");
119 const UnicodeString reverseSearchBasePrompt("(reverse-i-search)`");
120 const UnicodeString endSearchBasePrompt("': ");
121
DynamicPrompt(Terminal & terminal_,int initialDirection)122 DynamicPrompt::DynamicPrompt( Terminal& terminal_, int initialDirection )
123 : Prompt( terminal_ )
124 , _searchText()
125 , _direction( initialDirection ) {
126 update_screen_columns();
127 _cursorRowOffset = 0;
128 const UnicodeString* basePrompt =
129 (_direction > 0) ? &forwardSearchBasePrompt : &reverseSearchBasePrompt;
130 size_t promptStartLength = basePrompt->length();
131 _characterCount = static_cast<int>(promptStartLength + endSearchBasePrompt.length());
132 _byteCount = _characterCount;
133 _lastLinePosition = _characterCount; // TODO fix this, we are asssuming
134 // that the history prompt won't wrap (!)
135 _previousLen = _characterCount;
136 _text.assign( *basePrompt ).append( endSearchBasePrompt );
137 calculate_screen_position(
138 0, 0, screen_columns(), _characterCount,
139 _indentation, _extraLines
140 );
141 }
142
updateSearchPrompt(void)143 void DynamicPrompt::updateSearchPrompt(void) {
144 const UnicodeString* basePrompt =
145 (_direction > 0) ? &forwardSearchBasePrompt : &reverseSearchBasePrompt;
146 size_t promptStartLength = basePrompt->length();
147 _characterCount = static_cast<int>(promptStartLength + _searchText.length() +
148 endSearchBasePrompt.length());
149 _byteCount = _characterCount;
150 _text.assign( *basePrompt ).append( _searchText ).append( endSearchBasePrompt );
151 }
152
153 }
154
155