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